Bitcoin Core  26.99.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::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:131
#define Assert(val)
Identity function.
Definition: check.h:77
Widget that shows a list of sending or receiving addresses.
@ ForEditing
Open address book for editing.
interfaces::Node & m_node
An encapsulated private key.
Definition: key.h:33
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:161
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:188
Model for Bitcoin network client.
Definition: clientmodel.h:54
Dialog for editing an address and associated information.
void accept() override
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:41
static const PlatformStyle * instantiate(const QString &platformId)
Get style associated with provided platform name, or 0 if not known.
Line edit that can be marked as "invalid" to show input validation feedback.
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:52
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:70
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:301
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:287
bool error(const char *fmt, const Args &... args)
Definition: logging.h:262
std::unique_ptr< WalletLoader > MakeWalletLoader(Chain &chain, ArgsManager &args)
Return implementation of ChainClient interface for a wallet loader.
Definition: dummywallet.cpp:63
std::unique_ptr< Wallet > MakeWallet(wallet::WalletContext &context, const std::shared_ptr< wallet::CWallet > &wallet)
Return implementation of Wallet interface.
Definition: interfaces.cpp:688
Definition: init.h:25
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:190
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:140
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
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::shared_ptr< CWallet > wallet
WalletContext context
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
Definition: outputtype.cpp:50
void ConfirmMessage(QString *text, std::chrono::milliseconds msec)
Press "Ok" button in message box dialog.
Definition: util.cpp:16
node::NodeContext m_node
Definition: setup_common.h:50
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:98
Bilingual messages:
Definition: translation.h:18
ArgsManager * args
Definition: context.h:61
interfaces::WalletLoader * wallet_loader
Reference to chain client that should used to load or create wallets opened by the gui.
Definition: context.h:68
std::unique_ptr< interfaces::Chain > chain
Definition: context.h:63
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:36
#define LOCK(cs)
Definition: sync.h:257