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
This commit is contained in:
Russell Yanofsky
2020-01-21 15:00:33 -05:00
parent bc96a9bfc6
commit f7ba881bc6
4 changed files with 73 additions and 6 deletions

View File

@@ -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 <chainparams.h>
#include <consensus/validation.h>
#include <interfaces/chain.h>
#include <script/standard.h>
#include <test/util/setup_common.h>
#include <validation.h>
@@ -44,6 +47,16 @@ BOOST_AUTO_TEST_CASE(findBlock)
BOOST_CHECK(!chain->findBlock({}, FoundBlock()));
}
BOOST_AUTO_TEST_CASE(findAncestorByHeight)
{
auto chain = interfaces::MakeChain(m_node);
auto& active = ChainActive();
uint256 hash;
BOOST_CHECK(chain->findAncestorByHeight(active[20]->GetBlockHash(), 10, FoundBlock().hash(hash)));
BOOST_CHECK_EQUAL(hash, active[10]->GetBlockHash());
BOOST_CHECK(!chain->findAncestorByHeight(active[10]->GetBlockHash(), 20));
}
BOOST_AUTO_TEST_CASE(findAncestorByHash)
{
auto chain = interfaces::MakeChain(m_node);
@@ -54,4 +67,28 @@ BOOST_AUTO_TEST_CASE(findAncestorByHash)
BOOST_CHECK(!chain->findAncestorByHash(active[10]->GetBlockHash(), active[20]->GetBlockHash()));
}
BOOST_AUTO_TEST_CASE(findCommonAncestor)
{
auto chain = interfaces::MakeChain(m_node);
auto& active = ChainActive();
auto* orig_tip = active.Tip();
for (int i = 0; i < 10; ++i) {
BlockValidationState state;
ChainstateActive().InvalidateBlock(state, Params(), active.Tip());
}
BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight - 10);
coinbaseKey.MakeNewKey(true);
for (int i = 0; i < 20; ++i) {
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
}
BOOST_CHECK_EQUAL(active.Height(), orig_tip->nHeight + 10);
uint256 fork_hash;
int fork_height;
int orig_height;
BOOST_CHECK(chain->findCommonAncestor(orig_tip->GetBlockHash(), active.Tip()->GetBlockHash(), FoundBlock().height(fork_height).hash(fork_hash), FoundBlock().height(orig_height)));
BOOST_CHECK_EQUAL(orig_height, orig_tip->nHeight);
BOOST_CHECK_EQUAL(fork_height, orig_tip->nHeight - 10);
BOOST_CHECK_EQUAL(fork_hash, active[fork_height]->GetBlockHash());
}
BOOST_AUTO_TEST_SUITE_END()