Bitcoin Core  29.1.0
P2P Digital Currency
wallettests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2015-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 
5 #include <qt/test/wallettests.h>
6 #include <qt/test/util.h>
7 
8 #include <wallet/coincontrol.h>
9 #include <interfaces/chain.h>
10 #include <interfaces/node.h>
11 #include <key_io.h>
12 #include <qt/bitcoinamountfield.h>
13 #include <qt/bitcoinunits.h>
14 #include <qt/clientmodel.h>
15 #include <qt/optionsmodel.h>
16 #include <qt/overviewpage.h>
17 #include <qt/platformstyle.h>
18 #include <qt/qvalidatedlineedit.h>
19 #include <qt/receivecoinsdialog.h>
22 #include <qt/sendcoinsdialog.h>
23 #include <qt/sendcoinsentry.h>
25 #include <qt/transactionview.h>
26 #include <qt/walletmodel.h>
27 #include <script/solver.h>
28 #include <test/util/setup_common.h>
29 #include <validation.h>
30 #include <wallet/test/util.h>
31 #include <wallet/wallet.h>
32 
33 #include <chrono>
34 #include <memory>
35 
36 #include <QAbstractButton>
37 #include <QAction>
38 #include <QApplication>
39 #include <QCheckBox>
40 #include <QClipboard>
41 #include <QObject>
42 #include <QPushButton>
43 #include <QTimer>
44 #include <QVBoxLayout>
45 #include <QTextEdit>
46 #include <QListView>
47 #include <QDialogButtonBox>
48 
49 using wallet::AddWallet;
50 using wallet::CWallet;
58 
59 namespace
60 {
62 void ConfirmSend(QString* text = nullptr, QMessageBox::StandardButton confirm_type = QMessageBox::Yes)
63 {
64  QTimer::singleShot(0, [text, confirm_type]() {
65  for (QWidget* widget : QApplication::topLevelWidgets()) {
66  if (widget->inherits("SendConfirmationDialog")) {
67  SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
68  if (text) *text = dialog->text();
69  QAbstractButton* button = dialog->button(confirm_type);
70  button->setEnabled(true);
71  button->click();
72  }
73  }
74  });
75 }
76 
78 uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf,
79  QMessageBox::StandardButton confirm_type = QMessageBox::Yes)
80 {
81  QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
82  SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
83  entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
84  entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
85  sendCoinsDialog.findChild<QFrame*>("frameFee")
86  ->findChild<QFrame*>("frameFeeSelection")
87  ->findChild<QCheckBox*>("optInRBF")
88  ->setCheckState(rbf ? Qt::Checked : Qt::Unchecked);
89  uint256 txid;
90  boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const uint256& hash, ChangeType status) {
91  if (status == CT_NEW) txid = hash;
92  }));
93  ConfirmSend(/*text=*/nullptr, confirm_type);
94  bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false));
95  assert(invoked);
96  return txid;
97 }
98 
100 QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
101 {
102  QString hash = QString::fromStdString(txid.ToString());
103  int rows = model.rowCount({});
104  for (int row = 0; row < rows; ++row) {
105  QModelIndex index = model.index(row, 0, {});
106  if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
107  return index;
108  }
109  }
110  return {};
111 }
112 
114 void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
115 {
116  QTableView* table = view.findChild<QTableView*>("transactionView");
117  QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
118  QVERIFY2(index.isValid(), "Could not find BumpFee txid");
119 
120  // Select row in table, invoke context menu, and make sure bumpfee action is
121  // enabled or disabled as expected.
122  QAction* action = view.findChild<QAction*>("bumpFeeAction");
123  table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
124  action->setEnabled(expectDisabled);
125  table->customContextMenuRequested({});
126  QCOMPARE(action->isEnabled(), !expectDisabled);
127 
128  action->setEnabled(true);
129  QString text;
130  if (expectError.empty()) {
131  ConfirmSend(&text, cancel ? QMessageBox::Cancel : QMessageBox::Yes);
132  } else {
133  ConfirmMessage(&text, 0ms);
134  }
135  action->trigger();
136  QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
137 }
138 
139 void CompareBalance(WalletModel& walletModel, CAmount expected_balance, QLabel* balance_label_to_check)
140 {
141  BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit();
142  QString balanceComparison = BitcoinUnits::formatWithUnit(unit, expected_balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
143  QCOMPARE(balance_label_to_check->text().trimmed(), balanceComparison);
144 }
145 
146 // Verify the 'useAvailableBalance' functionality. With and without manually selected coins.
147 // Case 1: No coin control selected coins.
148 // 'useAvailableBalance' should fill the amount edit box with the total available balance
149 // Case 2: With coin control selected coins.
150 // 'useAvailableBalance' should fill the amount edit box with the sum of the selected coins values.
151 void VerifyUseAvailableBalance(SendCoinsDialog& sendCoinsDialog, const WalletModel& walletModel)
152 {
153  // Verify first entry amount and "useAvailableBalance" button
154  QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
155  QVERIFY(entries->count() == 1); // only one entry
156  SendCoinsEntry* send_entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
157  QVERIFY(send_entry->getValue().amount == 0);
158  // Now click "useAvailableBalance", check updated balance (the entire wallet balance should be set)
159  Q_EMIT send_entry->useAvailableBalance(send_entry);
160  QVERIFY(send_entry->getValue().amount == walletModel.getCachedBalance().balance);
161 
162  // Now manually select two coins and click on "useAvailableBalance". Then check updated balance
163  // (only the sum of the selected coins should be set).
164  int COINS_TO_SELECT = 2;
165  auto coins = walletModel.wallet().listCoins();
166  CAmount sum_selected_coins = 0;
167  int selected = 0;
168  QVERIFY(coins.size() == 1); // context check, coins received only on one destination
169  for (const auto& [outpoint, tx_out] : coins.begin()->second) {
170  sendCoinsDialog.getCoinControl()->Select(outpoint);
171  sum_selected_coins += tx_out.txout.nValue;
172  if (++selected == COINS_TO_SELECT) break;
173  }
174  QVERIFY(selected == COINS_TO_SELECT);
175 
176  // Now that we have 2 coins selected, "useAvailableBalance" should update the balance label only with
177  // the sum of them.
178  Q_EMIT send_entry->useAvailableBalance(send_entry);
179  QVERIFY(send_entry->getValue().amount == sum_selected_coins);
180 }
181 
182 void SyncUpWallet(const std::shared_ptr<CWallet>& wallet, interfaces::Node& node)
183 {
184  WalletRescanReserver reserver(*wallet);
185  reserver.reserve();
186  CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/false);
187  QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
188  QCOMPARE(result.last_scanned_block, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
189  QVERIFY(result.last_failed_block.IsNull());
190 }
191 
192 std::shared_ptr<CWallet> SetupLegacyWatchOnlyWallet(interfaces::Node& node, TestChain100Setup& test)
193 {
194  std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockableWalletDatabase());
195  wallet->LoadWallet();
196  {
197  LOCK(wallet->cs_wallet);
199  wallet->SetupLegacyScriptPubKeyMan();
200  // Add watched key
201  CPubKey pubKey = test.coinbaseKey.GetPubKey();
202  bool import_keys = wallet->ImportPubKeys({{pubKey.GetID(), false}}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*timestamp=*/1);
203  assert(import_keys);
204  wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
205  }
206  SyncUpWallet(wallet, node);
207  return wallet;
208 }
209 
210 std::shared_ptr<CWallet> SetupDescriptorsWallet(interfaces::Node& node, TestChain100Setup& test)
211 {
212  std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockableWalletDatabase());
213  wallet->LoadWallet();
214  LOCK(wallet->cs_wallet);
215  wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
216  wallet->SetupDescriptorScriptPubKeyMans();
217 
218  // Add the coinbase key
219  FlatSigningProvider provider;
220  std::string error;
221  auto descs = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false);
222  assert(!descs.empty());
223  assert(descs.size() == 1);
224  auto& desc = descs.at(0);
225  WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
226  if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
227  CTxDestination dest = GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type);
228  wallet->SetAddressBook(dest, "", wallet::AddressPurpose::RECEIVE);
229  wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
230  SyncUpWallet(wallet, node);
231  wallet->SetBroadcastTransactions(true);
232  return wallet;
233 }
234 
235 struct MiniGUI {
236 public:
237  SendCoinsDialog sendCoinsDialog;
238  TransactionView transactionView;
239  OptionsModel optionsModel;
240  std::unique_ptr<ClientModel> clientModel;
241  std::unique_ptr<WalletModel> walletModel;
242 
243  MiniGUI(interfaces::Node& node, const PlatformStyle* platformStyle) : sendCoinsDialog(platformStyle), transactionView(platformStyle), optionsModel(node) {
244  bilingual_str error;
245  QVERIFY(optionsModel.Init(error));
246  clientModel = std::make_unique<ClientModel>(node, &optionsModel);
247  }
248 
249  void initModelForWallet(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet, const PlatformStyle* platformStyle)
250  {
251  WalletContext& context = *node.walletLoader().context();
252  AddWallet(context, wallet);
253  walletModel = std::make_unique<WalletModel>(interfaces::MakeWallet(context, wallet), *clientModel, platformStyle);
254  RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
255  sendCoinsDialog.setModel(walletModel.get());
256  transactionView.setModel(walletModel.get());
257  }
258 
259 };
260 
262 //
263 // Test widgets can be debugged interactively calling show() on them and
264 // manually running the event loop, e.g.:
265 //
266 // sendCoinsDialog.show();
267 // QEventLoop().exec();
268 //
269 // This also requires overriding the default minimal Qt platform:
270 //
271 // QT_QPA_PLATFORM=xcb build/bin/test_bitcoin-qt # Linux
272 // QT_QPA_PLATFORM=windows build/bin/test_bitcoin-qt # Windows
273 // QT_QPA_PLATFORM=cocoa build/bin/test_bitcoin-qt # macOS
274 void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
275 {
276  // Create widgets for sending coins and listing transactions.
277  std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
278  MiniGUI mini_gui(node, platformStyle.get());
279  mini_gui.initModelForWallet(node, wallet, platformStyle.get());
280  WalletModel& walletModel = *mini_gui.walletModel;
281  SendCoinsDialog& sendCoinsDialog = mini_gui.sendCoinsDialog;
282  TransactionView& transactionView = mini_gui.transactionView;
283 
284  // Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel.
285  walletModel.pollBalanceChanged();
286  // Check balance in send dialog
287  CompareBalance(walletModel, walletModel.wallet().getBalance(), sendCoinsDialog.findChild<QLabel*>("labelBalance"));
288 
289  // Check 'UseAvailableBalance' functionality
290  VerifyUseAvailableBalance(sendCoinsDialog, walletModel);
291 
292  // Send two transactions, and verify they are added to transaction list.
293  TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
294  QCOMPARE(transactionTableModel->rowCount({}), 105);
295  uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false);
296  uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true);
297  // Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
298  qApp->processEvents();
299  QCOMPARE(transactionTableModel->rowCount({}), 107);
300  QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
301  QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
302 
303  // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
304  BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
305  BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
306  BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
307  BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);
308 
309  // Check current balance on OverviewPage
310  OverviewPage overviewPage(platformStyle.get());
311  overviewPage.setWalletModel(&walletModel);
312  walletModel.pollBalanceChanged(); // Manual balance polling update
313  CompareBalance(walletModel, walletModel.wallet().getBalance(), overviewPage.findChild<QLabel*>("labelBalance"));
314 
315  // Check Request Payment button
316  ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
317  receiveCoinsDialog.setModel(&walletModel);
318  RecentRequestsTableModel* requestTableModel = walletModel.getRecentRequestsTableModel();
319 
320  // Label input
321  QLineEdit* labelInput = receiveCoinsDialog.findChild<QLineEdit*>("reqLabel");
322  labelInput->setText("TEST_LABEL_1");
323 
324  // Amount input
325  BitcoinAmountField* amountInput = receiveCoinsDialog.findChild<BitcoinAmountField*>("reqAmount");
326  amountInput->setValue(1);
327 
328  // Message input
329  QLineEdit* messageInput = receiveCoinsDialog.findChild<QLineEdit*>("reqMessage");
330  messageInput->setText("TEST_MESSAGE_1");
331  int initialRowCount = requestTableModel->rowCount({});
332  QPushButton* requestPaymentButton = receiveCoinsDialog.findChild<QPushButton*>("receiveButton");
333  requestPaymentButton->click();
334  QString address;
335  for (QWidget* widget : QApplication::topLevelWidgets()) {
336  if (widget->inherits("ReceiveRequestDialog")) {
337  ReceiveRequestDialog* receiveRequestDialog = qobject_cast<ReceiveRequestDialog*>(widget);
338  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("payment_header")->text(), QString("Payment information"));
339  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("uri_tag")->text(), QString("URI:"));
340  QString uri = receiveRequestDialog->QObject::findChild<QLabel*>("uri_content")->text();
341  QCOMPARE(uri.count("bitcoin:"), 2);
342  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("address_tag")->text(), QString("Address:"));
343  QVERIFY(address.isEmpty());
344  address = receiveRequestDialog->QObject::findChild<QLabel*>("address_content")->text();
345  QVERIFY(!address.isEmpty());
346 
347  QCOMPARE(uri.count("amount=0.00000001"), 2);
348  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_tag")->text(), QString("Amount:"));
349  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_content")->text(), QString::fromStdString("0.00000001 " + CURRENCY_UNIT));
350 
351  QCOMPARE(uri.count("label=TEST_LABEL_1"), 2);
352  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("label_tag")->text(), QString("Label:"));
353  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("label_content")->text(), QString("TEST_LABEL_1"));
354 
355  QCOMPARE(uri.count("message=TEST_MESSAGE_1"), 2);
356  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("message_tag")->text(), QString("Message:"));
357  QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("message_content")->text(), QString("TEST_MESSAGE_1"));
358  }
359  }
360 
361  // Clear button
362  QPushButton* clearButton = receiveCoinsDialog.findChild<QPushButton*>("clearButton");
363  clearButton->click();
364  QCOMPARE(labelInput->text(), QString(""));
365  QCOMPARE(amountInput->value(), CAmount(0));
366  QCOMPARE(messageInput->text(), QString(""));
367 
368  // Check addition to history
369  int currentRowCount = requestTableModel->rowCount({});
370  QCOMPARE(currentRowCount, initialRowCount+1);
371 
372  // Check addition to wallet
373  std::vector<std::string> requests = walletModel.wallet().getAddressReceiveRequests();
374  QCOMPARE(requests.size(), size_t{1});
375  RecentRequestEntry entry;
376  DataStream{MakeUCharSpan(requests[0])} >> entry;
377  QCOMPARE(entry.nVersion, int{1});
378  QCOMPARE(entry.id, int64_t{1});
379  QVERIFY(entry.date.isValid());
380  QCOMPARE(entry.recipient.address, address);
381  QCOMPARE(entry.recipient.label, QString{"TEST_LABEL_1"});
382  QCOMPARE(entry.recipient.amount, CAmount{1});
383  QCOMPARE(entry.recipient.message, QString{"TEST_MESSAGE_1"});
384  QCOMPARE(entry.recipient.sPaymentRequest, std::string{});
385  QCOMPARE(entry.recipient.authenticatedMerchant, QString{});
386 
387  // Check Remove button
388  QTableView* table = receiveCoinsDialog.findChild<QTableView*>("recentRequestsView");
389  table->selectRow(currentRowCount-1);
390  QPushButton* removeRequestButton = receiveCoinsDialog.findChild<QPushButton*>("removeRequestButton");
391  removeRequestButton->click();
392  QCOMPARE(requestTableModel->rowCount({}), currentRowCount-1);
393 
394  // Check removal from wallet
395  QCOMPARE(walletModel.wallet().getAddressReceiveRequests().size(), size_t{0});
396 }
397 
398 void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test)
399 {
400  const std::shared_ptr<CWallet>& wallet = SetupLegacyWatchOnlyWallet(node, test);
401 
402  // Create widgets and init models
403  std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
404  MiniGUI mini_gui(node, platformStyle.get());
405  mini_gui.initModelForWallet(node, wallet, platformStyle.get());
406  WalletModel& walletModel = *mini_gui.walletModel;
407  SendCoinsDialog& sendCoinsDialog = mini_gui.sendCoinsDialog;
408 
409  // Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel.
410  walletModel.pollBalanceChanged();
411  // Check balance in send dialog
412  CompareBalance(walletModel, walletModel.wallet().getBalances().watch_only_balance,
413  sendCoinsDialog.findChild<QLabel*>("labelBalance"));
414 
415  // Set change address
417 
418  // Time to reject "save" PSBT dialog ('SendCoins' locks the main thread until the dialog receives the event).
419  QTimer timer;
420  timer.setInterval(500);
421  QObject::connect(&timer, &QTimer::timeout, [&](){
422  for (QWidget* widget : QApplication::topLevelWidgets()) {
423  if (widget->inherits("QMessageBox") && widget->objectName().compare("psbt_copied_message") == 0) {
424  QMessageBox* dialog = qobject_cast<QMessageBox*>(widget);
425  QAbstractButton* button = dialog->button(QMessageBox::Discard);
426  button->setEnabled(true);
427  button->click();
428  timer.stop();
429  break;
430  }
431  }
432  });
433  timer.start(500);
434 
435  // Send tx and verify PSBT copied to the clipboard.
436  SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false, QMessageBox::Save);
437  const std::string& psbt_string = QApplication::clipboard()->text().toStdString();
438  QVERIFY(!psbt_string.empty());
439 
440  // Decode psbt
441  std::optional<std::vector<unsigned char>> decoded_psbt = DecodeBase64(psbt_string);
442  QVERIFY(decoded_psbt);
444  std::string err;
445  QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
446 }
447 
448 void TestGUI(interfaces::Node& node)
449 {
450  // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
451  TestChain100Setup test;
452  for (int i = 0; i < 5; ++i) {
454  }
455  auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
456  test.m_node.wallet_loader = wallet_loader.get();
457  node.setContext(&test.m_node);
458 
459  // "Full" GUI tests, use descriptor wallet
460  const std::shared_ptr<CWallet>& desc_wallet = SetupDescriptorsWallet(node, test);
461  TestGUI(node, desc_wallet);
462 
463  // Legacy watch-only wallet test
464  // Verify PSBT creation.
465  TestGUIWatchOnly(node, test);
466 }
467 
468 } // namespace
469 
471 {
472 #ifdef Q_OS_MACOS
473  if (QApplication::platformName() == "minimal") {
474  // Disable for mac on "minimal" platform to avoid crashes inside the Qt
475  // framework when it tries to look up unimplemented cocoa functions,
476  // and fails to handle returned nulls
477  // (https://bugreports.qt.io/browse/QTBUG-49686).
478  qWarning() << "Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
479  "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.";
480  return;
481  }
482 #endif
483  TestGUI(m_node);
484 }
Widget for entering bitcoin amounts.
std::unique_ptr< interfaces::Chain > chain
Definition: context.h:76
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:327
Model for list of recently generated payment requests / bitcoin: URIs.
virtual CoinsList listCoins()=0
Dialog for requesting payment of bitcoins.
OptionsModel * getOptionsModel() const
void setWalletModel(WalletModel *walletModel)
Unit
Bitcoin units.
Definition: bitcoinunits.h:42
interfaces::Wallet & wallet() const
Definition: walletmodel.h:138
assert(!tx.IsCoinBase())
Bilingual messages:
Definition: translation.h:24
CTxDestination destChange
Custom change destination, if not set an address is generated.
Definition: coincontrol.h:84
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:182
wallet::CCoinControl * getCoinControl()
interfaces::WalletBalances getCachedBalance() const
TransactionTableModel * getTransactionTableModel() const
BitcoinUnit getDisplayUnit() const
Definition: optionsmodel.h:103
std::unique_ptr< Wallet > MakeWallet(wallet::WalletContext &context, const std::shared_ptr< wallet::CWallet > &wallet)
Return implementation of Wallet interface.
Definition: interfaces.cpp:705
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1081
A version of CTransaction with the PSBT format.
Definition: psbt.h:950
QTableView * transactionView
Line edit that can be marked as "invalid" to show input validation feedback.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:164
A single entry in the dialog for sending bitcoins.
int rowCount(const QModelIndex &parent) const override
static QString formatWithUnit(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
bool Init(bilingual_str &error)
void ConfirmMessage(QString *text, std::chrono::milliseconds msec)
Press "Ok" button in message box dialog.
Definition: util.cpp:16
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
void setModel(WalletModel *model)
std::unique_ptr< WalletLoader > MakeWalletLoader(Chain &chain, ArgsManager &args)
Return implementation of ChainClient interface for a wallet loader.
Definition: dummywallet.cpp:64
RecentRequestsTableModel * getRecentRequestsTableModel() const
CBlock CreateAndProcessBlock(const std::vector< CMutableTransaction > &txns, const CScript &scriptPubKey, Chainstate *chainstate=nullptr)
Create a new block with just given transactions, coinbase paying to scriptPubKey, and try to add it t...
#define LOCK(cs)
Definition: sync.h:257
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:146
std::optional< std::vector< unsigned char > > DecodeBase64(std::string_view str)
ArgsManager * args
Definition: context.h:74
An encapsulated public key.
Definition: pubkey.h:33
void walletTests()
Widget showing the transaction list for a wallet, including a filter row.
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
Dialog for sending bitcoins.
const std::string CURRENCY_UNIT
Definition: feerate.h:17
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:299
std::string ToString() const
Definition: uint256.cpp:47
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:140
UI model for the transaction table of a wallet.
void setModel(WalletModel *model)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:301
Descriptor with some wallet metadata.
Definition: walletutil.h:84
Definition: messages.h:20
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:161
interfaces::Node & m_node
Definition: wallettests.h:19
int rowCount(const QModelIndex &parent) const override
256-bit opaque blob.
Definition: uint256.h:201
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:186
void setModel(WalletModel *model)
auto result
Definition: common-types.h:74
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:42
const CChainParams & Params()
Return the currently selected parameters.
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:47
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:140
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition: span.h:269
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:36
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(Span
Like the Span constructor, but for (const) unsigned char member types only.
Definition: span.h:296
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 useAvailableBalance(SendCoinsEntry *entry)
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:294
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: solver.cpp:213
virtual CAmount getBalance()=0
Get balance.
virtual std::vector< std::string > getAddressReceiveRequests()=0
Get receive requests.
virtual WalletBalances getBalances()=0
Get balances.
ChangeType
General change type (added, updated, removed).
Definition: ui_change_type.h:9
bool DecodeRawPSBT(PartiallySignedTransaction &psbt, Span< const std::byte > tx_data, std::string &error)
Decode a raw (binary blob) PSBT into a PartiallySignedTransaction.
Definition: psbt.cpp:546
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:231
interfaces::WalletLoader * wallet_loader
Definition: context.h:82
node::NodeContext m_node
Definition: setup_common.h:66
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:70
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:149
Overview ("home") page widget.
Definition: overviewpage.h:28
void setValue(const CAmount &value)
PreselectedInput & Select(const COutPoint &outpoint)
Lock-in the given output for spending.
Definition: coincontrol.cpp:40
#define Assert(val)
Identity function.
Definition: check.h:85
void pollBalanceChanged()
Definition: walletmodel.cpp:90
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition: amount.h:15