aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--depends/packages/qt.mk11
-rw-r--r--depends/patches/qt/fix_android_jni_static.patch2
-rw-r--r--depends/patches/qt/fix_bigsur_drawing.patch31
-rw-r--r--doc/dependencies.md2
-rw-r--r--src/bench/block_assemble.cpp2
-rw-r--r--src/bench/duplicate_inputs.cpp3
-rw-r--r--src/index/base.cpp35
-rw-r--r--src/index/base.h6
-rw-r--r--src/index/coinstatsindex.cpp2
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/init.cpp6
-rw-r--r--src/miner.cpp12
-rw-r--r--src/miner.h2
-rw-r--r--src/net_processing.cpp21
-rw-r--r--src/rest.cpp37
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/mining.cpp3
-rw-r--r--src/test/blockfilter_index_tests.cpp2
-rw-r--r--src/test/coinstatsindex_tests.cpp2
-rw-r--r--src/test/txindex_tests.cpp3
-rw-r--r--src/test/util/setup_common.cpp3
-rw-r--r--src/validation.cpp12
-rw-r--r--src/validation.h15
-rwxr-xr-xtest/functional/feature_cltv.py23
-rwxr-xr-xtest/functional/mempool_reorg.py112
-rw-r--r--test/functional/test_framework/wallet.py5
26 files changed, 183 insertions, 173 deletions
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index d23a64923b..5f9958e0ed 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -1,22 +1,22 @@
PACKAGE=qt
-$(package)_version=5.12.10
+$(package)_version=5.12.11
$(package)_download_path=https://download.qt.io/official_releases/qt/5.12/$($(package)_version)/submodules
$(package)_suffix=everywhere-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix)
-$(package)_sha256_hash=8088f174e6d28e779516c083b6087b6a9e3c8322b4bc161fd1b54195e3c86940
+$(package)_sha256_hash=1c1b4e33137ca77881074c140d54c3c9747e845a31338cfe8680f171f0bc3a39
$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon
$(package)_qt_libs=corelib network widgets gui plugins testlib
$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch
$(package)_patches+= fix_android_qmake_conf.patch fix_android_jni_static.patch dont_hardcode_pwd.patch
$(package)_patches+= drop_lrelease_dependency.patch no_sdk_version_check.patch
$(package)_patches+= fix_lib_paths.patch fix_android_pch.patch
-$(package)_patches+= fix_bigsur_drawing.patch qtbase-moc-ignore-gcc-macro.patch
+$(package)_patches+= qtbase-moc-ignore-gcc-macro.patch
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
-$(package)_qttranslations_sha256_hash=e1de58ed108b7e0a138815ea60fd46a2c4e1fc31396a707e5630e92de79c53de
+$(package)_qttranslations_sha256_hash=577b0668a777eb2b451c61e8d026d79285371597ce9df06b6dee6c814164b7c3
$(package)_qttools_file_name=qttools-$($(package)_suffix)
-$(package)_qttools_sha256_hash=b0cfa6e7aac41b7c61fc59acc04843d7a98f9e1840370611751bcfc1834a636c
+$(package)_qttools_sha256_hash=98b2aaca230458f65996f3534fd471d2ffd038dd58ac997c0589c06dc2385b4f
$(package)_extra_sources = $($(package)_qttranslations_file_name)
$(package)_extra_sources += $($(package)_qttools_file_name)
@@ -232,7 +232,6 @@ define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \
patch -p1 -i $($(package)_patch_dir)/no_sdk_version_check.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_lib_paths.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_bigsur_drawing.patch && \
patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \
sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \
mkdir -p qtbase/mkspecs/macx-clang-linux &&\
diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch
index f891da6ddf..a186aeb8f6 100644
--- a/depends/patches/qt/fix_android_jni_static.patch
+++ b/depends/patches/qt/fix_android_jni_static.patch
@@ -1,6 +1,6 @@
--- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp
+++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp
-@@ -897,6 +897,14 @@
+@@ -898,6 +898,14 @@
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
diff --git a/depends/patches/qt/fix_bigsur_drawing.patch b/depends/patches/qt/fix_bigsur_drawing.patch
deleted file mode 100644
index 98c0c6be30..0000000000
--- a/depends/patches/qt/fix_bigsur_drawing.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-Fix GUI stuck on Big Sur
-
-See:
- - https://github.com/bitcoin-core/gui/issues/249
- - https://github.com/bitcoin/bitcoin/pull/21495
- - https://bugreports.qt.io/browse/QTBUG-87014
-
-We should be able to drop this once we are using one of the following versions:
- - Qt 5.12.11 or later, see upstream commit: c5d904639dbd690a36306e2b455610029704d821
- - Qt 5.15.3 or later, see upstream commit: 2cae34354bd41ae286258c7a6b3653b746e786ae
-
---- a/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm
-+++ b/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm
-@@ -95,8 +95,15 @@
- // by AppKit at a point where we've already set up other parts of the platform plugin
- // based on the presence of layers or not. Once we've rewritten these parts to support
- // dynamically picking up layer enablement we can let AppKit do its thing.
-- return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave
-- && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave;
-+
-+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSBigSur)
-+ return true; // Big Sur always enables layer-backing, regardless of SDK
-+
-+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave
-+ && QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave)
-+ return true; // Mojave and Catalina enable layers based on the app's SDK
-+
-+ return false; // Prior versions needed explicitly enabled layer backing
- }
-
- - (BOOL)layerExplicitlyRequested
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 854ff7f52d..9754952221 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -21,7 +21,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| PCRE | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) |
| Python (tests) | | [3.6](https://www.python.org/downloads) | | | |
| qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | |
-| Qt | [5.12.10](https://download.qt.io/official_releases/qt/) | [5.9.5](https://github.com/bitcoin/bitcoin/issues/20104) | No | | |
+| Qt | [5.12.11](https://download.qt.io/official_releases/qt/) | [5.9.5](https://github.com/bitcoin/bitcoin/issues/20104) | No | | |
| SQLite | [3.32.1](https://sqlite.org/download.html) | [3.7.17](https://github.com/bitcoin/bitcoin/pull/19077) | | | |
| XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Linux only) |
| xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Linux only) |
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index aa72981cb4..b4b33d115f 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -37,7 +37,7 @@ static void AssembleBlock(benchmark::Bench& bench)
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
for (const auto& txr : txs) {
- const MempoolAcceptResult res = ::AcceptToMemoryPool(::ChainstateActive(), *test_setup->m_node.mempool, txr, false /* bypass_limits */);
+ const MempoolAcceptResult res = ::AcceptToMemoryPool(test_setup->m_node.chainman->ActiveChainstate(), *test_setup->m_node.mempool, txr, false /* bypass_limits */);
assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID);
}
}
diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp
index 25d1a2b56c..4f6e1122b8 100644
--- a/src/bench/duplicate_inputs.cpp
+++ b/src/bench/duplicate_inputs.cpp
@@ -25,7 +25,8 @@ static void DuplicateInputs(benchmark::Bench& bench)
CMutableTransaction naughtyTx{};
LOCK(cs_main);
- CBlockIndex* pindexPrev = ::ChainActive().Tip();
+ assert(std::addressof(::ChainActive()) == std::addressof(testing_setup->m_node.chainman->ActiveChain()));
+ CBlockIndex* pindexPrev = testing_setup->m_node.chainman->ActiveChain().Tip();
assert(pindexPrev != nullptr);
block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus());
block.nNonce = 0;
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 4079fc4569..3a61af28b7 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -60,33 +60,34 @@ bool BaseIndex::Init()
}
LOCK(cs_main);
+ CChain& active_chain = m_chainstate->m_chain;
if (locator.IsNull()) {
m_best_block_index = nullptr;
} else {
- m_best_block_index = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator);
+ m_best_block_index = m_chainstate->m_blockman.FindForkInGlobalIndex(active_chain, locator);
}
- m_synced = m_best_block_index.load() == ::ChainActive().Tip();
+ m_synced = m_best_block_index.load() == active_chain.Tip();
if (!m_synced) {
bool prune_violation = false;
if (!m_best_block_index) {
// index is not built yet
// make sure we have all block data back to the genesis
- const CBlockIndex* block = ::ChainActive().Tip();
+ const CBlockIndex* block = active_chain.Tip();
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
block = block->pprev;
}
- prune_violation = block != ::ChainActive().Genesis();
+ prune_violation = block != active_chain.Genesis();
}
// in case the index has a best block set and is not fully synced
// check if we have the required blocks to continue building the index
else {
const CBlockIndex* block_to_test = m_best_block_index.load();
- if (!ChainActive().Contains(block_to_test)) {
+ if (!active_chain.Contains(block_to_test)) {
// if the bestblock is not part of the mainchain, find the fork
// and make sure we have all data down to the fork
- block_to_test = ::ChainActive().FindFork(block_to_test);
+ block_to_test = active_chain.FindFork(block_to_test);
}
- const CBlockIndex* block = ::ChainActive().Tip();
+ const CBlockIndex* block = active_chain.Tip();
prune_violation = true;
// check backwards from the tip if we have all block data until we reach the indexes bestblock
while (block_to_test && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
@@ -104,20 +105,20 @@ bool BaseIndex::Init()
return true;
}
-static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain& chain) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
if (!pindex_prev) {
- return ::ChainActive().Genesis();
+ return chain.Genesis();
}
- const CBlockIndex* pindex = ::ChainActive().Next(pindex_prev);
+ const CBlockIndex* pindex = chain.Next(pindex_prev);
if (pindex) {
return pindex;
}
- return ::ChainActive().Next(::ChainActive().FindFork(pindex_prev));
+ return chain.Next(chain.FindFork(pindex_prev));
}
void BaseIndex::ThreadSync()
@@ -140,7 +141,7 @@ void BaseIndex::ThreadSync()
{
LOCK(cs_main);
- const CBlockIndex* pindex_next = NextSyncBlock(pindex);
+ const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain);
if (!pindex_next) {
m_best_block_index = pindex;
m_synced = true;
@@ -203,7 +204,7 @@ bool BaseIndex::Commit()
bool BaseIndex::CommitInternal(CDBBatch& batch)
{
LOCK(cs_main);
- GetDB().WriteBestBlock(batch, ::ChainActive().GetLocator(m_best_block_index));
+ GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index));
return true;
}
@@ -279,7 +280,7 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
const CBlockIndex* locator_tip_index;
{
LOCK(cs_main);
- locator_tip_index = g_chainman.m_blockman.LookupBlockIndex(locator_tip_hash);
+ locator_tip_index = m_chainstate->m_blockman.LookupBlockIndex(locator_tip_hash);
}
if (!locator_tip_index) {
@@ -320,7 +321,7 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain() const
// Skip the queue-draining stuff if we know we're caught up with
// ::ChainActive().Tip().
LOCK(cs_main);
- const CBlockIndex* chain_tip = ::ChainActive().Tip();
+ const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip();
const CBlockIndex* best_block_index = m_best_block_index.load();
if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) {
return true;
@@ -337,8 +338,10 @@ void BaseIndex::Interrupt()
m_interrupt();
}
-bool BaseIndex::Start()
+bool BaseIndex::Start(CChainState& active_chainstate)
{
+ assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
+ m_chainstate = &active_chainstate;
// Need to register this ValidationInterface before running Init(), so that
// callbacks are not missed if Init sets m_synced to true.
RegisterValidationInterface(this);
diff --git a/src/index/base.h b/src/index/base.h
index 59eefab29e..df4bdff1ea 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -12,6 +12,7 @@
#include <validationinterface.h>
class CBlockIndex;
+class CChainState;
struct IndexSummary {
std::string name;
@@ -75,8 +76,9 @@ private:
/// to a chain reorganization), the index must halt until Commit succeeds or else it could end up
/// getting corrupted.
bool Commit();
-
protected:
+ CChainState* m_chainstate{nullptr};
+
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override;
void ChainStateFlushed(const CBlockLocator& locator) override;
@@ -117,7 +119,7 @@ public:
/// Start initializes the sync state and registers the instance as a
/// ValidationInterface so that it stays in sync with blockchain updates.
- [[nodiscard]] bool Start();
+ [[nodiscard]] bool Start(CChainState& active_chainstate);
/// Stops the instance from staying in sync with blockchain updates.
void Stop();
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index e046527283..8c6046489b 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -266,7 +266,7 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n
{
LOCK(cs_main);
- CBlockIndex* iter_tip{g_chainman.m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
+ CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
const auto& consensus_params{Params().GetConsensus()};
do {
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index d9e437ad10..782e557478 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -204,7 +204,7 @@ bool TxIndex::Init()
// Attempt to migrate txindex from the old database to the new one. Even if
// chain_tip is null, the node could be reindexing and we still want to
// delete txindex records in the old database.
- if (!m_db->MigrateData(*pblocktree, ::ChainActive().GetLocator())) {
+ if (!m_db->MigrateData(*pblocktree, m_chainstate->m_chain.GetLocator())) {
return false;
}
diff --git a/src/init.cpp b/src/init.cpp
index a835df0572..7f64b1acfa 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1549,21 +1549,21 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 8: start indexers
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex);
- if (!g_txindex->Start()) {
+ if (!g_txindex->Start(::ChainstateActive())) {
return false;
}
}
for (const auto& filter_type : g_enabled_filter_types) {
InitBlockFilterIndex(filter_type, filter_index_cache, false, fReindex);
- if (!GetBlockFilterIndex(filter_type)->Start()) {
+ if (!GetBlockFilterIndex(filter_type)->Start(::ChainstateActive())) {
return false;
}
}
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
g_coin_stats_index = std::make_unique<CoinStatsIndex>(/* cache size */ 0, false, fReindex);
- if (!g_coin_stats_index->Start()) {
+ if (!g_coin_stats_index->Start(::ChainstateActive())) {
return false;
}
}
diff --git a/src/miner.cpp b/src/miner.cpp
index 3bc7fdd458..eccddbb04f 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -39,13 +39,21 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime;
}
-void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block)
+void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
{
CMutableTransaction tx{*block.vtx.at(0)};
tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block));
block.vtx.at(0) = MakeTransactionRef(tx);
- WITH_LOCK(::cs_main, assert(g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock) == prev_block));
+ CBlockIndex* prev_block;
+ {
+ // TODO: Temporary scope to check correctness of refactored code.
+ // Should be removed manually after merge of
+ // https://github.com/bitcoin/bitcoin/pull/20158
+ LOCK(::cs_main);
+ assert(std::addressof(g_chainman.m_blockman) == std::addressof(chainman.m_blockman));
+ prev_block = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
+ }
GenerateCoinbaseCommitment(block, prev_block, Params().GetConsensus());
block.hashMerkleRoot = BlockMerkleRoot(block);
diff --git a/src/miner.h b/src/miner.h
index becf362b79..10a80f4392 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -203,6 +203,6 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
-void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block);
+void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
#endif // BITCOIN_MINER_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 0b83f756b3..65224b4259 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -491,7 +491,8 @@ private:
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main);
- void ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing);
+ /** Process a new block. Perform any post-processing housekeeping */
+ void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing);
/** Relay map (txid or wtxid -> CTransactionRef) */
typedef std::map<uint256, CTransactionRef> MapRelay;
@@ -2384,15 +2385,15 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv)
m_connman.PushMessage(&peer, std::move(msg));
}
-void PeerManagerImpl::ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing)
+void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing)
{
- bool fNewBlock = false;
- m_chainman.ProcessNewBlock(m_chainparams, pblock, fForceProcessing, &fNewBlock);
- if (fNewBlock) {
- pfrom.nLastBlockTime = GetTime();
+ bool new_block{false};
+ m_chainman.ProcessNewBlock(m_chainparams, block, force_processing, &new_block);
+ if (new_block) {
+ node.nLastBlockTime = GetTime();
} else {
LOCK(cs_main);
- mapBlockSource.erase(pblock->GetHash());
+ mapBlockSource.erase(block->GetHash());
}
}
@@ -3475,7 +3476,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LOCK(cs_main);
mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom.GetId(), false));
}
- // Setting fForceProcessing to true means that we bypass some of
+ // Setting force_processing to true means that we bypass some of
// our anti-DoS protections in AcceptBlock, which filters
// unrequested blocks that might be trying to waste our resources
// (eg disk space). Because we only try to reconstruct blocks when
@@ -3484,7 +3485,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// we have a chain with at least nMinimumChainWork), and we ignore
// compact blocks with less work than our tip, it is safe to treat
// reconstructed compact blocks as having been requested.
- ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true);
+ ProcessBlock(pfrom, pblock, /*force_processing=*/true);
LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid()
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) {
// Clear download state for this block, which is in
@@ -3567,7 +3568,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// disk-space attacks), but this should be safe due to the
// protections in the compact block handler -- see related comment
// in compact block optimistic reconstruction handling.
- ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true);
+ ProcessBlock(pfrom, pblock, /*force_processing=*/true);
}
return;
}
diff --git a/src/rest.cpp b/src/rest.cpp
index d41f374c49..747c7aea19 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -107,6 +107,27 @@ static CTxMemPool* GetMemPool(const std::any& context, HTTPRequest* req)
return node_context->mempool.get();
}
+/**
+ * Get the node context chainstatemanager.
+ *
+ * @param[in] req The HTTP request, whose status code will be set if node
+ * context chainstatemanager is not found.
+ * @returns Pointer to the chainstatemanager or nullptr if none found.
+ */
+static ChainstateManager* GetChainman(const std::any& context, HTTPRequest* req)
+{
+ auto node_context = util::AnyPtr<NodeContext>(context);
+ if (!node_context || !node_context->chainman) {
+ RESTERR(req, HTTP_INTERNAL_SERVER_ERROR,
+ strprintf("%s:%d (%s)\n"
+ "Internal bug detected: Chainman disabled or instance not found!\n"
+ "You may report this issue here: %s\n",
+ __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
+ return nullptr;
+ }
+ return node_context->chainman;
+}
+
static RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
{
const std::string::size_type pos = strReq.rfind('.');
@@ -181,7 +202,9 @@ static bool rest_headers(const std::any& context,
std::vector<const CBlockIndex *> headers;
headers.reserve(count);
{
- ChainstateManager& chainman = EnsureAnyChainman(context);
+ ChainstateManager* maybe_chainman = GetChainman(context, req);
+ if (!maybe_chainman) return false;
+ ChainstateManager& chainman = *maybe_chainman;
LOCK(cs_main);
CChain& active_chain = chainman.ActiveChain();
tip = active_chain.Tip();
@@ -252,7 +275,9 @@ static bool rest_block(const std::any& context,
CBlockIndex* pblockindex = nullptr;
CBlockIndex* tip = nullptr;
{
- ChainstateManager& chainman = EnsureAnyChainman(context);
+ ChainstateManager* maybe_chainman = GetChainman(context, req);
+ if (!maybe_chainman) return false;
+ ChainstateManager& chainman = *maybe_chainman;
LOCK(cs_main);
tip = chainman.ActiveChain().Tip();
pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
@@ -541,7 +566,9 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
std::string bitmapStringRepresentation;
std::vector<bool> hits;
bitmap.resize((vOutPoints.size() + 7) / 8);
- ChainstateManager& chainman = EnsureAnyChainman(context);
+ ChainstateManager* maybe_chainman = GetChainman(context, req);
+ if (!maybe_chainman) return false;
+ ChainstateManager& chainman = *maybe_chainman;
{
auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) {
for (const COutPoint& vOutPoint : vOutPoints) {
@@ -644,7 +671,9 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req,
CBlockIndex* pblockindex = nullptr;
{
- ChainstateManager& chainman = EnsureAnyChainman(context);
+ ChainstateManager* maybe_chainman = GetChainman(context, req);
+ if (!maybe_chainman) return false;
+ ChainstateManager& chainman = *maybe_chainman;
LOCK(cs_main);
const CChain& active_chain = chainman.ActiveChain();
if (blockheight > active_chain.Height()) {
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 03f28239ba..83c1975d38 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1196,7 +1196,7 @@ static RPCHelpMan gettxoutsetinfo()
CCoinsStats prev_stats{hash_type};
if (pindex->nHeight > 0) {
- GetUTXOStats(coins_view, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), prev_stats, node.rpc_interruption_point, pindex->pprev);
+ GetUTXOStats(coins_view, *blockman, prev_stats, node.rpc_interruption_point, pindex->pprev);
}
UniValue block_info(UniValue::VOBJ);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 8190a2f006..6826e6fd07 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -378,8 +378,7 @@ static RPCHelpMan generateblock()
// Add transactions
block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
- CBlockIndex* prev_block = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock));
- RegenerateCommitments(block, prev_block);
+ RegenerateCommitments(block, chainman);
{
LOCK(cs_main);
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 1cb1c002f4..2f532ef598 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -131,7 +131,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
// BlockUntilSyncedToCurrentChain should return false before index is started.
BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(filter_index.Start());
+ BOOST_REQUIRE(filter_index.Start(::ChainstateActive()));
// Allow filter index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000;
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp
index bf7a80ae5c..106fcd2a33 100644
--- a/src/test/coinstatsindex_tests.cpp
+++ b/src/test/coinstatsindex_tests.cpp
@@ -32,7 +32,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
// is started.
BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(coin_stats_index.Start());
+ BOOST_REQUIRE(coin_stats_index.Start(::ChainstateActive()));
// Allow the CoinStatsIndex to catch up with the block index that is syncing
// in a background thread.
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 082655d811..d47c54fd6e 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -7,6 +7,7 @@
#include <script/standard.h>
#include <test/util/setup_common.h>
#include <util/time.h>
+#include <validation.h>
#include <boost/test/unit_test.hpp>
@@ -27,7 +28,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
// BlockUntilSyncedToCurrentChain should return false before txindex is started.
BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(txindex.Start());
+ BOOST_REQUIRE(txindex.Start(::ChainstateActive()));
// Allow tx index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000;
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 0ac178443a..863c3ab565 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -246,8 +246,7 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa
for (const CMutableTransaction& tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx));
}
- CBlockIndex* prev_block = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock));
- RegenerateCommitments(block, prev_block);
+ RegenerateCommitments(block, *Assert(m_node.chainman));
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
diff --git a/src/validation.cpp b/src/validation.cpp
index 86539ab01f..4c861599fd 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -3591,14 +3591,14 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
return true;
}
-bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock)
+bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block)
{
AssertLockNotHeld(cs_main);
assert(std::addressof(::ChainstateActive()) == std::addressof(ActiveChainstate()));
{
CBlockIndex *pindex = nullptr;
- if (fNewBlock) *fNewBlock = false;
+ if (new_block) *new_block = false;
BlockValidationState state;
// CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race.
@@ -3607,13 +3607,13 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
// Ensure that CheckBlock() passes before calling AcceptBlock, as
// belt-and-suspenders.
- bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
+ bool ret = CheckBlock(*block, state, chainparams.GetConsensus());
if (ret) {
// Store to disk
- ret = ActiveChainstate().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
+ ret = ActiveChainstate().AcceptBlock(block, state, chainparams, &pindex, force_processing, nullptr, new_block);
}
if (!ret) {
- GetMainSignals().BlockChecked(*pblock, state);
+ GetMainSignals().BlockChecked(*block, state);
return error("%s: AcceptBlock FAILED (%s)", __func__, state.ToString());
}
}
@@ -3621,7 +3621,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
NotifyHeaderTip(ActiveChainstate());
BlockValidationState state; // Only used to report errors, not invalidity - ignore it
- if (!ActiveChainstate().ActivateBestChain(state, chainparams, pblock))
+ if (!ActiveChainstate().ActivateBestChain(state, chainparams, block))
return error("%s: ActivateBestChain failed (%s)", __func__, state.ToString());
return true;
diff --git a/src/validation.h b/src/validation.h
index 43e1c5c22e..9c718b3d63 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -970,22 +970,21 @@ public:
* block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity!
*
- * If you want to *possibly* get feedback on whether pblock is valid, you must
+ * If you want to *possibly* get feedback on whether block is valid, you must
* install a CValidationInterface (see validationinterface.h) - this will have
* its BlockChecked method called whenever *any* block completes validation.
*
- * Note that we guarantee that either the proof-of-work is valid on pblock, or
+ * Note that we guarantee that either the proof-of-work is valid on block, or
* (and possibly also) BlockChecked will have been called.
*
- * May not be called in a
- * validationinterface callback.
+ * May not be called in a validationinterface callback.
*
- * @param[in] pblock The block we want to process.
- * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources.
- * @param[out] fNewBlock A boolean which is set to indicate if the block was first received via this call
+ * @param[in] block The block we want to process.
+ * @param[in] force_processing Process this block even if unrequested; used for non-network block sources.
+ * @param[out] new_block A boolean which is set to indicate if the block was first received via this call
* @returns If the block was processed, independently of block validity
*/
- bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock) LOCKS_EXCLUDED(cs_main);
+ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main);
/**
* Process incoming block headers.
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index d25aaa070d..10d2072dba 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -37,7 +37,7 @@ CLTV_HEIGHT = 1351
# Helper function to modify a transaction by
# 1) prepending a given script to the scriptSig of vin 0 and
# 2) (optionally) modify the nSequence of vin 0 and the tx's nLockTime
-def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None):
+def cltv_modify_tx(tx, prepend_scriptsig, nsequence=None, nlocktime=None):
assert_equal(len(tx.vin), 1)
if nsequence is not None:
tx.vin[0].nSequence = nsequence
@@ -45,10 +45,9 @@ def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None):
tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(tx.vin[0].scriptSig)))
tx.rehash()
- return tx
-def cltv_invalidate(node, tx, failure_reason):
+def cltv_invalidate(tx, failure_reason):
# Modify the signature in vin 0 and nSequence/nLockTime of the tx to fail CLTV
#
# According to BIP65, OP_CHECKLOCKTIMEVERIFY can fail due the following reasons:
@@ -69,14 +68,14 @@ def cltv_invalidate(node, tx, failure_reason):
[[CScriptNum(500), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 500],
][failure_reason]
- return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
+ cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
-def cltv_validate(node, tx, height):
+def cltv_validate(tx, height):
# Modify the signature in vin 0 and nSequence/nLockTime of the tx to pass CLTV
scheme = [[CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, height]
- return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
+ cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
class BIP65Test(BitcoinTestFramework):
@@ -111,17 +110,17 @@ class BIP65Test(BitcoinTestFramework):
self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block")
# create one invalid tx per CLTV failure reason (5 in total) and collect them
- invalid_ctlv_txs = []
+ invalid_cltv_txs = []
for i in range(5):
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
- spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
- invalid_ctlv_txs.append(spendtx)
+ cltv_invalidate(spendtx, i)
+ invalid_cltv_txs.append(spendtx)
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time)
block.nVersion = 3
- block.vtx.extend(invalid_ctlv_txs)
+ block.vtx.extend(invalid_cltv_txs)
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
@@ -149,7 +148,7 @@ class BIP65Test(BitcoinTestFramework):
# create and test one invalid tx per CLTV failure reason (5 in total)
for i in range(5):
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
- spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
+ cltv_invalidate(spendtx, i)
expected_cltv_reject_reason = [
"non-mandatory-script-verify-flag (Operation not valid with the current stack size)",
@@ -182,7 +181,7 @@ class BIP65Test(BitcoinTestFramework):
peer.sync_with_ping()
self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
- spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)
+ cltv_validate(spendtx, CLTV_HEIGHT - 1)
block.vtx.pop(1)
block.vtx.append(spendtx)
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index a815146eae..bcc6aa7bcc 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -8,13 +8,9 @@ Test re-org scenarios with a mempool that contains transactions
that spend (directly or indirectly) coinbase transactions.
"""
-from test_framework.blocktools import (
- COINBASE_MATURITY,
- create_raw_transaction,
-)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
-
+from test_framework.wallet import MiniWallet
class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
@@ -26,86 +22,90 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
[]
]
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
+ wallet = MiniWallet(self.nodes[0])
+
# Start with a 200 block chain
assert_equal(self.nodes[0].getblockcount(), 200)
- # Mine four blocks. After this, nodes[0] blocks
- # 101, 102, and 103 are spend-able.
- new_blocks = self.nodes[1].generate(4)
- self.sync_all()
-
- node0_address = self.nodes[0].getnewaddress()
- node1_address = self.nodes[1].getnewaddress()
+ self.log.info("Add 4 coinbase utxos to the miniwallet")
+ # Block 76 contains the first spendable coinbase txs.
+ first_block = 76
+ wallet.scan_blocks(start=first_block, num=4)
# Three scenarios for re-orging coinbase spends in the memory pool:
- # 1. Direct coinbase spend : spend_101
- # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
- # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
- # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
+ # 1. Direct coinbase spend : spend_1
+ # 2. Indirect (coinbase spend in chain, child in mempool) : spend_2 and spend_2_1
+ # 3. Indirect (coinbase and child both in chain) : spend_3 and spend_3_1
+ # Use invalidateblock to make all of the above coinbase spends invalid (immature coinbase),
# and make sure the mempool code behaves correctly.
- b = [self.nodes[0].getblockhash(n) for n in range(COINBASE_MATURITY + 1, COINBASE_MATURITY + 5)]
+ b = [self.nodes[0].getblockhash(n) for n in range(first_block, first_block+4)]
coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
- spend_101_raw = create_raw_transaction(self.nodes[0], coinbase_txids[1], node1_address, amount=49.99)
- spend_102_raw = create_raw_transaction(self.nodes[0], coinbase_txids[2], node0_address, amount=49.99)
- spend_103_raw = create_raw_transaction(self.nodes[0], coinbase_txids[3], node0_address, amount=49.99)
-
- # Create a transaction which is time-locked to two blocks in the future
- timelock_tx = self.nodes[0].createrawtransaction(
- inputs=[{
- "txid": coinbase_txids[0],
- "vout": 0,
- }],
- outputs={node0_address: 49.99},
- locktime=self.nodes[0].getblockcount() + 2,
- )
- timelock_tx = self.nodes[0].signrawtransactionwithwallet(timelock_tx)["hex"]
- # This will raise an exception because the timelock transaction is too immature to spend
+ utxo_1 = wallet.get_utxo(txid=coinbase_txids[1])
+ utxo_2 = wallet.get_utxo(txid=coinbase_txids[2])
+ utxo_3 = wallet.get_utxo(txid=coinbase_txids[3])
+ self.log.info("Create three transactions spending from coinbase utxos: spend_1, spend_2, spend_3")
+ spend_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_1)
+ spend_2 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_2)
+ spend_3 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_3)
+
+ self.log.info("Create another transaction which is time-locked to two blocks in the future")
+ utxo = wallet.get_utxo(txid=coinbase_txids[0])
+ timelock_tx = wallet.create_self_transfer(
+ from_node=self.nodes[0],
+ utxo_to_spend=utxo,
+ mempool_valid=False,
+ locktime=self.nodes[0].getblockcount() + 2
+ )['hex']
+
+ self.log.info("Check that the time-locked transaction is too immature to spend")
assert_raises_rpc_error(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx)
- # Broadcast and mine spend_102 and 103:
- spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
- spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
+ self.log.info("Broadcast and mine spend_2 and spend_3")
+ wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=spend_2['hex'])
+ wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=spend_3['hex'])
+ self.log.info("Generate a block")
self.nodes[0].generate(1)
- # Time-locked transaction is still too immature to spend
+ self.log.info("Check that time-locked transaction is still too immature to spend")
assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, timelock_tx)
- # Create 102_1 and 103_1:
- spend_102_1_raw = create_raw_transaction(self.nodes[0], spend_102_id, node1_address, amount=49.98)
- spend_103_1_raw = create_raw_transaction(self.nodes[0], spend_103_id, node1_address, amount=49.98)
+ self.log.info("Create spend_2_1 and spend_3_1")
+ spend_2_utxo = wallet.get_utxo(txid=spend_2['txid'])
+ spend_2_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_2_utxo)
+ spend_3_utxo = wallet.get_utxo(txid=spend_3['txid'])
+ spend_3_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_3_utxo)
- # Broadcast and mine 103_1:
- spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
+ self.log.info("Broadcast and mine spend_3_1")
+ spend_3_1_id = self.nodes[0].sendrawtransaction(spend_3_1['hex'])
+ self.log.info("Generate a block")
last_block = self.nodes[0].generate(1)
# Sync blocks, so that peer 1 gets the block before timelock_tx
# Otherwise, peer 1 would put the timelock_tx in recentRejects
self.sync_all()
- # Time-locked transaction can now be spent
+ self.log.info("The time-locked transaction can now be spent")
timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)
- # ... now put spend_101 and spend_102_1 in memory pools:
- spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)
- spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)
+ self.log.info("Add spend_1 and spend_2_1 to the mempool")
+ spend_1_id = self.nodes[0].sendrawtransaction(spend_1['hex'])
+ spend_2_1_id = self.nodes[0].sendrawtransaction(spend_2_1['hex'])
- assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id})
+ assert_equal(set(self.nodes[0].getrawmempool()), {spend_1_id, spend_2_1_id, timelock_tx_id})
self.sync_all()
+ self.log.info("invalidate the last block")
for node in self.nodes:
node.invalidateblock(last_block[0])
- # Time-locked transaction is now too immature and has been removed from the mempool
- # spend_103_1 has been re-orged out of the chain and is back in the mempool
- assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id})
+ self.log.info("The time-locked transaction is now too immature and has been removed from the mempool")
+ self.log.info("spend_3_1 has been re-orged out of the chain and is back in the mempool")
+ assert_equal(set(self.nodes[0].getrawmempool()), {spend_1_id, spend_2_1_id, spend_3_1_id})
- # Use invalidateblock to re-org back and make all those coinbase spends
- # immature/invalid:
+ self.log.info("Use invalidateblock to re-org back and make all those coinbase spends immature/invalid")
+ b = self.nodes[0].getblockhash(first_block + 100)
for node in self.nodes:
- node.invalidateblock(new_blocks[0])
+ node.invalidateblock(b)
- # mempool should be empty.
+ self.log.info("Check that the mempool is empty")
assert_equal(set(self.nodes[0].getrawmempool()), set())
self.sync_all()
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 05bda5d899..bfb5916c37 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -123,13 +123,13 @@ class MiniWallet:
else:
return self._utxos[index]
- def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None):
+ def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, locktime=0):
"""Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
tx = self.create_self_transfer(fee_rate=fee_rate, from_node=from_node, utxo_to_spend=utxo_to_spend)
self.sendrawtransaction(from_node=from_node, tx_hex=tx['hex'])
return tx
- def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True):
+ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=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'])
utxo_to_spend = utxo_to_spend or self._utxos.pop() # Pick the largest utxo (if none provided) and hope it covers the fee
@@ -141,6 +141,7 @@ class MiniWallet:
tx = CTransaction()
tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))]
tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)]
+ tx.nLockTime = locktime
if not self._address:
# raw script
if self._priv_key is not None: