From e4774b9dad2fa7cbc59cdd57a83eed81e84d75f1 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 26 Aug 2021 22:49:27 +0300 Subject: [PATCH 01/14] Merge bitcoin-core/gui#384: Add copy IP/Netmask action for banned peer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ab1461d5d36b70fd4982679ac6143c25e7617dbf qt: Add copy IP/Netmask action for banned peer (Shashwat) Pull request description: This PR adds a Copy IP/Netmask context menu action to the Banned Peers Table. This feature is helpful if a node using GUI might want to alert its peer about a particular malicious user. So it can copy that user’s IP/Netmask and broadcast it to its peers so they can ban it instantly using the setban command in the console. | Master | PR | | ----------- | ----------- | | ![Screenshot_from_2021-07-21_00-01-331](https://user-images.githubusercontent.com/23396902/126377808-bd23bb19-3f47-4f1b-8371-39baa9747bbe.png) | ![Screenshot from 2021-08-20 20-13-28(1)(1)](https://user-images.githubusercontent.com/85434418/130251441-a8d0f816-a2e9-4e63-a22d-94885c5cec98.png) | ACKs for top commit: jarolrod: re-ACK ab1461d hebasto: re-ACK ab1461d5d36b70fd4982679ac6143c25e7617dbf, tested on Linux Mint 20.2 (Qt 5.12.8). Tree-SHA512: a528f089bd4cb5b51fec987550d21c2587459ad80f854b55850bc62c776c21f3fa31052a17e2b0e9e9d0b3468799c8070ed306543730fb7b324f283847151e17 --- src/qt/rpcconsole.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index b76b05bced..ab15df60c9 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -744,6 +744,13 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ // create ban table context menu banTableContextMenu = new QMenu(this); + /*: Context menu action to copy the IP/Netmask of a banned peer. + IP/Netmask is the combination of a peer's IP address and its Netmask. + For IP address see: https://en.wikipedia.org/wiki/IP_address */ + banTableContextMenu->addAction(tr("&Copy IP/Netmask"), [this] { + GUIUtil::copyEntryData(ui->banlistWidget, BanTableModel::Address, Qt::DisplayRole); + }); + banTableContextMenu->addSeparator(); banTableContextMenu->addAction(tr("&Unban"), this, &RPCConsole::unbanSelectedNode); connect(ui->banlistWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showBanTableContextMenu); From 02b5fce94266f1bd3caf337b43e749a32dab9517 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 12 Sep 2021 18:58:21 +0300 Subject: [PATCH 02/14] Merge bitcoin-core/gui#318: Add `Copy address` Peers Tab Context Menu Action 3ec061d9da0c8742bd9dec94ffeb82a11d000aba qt: Add "Copy address" item to the context menu in the Peers table (Hennadii Stepanov) Pull request description: Picking up #264 This adds a `Copy Address` context menu action to the `Peers Tab`. Based on the first commit of PR #317 so that we can use `Qt::DisplayRole` in the `copyEntryData` function. | Master | PR | | ----------- | ----------- | | ![Screen Shot 2021-05-05 at 4 51 11 AM](https://user-images.githubusercontent.com/23396902/117117822-fb067400-ad5d-11eb-9466-228456108e52.png) | ![Screen Shot 2021-05-05 at 4 49 15 AM](https://user-images.githubusercontent.com/23396902/117117835-fe99fb00-ad5d-11eb-8de0-f6a9acdbf40e.png) | ACKs for top commit: shaavan: tACK 3ec061d9da0c8742bd9dec94ffeb82a11d000aba luke-jr: utACK 3ec061d9da0c8742bd9dec94ffeb82a11d000aba hebasto: ACK 3ec061d9da0c8742bd9dec94ffeb82a11d000aba, tested on Linux Mint 20.2 (Qt 5.12.8): Tree-SHA512: be0d7324592aae3928fa3cc522294f17226419fe8cbe3587df12a36bd4fa9c81bead377b13051e950b9a3fcd290b273861e70d6c76b75cdf76eaf58224b834cd --- src/qt/rpcconsole.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ab15df60c9..084a65ff68 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -718,6 +718,11 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ // create peer table context menu peersTableContextMenu = new QMenu(this); + //: Context menu action to copy the address of a peer + peersTableContextMenu->addAction(tr("&Copy address"), [this] { + GUIUtil::copyEntryData(ui->peerWidget, PeerTableModel::Address, Qt::DisplayRole); + }); + peersTableContextMenu->addSeparator(); peersTableContextMenu->addAction(tr("&Disconnect"), this, &RPCConsole::disconnectSelectedNode); peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 &hour"), [this] { banSelectedNode(60 * 60); }); peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 d&ay"), [this] { banSelectedNode(60 * 60 * 24); }); From 95aeb6a08d20c20bae46a2279df27a6bc9d9dc2b Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 29 Sep 2021 17:18:33 +0300 Subject: [PATCH 03/14] Merge bitcoin-core/gui#436: Include vout when copying transaction ID from coin selection 10c6929d55ba9bc203bbadfb834537445dbd67ce Include vout when copying transaction ID from coin selection (Samuel Dobson) Pull request description: Fixes #432 I think it makes sense to just add the vout to the existing function because I can't imagine a situation where a user in the coin selection dialog would want just the transaction ID rather than the specific outpoint, and they can just delete it from the end anyway. ACKs for top commit: kristapsk: ACK 10c6929d55ba9bc203bbadfb834537445dbd67ce hebasto: ACK 10c6929d55ba9bc203bbadfb834537445dbd67ce, tested on Linux Mint 20.2 (Qt 5.12.8). shaavan: ACK 10c6929 Tree-SHA512: df4d132b6c2fd0b590594e91cf54f82c6c0f77ee9ca06296fb726bc3c52b9ae459ca3b50c48b2bf303ccafe832b6b4dba692a812f439991ca6d807ea0d8df934 --- src/qt/coincontroldialog.cpp | 16 ++++++++++------ src/qt/coincontroldialog.h | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 8a88c6161b..4ada490a7a 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -67,7 +67,7 @@ CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _m contextMenu->addAction(tr("&Copy address"), this, &CoinControlDialog::copyAddress); contextMenu->addAction(tr("Copy &label"), this, &CoinControlDialog::copyLabel); contextMenu->addAction(tr("Copy &amount"), this, &CoinControlDialog::copyAmount); - copyTransactionHashAction = contextMenu->addAction(tr("Copy transaction &ID"), this, &CoinControlDialog::copyTransactionHash); + m_copy_transaction_outpoint_action = contextMenu->addAction(tr("Copy transaction &ID and output index"), this, &CoinControlDialog::copyTransactionOutpoint); contextMenu->addSeparator(); lockAction = contextMenu->addAction(tr("L&ock unspent"), this, &CoinControlDialog::lockCoin); unlockAction = contextMenu->addAction(tr("&Unlock unspent"), this, &CoinControlDialog::unlockCoin); @@ -235,7 +235,7 @@ void CoinControlDialog::showMenu(const QPoint &point) // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu if (item->data(COLUMN_ADDRESS, TxHashRole).toString().length() == 64) // transaction hash is 64 characters (this means it is a child node, so it is not a parent node in tree mode) { - copyTransactionHashAction->setEnabled(true); + m_copy_transaction_outpoint_action->setEnabled(true); if (model->wallet().isLockedCoin(COutPoint(uint256S(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt()))) { lockAction->setEnabled(false); @@ -249,7 +249,7 @@ void CoinControlDialog::showMenu(const QPoint &point) } else // this means click on parent node in tree mode -> disable all { - copyTransactionHashAction->setEnabled(false); + m_copy_transaction_outpoint_action->setEnabled(false); lockAction->setEnabled(false); unlockAction->setEnabled(false); } @@ -283,10 +283,14 @@ void CoinControlDialog::copyAddress() GUIUtil::setClipboard(contextMenuItem->text(COLUMN_ADDRESS)); } -// context menu action: copy transaction id -void CoinControlDialog::copyTransactionHash() +// context menu action: copy transaction id and vout index +void CoinControlDialog::copyTransactionOutpoint() { - GUIUtil::setClipboard(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString()); + const QString address = contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString(); + const QString vout = contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toString(); + const QString outpoint = QString("%1:%2").arg(address).arg(vout); + + GUIUtil::setClipboard(outpoint); } // context menu action: lock coin diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 3336f2c396..601b4bcb5b 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -59,7 +59,7 @@ private: QMenu *contextMenu; QTreeWidgetItem *contextMenuItem; - QAction *copyTransactionHashAction; + QAction* m_copy_transaction_outpoint_action; QAction *lockAction; QAction *unlockAction; @@ -92,7 +92,7 @@ private Q_SLOTS: void copyAmount(); void copyLabel(); void copyAddress(); - void copyTransactionHash(); + void copyTransactionOutpoint(); void lockCoin(); void unlockCoin(); void clipboardQuantity(); From 7455b5557acea71ea9cd20efa2088b59f6186b43 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 22 Oct 2021 23:43:28 +0300 Subject: [PATCH 04/14] Merge bitcoin-core/gui#454: Use only Qt translation primitives in GUI code 58765a450c40152db8160bca8a6b0f5b754c5858 qt: Use only Qt translation primitives in GUI code (W. J. van der Laan) Pull request description: Use `Object::tr`, `QT_TRANSLATE_NOOP`, and `QCoreApplication::translate` as appropriate instead of using `_()` which doesn't get picked up. Replaces bitcoin/bitcoin#22764 Edit: I checked that the strings end up in the appropriate context in `bitcoin_en.ts` after `make translate`: - "Settings file could not be read" "Settings file could not be written" end up in `bitcoin-core` - "(press q to shutdown and continue later)" and "press q to shutdown" end up in `SplashScreen` ACKs for top commit: hebasto: ACK 58765a450c40152db8160bca8a6b0f5b754c5858 Tree-SHA512: d0cc5901426c47d411d0fe75aac195b9684b51385f74c161da772dbf9f0977f7ad7a0976e17366f49b40718e9b6eb87c3e93306dc845f97adddbc47d00731742 --- src/qt/bitcoin.cpp | 14 ++++++++------ src/qt/splashscreen.cpp | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index af50ae0129..47b5801c51 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -156,10 +156,11 @@ static bool InitSettings() std::vector errors; if (!gArgs.ReadSettingsFile(&errors)) { - bilingual_str error = _("Settings file could not be read"); - InitError(Untranslated(strprintf("%s:\n%s\n", error.original, MakeUnorderedList(errors)))); + std::string error = QT_TRANSLATE_NOOP("dash-core", "Settings file could not be read"); + std::string error_translated = QCoreApplication::translate("dash-core", error.c_str()).toStdString(); + InitError(Untranslated(strprintf("%s:\n%s\n", error, MakeUnorderedList(errors)))); - QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Reset | QMessageBox::Abort); + QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error_translated)), QMessageBox::Reset | QMessageBox::Abort); /*: Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. */ messagebox.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?")); @@ -178,10 +179,11 @@ static bool InitSettings() errors.clear(); if (!gArgs.WriteSettingsFile(&errors)) { - bilingual_str error = _("Settings file could not be written"); - InitError(Untranslated(strprintf("%s:\n%s\n", error.original, MakeUnorderedList(errors)))); + std::string error = QT_TRANSLATE_NOOP("dash-core", "Settings file could not be written"); + std::string error_translated = QCoreApplication::translate("dash-core", error.c_str()).toStdString(); + InitError(Untranslated(strprintf("%s:\n%s\n", error, MakeUnorderedList(errors)))); - QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Ok); + QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error_translated)), QMessageBox::Ok); /*: Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.*/ diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index dbe7aa7e65..005c3bcdb4 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -189,8 +189,8 @@ static void InitMessage(SplashScreen *splash, const std::string &message) static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible) { InitMessage(splash, title + std::string("\n") + - (resume_possible ? _("(press q to shutdown and continue later)").translated - : _("press q to shutdown").translated) + + (resume_possible ? SplashScreen::tr("(press q to shutdown and continue later)").toStdString() + : SplashScreen::tr("press q to shutdown").toStdString()) + strprintf("\n%d", nProgress) + "%"); } From c2fd4fe379f6bb123b5127d466e3ee00daf69715 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 15 Nov 2021 17:19:52 +0100 Subject: [PATCH 05/14] Merge bitcoin/bitcoin#23515: test: Return the largest utxo in MiniWallet.get_utxo fa62207737657e76ba45d5bf826fc0ccac658df6 test: Return the largest utxo in MiniWallet.get_utxo (MarcoFalke) Pull request description: This is for consistency with the `send_self_transfer` method. Also, remove the feature that the change of the last transfer can be retrieved via `get_utxo`. This can trivially and clearer be achieved by simply passing the txid of the transfer. Also, this fixes the bug in `feature_txindex_compatibility` in current master after a silent merge conflict. Fixes #23514 Top commit has no ACKs. Tree-SHA512: edd066d372aaa72b4e0fc7526f84931c8d1f6d14f53678cb7832bc8e3d211f44b90ec9c59b7d915ef24acc63a36e7d66c8d3b7598355bd490ac637ed3bcc3dff --- test/functional/rpc_txoutproof.py | 2 +- test/functional/test_framework/wallet.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index 34eb48a89e..9fed9cbe15 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -54,7 +54,7 @@ class MerkleBlockTest(BitcoinTestFramework): assert_equal(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid1, txid2])), txlist) assert_equal(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid1, txid2], blockhash)), txlist) - txin_spent = miniwallet.get_utxo() # Get the change from txid2 + txin_spent = miniwallet.get_utxo(txid=txid2) # Get the change from txid2 tx3 = miniwallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=txin_spent) txid3 = tx3['txid'] self.generate(self.nodes[0], 1) diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 6d494ee2c6..d0285f3ad9 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -135,10 +135,9 @@ class MiniWallet: Args: txid: get the first utxo we find from a specific transaction - - Note: Can be used to get the change output immediately after a send_self_transfer """ index = -1 # by default the last utxo + self._utxos = sorted(self._utxos, key=lambda k: (k['value'], -k['height'])) # Put the largest utxo last if txid: utxo = next(filter(lambda utxo: txid == utxo['txid'], self._utxos)) index = self._utxos.index(utxo) @@ -155,8 +154,7 @@ class MiniWallet: def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=0): """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" - self._utxos = sorted(self._utxos, key=lambda k: (k['value'], -k['height'])) - utxo_to_spend = utxo_to_spend or self._utxos.pop() # Pick the largest utxo (if none provided) and hope it covers the fee + utxo_to_spend = utxo_to_spend or self.get_utxo() if self._priv_key is None: vsize = Decimal(85) # anyone-can-spend else: From 73e1861576792f043ebf7c919b49f4f331ded5fb Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 16 Dec 2021 08:46:06 +0100 Subject: [PATCH 06/14] Merge bitcoin/bitcoin#23750: rpcwallet: mention labels are disabled for ranged descriptors 65efbba45d817261f590d043c69a9981e6b637bd rpcwallet: mention labels are deactivated for ranged descriptors (Antoine Poinsot) Pull request description: It was confusing when trying to use it as a blackbox. So mention it so next ones don't have to open the said box :) See #23749 for context ACKs for top commit: Sjors: utACK 65efbba45d817261f590d043c69a9981e6b637bd achow101: ACK 65efbba45d817261f590d043c69a9981e6b637bd Tree-SHA512: d8a3d1f81c16d95855ac2b01e8fd20e83d6dac1721b3da464a9a890e46102992a6882918be87b2a28b929349ee7f1beb1af6c88b22f065fbbb6948275a6d2b8f --- src/wallet/rpcdump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 4d75d2ae1c..801605dd27 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1802,7 +1802,7 @@ RPCHelpMan importdescriptors() { /* oneline_description */ "", {"timestamp | \"now\"", "integer / string"} }, {"internal", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether matching outputs should be treated as not incoming payments (e.g. change)"}, - {"label", RPCArg::Type::STR, RPCArg::Default{""}, "Label to assign to the address, only allowed with internal=false"}, + {"label", RPCArg::Type::STR, RPCArg::Default{""}, "Label to assign to the address, only allowed with internal=false. Disabled for ranged descriptors"}, }, }, }, From acbf718b57d4365a7dc3b6131b06bb04bfb8b5d7 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 19 Jan 2022 15:31:52 +0100 Subject: [PATCH 07/14] Merge bitcoin/bitcoin#23976: document and clean up MaybeUpdateMempoolForReorg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit e177fcab3831b6d259da5164cabedcc9e78f6957 Replace `struct update_lock_points` with lambda (glozow) c7cd98c7176800a51e6a6b3634a26b508aa33ff2 document and clean up MaybeUpdateMempoolForReorg (glozow) Pull request description: followup to #23683, addressing https://github.com/bitcoin/bitcoin/pull/23683#issuecomment-989741186 ACKs for top commit: hebasto: ACK e177fcab3831b6d259da5164cabedcc9e78f6957, I have reviewed the code and it looks OK, I agree it can be merged. instagibbs: ACK e177fcab3831b6d259da5164cabedcc9e78f6957 MarcoFalke: Approach ACK e177fcab3831b6d259da5164cabedcc9e78f6957 😶 Tree-SHA512: 8c2709dd5cab73cde41f3e5655d5f237bacfb341f78eac026169be579528695ca628c8777b7d89760d8677a4e6786913293681cfe16ab702b30c909703e1824c --- src/txmempool.h | 22 ++++++++-------------- src/validation.cpp | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/txmempool.h b/src/txmempool.h index 13f2b964d2..3e06fff3a4 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -311,16 +311,6 @@ public: } }; -struct update_lock_points -{ - explicit update_lock_points(const LockPoints& _lp) : lp(_lp) { } - - void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); } - -private: - const LockPoints& lp; -}; - // Multi_index tag names struct descendant_score {}; struct entry_time {}; @@ -634,10 +624,14 @@ public: bool removeSpentIndex(const uint256 txhash); void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs); - /** After reorg, check if mempool entries are now non-final, premature coinbase spends, or have - * invalid lockpoints. Update lockpoints and remove entries (and descendants of entries) that - * are no longer valid. */ - void removeForReorg(CChain& chain, std::function check_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); + /** After reorg, filter the entries that would no longer be valid in the next block, and update + * the entries' cached LockPoints if needed. The mempool does not have any knowledge of + * consensus rules. It just appplies the callable function and removes the ones for which it + * returns true. + * @param[in] filter_final_and_mature Predicate that checks the relevant validation rules + * and updates an entry's LockPoints. + * */ + void removeForReorg(CChain& chain, std::function filter_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID &keyId) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSLazyPublicKey &pubKey) EXCLUSIVE_LOCKS_REQUIRED(cs); diff --git a/src/validation.cpp b/src/validation.cpp index 38a030ace1..a02c1e4b54 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -373,21 +373,37 @@ void CChainState::MaybeUpdateMempoolForReorg( // the disconnectpool that were added back and cleans up the mempool state. m_mempool->UpdateTransactionsFromBlock(vHashUpdate); - const auto check_final_and_mature = [this, flags=STANDARD_LOCKTIME_VERIFY_FLAGS](CTxMemPool::txiter it) + // Predicate to use for filtering transactions in removeForReorg. + // Checks whether the transaction is still final and, if it spends a coinbase output, mature. + // Also updates valid entries' cached LockPoints if needed. + // If false, the tx is still valid and its lockpoints are updated. + // If true, the tx would be invalid in the next block; remove this entry and all of its descendants. + const auto filter_final_and_mature = [this, flags=STANDARD_LOCKTIME_VERIFY_FLAGS](CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main) { - bool should_remove = false; AssertLockHeld(m_mempool->cs); AssertLockHeld(::cs_main); const CTransaction& tx = it->GetTx(); + + // The transaction must be final. + if (!CheckFinalTx(m_chain.Tip(), tx, flags)) return true; LockPoints lp = it->GetLockPoints(); const bool validLP{TestLockPointValidity(m_chain, lp)}; CCoinsViewMemPool view_mempool(&CoinsTip(), *m_mempool); - if (!CheckFinalTx(m_chain.Tip(), tx, flags) - || !CheckSequenceLocks(m_chain.Tip(), view_mempool, tx, flags, &lp, validLP)) { - // Note if CheckSequenceLocks fails the LockPoints may still be invalid - // So it's critical that we remove the tx and not depend on the LockPoints. - should_remove = true; - } else if (it->GetSpendsCoinbase()) { + // CheckSequenceLocks checks if the transaction will be final in the next block to be + // created on top of the new chain. We use useExistingLockPoints=false so that, instead of + // using the information in lp (which might now refer to a block that no longer exists in + // the chain), it will update lp to contain LockPoints relevant to the new chain. + if (!CheckSequenceLocks(m_chain.Tip(), view_mempool, tx, flags, &lp, validLP)) { + // If CheckSequenceLocks fails, remove the tx and don't depend on the LockPoints. + return true; + } else if (!validLP) { + // If CheckSequenceLocks succeeded, it also updated the LockPoints. + // Now update the mempool entry lockpoints as well. + m_mempool->mapTx.modify(it, [&lp](CTxMemPoolEntry& e) { e.UpdateLockPoints(lp); }); + } + + // If the transaction spends any coinbase outputs, it must be mature. + if (it->GetSpendsCoinbase()) { for (const CTxIn& txin : tx.vin) { auto it2 = m_mempool->mapTx.find(txin.prevout.hash); if (it2 != m_mempool->mapTx.end()) @@ -396,18 +412,16 @@ void CChainState::MaybeUpdateMempoolForReorg( assert(!coin.IsSpent()); const auto mempool_spend_height{m_chain.Tip()->nHeight + 1}; if (coin.IsSpent() || (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY)) { - should_remove = true; - break; + return true; } } } - // CheckSequenceLocks updates lp. Update the mempool entry LockPoints. - if (!validLP) m_mempool->mapTx.modify(it, update_lock_points(lp)); - return should_remove; + // Transaction is still valid and cached LockPoints are updated. + return false; }; // We also need to remove any now-immature transactions - m_mempool->removeForReorg(m_chain, check_final_and_mature); + m_mempool->removeForReorg(m_chain, filter_final_and_mature); // Re-limit mempool size, in case we added any transactions LimitMempoolSize( *m_mempool, From a1691c7c2ae8efaa9b1fb223df28fbb5dc08dbdd Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 24 Jan 2022 12:43:19 +0100 Subject: [PATCH 08/14] Merge bitcoin/bitcoin#24102: mempool: Run coin.IsSpent only once in a row fa2bcc4e42e7fed61727b3de4019e9702d4090ce Run coin.IsSpent only once in a row (MarcoFalke) Pull request description: Follow-up to commit 64e4963c635ec3a73a5fa3f32f6ec08e70609f60 and https://github.com/bitcoin/bitcoin/pull/23976#discussion_r787758193 ACKs for top commit: glozow: utACK fa2bcc4e42e7fed61727b3de4019e9702d4090ce, agree the assertion is sufficient theStack: Code-review ACK fa2bcc4e42e7fed61727b3de4019e9702d4090ce w0xlt: crACK https://github.com/bitcoin/bitcoin/pull/24102/commits/fa2bcc4e42e7fed61727b3de4019e9702d4090ce shaavan: Code Review ACK fa2bcc4e42e7fed61727b3de4019e9702d4090ce brunoerg: crACK fa2bcc4e42e7fed61727b3de4019e9702d4090ce Tree-SHA512: 3be9d6b313bf6bb835f031826c81777b4659118d839001d084e72462391cb64ba81d06a5e07fd21fcfb709a71b08892b23212a98604ce8481da489476b72f072 --- src/validation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index a02c1e4b54..ed480eaad3 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -408,10 +408,10 @@ void CChainState::MaybeUpdateMempoolForReorg( auto it2 = m_mempool->mapTx.find(txin.prevout.hash); if (it2 != m_mempool->mapTx.end()) continue; - const Coin &coin = CoinsTip().AccessCoin(txin.prevout); + const Coin& coin{CoinsTip().AccessCoin(txin.prevout)}; assert(!coin.IsSpent()); const auto mempool_spend_height{m_chain.Tip()->nHeight + 1}; - if (coin.IsSpent() || (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY)) { + if (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY) { return true; } } From 36e9b5fead3e222df445103be6910423f4c6ee60 Mon Sep 17 00:00:00 2001 From: laanwj <126646+laanwj@users.noreply.github.com> Date: Wed, 23 Feb 2022 15:48:48 +0100 Subject: [PATCH 09/14] Merge bitcoin/bitcoin#24381: test: Run symlink regression tests on Windows fad7ddf9e3710405d727f61d8200d5efed1e705b test: Run symlink regression tests on Windows (MarcoFalke) Pull request description: Seems odd to add tests, but not run them on the platform that needs them most. ACKs for top commit: laanwj: Code review ACK fad7ddf9e3710405d727f61d8200d5efed1e705b ryanofsky: Code review ACK fad7ddf9e3710405d727f61d8200d5efed1e705b, just removing new test. Would be nice if the test could be added later, of course. Tree-SHA512: 64b235967a38c2eb90657e8d7a0447bcc8ce81d1b75a275b6c48bd42efd9ea7e7939257e484f297ee84598def3738eaeb289561aeba1dd6a99b258d389995139 --- src/test/fs_tests.cpp | 4 ++-- test/functional/feature_dirsymlinks.py | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index 4a8803a205..726d19a775 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -152,7 +152,7 @@ BOOST_AUTO_TEST_CASE(rename) fs::remove(path2); } -#ifndef WIN32 +#ifndef __MINGW64__ // no symlinks on mingw BOOST_AUTO_TEST_CASE(create_directories) { // Test fs::create_directories workaround. @@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(create_directories) fs::remove(symlink); fs::remove(dir); } -#endif // WIN32 +#endif // __MINGW64__ BOOST_AUTO_TEST_SUITE_END() diff --git a/test/functional/feature_dirsymlinks.py b/test/functional/feature_dirsymlinks.py index 85c8e27600..288754c04c 100755 --- a/test/functional/feature_dirsymlinks.py +++ b/test/functional/feature_dirsymlinks.py @@ -6,9 +6,8 @@ """ import os -import sys -from test_framework.test_framework import BitcoinTestFramework, SkipTest +from test_framework.test_framework import BitcoinTestFramework def rename_and_link(*, from_name, to_name): @@ -16,24 +15,27 @@ def rename_and_link(*, from_name, to_name): os.symlink(to_name, from_name) assert os.path.islink(from_name) and os.path.isdir(from_name) -class SymlinkTest(BitcoinTestFramework): - def skip_test_if_missing_module(self): - if sys.platform == 'win32': - raise SkipTest("Symlinks test skipped on Windows") +class SymlinkTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 def run_test(self): + dir_new_blocks = self.nodes[0].chain_path / "new_blocks" + dir_new_chainstate = self.nodes[0].chain_path / "new_chainstate" self.stop_node(0) - rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "blocks"), - to_name=os.path.join(self.nodes[0].datadir, self.chain, "newblocks")) - rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "chainstate"), - to_name=os.path.join(self.nodes[0].datadir, self.chain, "newchainstate")) + rename_and_link( + from_name=self.nodes[0].chain_path / "blocks", + to_name=dir_new_blocks, + ) + rename_and_link( + from_name=self.nodes[0].chain_path / "chainstate", + to_name=dir_new_chainstate, + ) self.start_node(0) -if __name__ == '__main__': +if __name__ == "__main__": SymlinkTest().main() From 33b9771ebc45508bf4e112dc6b1571909d5d4636 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 5 Apr 2022 14:03:41 +0200 Subject: [PATCH 10/14] Merge bitcoin/bitcoin#24749: test: use MiniWallet for mempool_unbroadcast.py d2ba43fec82af84521f1dbe4475d01888ccf4d0d test: use MiniWallet for mempool_unbroadcast.py (Ayush Sharma) Pull request description: This PR enables one of the non-wallet functional tests (mempool_unbroadcast.py) to be run even with the Bitcoin Core wallet disabled by using the MiniWallet instead, as proposed in #20078 . Top commit has no ACKs. Tree-SHA512: e4c577899b66855dafca9dab875fa9b9c68b762a8cdb14f3a7547841c4f001e79d62641e6ae202fb56a3f28aeea1779143164c872507ff8da0bd9930a8ed182e --- test/functional/mempool_unbroadcast.py | 45 ++++++++++++-------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py index d200689352..45abcc5a64 100755 --- a/test/functional/mempool_unbroadcast.py +++ b/test/functional/mempool_unbroadcast.py @@ -9,21 +9,20 @@ import time from test_framework.p2p import P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import ( - assert_equal, - create_confirmed_utxos, -) +from test_framework.util import assert_equal +from test_framework.wallet import MiniWallet MAX_INITIAL_BROADCAST_DELAY = 15 * 60 # 15 minutes in seconds class MempoolUnbroadcastTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() + if self.is_wallet_compiled(): + self.requires_wallet = True def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + self.wallet.rescan_utxos() self.test_broadcast() self.test_txn_removal() @@ -31,30 +30,25 @@ class MempoolUnbroadcastTest(BitcoinTestFramework): self.log.info("Test that mempool reattempts delivery of locally submitted transaction") node = self.nodes[0] - min_relay_fee = node.getnetworkinfo()["relayfee"] - utxos = create_confirmed_utxos(self, min_relay_fee, node, 10) - self.disconnect_nodes(0, 1) self.log.info("Generate transactions that only node 0 knows about") - # generate a wallet txn - addr = node.getnewaddress() - wallet_tx_hsh = node.sendtoaddress(addr, 0.0001) + if self.is_wallet_compiled(): + # generate a wallet txn + addr = node.getnewaddress() + wallet_tx_hsh = node.sendtoaddress(addr, 0.0001) # generate a txn using sendrawtransaction - us0 = utxos.pop() - inputs = [{"txid": us0["txid"], "vout": us0["vout"]}] - outputs = {addr: 0.0001} - tx = node.createrawtransaction(inputs, outputs) - node.settxfee(min_relay_fee) - txF = node.fundrawtransaction(tx) - txFS = node.signrawtransactionwithwallet(txF["hex"]) + txFS = self.wallet.create_self_transfer(from_node=node) rpc_tx_hsh = node.sendrawtransaction(txFS["hex"]) # check transactions are in unbroadcast using rpc mempoolinfo = self.nodes[0].getmempoolinfo() - assert_equal(mempoolinfo['unbroadcastcount'], 2) + unbroadcast_count = 1 + if self.is_wallet_compiled(): + unbroadcast_count += 1 + assert_equal(mempoolinfo['unbroadcastcount'], unbroadcast_count) mempool = self.nodes[0].getrawmempool(True) for tx in mempool: assert_equal(mempool[tx]['unbroadcast'], True) @@ -62,7 +56,8 @@ class MempoolUnbroadcastTest(BitcoinTestFramework): # check that second node doesn't have these two txns mempool = self.nodes[1].getrawmempool() assert rpc_tx_hsh not in mempool - assert wallet_tx_hsh not in mempool + if self.is_wallet_compiled(): + assert wallet_tx_hsh not in mempool # ensure that unbroadcast txs are persisted to mempool.dat self.restart_node(0) @@ -75,7 +70,8 @@ class MempoolUnbroadcastTest(BitcoinTestFramework): self.sync_mempools(timeout=30) mempool = self.nodes[1].getrawmempool() assert rpc_tx_hsh in mempool - assert wallet_tx_hsh in mempool + if self.is_wallet_compiled(): + assert wallet_tx_hsh in mempool # check that transactions are no longer in first node's unbroadcast set mempool = self.nodes[0].getrawmempool(True) @@ -104,8 +100,7 @@ class MempoolUnbroadcastTest(BitcoinTestFramework): # since the node doesn't have any connections, it will not receive # any GETDATAs & thus the transaction will remain in the unbroadcast set. - addr = node.getnewaddress() - txhsh = node.sendtoaddress(addr, 0.0001) + txhsh = self.wallet.send_self_transfer(from_node=node)["txid"] # check transaction was removed from unbroadcast set due to presence in # a block From 656f52585564365f7fdaf3cb70453e8bc4dc0c89 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 13 Apr 2022 00:54:47 +0200 Subject: [PATCH 11/14] Merge bitcoin-core/gui#543: peers-tab: add connection duration column to tableview 51708c4516cb9d52e84dc8850d93f556dda1a75b gui: peersWidget - ResizeToContents Age and IP/Netmask columns (randymcmillan) 209301a442512579d57f79c82417dc7c496248b6 gui: add Age column to peers tab (randymcmillan) 127de22c5fb396e1670d2a911faf7a9adc9241e2 gui: add FormatPeerAge() utility helper (Jon Atack) Pull request description: This change adds an "Age" column to the peers table view, which displays the duration of each peer's connection. ACKs for top commit: jonatack: re-ACK 51708c4516cb9d52e84dc8850d93f556dda1a75b Jamewood: > re-ACK 51708c4 shaavan: reACK 51708c4516cb9d52e84dc8850d93f556dda1a75b hebasto: ACK 51708c4516cb9d52e84dc8850d93f556dda1a75b, I have reviewed the code and it looks OK, I agree it can be merged. Tree-SHA512: 27323f7080ec0d3fcdbf1b190fba1cd2d7406840ab6607c221cf8af950db9134e22721cc5a88f4fc4f390d8b05e98bc4b7521661a31fadad9e2c6c6390e71788 --- src/qt/guiutil.cpp | 12 ++++++++++++ src/qt/guiutil.h | 3 +++ src/qt/peertablemodel.cpp | 3 +++ src/qt/peertablemodel.h | 4 ++++ src/qt/peertablesortproxy.cpp | 2 ++ src/qt/rpcconsole.cpp | 2 ++ 6 files changed, 26 insertions(+) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 14bcc39eed..40f74f73e7 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -89,6 +89,8 @@ void ForceActivation(); #endif +using namespace std::chrono_literals; + namespace GUIUtil { static RecursiveMutex cs_css; @@ -1729,6 +1731,16 @@ QString formatDurationStr(std::chrono::seconds dur) return str_list.join(" "); } +QString FormatPeerAge(std::chrono::seconds time_connected) +{ + const auto time_now{GetTime()}; + const auto age{time_now - time_connected}; + if (age >= 24h) return QObject::tr("%1 d").arg(age / 24h); + if (age >= 1h) return QObject::tr("%1 h").arg(age / 1h); + if (age >= 1min) return QObject::tr("%1 m").arg(age / 1min); + return QObject::tr("%1 s").arg(age / 1s); +} + QString formatServicesStr(quint64 mask) { QStringList strList; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 8f3cb7df71..3507043262 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -420,6 +420,9 @@ namespace GUIUtil /** Convert seconds into a QString with days, hours, mins, secs */ QString formatDurationStr(std::chrono::seconds dur); + /** Convert peer connection time to a QString denominated in the most relevant unit. */ + QString FormatPeerAge(std::chrono::seconds time_connected); + /** Format CNodeStats.nServices bitmask into a user-readable string */ QString formatServicesStr(quint64 mask); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index ecd305a77d..182ff17b55 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -71,6 +71,8 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const switch (column) { case NetNodeId: return (qint64)rec->nodeStats.nodeid; + case Age: + return GUIUtil::FormatPeerAge(rec->nodeStats.m_connected); case Address: // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection return QString::fromStdString((rec->nodeStats.fInbound ? "↓ " : "↑ ") + rec->nodeStats.m_addr_name); @@ -91,6 +93,7 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const } else if (role == Qt::TextAlignmentRole) { switch (column) { case NetNodeId: + case Age: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case Address: return {}; diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 0ff1b5dba7..cf101149fd 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -47,6 +47,7 @@ public: enum ColumnIndex { NetNodeId = 0, + Age, Address, ConnectionType, Network, @@ -84,6 +85,9 @@ private: /*: Title of Peers Table column which contains a unique number used to identify a connection. */ tr("Peer"), + /*: Title of Peers Table column which indicates the duration (length of time) + since the peer connection started. */ + tr("Age"), /*: Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. */ tr("Address"), diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp index ad966fbcab..6d716366fa 100644 --- a/src/qt/peertablesortproxy.cpp +++ b/src/qt/peertablesortproxy.cpp @@ -24,6 +24,8 @@ bool PeerTableSortProxy::lessThan(const QModelIndex& left_index, const QModelInd switch (static_cast(left_index.column())) { case PeerTableModel::NetNodeId: return left_stats.nodeid < right_stats.nodeid; + case PeerTableModel::Age: + return left_stats.m_connected > right_stats.m_connected; case PeerTableModel::Address: return left_stats.m_addr_name.compare(right_stats.m_addr_name) < 0; case PeerTableModel::ConnectionType: diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 084a65ff68..cd9f2bddcd 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -713,6 +713,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); } + ui->peerWidget->horizontalHeader()->setSectionResizeMode(PeerTableModel::Age, QHeaderView::ResizeToContents); ui->peerWidget->horizontalHeader()->setStretchLastSection(true); ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this)); @@ -745,6 +746,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH); ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH); } + ui->banlistWidget->horizontalHeader()->setSectionResizeMode(BanTableModel::Address, QHeaderView::ResizeToContents); ui->banlistWidget->horizontalHeader()->setStretchLastSection(true); // create ban table context menu From 1288494d4a56fac60c870d789499488ca5e6ff4c Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 4 May 2022 18:57:49 +0100 Subject: [PATCH 12/14] Merge bitcoin/bitcoin#24976: netgroup: Follow-up for #22910 e5d183151709ab59d2fa6fe9e0243000e8d6abbe [netgroup] Use nStartByte as offset for the last byte of the group (dergoegge) Pull request description: This addresses my review [comments](https://github.com/bitcoin/bitcoin/pull/22910#discussion_r856095896) I left on #22910. This has no effect on the current logic as `nStartByte` is only used for internal addresses which only ever add 10 whole bytes to the returned group. However to avoid future bugs, I think we should use `nStartByte` as offset for the last byte as well, in case we ever add a new address type that makes makes use of `nStartByte` and adds fractional bytes to the group. ACKs for top commit: jnewbery: Code review ACK e5d183151709ab59d2fa6fe9e0243000e8d6abbe theStack: Concept and code-review ACK e5d183151709ab59d2fa6fe9e0243000e8d6abbe Tree-SHA512: 4c08c7d6cb38b553e998798b3e3b790177aaa2141a48e277dfd538e01a7fccadf644329e93c5b0fb5e7e4037494c8dfe061b94eb52c6b31dc21bdf99eb0e311a --- src/netgroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netgroup.cpp b/src/netgroup.cpp index 3dc59725e1..c3162d0b28 100644 --- a/src/netgroup.cpp +++ b/src/netgroup.cpp @@ -71,7 +71,7 @@ std::vector NetGroupManager::GetGroup(const CNetAddr& address) co // ...for the last byte, push nBits and for the rest of the byte push 1's if (nBits > 0) { assert(num_bytes < addr_bytes.size()); - vchRet.push_back(addr_bytes[num_bytes] | ((1 << (8 - nBits)) - 1)); + vchRet.push_back(addr_bytes[num_bytes + nStartByte] | ((1 << (8 - nBits)) - 1)); } return vchRet; From e4f8b7097d73c8804cee3a983ec6479a42626170 Mon Sep 17 00:00:00 2001 From: laanwj <126646+laanwj@users.noreply.github.com> Date: Wed, 4 May 2022 20:19:51 +0200 Subject: [PATCH 13/14] Merge bitcoin/bitcoin#24852: util: optimize HexStr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 5e61532e72c1021fda9c7b213bd9cf397cb3a802 util: optimizes HexStr (Martin Leitner-Ankerl) 4e2b99f72a90b956f3050095abed4949aff9b516 bench: Adds a benchmark for HexStr (Martin Leitner-Ankerl) 67c8411c37b483caa2fe3f7f4f40b68ed2a9bcf7 test: Adds a test for HexStr that checks all 256 bytes (Martin Leitner-Ankerl) Pull request description: In my benchmark, this rewrite improves runtime 27% (g++) to 46% (clang++) for the benchmark `HexStrBench`: g++ 11.2.0 | ns/byte | byte/s | err% | ins/byte | cyc/byte | IPC | bra/byte | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 0.94 | 1,061,381,310.36 | 0.7% | 12.00 | 3.01 | 3.990 | 1.00 | 0.0% | 0.01 | `HexStrBench` master | 0.68 | 1,465,366,544.25 | 1.7% | 6.00 | 2.16 | 2.778 | 1.00 | 0.0% | 0.01 | `HexStrBench` branch clang++ 13.0.1 | ns/byte | byte/s | err% | ins/byte | cyc/byte | IPC | bra/byte | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 0.80 | 1,244,713,415.92 | 0.9% | 10.00 | 2.56 | 3.913 | 0.50 | 0.0% | 0.01 | `HexStrBench` master | 0.43 | 2,324,188,940.72 | 0.2% | 4.00 | 1.37 | 2.914 | 0.25 | 0.0% | 0.01 | `HexStrBench` branch Note that the idea for this change comes from denis2342 in #23364. This is a rewrite so no unaligned accesses occur. Also, the lookup table is now calculated at compile time, which hopefully makes the code a bit easier to review. ACKs for top commit: laanwj: Code review ACK 5e61532e72c1021fda9c7b213bd9cf397cb3a802 aureleoules: tACK 5e61532e72c1021fda9c7b213bd9cf397cb3a802. theStack: ACK 5e61532e72c1021fda9c7b213bd9cf397cb3a802 🚤 Tree-SHA512: 40b53d5908332473ef24918d3a80ad1292b60566c02585fa548eb4c3189754971be5a70325f4968fce6d714df898b52d9357aba14d4753a8c70e6ffd273a2319 --- src/Makefile.bench.include | 1 + src/bench/strencodings.cpp | 18 ++++++++++++++++++ src/test/util_tests.cpp | 18 ++++++++++++++++++ src/util/strencodings.cpp | 33 +++++++++++++++++++++++++++------ 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/bench/strencodings.cpp diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 133bc282ef..6fde78ddad 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -44,6 +44,7 @@ bench_bench_dash_SOURCES = \ bench/pool.cpp \ bench/rpc_blockchain.cpp \ bench/rpc_mempool.cpp \ + bench/strencodings.cpp \ bench/util_time.cpp \ bench/base58.cpp \ bench/bech32.cpp \ diff --git a/src/bench/strencodings.cpp b/src/bench/strencodings.cpp new file mode 100644 index 0000000000..4be7cd6d6f --- /dev/null +++ b/src/bench/strencodings.cpp @@ -0,0 +1,18 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +static void HexStrBench(benchmark::Bench& bench) +{ + auto const& data = benchmark::data::block813851; + bench.batch(data.size()).unit("byte").run([&] { + auto hex = HexStr(data); + ankerl::nanobench::doNotOptimizeAway(hex); + }); +} + +BENCHMARK(HexStrBench); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 444714ec78..ae0cf8e060 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -206,6 +206,24 @@ BOOST_AUTO_TEST_CASE(util_HexStr) BOOST_CHECK_EQUAL(HexStr(in_s), out_exp); BOOST_CHECK_EQUAL(HexStr(in_b), out_exp); } + + { + auto input = std::string(); + for (size_t i=0; i<256; ++i) { + input.push_back(static_cast(i)); + } + + auto hex = HexStr(input); + BOOST_TEST_REQUIRE(hex.size() == 512); + static constexpr auto hexmap = std::string_view("0123456789abcdef"); + for (size_t i = 0; i < 256; ++i) { + auto upper = hexmap.find(hex[i * 2]); + auto lower = hexmap.find(hex[i * 2 + 1]); + BOOST_TEST_REQUIRE(upper != std::string_view::npos); + BOOST_TEST_REQUIRE(lower != std::string_view::npos); + BOOST_TEST_REQUIRE(i == upper*16 + lower); + } + } } BOOST_AUTO_TEST_CASE(span_write_bytes) diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 64f1a08425..95050042fb 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -493,17 +494,37 @@ std::string Capitalize(std::string str) return str; } +namespace { + +using ByteAsHex = std::array; + +constexpr std::array CreateByteToHexMap() +{ + constexpr char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + std::array byte_to_hex{}; + for (size_t i = 0; i < byte_to_hex.size(); ++i) { + byte_to_hex[i][0] = hexmap[i >> 4]; + byte_to_hex[i][1] = hexmap[i & 15]; + } + return byte_to_hex; +} + +} // namespace + std::string HexStr(const Span s) { std::string rv(s.size() * 2, '\0'); - static constexpr char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - auto it = rv.begin(); + static constexpr auto byte_to_hex = CreateByteToHexMap(); + static_assert(sizeof(byte_to_hex) == 512); + + char* it = rv.data(); for (uint8_t v : s) { - *it++ = hexmap[v >> 4]; - *it++ = hexmap[v & 15]; + std::memcpy(it, byte_to_hex[v].data(), 2); + it += 2; } - assert(it == rv.end()); + + assert(it == rv.data() + rv.size()); return rv; } From 90744d0d658616532647251f59a87cd9239ea2e4 Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 12 May 2022 21:07:32 +0100 Subject: [PATCH 14/14] Merge bitcoin/bitcoin#25115: scripted-diff: replace non-standard fixed width integer types (`u_int`... -> `uint`...) 672d49c863fd6b0f096f166aeb3504f51dfa7d19 scripted-diff: replace non-standard fixed width integer types (`u_int`...` -> `uint`...) (Sebastian Falbesoner) Pull request description: Fixed width integer types prefixed with `u_int` are not part of C++ (see https://en.cppreference.com/w/cpp/types/integer), so it's better to avoid and replace them with their standard-conforming counterparts. (For those interested in history, according to one theory those u_int... types have been introduced by BSD: https://stackoverflow.com/a/5163960, http://lists.freedesktop.org/archives/release-wranglers/2004-August/000923.html). ACKs for top commit: laanwj: Code review ACK 672d49c863fd6b0f096f166aeb3504f51dfa7d19 fanquake: ACK 672d49c863fd6b0f096f166aeb3504f51dfa7d19 Tree-SHA512: 68134a0adca0d5c87a7432367cb493491a67288d69a174be2181f8e26efa968d966b9eb1cde94813942405063ee3be2a3437cf2aa5f71375f59205cbdbf501bb --- src/validation.cpp | 6 +++--- src/wallet/bdb.cpp | 4 ++-- src/wallet/bdb.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index ed480eaad3..1243625f3a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2485,9 +2485,9 @@ bool CChainState::FlushStateToDisk( full_flush_completed = true; TRACE5(utxocache, flush, (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs) - (u_int32_t)mode, - (u_int64_t)coins_count, - (u_int64_t)coins_mem_usage, + (uint32_t)mode, + (uint64_t)coins_count, + (uint64_t)coins_mem_usage, (bool)fFlushForPrune); } } diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 110f1ace98..4ffc08335c 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -98,7 +98,7 @@ void BerkeleyEnvironment::Close() if (ret != 0) LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) - DbEnv((u_int32_t)0).remove(strPath.c_str(), 0); + DbEnv((uint32_t)0).remove(strPath.c_str(), 0); if (error_file) fclose(error_file); @@ -246,7 +246,7 @@ const void* BerkeleyBatch::SafeDbt::get_data() const return m_dbt.get_data(); } -u_int32_t BerkeleyBatch::SafeDbt::get_size() const +uint32_t BerkeleyBatch::SafeDbt::get_size() const { return m_dbt.get_size(); } diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 4ea0f460fe..f09e76047b 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -34,7 +34,7 @@ static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100; static const bool DEFAULT_WALLET_PRIVDB = true; struct WalletDatabaseFileId { - u_int8_t value[DB_FILE_ID_LEN]; + uint8_t value[DB_FILE_ID_LEN]; bool operator==(const WalletDatabaseFileId& rhs) const; }; @@ -182,7 +182,7 @@ class BerkeleyBatch : public DatabaseBatch // delegate to Dbt const void* get_data() const; - u_int32_t get_size() const; + uint32_t get_size() const; // conversion operator to access the underlying Dbt operator Dbt*();