Bitcoin Core  26.1.0
P2P Digital Currency
addressbooktests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2022 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 #include <qt/test/util.h>
8 
9 #include <interfaces/chain.h>
10 #include <interfaces/node.h>
11 #include <qt/addressbookpage.h>
12 #include <qt/clientmodel.h>
13 #include <qt/editaddressdialog.h>
14 #include <qt/optionsmodel.h>
15 #include <qt/platformstyle.h>
16 #include <qt/qvalidatedlineedit.h>
17 #include <qt/walletmodel.h>
18 
19 #include <key.h>
20 #include <key_io.h>
21 #include <wallet/wallet.h>
22 #include <wallet/test/util.h>
23 #include <walletinitinterface.h>
24 
25 #include <chrono>
26 
27 #include <QApplication>
28 #include <QLineEdit>
29 #include <QMessageBox>
30 #include <QTableView>
31 #include <QTimer>
32 
33 using wallet::AddWallet;
34 using wallet::CWallet;
39 
40 namespace
41 {
42 
47 void EditAddressAndSubmit(
48  EditAddressDialog* dialog,
49  const QString& label, const QString& address, QString expected_msg)
50 {
51  QString warning_text;
52 
53  dialog->findChild<QLineEdit*>("labelEdit")->setText(label);
54  dialog->findChild<QValidatedLineEdit*>("addressEdit")->setText(address);
55 
56  ConfirmMessage(&warning_text, 5ms);
57  dialog->accept();
58  QCOMPARE(warning_text, expected_msg);
59 }
60 
73 void TestAddAddressesToSendBook(interfaces::Node& node)
74 {
75  TestChain100Setup test;
76  auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
77  test.m_node.wallet_loader = wallet_loader.get();
78  node.setContext(&test.m_node);
79  const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockableWalletDatabase());
80  wallet->LoadWallet();
81  wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
82  {
83  LOCK(wallet->cs_wallet);
84  wallet->SetupDescriptorScriptPubKeyMans();
85  }
86 
87  auto build_address = [&wallet]() {
88  CKey key;
89  key.MakeNewKey(true);
91  key.GetPubKey(), wallet->m_default_address_type));
92 
93  return std::make_pair(dest, QString::fromStdString(EncodeDestination(dest)));
94  };
95 
96  CTxDestination r_key_dest, s_key_dest;
97 
98  // Add a preexisting "receive" entry in the address book.
99  QString preexisting_r_address;
100  QString r_label("already here (r)");
101 
102  // Add a preexisting "send" entry in the address book.
103  QString preexisting_s_address;
104  QString s_label("already here (s)");
105 
106  // Define a new address (which should add to the address book successfully).
107  QString new_address_a;
108  QString new_address_b;
109 
110  std::tie(r_key_dest, preexisting_r_address) = build_address();
111  std::tie(s_key_dest, preexisting_s_address) = build_address();
112  std::tie(std::ignore, new_address_a) = build_address();
113  std::tie(std::ignore, new_address_b) = build_address();
114 
115  {
116  LOCK(wallet->cs_wallet);
117  wallet->SetAddressBook(r_key_dest, r_label.toStdString(), wallet::AddressPurpose::RECEIVE);
118  wallet->SetAddressBook(s_key_dest, s_label.toStdString(), wallet::AddressPurpose::SEND);
119  }
120 
121  auto check_addbook_size = [&wallet](int expected_size) {
122  LOCK(wallet->cs_wallet);
123  QCOMPARE(static_cast<int>(wallet->m_address_book.size()), expected_size);
124  };
125 
126  // We should start with the two addresses we added earlier and nothing else.
127  check_addbook_size(2);
128 
129  // Initialize relevant QT models.
130  std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
131  OptionsModel optionsModel(node);
133  QVERIFY(optionsModel.Init(error));
134  ClientModel clientModel(node, &optionsModel);
135  WalletContext& context = *node.walletLoader().context();
137  WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get());
138  RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
140  editAddressDialog.setModel(walletModel.getAddressTableModel());
141 
142  AddressBookPage address_book{platformStyle.get(), AddressBookPage::ForEditing, AddressBookPage::SendingTab};
143  address_book.setModel(walletModel.getAddressTableModel());
144  auto table_view = address_book.findChild<QTableView*>("tableView");
145  QCOMPARE(table_view->model()->rowCount(), 1);
146 
147  EditAddressAndSubmit(
148  &editAddressDialog, QString("uhoh"), preexisting_r_address,
149  QString(
150  "Address \"%1\" already exists as a receiving address with label "
151  "\"%2\" and so cannot be added as a sending address."
152  ).arg(preexisting_r_address).arg(r_label));
153  check_addbook_size(2);
154  QCOMPARE(table_view->model()->rowCount(), 1);
155 
156  EditAddressAndSubmit(
157  &editAddressDialog, QString("uhoh, different"), preexisting_s_address,
158  QString(
159  "The entered address \"%1\" is already in the address book with "
160  "label \"%2\"."
161  ).arg(preexisting_s_address).arg(s_label));
162  check_addbook_size(2);
163  QCOMPARE(table_view->model()->rowCount(), 1);
164 
165  // Submit a new address which should add successfully - we expect the
166  // warning message to be blank.
167  EditAddressAndSubmit(
168  &editAddressDialog, QString("io - new A"), new_address_a, QString(""));
169  check_addbook_size(3);
170  QCOMPARE(table_view->model()->rowCount(), 2);
171 
172  EditAddressAndSubmit(
173  &editAddressDialog, QString("io - new B"), new_address_b, QString(""));
174  check_addbook_size(4);
175  QCOMPARE(table_view->model()->rowCount(), 3);
176 
177  auto search_line = address_book.findChild<QLineEdit*>("searchLineEdit");
178 
179  search_line->setText(r_label);
180  QCOMPARE(table_view->model()->rowCount(), 0);
181 
182  search_line->setText(s_label);
183  QCOMPARE(table_view->model()->rowCount(), 1);
184 
185  search_line->setText("io");
186  QCOMPARE(table_view->model()->rowCount(), 2);
187 
188  // Check wildcard "?".
189  search_line->setText("io?new");
190  QCOMPARE(table_view->model()->rowCount(), 0);
191  search_line->setText("io???new");
192  QCOMPARE(table_view->model()->rowCount(), 2);
193 
194  // Check wildcard "*".
195  search_line->setText("io*new");
196  QCOMPARE(table_view->model()->rowCount(), 2);
197  search_line->setText("*");
198  QCOMPARE(table_view->model()->rowCount(), 3);
199 
200  search_line->setText(preexisting_r_address);
201  QCOMPARE(table_view->model()->rowCount(), 0);
202 
203  search_line->setText(preexisting_s_address);
204  QCOMPARE(table_view->model()->rowCount(), 1);
205 
206  search_line->setText(new_address_a);
207  QCOMPARE(table_view->model()->rowCount(), 1);
208 
209  search_line->setText(new_address_b);
210  QCOMPARE(table_view->model()->rowCount(), 1);
211 
212  search_line->setText("");
213  QCOMPARE(table_view->model()->rowCount(), 3);
214 }
215 
216 } // namespace
217 
219 {
220 #ifdef Q_OS_MACOS
221  if (QApplication::platformName() == "minimal") {
222  // Disable for mac on "minimal" platform to avoid crashes inside the Qt
223  // framework when it tries to look up unimplemented cocoa functions,
224  // and fails to handle returned nulls
225  // (https://bugreports.qt.io/browse/QTBUG-49686).
226  QWARN("Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
227  "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.");
228  return;
229  }
230 #endif
231  TestAddAddressesToSendBook(m_node);
232 }
std::unique_ptr< interfaces::Chain > chain
Definition: context.h:63
Bilingual messages:
Definition: translation.h:18
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:188
std::unique_ptr< Wallet > MakeWallet(wallet::WalletContext &context, const std::shared_ptr< wallet::CWallet > &wallet)
Return implementation of Wallet interface.
Definition: interfaces.cpp:682
Open address book for editing.
Line edit that can be marked as "invalid" to show input validation feedback.
interfaces::Node & m_node
void ConfirmMessage(QString *text, std::chrono::milliseconds msec)
Press "Ok" button in message box dialog.
Definition: util.cpp:16
std::unique_ptr< WalletLoader > MakeWalletLoader(Chain &chain, ArgsManager &args)
Return implementation of ChainClient interface for a wallet loader.
Definition: dummywallet.cpp:63
#define LOCK(cs)
Definition: sync.h:258
ArgsManager * args
Definition: context.h:61
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:161
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
WalletContext context
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:300
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:98
Widget that shows a list of sending or receiving addresses.
Model for Bitcoin network client.
Definition: clientmodel.h:53
Definition: init.h:25
void accept() override
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:152
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:129
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:190
static const PlatformStyle * instantiate(const QString &platformId)
Get style associated with provided platform name, or 0 if not known.
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:40
bool error(const char *fmt, const Args &... args)
Definition: logging.h:262
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:51
Dialog for editing an address and associated information.
WalletContext struct containing references to state shared between CWallet instances, like the reference to the chain interface, and the list of opened wallets.
Definition: context.h:35
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
Definition: outputtype.cpp:50
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:287
An encapsulated private key.
Definition: key.h:32
std::shared_ptr< CWallet > wallet
interfaces::WalletLoader * wallet_loader
Reference to chain client that should used to load or create wallets opened by the gui...
Definition: context.h:68
node::NodeContext m_node
Definition: setup_common.h:50
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:69
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:140
#define Assert(val)
Identity function.
Definition: check.h:73