Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
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
6#include <qt/test/util.h>
7
9#include <interfaces/chain.h>
10#include <interfaces/node.h>
11#include <key_io.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>
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>
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
50using wallet::CWallet;
58
59namespace
60{
62void 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
78uint256 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
100QModelIndex 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
114void 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
139void 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.
151void 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
182void 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
192std::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);
198 wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
199 wallet->SetupLegacyScriptPubKeyMan();
200 // Add watched key
201 CPubKey pubKey = test.coinbaseKey.GetPubKey();
202 bool import_keys = wallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*internal=*/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
210std::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 std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false);
222 assert(desc);
223 WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
224 if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
225 CTxDestination dest = GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type);
226 wallet->SetAddressBook(dest, "", wallet::AddressPurpose::RECEIVE);
227 wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
228 SyncUpWallet(wallet, node);
229 wallet->SetBroadcastTransactions(true);
230 return wallet;
231}
232
233struct MiniGUI {
234public:
235 SendCoinsDialog sendCoinsDialog;
236 TransactionView transactionView;
237 OptionsModel optionsModel;
238 std::unique_ptr<ClientModel> clientModel;
239 std::unique_ptr<WalletModel> walletModel;
240
241 MiniGUI(interfaces::Node& node, const PlatformStyle* platformStyle) : sendCoinsDialog(platformStyle), transactionView(platformStyle), optionsModel(node) {
242 bilingual_str error;
243 QVERIFY(optionsModel.Init(error));
244 clientModel = std::make_unique<ClientModel>(node, &optionsModel);
245 }
246
247 void initModelForWallet(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet, const PlatformStyle* platformStyle)
248 {
249 WalletContext& context = *node.walletLoader().context();
250 AddWallet(context, wallet);
251 walletModel = std::make_unique<WalletModel>(interfaces::MakeWallet(context, wallet), *clientModel, platformStyle);
252 RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
253 sendCoinsDialog.setModel(walletModel.get());
254 transactionView.setModel(walletModel.get());
255 }
256
257};
258
260//
261// Test widgets can be debugged interactively calling show() on them and
262// manually running the event loop, e.g.:
263//
264// sendCoinsDialog.show();
265// QEventLoop().exec();
266//
267// This also requires overriding the default minimal Qt platform:
268//
269// QT_QPA_PLATFORM=xcb src/qt/test/test_bitcoin-qt # Linux
270// QT_QPA_PLATFORM=windows src/qt/test/test_bitcoin-qt # Windows
271// QT_QPA_PLATFORM=cocoa src/qt/test/test_bitcoin-qt # macOS
272void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
273{
274 // Create widgets for sending coins and listing transactions.
275 std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
276 MiniGUI mini_gui(node, platformStyle.get());
277 mini_gui.initModelForWallet(node, wallet, platformStyle.get());
278 WalletModel& walletModel = *mini_gui.walletModel;
279 SendCoinsDialog& sendCoinsDialog = mini_gui.sendCoinsDialog;
280 TransactionView& transactionView = mini_gui.transactionView;
281
282 // Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel.
283 walletModel.pollBalanceChanged();
284 // Check balance in send dialog
285 CompareBalance(walletModel, walletModel.wallet().getBalance(), sendCoinsDialog.findChild<QLabel*>("labelBalance"));
286
287 // Check 'UseAvailableBalance' functionality
288 VerifyUseAvailableBalance(sendCoinsDialog, walletModel);
289
290 // Send two transactions, and verify they are added to transaction list.
291 TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
292 QCOMPARE(transactionTableModel->rowCount({}), 105);
293 uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false);
294 uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true);
295 // Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
296 qApp->processEvents();
297 QCOMPARE(transactionTableModel->rowCount({}), 107);
298 QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
299 QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
300
301 // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
302 BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
303 BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
304 BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
305 BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);
306
307 // Check current balance on OverviewPage
308 OverviewPage overviewPage(platformStyle.get());
309 overviewPage.setWalletModel(&walletModel);
310 walletModel.pollBalanceChanged(); // Manual balance polling update
311 CompareBalance(walletModel, walletModel.wallet().getBalance(), overviewPage.findChild<QLabel*>("labelBalance"));
312
313 // Check Request Payment button
314 ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
315 receiveCoinsDialog.setModel(&walletModel);
316 RecentRequestsTableModel* requestTableModel = walletModel.getRecentRequestsTableModel();
317
318 // Label input
319 QLineEdit* labelInput = receiveCoinsDialog.findChild<QLineEdit*>("reqLabel");
320 labelInput->setText("TEST_LABEL_1");
321
322 // Amount input
323 BitcoinAmountField* amountInput = receiveCoinsDialog.findChild<BitcoinAmountField*>("reqAmount");
324 amountInput->setValue(1);
325
326 // Message input
327 QLineEdit* messageInput = receiveCoinsDialog.findChild<QLineEdit*>("reqMessage");
328 messageInput->setText("TEST_MESSAGE_1");
329 int initialRowCount = requestTableModel->rowCount({});
330 QPushButton* requestPaymentButton = receiveCoinsDialog.findChild<QPushButton*>("receiveButton");
331 requestPaymentButton->click();
332 QString address;
333 for (QWidget* widget : QApplication::topLevelWidgets()) {
334 if (widget->inherits("ReceiveRequestDialog")) {
335 ReceiveRequestDialog* receiveRequestDialog = qobject_cast<ReceiveRequestDialog*>(widget);
336 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("payment_header")->text(), QString("Payment information"));
337 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("uri_tag")->text(), QString("URI:"));
338 QString uri = receiveRequestDialog->QObject::findChild<QLabel*>("uri_content")->text();
339 QCOMPARE(uri.count("bitcoin:"), 2);
340 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("address_tag")->text(), QString("Address:"));
341 QVERIFY(address.isEmpty());
342 address = receiveRequestDialog->QObject::findChild<QLabel*>("address_content")->text();
343 QVERIFY(!address.isEmpty());
344
345 QCOMPARE(uri.count("amount=0.00000001"), 2);
346 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_tag")->text(), QString("Amount:"));
347 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_content")->text(), QString::fromStdString("0.00000001 " + CURRENCY_UNIT));
348
349 QCOMPARE(uri.count("label=TEST_LABEL_1"), 2);
350 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("label_tag")->text(), QString("Label:"));
351 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("label_content")->text(), QString("TEST_LABEL_1"));
352
353 QCOMPARE(uri.count("message=TEST_MESSAGE_1"), 2);
354 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("message_tag")->text(), QString("Message:"));
355 QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("message_content")->text(), QString("TEST_MESSAGE_1"));
356 }
357 }
358
359 // Clear button
360 QPushButton* clearButton = receiveCoinsDialog.findChild<QPushButton*>("clearButton");
361 clearButton->click();
362 QCOMPARE(labelInput->text(), QString(""));
363 QCOMPARE(amountInput->value(), CAmount(0));
364 QCOMPARE(messageInput->text(), QString(""));
365
366 // Check addition to history
367 int currentRowCount = requestTableModel->rowCount({});
368 QCOMPARE(currentRowCount, initialRowCount+1);
369
370 // Check addition to wallet
371 std::vector<std::string> requests = walletModel.wallet().getAddressReceiveRequests();
372 QCOMPARE(requests.size(), size_t{1});
373 RecentRequestEntry entry;
374 DataStream{MakeUCharSpan(requests[0])} >> entry;
375 QCOMPARE(entry.nVersion, int{1});
376 QCOMPARE(entry.id, int64_t{1});
377 QVERIFY(entry.date.isValid());
378 QCOMPARE(entry.recipient.address, address);
379 QCOMPARE(entry.recipient.label, QString{"TEST_LABEL_1"});
380 QCOMPARE(entry.recipient.amount, CAmount{1});
381 QCOMPARE(entry.recipient.message, QString{"TEST_MESSAGE_1"});
382 QCOMPARE(entry.recipient.sPaymentRequest, std::string{});
383 QCOMPARE(entry.recipient.authenticatedMerchant, QString{});
384
385 // Check Remove button
386 QTableView* table = receiveCoinsDialog.findChild<QTableView*>("recentRequestsView");
387 table->selectRow(currentRowCount-1);
388 QPushButton* removeRequestButton = receiveCoinsDialog.findChild<QPushButton*>("removeRequestButton");
389 removeRequestButton->click();
390 QCOMPARE(requestTableModel->rowCount({}), currentRowCount-1);
391
392 // Check removal from wallet
393 QCOMPARE(walletModel.wallet().getAddressReceiveRequests().size(), size_t{0});
394}
395
396void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test)
397{
398 const std::shared_ptr<CWallet>& wallet = SetupLegacyWatchOnlyWallet(node, test);
399
400 // Create widgets and init models
401 std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
402 MiniGUI mini_gui(node, platformStyle.get());
403 mini_gui.initModelForWallet(node, wallet, platformStyle.get());
404 WalletModel& walletModel = *mini_gui.walletModel;
405 SendCoinsDialog& sendCoinsDialog = mini_gui.sendCoinsDialog;
406
407 // Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel.
408 walletModel.pollBalanceChanged();
409 // Check balance in send dialog
410 CompareBalance(walletModel, walletModel.wallet().getBalances().watch_only_balance,
411 sendCoinsDialog.findChild<QLabel*>("labelBalance"));
412
413 // Set change address
415
416 // Time to reject "save" PSBT dialog ('SendCoins' locks the main thread until the dialog receives the event).
417 QTimer timer;
418 timer.setInterval(500);
419 QObject::connect(&timer, &QTimer::timeout, [&](){
420 for (QWidget* widget : QApplication::topLevelWidgets()) {
421 if (widget->inherits("QMessageBox") && widget->objectName().compare("psbt_copied_message") == 0) {
422 QMessageBox* dialog = qobject_cast<QMessageBox*>(widget);
423 QAbstractButton* button = dialog->button(QMessageBox::Discard);
424 button->setEnabled(true);
425 button->click();
426 timer.stop();
427 break;
428 }
429 }
430 });
431 timer.start(500);
432
433 // Send tx and verify PSBT copied to the clipboard.
434 SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false, QMessageBox::Save);
435 const std::string& psbt_string = QApplication::clipboard()->text().toStdString();
436 QVERIFY(!psbt_string.empty());
437
438 // Decode psbt
439 std::optional<std::vector<unsigned char>> decoded_psbt = DecodeBase64(psbt_string);
440 QVERIFY(decoded_psbt);
442 std::string err;
443 QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
444}
445
446void TestGUI(interfaces::Node& node)
447{
448 // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
450 for (int i = 0; i < 5; ++i) {
452 }
453 auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
454 test.m_node.wallet_loader = wallet_loader.get();
455 node.setContext(&test.m_node);
456
457 // "Full" GUI tests, use descriptor wallet
458 const std::shared_ptr<CWallet>& desc_wallet = SetupDescriptorsWallet(node, test);
459 TestGUI(node, desc_wallet);
460
461 // Legacy watch-only wallet test
462 // Verify PSBT creation.
463 TestGUIWatchOnly(node, test);
464}
465
466} // namespace
467
469{
470#ifdef Q_OS_MACOS
471 if (QApplication::platformName() == "minimal") {
472 // Disable for mac on "minimal" platform to avoid crashes inside the Qt
473 // framework when it tries to look up unimplemented cocoa functions,
474 // and fails to handle returned nulls
475 // (https://bugreports.qt.io/browse/QTBUG-49686).
476 QWARN("Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
477 "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.");
478 return;
479 }
480#endif
481 TestGUI(m_node);
482}
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
int64_t CAmount
Amount in satoshis (Can be negative)
Definition amount.h:12
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition amount.h:15
const CChainParams & Params()
Return the currently selected parameters.
#define Assert(val)
Identity function.
Definition check.h:77
Widget for entering bitcoin amounts.
void setValue(const CAmount &value)
static QString formatWithUnit(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
Unit
Bitcoin units.
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition key.cpp:182
An encapsulated public key.
Definition pubkey.h:34
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition pubkey.h:164
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:147
Interface from Qt to configuration data structure for Bitcoin client.
bool Init(bilingual_str &error)
BitcoinUnit getDisplayUnit() const
Overview ("home") page widget.
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.
Dialog for requesting payment of bitcoins.
int64_t id
SendCoinsRecipient recipient
int nVersion
QDateTime date
Model for list of recently generated payment requests / bitcoin: URIs.
int rowCount(const QModelIndex &parent) const override
Dialog for sending bitcoins.
void setModel(WalletModel *model)
wallet::CCoinControl * getCoinControl()
A single entry in the dialog for sending bitcoins.
void useAvailableBalance(SendCoinsEntry *entry)
SendCoinsRecipient getValue()
UI model for the transaction table of a wallet.
@ TxHashRole
Transaction hash.
int rowCount(const QModelIndex &parent) const override
Widget showing the transaction list for a wallet, including a filter row.
void setModel(WalletModel *model)
QTableView * transactionView
Interface to Bitcoin wallet from Qt view code.
Definition walletmodel.h:48
RecentRequestsTableModel * getRecentRequestsTableModel() const
void pollBalanceChanged()
TransactionTableModel * getTransactionTableModel() const
interfaces::Wallet & wallet() const
OptionsModel * getOptionsModel() const
interfaces::WalletBalances getCachedBalance() const
void walletTests()
interfaces::Node & m_node
Definition wallettests.h:19
std::string ToString() const
Definition uint256.cpp:47
Top-level interface for a bitcoin node (bitcoind process).
Definition node.h:70
virtual CoinsList listCoins()=0
virtual CAmount getBalance()=0
Get balance.
virtual WalletBalances getBalances()=0
Get balances.
virtual std::vector< std::string > getAddressReceiveRequests()=0
Get receive requests.
256-bit opaque blob.
Definition uint256.h:178
PreselectedInput & Select(const COutPoint &outpoint)
Lock-in the given output for spending.
CTxDestination destChange
Custom change destination, if not set an address is generated.
Definition coincontrol.h:84
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition wallet.h:300
Descriptor with some wallet metadata.
Definition walletutil.h:85
RAII object to check and reserve a wallet rescan.
Definition wallet.h:1073
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition client.cpp:321
const std::string CURRENCY_UNIT
Definition feerate.h:17
std::string EncodeSecret(const CKey &key)
Definition key_io.cpp:231
std::string EncodeDestination(const CTxDestination &dest)
Definition key_io.cpp:291
std::unique_ptr< WalletLoader > MakeWalletLoader(Chain &chain, ArgsManager &args)
Return implementation of ChainClient interface for a wallet loader.
std::unique_ptr< Wallet > MakeWallet(wallet::WalletContext &context, const std::shared_ptr< wallet::CWallet > &wallet)
Return implementation of Wallet interface.
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition util.cpp:185
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition wallet.cpp:149
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition walletutil.h:74
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition walletutil.h:51
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
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
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
void ConfirmMessage(QString *text, std::chrono::milliseconds msec)
Press "Ok" button in message box dialog.
Definition util.cpp:16
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition solver.cpp:213
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition span.h:277
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(Span{std::forward< V >(v)}))
Like the Span constructor, but for (const) unsigned char member types only.
Definition span.h:304
node::NodeContext m_node
A version of CTransaction with the PSBT format.
Definition psbt.h:951
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
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...
Bilingual messages:
Definition translation.h:18
ArgsManager * args
Definition context.h:71
interfaces::WalletLoader * wallet_loader
Definition context.h:79
std::unique_ptr< interfaces::Chain > chain
Definition context.h:73
WalletContext struct containing references to state shared between CWallet instances,...
Definition context.h:36
#define LOCK(cs)
Definition sync.h:257
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition sync.h:301
ChangeType
General change type (added, updated, removed).
std::optional< std::vector< unsigned char > > DecodeBase64(std::string_view str)
assert(!tx.IsCoinBase())