diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,4 +4,6 @@ <https://download.bitcoinabc.org/0.26.12/> -This is a maintenance release with no user-visible change. + - Removed 10-block rolling finalization. This only affects configurations + where Avalanche is explicitly disabled. This removal includes associated + command-line parameters `-finalizationdelay` and `-maxreorgdepth`. diff --git a/src/avalanche/processor.cpp b/src/avalanche/processor.cpp --- a/src/avalanche/processor.cpp +++ b/src/avalanche/processor.cpp @@ -988,11 +988,6 @@ return false; } - if (processor.chainman.ActiveChainstate().IsBlockFinalized(pindex)) { - // There is no point polling finalized block. - return false; - } - return true; } diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -522,23 +522,11 @@ strprintf("Set database cache size in MiB (%d to %d, default: %d)", MIN_DB_CACHE_MB, MAX_DB_CACHE_MB, DEFAULT_DB_CACHE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg( - "-finalizationdelay=<n>", - strprintf("Set the minimum amount of time to wait between a " - "block header reception and the block finalization. " - "Unit is seconds (default: %d)", - DEFAULT_MIN_FINALIZATION_DELAY), - ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg( "-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path " "(only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-maxreorgdepth=<n>", - strprintf("Configure at what depth blocks are considered " - "final (default: %d). Use -1 to disable.", - DEFAULT_MAX_REORG_DEPTH), - ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -232,29 +232,6 @@ }; } -RPCHelpMan getfinalizedblockhash() { - return RPCHelpMan{ - "getfinalizedblockhash", - "Returns the hash of the currently finalized block\n", - {}, - RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"}, - RPCExamples{HelpExampleCli("getfinalizedblockhash", "") + - HelpExampleRpc("getfinalizedblockhash", "")}, - [&](const RPCHelpMan &self, const Config &config, - const JSONRPCRequest &request) -> UniValue { - ChainstateManager &chainman = EnsureAnyChainman(request.context); - LOCK(cs_main); - CChainState &active_chainstate = chainman.ActiveChainstate(); - const CBlockIndex *blockIndexFinalized = - active_chainstate.GetFinalizedBlock(); - if (blockIndexFinalized) { - return blockIndexFinalized->GetBlockHash().GetHex(); - } - return UniValue(UniValue::VSTR); - }, - }; -} - void RPCNotifyBlockChange(const CBlockIndex *pindex) { if (pindex) { LOCK(cs_blockchange); @@ -2201,53 +2178,6 @@ }; } -RPCHelpMan finalizeblock() { - return RPCHelpMan{ - "finalizeblock", - "Treats a block as final. It cannot be reorged. Any chain\n" - "that does not contain this block is invalid. Used on a less\n" - "work chain, it can effectively PUT YOU OUT OF CONSENSUS.\n" - "USE WITH CAUTION!\n", - { - {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, - "the hash of the block to mark as invalid"}, - }, - RPCResult{RPCResult::Type::NONE, "", ""}, - RPCExamples{HelpExampleCli("finalizeblock", "\"blockhash\"") + - HelpExampleRpc("finalizeblock", "\"blockhash\"")}, - [&](const RPCHelpMan &self, const Config &config, - const JSONRPCRequest &request) -> UniValue { - std::string strHash = request.params[0].get_str(); - BlockHash hash(uint256S(strHash)); - BlockValidationState state; - - ChainstateManager &chainman = EnsureAnyChainman(request.context); - CBlockIndex *pblockindex = nullptr; - { - LOCK(cs_main); - pblockindex = chainman.m_blockman.LookupBlockIndex(hash); - if (!pblockindex) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Block not found"); - } - } // end of locked cs_main scope - - chainman.ActiveChainstate().FinalizeBlock(config, state, - pblockindex); - - if (state.IsValid()) { - chainman.ActiveChainstate().ActivateBestChain(config, state); - } - - if (!state.IsValid()) { - throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); - } - - return NullUniValue; - }, - }; -} - static RPCHelpMan invalidateblock() { return RPCHelpMan{ "invalidateblock", @@ -3437,8 +3367,6 @@ { "blockchain", getblockfilter, }, /* Not shown in help */ - { "hidden", getfinalizedblockhash, }, - { "hidden", finalizeblock, }, { "hidden", invalidateblock, }, { "hidden", parkblock, }, { "hidden", reconsiderblock, }, diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -160,7 +160,6 @@ dnsseeds_tests.cpp dstencode_tests.cpp feerate_tests.cpp - finalization_tests.cpp flatfile_tests.cpp fs_tests.cpp getarg_tests.cpp diff --git a/src/test/finalization_tests.cpp b/src/test/finalization_tests.cpp deleted file mode 100644 --- a/src/test/finalization_tests.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2018-2019 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <chain.h> -#include <chainparams.h> -#include <config.h> -#include <util/time.h> -#include <validation.h> - -#include <test/util/setup_common.h> - -#include <boost/test/unit_test.hpp> - -BOOST_FIXTURE_TEST_SUITE(finalization_tests, TestChain100Setup) - -BOOST_AUTO_TEST_CASE(finalizationDelay) { - CScript p2pk_scriptPubKey = - CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - CBlock block; - - { - LOCK(cs_main); - // We should have no finalized block because the 100 blocks generated by - // the deterministic test setup were created before the startup time; - BOOST_CHECK_MESSAGE( - m_node.chainman->ActiveChainstate().GetFinalizedBlock() == nullptr, - "No block finalized (tip at height " - << m_node.chainman->ActiveHeight() << ")"); - } - - // CChainState::FindBlockToFinalize takes both the mockable time and the - // startup time (not mockable) into account to decide if a block is mature - // enough for finalization. - int64_t mockedTime = std::max<int64_t>(GetTime(), GetStartupTime()); - SetMockTime(mockedTime); - - // Create maxreorgdepth blocks. Auto-finalization will not occur because - // the delay is not expired - for (uint32_t i = 0; i < DEFAULT_MAX_REORG_DEPTH; i++) { - block = CreateAndProcessBlock({}, p2pk_scriptPubKey); - LOCK(cs_main); - // These blocks are too recent. - BOOST_CHECK_MESSAGE( - m_node.chainman->ActiveChainstate().GetFinalizedBlock() == nullptr, - "No block finalized (tip at height " - << m_node.chainman->ActiveHeight() << ")"); - } - - // Make the finalization time to expire - mockedTime += DEFAULT_MIN_FINALIZATION_DELAY + 1; - SetMockTime(mockedTime); - - // Next maxreorgdepth blocks should cause auto-finalization - CBlockIndex *blockToFinalize = m_node.chainman->ActiveTip()->GetAncestor( - m_node.chainman->ActiveHeight() - DEFAULT_MAX_REORG_DEPTH); - - for (uint32_t i = 0; i < DEFAULT_MAX_REORG_DEPTH; i++) { - blockToFinalize = m_node.chainman->ActiveChain().Next(blockToFinalize); - block = CreateAndProcessBlock({}, p2pk_scriptPubKey); - LOCK(cs_main); - BOOST_CHECK_MESSAGE( - m_node.chainman->ActiveChainstate().GetFinalizedBlock() == - blockToFinalize, - "Block finalized at height " - << blockToFinalize->nHeight << " (tip at height " - << m_node.chainman->ActiveHeight() << ")"); - } - - // Next blocks won't cause auto-finalization because the delay is not - // expired - for (uint32_t i = 0; i < DEFAULT_MAX_REORG_DEPTH; i++) { - block = CreateAndProcessBlock({}, p2pk_scriptPubKey); - LOCK(cs_main); - // These blocks are finalized. - BOOST_CHECK_MESSAGE( - m_node.chainman->ActiveChainstate().GetFinalizedBlock() == - blockToFinalize, - "Finalized block remains unchanged at height " - << blockToFinalize->nHeight << " (tip at height " - << m_node.chainman->ActiveHeight() << ")"); - } - - // Make the finalization time to expire - mockedTime += DEFAULT_MIN_FINALIZATION_DELAY + 1; - SetMockTime(mockedTime); - - blockToFinalize = m_node.chainman->ActiveTip()->GetAncestor( - m_node.chainman->ActiveHeight() - DEFAULT_MAX_REORG_DEPTH); - - // Create some more blocks. - // Finalization should start moving again. - for (uint32_t i = 0; i < DEFAULT_MAX_REORG_DEPTH; i++) { - blockToFinalize = m_node.chainman->ActiveChain().Next(blockToFinalize); - block = CreateAndProcessBlock({}, p2pk_scriptPubKey); - LOCK(cs_main); - BOOST_CHECK_MESSAGE( - m_node.chainman->ActiveChainstate().GetFinalizedBlock() == - blockToFinalize, - "Block finalized at height " - << blockToFinalize->nHeight << " (tip at height " - << m_node.chainman->ActiveHeight() << ")"); - } -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -94,15 +94,6 @@ /** Default for -stopatheight */ static const int DEFAULT_STOPATHEIGHT = 0; -/** Default for -maxreorgdepth */ -static const int DEFAULT_MAX_REORG_DEPTH = 10; -/** - * Default for -finalizationdelay - * This is the minimum time between a block header reception and the block - * finalization. - * This value should be >> block propagation and validation time - */ -static const int64_t DEFAULT_MIN_FINALIZATION_DELAY = 2 * 60 * 60; /** * Block files containing a block-height within MIN_BLOCKS_TO_KEEP of * ActiveChain().Tip() will not be pruned. @@ -689,12 +680,6 @@ //! `m_chain`. std::unique_ptr<CoinsViews> m_coins_views; - /** - * The best finalized block. - * This block cannot be reorged in any way except by explicit user action. - */ - const CBlockIndex *m_finalizedBlockIndex GUARDED_BY(cs_main) = nullptr; - mutable Mutex cs_avalancheFinalizedBlockIndex; /** @@ -893,22 +878,6 @@ CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex); - /** - * Finalize a block. - * A finalized block can not be reorged in any way. - */ - bool FinalizeBlock(const Config &config, BlockValidationState &state, - CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main) - EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex); - /** Return the currently finalized block index. */ - const CBlockIndex *GetFinalizedBlock() const - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - /** - * Checks if a block is finalized. - */ - bool IsBlockFinalized(const CBlockIndex *pindex) const - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - /** * Mark a block as finalized by avalanche. */ @@ -1012,9 +981,6 @@ CBlockIndex * FindMostWorkChain(std::vector<const CBlockIndex *> &blocksToReconcile) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - bool MarkBlockAsFinal(BlockValidationState &state, - const CBlockIndex *pindex) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); void ReceivedBlockTransactions(const CBlock &block, CBlockIndex *pindexNew, const FlatFilePos &pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1376,9 +1376,6 @@ // If the invalid chain found is supposed to be finalized, we need to move // back the finalization point. - if (IsBlockFinalized(pindexNew)) { - m_finalizedBlockIndex = pindexNew->pprev; - } if (IsBlockAvalancheFinalized(pindexNew)) { LOCK(cs_avalancheFinalizedBlockIndex); m_avalancheFinalizedBlockIndex = pindexNew->pprev; @@ -2563,11 +2560,6 @@ } } - // If the tip is finalized, then undo it. - if (m_finalizedBlockIndex == pindexDelete) { - m_finalizedBlockIndex = pindexDelete->pprev; - } - m_chain.SetTip(pindexDelete->pprev); UpdateTip(pindexDelete->pprev); @@ -2625,83 +2617,6 @@ } }; -bool CChainState::MarkBlockAsFinal(BlockValidationState &state, - const CBlockIndex *pindex) { - AssertLockHeld(cs_main); - if (pindex->nStatus.isInvalid()) { - // We try to finalize an invalid block. - LogPrintf("ERROR: %s: Trying to finalize invalid block %s\n", __func__, - pindex->GetBlockHash().ToString()); - return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, - "finalize-invalid-block"); - } - - // Check that the request is consistent with current finalization. - if (m_finalizedBlockIndex && - !AreOnTheSameFork(pindex, m_finalizedBlockIndex)) { - LogPrintf("ERROR: %s: Trying to finalize block %s which conflicts with " - "already finalized block\n", - __func__, pindex->GetBlockHash().ToString()); - return state.Invalid(BlockValidationResult::BLOCK_FINALIZATION, - "bad-fork-prior-finalized"); - } - - if (IsBlockFinalized(pindex)) { - // The block is already finalized. - return true; - } - - // We have a new block to finalize. - m_finalizedBlockIndex = pindex; - return true; -} - -const CBlockIndex *CChainState::FindBlockToFinalize(CBlockIndex *pindexNew) { - AssertLockHeld(cs_main); - - const int32_t maxreorgdepth = - gArgs.GetIntArg("-maxreorgdepth", DEFAULT_MAX_REORG_DEPTH); - - const int64_t finalizationdelay = - gArgs.GetIntArg("-finalizationdelay", DEFAULT_MIN_FINALIZATION_DELAY); - - // Find our candidate. - // If maxreorgdepth is < 0 pindex will be null and auto finalization - // disabled - const CBlockIndex *pindex = - pindexNew->GetAncestor(pindexNew->nHeight - maxreorgdepth); - - int64_t now = GetTime(); - - // If the finalization delay is not expired since the startup time, - // finalization should be avoided. Header receive time is not saved to disk - // and so cannot be anterior to startup time. - if (now < (GetStartupTime() + finalizationdelay)) { - return nullptr; - } - - // While our candidate is not eligible (finalization delay not expired), try - // the previous one. - while (pindex && (pindex != GetFinalizedBlock())) { - // Check that the block to finalize is known for a long enough time. - // This test will ensure that an attacker could not cause a block to - // finalize by forking the chain with a depth > maxreorgdepth. - // If the block is loaded from disk, header receive time is 0 and the - // block will be finalized. This is safe because the delay since the - // node startup is already expired. - auto headerReceivedTime = pindex->GetHeaderReceivedTime(); - - // If finalization delay is <= 0, finalization always occurs immediately - if (now >= (headerReceivedTime + finalizationdelay)) { - return pindex; - } - - pindex = pindex->pprev; - } - - return nullptr; -} - /** * Connect a new block to m_chain. pblock is either nullptr or a pointer to * a CBlock corresponding to pindexNew, to bypass loading it again from disk. @@ -2759,14 +2674,6 @@ state.ToString()); } - // Update the finalized block. - const CBlockIndex *pindexToFinalize = FindBlockToFinalize(pindexNew); - if (pindexToFinalize && !MarkBlockAsFinal(state, pindexToFinalize)) { - return error("ConnectTip(): MarkBlockAsFinal %s failed (%s)", - pindexNew->GetBlockHash().ToString(), - state.ToString()); - } - nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; assert(nBlocksTotal > 0); @@ -2853,18 +2760,6 @@ pindexNew = *it; } - // If this block will cause a finalized block to be reorged, then we - // mark it as invalid. - if (m_finalizedBlockIndex && - !AreOnTheSameFork(pindexNew, m_finalizedBlockIndex)) { - LogPrintf("Mark block %s invalid because it forks prior to the " - "finalization point %d.\n", - pindexNew->GetBlockHash().ToString(), - m_finalizedBlockIndex->nHeight); - pindexNew->nStatus = pindexNew->nStatus.withFailed(); - InvalidChainFound(pindexNew); - } - // If this block will cause an avalanche finalized block to be reorged, // then we park it. { @@ -3600,50 +3495,6 @@ return UnwindBlock(config, state, pindex, false); } -bool CChainState::FinalizeBlock(const Config &config, - BlockValidationState &state, - CBlockIndex *pindex) { - AssertLockNotHeld(m_chainstate_mutex); - AssertLockNotHeld(::cs_main); - // See 'Note for backport of Core PR16849' in CChainState::UnwindBlock - LOCK(m_chainstate_mutex); - - AssertLockNotHeld(cs_main); - CBlockIndex *pindexToInvalidate = nullptr; - { - LOCK(cs_main); - if (!MarkBlockAsFinal(state, pindex)) { - // state is set by MarkBlockAsFinal. - return false; - } - - // We have a valid candidate, make sure it is not parked. - if (pindex->nStatus.isOnParkedChain()) { - UnparkBlock(pindex); - } - - // If the finalized block is on the active chain, there is no need to - // rewind. - if (m_chain.Contains(pindex)) { - return true; - } - - // If the finalized block is not on the active chain, that chain is - // invalid - // ... - const CBlockIndex *pindexFork = m_chain.FindFork(pindex); - pindexToInvalidate = m_chain.Next(pindexFork); - if (!pindexToInvalidate) { - return false; - } - } // end of locked cs_main scope - - // ... therefore, we invalidate the block on the active chain that comes - // immediately after it - return UnwindBlock(config, state, pindexToInvalidate, - true /* invalidating */); -} - template <typename F> bool CChainState::UpdateFlagsForBlock(CBlockIndex *pindexBase, CBlockIndex *pindex, F f) { @@ -3700,13 +3551,6 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { AssertLockHeld(cs_main); - // In case we are reconsidering something before the finalization point, - // move the finalization point to the last common ancestor. - if (m_finalizedBlockIndex) { - m_finalizedBlockIndex = - LastCommonAncestor(pindex, m_finalizedBlockIndex); - } - UpdateFlags( pindex, m_chainman.m_best_invalid, [](const BlockStatus status) { @@ -3745,18 +3589,6 @@ return UnparkBlockImpl(pindex, false); } -bool CChainState::IsBlockFinalized(const CBlockIndex *pindex) const { - AssertLockHeld(cs_main); - return m_finalizedBlockIndex && - m_finalizedBlockIndex->GetAncestor(pindex->nHeight) == pindex; -} - -/** Return the currently finalized block index. */ -const CBlockIndex *CChainState::GetFinalizedBlock() const { - AssertLockHeld(cs_main); - return m_finalizedBlockIndex; -} - bool CChainState::AvalancheFinalizeBlock(CBlockIndex *pindex) { if (!pindex) { return false; @@ -4977,9 +4809,6 @@ AssertLockHeld(::cs_main); nBlockSequenceId = 1; setBlockIndexCandidates.clear(); - - // Do not point to CBlockIndex that will be free'd - m_finalizedBlockIndex = nullptr; } // May NOT be used after any connections are up as much diff --git a/test/functional/abc-finalize-block.py b/test/functional/abc-finalize-block.py deleted file mode 100755 --- a/test/functional/abc-finalize-block.py +++ /dev/null @@ -1,323 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2018 The Bitcoin developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test the finalizeblock RPC calls.""" - -import time - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import ( - assert_equal, - assert_raises_rpc_error, - set_node_times, -) - -RPC_FINALIZE_INVALID_BLOCK_ERROR = 'finalize-invalid-block' -RPC_FORK_PRIOR_FINALIZED_ERROR = 'bad-fork-prior-finalized' -RPC_BLOCK_NOT_FOUND_ERROR = 'Block not found' - - -class FinalizeBlockTest(BitcoinTestFramework): - def set_test_params(self): - self.num_nodes = 3 - self.extra_args = [["-finalizationdelay=0", "-whitelist=noban@127.0.0.1"], - ["-finalizationdelay=0"], []] - self.finalization_delay = 2 * 60 * 60 - - def run_test(self): - node = self.nodes[0] - - self.mocktime = int(time.time()) - - self.log.info("Test block finalization...") - self.generate(node, 10, sync_fun=self.no_op) - tip = node.getbestblockhash() - node.finalizeblock(tip) - assert_equal(node.getbestblockhash(), tip) - assert_equal(node.getfinalizedblockhash(), tip) - - def wait_for_tip(node, tip): - def check_tip(): - return node.getbestblockhash() == tip - self.wait_until(check_tip) - - alt_node = self.nodes[1] - wait_for_tip(alt_node, tip) - - alt_node.invalidateblock(tip) - # We will use this later - fork_block = alt_node.getbestblockhash() - - # Node 0 should not accept the whole alt_node's chain due to tip being finalized, - # even though it is longer. - # Headers would not be accepted if previousblock is invalid: - # - First block from alt node has same height than node tip, but is on a minority chain. Its - # status is "valid-headers" - # - Second block from alt node has height > node tip height, will be marked as invalid because - # node tip is finalized - # - Later blocks from alt node will be rejected because their previous block are invalid - # - # Expected state: - # - # On alt_node: - # >(210)->(211)-> // ->(218 tip) - # / - # (200)->(201)-> // ->(209)->(210 invalid) - # - # On node: - # >(210 valid-headers)->(211 invalid)->(212 to 218 dropped) - # / - # (200)->(201)-> // ->(209)->(210 finalized, tip) - - def wait_for_block(node, block, status="invalid"): - def check_block(): - for tip in node.getchaintips(): - if tip["hash"] == block: - assert tip["status"] != "active" - return tip["status"] == status - return False - self.wait_until(check_block) - - # First block header is accepted as valid-header - self.generate(alt_node, 1, sync_fun=self.no_op) - wait_for_block(node, alt_node.getbestblockhash(), "valid-headers") - - # Second block header is accepted but set invalid - self.generate(alt_node, 1, sync_fun=self.no_op) - invalid_block = alt_node.getbestblockhash() - wait_for_block(node, invalid_block) - - # Later block headers are rejected - for _ in range(2, 9): - self.generate(alt_node, 1, sync_fun=self.no_op) - assert_raises_rpc_error(-5, RPC_BLOCK_NOT_FOUND_ERROR, - node.getblockheader, alt_node.getbestblockhash()) - - assert_equal(node.getbestblockhash(), tip) - assert_equal(node.getfinalizedblockhash(), tip) - - self.log.info("Test that an invalid block cannot be finalized...") - assert_raises_rpc_error(-20, RPC_FINALIZE_INVALID_BLOCK_ERROR, - node.finalizeblock, invalid_block) - - self.log.info( - "Test that invalidating a finalized block moves the finalization backward...") - - # Node's finalized block will be invalidated, which causes the finalized block to - # move to the previous block. - # - # Expected state: - # - # On alt_node: - # >(210)->(211)-> // ->(218 tip) - # / - # (200)->(201)-> // ->(208 auto-finalized)->(209)->(210 invalid) - # - # On node: - # >(210 valid-headers)->(211 invalid)->(212 to 218 dropped) - # / - # (200)->(201)-> // ->(209 finalized)->(210 tip) - node.invalidateblock(tip) - node.reconsiderblock(tip) - - assert_equal(node.getbestblockhash(), tip) - assert_equal(node.getfinalizedblockhash(), fork_block) - - assert_equal(alt_node.getfinalizedblockhash(), node.getblockheader( - node.getfinalizedblockhash())['previousblockhash']) - - # The node will now accept that chain as the finalized block moved back. - # Generate a new block on alt_node to trigger getheader from node - # Previous 212-218 height blocks have been droped because their previous was invalid - # - # Expected state: - # - # On alt_node: - # >(210)->(211)-> // ->(218)->(219 tip) - # / - # (200)->(201)-> // ->(209 auto-finalized)->(210 invalid) - # - # On node: - # >(210)->(211)->(212)-> // ->(218)->(219 tip) - # / - # (200)->(201)-> // ->(209 finalized)->(210) - node.reconsiderblock(invalid_block) - - alt_node_tip = self.generate(alt_node, 1, sync_fun=self.no_op)[-1] - wait_for_tip(node, alt_node_tip) - - assert_equal(node.getbestblockhash(), alt_node.getbestblockhash()) - assert_equal(node.getfinalizedblockhash(), fork_block) - assert_equal(alt_node.getfinalizedblockhash(), fork_block) - - self.log.info("Trigger reorg via block finalization...") - # Finalize node tip to reorg - # - # Expected state: - # - # On alt_node: - # >(210)->(211)-> // ->(218)->(219 tip) - # / - # (200)->(201)-> // ->(209 auto-finalized)->(210 invalid) - # - # On node: - # >(210 invalid)-> // ->(219 invalid) - # / - # (200)->(201)-> // ->(209)->(210 finalized, tip) - node.finalizeblock(tip) - assert_equal(node.getfinalizedblockhash(), tip) - - self.log.info("Try to finalize a block on a competiting fork...") - assert_raises_rpc_error(-20, RPC_FINALIZE_INVALID_BLOCK_ERROR, - node.finalizeblock, alt_node.getbestblockhash()) - assert_equal(node.getfinalizedblockhash(), tip) - - self.log.info( - "Check auto-finalization occurs as the tip move forward...") - # Reconsider alt_node tip then generate some more blocks on alt_node. - # Auto-finalization will occur on both chains. - # - # Expected state: - # - # On alt_node: - # >(210)->(211)-> // ->(219 auto-finalized)-> // ->(229 tip) - # / - # (200)->(201)-> // ->(209)->(210 invalid) - # - # On node: - # >(210)->(211)-> // ->(219 auto-finalized)-> // ->(229 tip) - # / - # (200)->(201)-> // ->(209)->(210 invalid) - node.reconsiderblock(alt_node.getbestblockhash()) - block_to_autofinalize = self.generate( - alt_node, 1, sync_fun=self.no_op)[-1] - alt_node_new_tip = self.generate(alt_node, 9, sync_fun=self.no_op)[-1] - wait_for_tip(node, alt_node_new_tip) - - assert_equal(node.getbestblockhash(), alt_node.getbestblockhash()) - assert_equal(node.getfinalizedblockhash(), alt_node_tip) - assert_equal(alt_node.getfinalizedblockhash(), alt_node_tip) - - self.log.info( - "Try to finalize a block on an already finalized chain...") - # Finalizing a block of an already finalized chain should have no - # effect - block_218 = node.getblockheader(alt_node_tip)['previousblockhash'] - node.finalizeblock(block_218) - assert_equal(node.getfinalizedblockhash(), alt_node_tip) - - self.log.info( - "Make sure reconsidering block move the finalization point...") - # Reconsidering the tip will move back the finalized block on node - # - # Expected state: - # - # On alt_node: - # >(210)->(211)-> // ->(219 auto-finalized)-> // ->(229 tip) - # / - # (200)->(201)-> // ->(209)->(210 invalid) - # - # On node: - # >(210)->(211)-> // ->(219)-> // ->(229 tip) - # / - # (200)->(201)-> // ->(209 finalized)->(210) - node.reconsiderblock(tip) - - assert_equal(node.getbestblockhash(), alt_node_new_tip) - assert_equal(node.getfinalizedblockhash(), fork_block) - - # TEST FINALIZATION DELAY - - self.log.info("Check that finalization delay prevents eclipse attacks") - # Because there has been no delay since the beginning of this test, - # there should have been no auto-finalization on delay_node. - # - # Expected state: - # - # On alt_node: - # >(210)->(211)-> // ->(219 auto-finalized)-> // ->(229 tip) - # / - # (200)->(201)-> // ->(209)->(210 invalid) - # - # On delay_node: - # >(210)->(211)-> // ->(219)-> // ->(229 tip) - # / - # (200)->(201)-> // ->(209)->(210) - delay_node = self.nodes[2] - wait_for_tip(delay_node, alt_node_new_tip) - assert_equal(delay_node.getfinalizedblockhash(), str()) - - self.log.info( - "Check that finalization delay does not prevent auto-finalization") - # Expire the delay, then generate 1 new block with alt_node to - # update the tip on all chains. - # Because the finalization delay is expired, auto-finalization - # should occur. - # - # Expected state: - # - # On alt_node: - # >(220 auto-finalized)-> // ->(230 tip) - # / - # (200)->(201)-> // ->(209)->(210 invalid) - # - # On delay_node: - # >(220 auto-finalized)-> // ->(230 tip) - # / - # (200)->(201)-> // ->(209)->(210) - self.mocktime += self.finalization_delay - set_node_times([delay_node], self.mocktime) - new_tip = self.generate(alt_node, 1, sync_fun=self.no_op)[-1] - - assert_equal(alt_node.getbestblockhash(), new_tip) - assert_equal(alt_node.getfinalizedblockhash(), block_to_autofinalize) - - wait_for_tip(node, new_tip) - assert_equal(node.getfinalizedblockhash(), block_to_autofinalize) - - wait_for_tip(delay_node, new_tip) - self.log.info( - "Check that finalization delay is effective on node boot") - # Restart the new node, so the blocks have no header received time. - self.restart_node(2) - - # There should be no finalized block (getfinalizedblockhash returns an - # empty string) - assert_equal(delay_node.getfinalizedblockhash(), str()) - - # Generate 20 blocks with no delay. This should not trigger auto-finalization. - # - # Expected state: - # - # On delay_node: - # >(220)-> // ->(250 tip) - # / - # (200)->(201)-> // ->(209)->(210) - blocks = self.generate(delay_node, 20, sync_fun=self.no_op) - reboot_autofinalized_block = blocks[10] - new_tip = blocks[-1] - wait_for_tip(delay_node, new_tip) - - assert_equal(delay_node.getfinalizedblockhash(), str()) - - # Now let the finalization delay to expire, then generate one more block. - # This should resume auto-finalization. - # - # Expected state: - # - # On delay_node: - # >(220)-> // ->(241 auto-finalized)-> // ->(251 tip) - # / - # (200)->(201)-> // ->(209)->(210) - self.mocktime += self.finalization_delay - set_node_times([delay_node], self.mocktime) - new_tip = self.generate(delay_node, 1, sync_fun=self.no_op)[-1] - wait_for_tip(delay_node, new_tip) - - assert_equal(delay_node.getfinalizedblockhash(), - reboot_autofinalized_block) - - -if __name__ == '__main__': - FinalizeBlockTest().main() diff --git a/test/functional/abc-parkedchain.py b/test/functional/abc-parkedchain.py --- a/test/functional/abc-parkedchain.py +++ b/test/functional/abc-parkedchain.py @@ -19,7 +19,6 @@ ], [ "-automaticunparking=1", - "-maxreorgdepth=-1" ] ] diff --git a/test/functional/abc_p2p_avalanche_voting.py b/test/functional/abc_p2p_avalanche_voting.py --- a/test/functional/abc_p2p_avalanche_voting.py +++ b/test/functional/abc_p2p_avalanche_voting.py @@ -43,7 +43,6 @@ '-avaminquorumstake=0', '-avaminavaproofsnodecount=0', '-noparkdeepreorg', - '-maxreorgdepth=-1', '-whitelist=noban@127.0.0.1', ], ] diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -43,12 +43,10 @@ self.extra_args = [ [ "-noparkdeepreorg", - "-maxreorgdepth=-1", "-acceptnonstdtxn=1", ], [ "-acceptnonstdtxn=0", - "-maxreorgdepth=-1", "-automaticunparking=1", ] ] diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -76,7 +76,7 @@ self.setup_clean_chain = True # This is a consensus block test, we don't care about tx policy self.extra_args = [['-noparkdeepreorg', - '-maxreorgdepth=-1', '-acceptnonstdtxn=1']] + '-acceptnonstdtxn=1']] def run_test(self): node = self.nodes[0] # convenience reference to the node diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -86,17 +86,17 @@ # Create nodes 0 and 1 to mine. # Create node 2 to test pruning. self.full_node_default_args = ["-maxreceivebuffer=20000", "-blockmaxsize=999000", - "-checkblocks=5", "-noparkdeepreorg", "-maxreorgdepth=-1"] + "-checkblocks=5", "-noparkdeepreorg"] # Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later) # Create nodes 5 to test wallet in prune mode, but do not connect self.extra_args = [self.full_node_default_args, self.full_node_default_args, ["-maxreceivebuffer=20000", "-prune=550", - "-noparkdeepreorg", "-maxreorgdepth=-1"], + "-noparkdeepreorg"], ["-maxreceivebuffer=20000", "-blockmaxsize=999000", - "-noparkdeepreorg", "-maxreorgdepth=-1"], + "-noparkdeepreorg"], ["-maxreceivebuffer=20000", "-blockmaxsize=999000", - "-noparkdeepreorg", "-maxreorgdepth=-1"], + "-noparkdeepreorg"], ["-prune=550"]] self.rpc_timeout = 120 @@ -383,7 +383,7 @@ # check that the pruning node's wallet is still in good shape self.log.info("Stop and start pruning node to trigger wallet rescan") self.restart_node( - 2, extra_args=["-prune=550", "-noparkdeepreorg", "-maxreorgdepth=-1"]) + 2, extra_args=["-prune=550", "-noparkdeepreorg"]) self.log.info("Success") # check that wallet loads successfully when restarting a pruned node after IBD. @@ -393,7 +393,7 @@ nds = [self.nodes[0], self.nodes[5]] self.sync_blocks(nds, wait=5, timeout=300) self.restart_node( - 5, extra_args=["-prune=550", "-noparkdeepreorg", "-maxreorgdepth=-1"]) + 5, extra_args=["-prune=550", "-noparkdeepreorg"]) self.log.info("Success") def run_test(self): diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -701,7 +701,7 @@ def check_script_prefixes(all_scripts): """Check that no more than `EXPECTED_VIOLATION_COUNT` of the test scripts don't start with one of the allowed name prefixes.""" - EXPECTED_VIOLATION_COUNT = 16 + EXPECTED_VIOLATION_COUNT = 15 # LEEWAY is provided as a transition measure, so that pull-requests # that introduce new tests that don't conform with the naming