nlr
This commit is contained in:
parent
998ac47e9a
commit
2fe045194c
@ -139,6 +139,7 @@ public:
|
||||
pchMessageStart[3] = 0xf1;
|
||||
nDefaultPort = 7312;
|
||||
nPruneAfterHeight = 100000;
|
||||
nNlrLimit = 100; // 100 * ~40s = ~66 minutes
|
||||
|
||||
genesis = CreateGenesisBlock(1371488396, 1000112548, 0x1e0ffff0, 1, 100 * COIN);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
@ -275,6 +276,7 @@ public:
|
||||
pchMessageStart[3] = 0xf2;
|
||||
nDefaultPort = 17312;
|
||||
nPruneAfterHeight = 100000;
|
||||
nNlrLimit = 50; // 50 * ~40s = ~33 minutes
|
||||
|
||||
genesis = CreateGenesisBlock(1371387277, 1000580675, 0x1e0ffff0, 1, 100 * COIN);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
@ -389,6 +391,7 @@ public:
|
||||
pchMessageStart[3] = 0xda;
|
||||
nDefaultPort = 17412;
|
||||
nPruneAfterHeight = 1000;
|
||||
nNlrLimit = 10;
|
||||
|
||||
genesis = CreateGenesisBlock(1371387277, 0, 0x207fffff, 1, 100 * COIN);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
|
||||
@ -63,6 +63,7 @@ public:
|
||||
const Consensus::Params& GetConsensus() const { return consensus; }
|
||||
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
|
||||
int GetDefaultPort() const { return nDefaultPort; }
|
||||
int NoLargeReorgLimit() const { return nNlrLimit; }
|
||||
|
||||
const CBlock& GenesisBlock() const { return genesis; }
|
||||
/** Default value for -checkmempool and -checkblockindex argument */
|
||||
@ -87,6 +88,7 @@ protected:
|
||||
CMessageHeader::MessageStartChars pchMessageStart;
|
||||
int nDefaultPort;
|
||||
uint64_t nPruneAfterHeight;
|
||||
int nNlrLimit;
|
||||
std::vector<CDNSSeedData> vSeeds;
|
||||
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
|
||||
std::string strNetworkID;
|
||||
|
||||
@ -401,6 +401,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER));
|
||||
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER));
|
||||
strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT));
|
||||
strUsage += HelpMessageOpt("-nlrlimit=<n>", strprintf(_("Set the limit to be considered a large reorg, -nlrlimit=0 to disable NLR mode (default: %u)"), defaultChainParams->NoLargeReorgLimit()));
|
||||
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
|
||||
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
|
||||
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
|
||||
|
||||
@ -1457,7 +1457,7 @@ UniValue reconsiderblock(const JSONRPCRequest& request)
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
ActivateBestChain(state, Params());
|
||||
ActivateBestChain(state, Params(), std::shared_ptr<const CBlock>(), true);
|
||||
|
||||
if (!state.IsValid()) {
|
||||
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
|
||||
|
||||
@ -2313,12 +2313,42 @@ static void PruneBlockIndexCandidates() {
|
||||
* Try to make some progress towards making pindexMostWork the active block.
|
||||
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
|
||||
*/
|
||||
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
|
||||
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace, bool reconsider)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
||||
|
||||
int nNlrLimit = gArgs.GetArg("-nlrlimit", Params().NoLargeReorgLimit());
|
||||
if (nNlrLimit != 0 && !reconsider && !IsInitialBlockDownload() && pindexFork != nullptr
|
||||
&& chainActive.Tip()->nHeight - pindexFork->nHeight >= nNlrLimit) {
|
||||
LogPrintf("%s: NLR triggered! current height=%d current hash=%s | fork height=%d fork hash=%s\n", __func__,
|
||||
pindexOldTip->nHeight, pindexOldTip->GetBlockHash().ToString(), pindexMostWork->nHeight,
|
||||
pindexMostWork->GetBlockHash().ToString());
|
||||
CBlockIndex *pindexWalk = pindexMostWork;
|
||||
|
||||
// mark invalid_child from tip of fork to second block of fork
|
||||
while (pindexWalk->nHeight != pindexFork->nHeight+2) {
|
||||
pindexWalk = pindexWalk->pprev;
|
||||
pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
|
||||
setDirtyBlockIndex.insert(pindexWalk);
|
||||
setBlockIndexCandidates.erase(pindexWalk);
|
||||
}
|
||||
|
||||
// mark invalid first block of fork
|
||||
pindexWalk = pindexWalk->pprev;
|
||||
pindexWalk->nStatus |= BLOCK_FAILED_VALID;
|
||||
setDirtyBlockIndex.insert(pindexWalk);
|
||||
setBlockIndexCandidates.erase(pindexWalk);
|
||||
|
||||
// sanity check
|
||||
assert(pindexWalk->pprev == pindexFork);
|
||||
|
||||
fInvalidFound = true;
|
||||
InvalidChainFound(pindexMostWork);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disconnect active blocks which are no longer in the best chain.
|
||||
bool fBlocksDisconnected = false;
|
||||
DisconnectedBlockTransactions disconnectpool;
|
||||
@ -2420,7 +2450,7 @@ static void NotifyHeaderTip() {
|
||||
* or an activated best chain. pblock is either nullptr or a pointer to a block
|
||||
* that is already loaded (to avoid loading it again from disk).
|
||||
*/
|
||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock, bool reconsider) {
|
||||
// Note that while we're often called here from ProcessNewBlock, this is
|
||||
// far from a guarantee. Things in the P2P/RPC will often end up calling
|
||||
// us in the middle of ProcessNewBlock - do not assume pblock is set
|
||||
@ -2451,7 +2481,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
||||
|
||||
bool fInvalidFound = false;
|
||||
std::shared_ptr<const CBlock> nullBlockPtr;
|
||||
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
|
||||
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace, reconsider))
|
||||
return false;
|
||||
|
||||
if (fInvalidFound) {
|
||||
|
||||
@ -273,7 +273,7 @@ bool IsInitialBlockDownload();
|
||||
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
||||
bool GetTransaction(const uint256 &hash, CTransactionRef &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
|
||||
/** Find the best known block, and make it the tip of the block chain */
|
||||
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
|
||||
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>(), bool reconsider=false);
|
||||
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
|
||||
|
||||
/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
|
||||
|
||||
105
test/functional/nlr.py
Normal file
105
test/functional/nlr.py
Normal file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
# Copyright (c) Flo Developers 2013-2018
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test the getchaintips RPC.
|
||||
|
||||
- introduce a network split
|
||||
- work on chains of different lengths
|
||||
- join the network together again
|
||||
- verify that getchaintips now returns two chain tips.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal
|
||||
|
||||
class GetChainTipsTest (BitcoinTestFramework):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.num_nodes = 4
|
||||
self.extra_args = [['-nlrlimit=0'], ['-nlrlimit=10'], ['-nlrlimit=10'], ['-nlrlimit=10']]
|
||||
self.setup_clean_chain = False
|
||||
|
||||
def run_test (self):
|
||||
|
||||
tips = self.nodes[0].getchaintips ()
|
||||
assert_equal (len (tips), 1)
|
||||
assert_equal (tips[0]['branchlen'], 0)
|
||||
assert_equal (tips[0]['height'], 200)
|
||||
assert_equal (tips[0]['status'], 'active')
|
||||
|
||||
# Split the network and build two chains of different lengths.
|
||||
self.split_network()
|
||||
self.nodes[0].generate(10)
|
||||
self.nodes[2].generate(20)
|
||||
self.sync_all([self.nodes[:2], self.nodes[2:]])
|
||||
|
||||
tips = self.nodes[1].getchaintips ()
|
||||
assert_equal (len (tips), 1)
|
||||
shortTip = tips[0]
|
||||
assert_equal(shortTip['branchlen'], 0)
|
||||
assert_equal(shortTip['height'], 210)
|
||||
assert_equal(tips[0]['status'], 'active')
|
||||
|
||||
tips = self.nodes[3].getchaintips ()
|
||||
assert_equal (len (tips), 1)
|
||||
longTip = tips[0]
|
||||
assert_equal (longTip['branchlen'], 0)
|
||||
assert_equal (longTip['height'], 220)
|
||||
assert_equal (tips[0]['status'], 'active')
|
||||
|
||||
# Join the network halves and check that we now have two tips
|
||||
# (at least at the nodes that previously had the short chain).
|
||||
print("pre join")
|
||||
self.join_network_no_sync ()
|
||||
time.sleep(10)
|
||||
print("post join")
|
||||
|
||||
print("node 0")
|
||||
print(self.nodes[0].getchaintips())
|
||||
print("node 1")
|
||||
print(self.nodes[1].getchaintips())
|
||||
print("node 2")
|
||||
print(self.nodes[2].getchaintips())
|
||||
|
||||
print("reconsider")
|
||||
self.nodes[1].reconsiderblock(self.nodes[2].getbestblockhash())
|
||||
self.sync_all()
|
||||
|
||||
print("node 0")
|
||||
print(self.nodes[0].getchaintips ())
|
||||
print("node 1")
|
||||
print(self.nodes[1].getchaintips ())
|
||||
print("node 2")
|
||||
print(self.nodes[2].getchaintips ())
|
||||
self.nodes[2].generate(20)
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[1].generate(20)
|
||||
|
||||
self.sync_all()
|
||||
|
||||
print("node 0")
|
||||
print(self.nodes[0].getchaintips ())
|
||||
print("node 1")
|
||||
print(self.nodes[1].getchaintips ())
|
||||
print("node 2")
|
||||
print(self.nodes[2].getchaintips ())
|
||||
|
||||
# tips = self.nodes[1].getchaintips ()
|
||||
# assert_equal (len (tips), 2)
|
||||
# assert_equal (tips[0], longTip)
|
||||
#
|
||||
# assert_equal (tips[1]['branchlen'], 10)
|
||||
# assert_equal (tips[1]['status'], 'valid-fork')
|
||||
# tips[1]['branchlen'] = 0
|
||||
# tips[1]['status'] = 'active'
|
||||
# assert_equal (tips[1], shortTip)
|
||||
|
||||
assert_equal(1, 3)
|
||||
|
||||
if __name__ == '__main__':
|
||||
GetChainTipsTest().main()
|
||||
@ -310,6 +310,12 @@ class BitcoinTestFramework(object):
|
||||
connect_nodes_bi(self.nodes, 1, 2)
|
||||
self.sync_all()
|
||||
|
||||
def join_network_no_sync(self):
|
||||
"""
|
||||
Join the (previously split) network halves together. Do not wait sync.
|
||||
"""
|
||||
connect_nodes_bi(self.nodes, 1, 2)
|
||||
|
||||
def sync_all(self, node_groups=None):
|
||||
if not node_groups:
|
||||
node_groups = [self.nodes]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user