From f7ba881bc669451a60fedac58a449794702a3e23 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Tue, 21 Jan 2020 15:00:33 -0500 Subject: [PATCH] wallet: Avoid use of Chain::Lock in listsinceblock This is a step toward removing the Chain::Lock class and reducing cs_main locking. This change only affects behavior in the case where wallet last block processed falls behind the chain tip. Previously listsinceblock might not have returned all transactions up to the claimed "lastblock" value in this case, resulting in race conditions and potentially missing transactions in cases where listsinceblock was called in a loop like https://github.com/bitcoin/bitcoin/issues/14338#issuecomment-426706574 --- src/interfaces/chain.cpp | 18 +++++++++++++++++ src/interfaces/chain.h | 12 ++++++++++++ src/test/interfaces_tests.cpp | 37 +++++++++++++++++++++++++++++++++++ src/wallet/rpcwallet.cpp | 12 ++++++------ 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index dbc49eca1b..8cd4ab0b6d 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -260,6 +260,16 @@ public: WAIT_LOCK(cs_main, lock); return FillBlock(LookupBlockIndex(hash), block, lock); } + bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override + { + WAIT_LOCK(cs_main, lock); + if (const CBlockIndex* block = LookupBlockIndex(block_hash)) { + if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) { + return FillBlock(ancestor, ancestor_out, lock); + } + } + return FillBlock(nullptr, ancestor_out, lock); + } bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override { WAIT_LOCK(cs_main, lock); @@ -268,6 +278,14 @@ public: if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr; return FillBlock(ancestor, ancestor_out, lock); } + bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override + { + WAIT_LOCK(cs_main, lock); + const CBlockIndex* block1 = LookupBlockIndex(block_hash1); + const CBlockIndex* block2 = LookupBlockIndex(block_hash2); + const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr; + return FillBlock(ancestor, ancestor_out, lock) & FillBlock(block1, block1_out, lock) & FillBlock(block2, block2_out, lock); + } void findCoins(std::map& coins) override { return FindCoins(m_node, coins); } double guessVerificationProgress(const uint256& block_hash) override { diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 4c711a618d..ee79b3e6dc 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -146,12 +146,24 @@ public: //! or contents. virtual bool findBlock(const uint256& hash, const FoundBlock& block={}) = 0; + //! Find ancestor of block at specified height and optionally return + //! ancestor information. + virtual bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out={}) = 0; + //! Return whether block descends from a specified ancestor, and //! optionally return ancestor information. virtual bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out={}) = 0; + //! Find most recent common ancestor between two blocks and optionally + //! return block information. + virtual bool findCommonAncestor(const uint256& block_hash1, + const uint256& block_hash2, + const FoundBlock& ancestor_out={}, + const FoundBlock& block1_out={}, + const FoundBlock& block2_out={}) = 0; + //! Look up unspent output information. Returns coins in the mempool and in //! the current chain UTXO set. Iterates through all the keys in the map and //! populates the values. diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp index caa988df0d..f95743ec40 100644 --- a/src/test/interfaces_tests.cpp +++ b/src/test/interfaces_tests.cpp @@ -2,7 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include #include +#include