diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2016-08-26 23:05:09 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2016-08-26 23:05:45 +0200 |
commit | 5127c4f21ca3f092b3a853833631dfc7f9c9456b (patch) | |
tree | a325ed7934f5d5ac0e3ac7ff3b393f2fce33abcc | |
parent | c072b8fd95cd4fa84f08189a0cd8b173ea2dbb8e (diff) |
Add preciousblock RPC
Includes a bugfix by Luke-Jr.
-rw-r--r-- | src/chain.h | 2 | ||||
-rw-r--r-- | src/main.cpp | 38 | ||||
-rw-r--r-- | src/main.h | 3 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 40 |
4 files changed, 80 insertions, 3 deletions
diff --git a/src/chain.h b/src/chain.h index 76a774c123..bf801c5cbe 100644 --- a/src/chain.h +++ b/src/chain.h @@ -200,7 +200,7 @@ public: unsigned int nNonce; //! (memory only) Sequential id assigned to distinguish order in which blocks are received. - uint32_t nSequenceId; + int32_t nSequenceId; void SetNull() { diff --git a/src/main.cpp b/src/main.cpp index 30edc5dbeb..8456039c8f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -167,7 +167,11 @@ namespace { */ CCriticalSection cs_nBlockSequenceId; /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */ - uint32_t nBlockSequenceId = 1; + int32_t nBlockSequenceId = 1; + /** Decreasing counter (used by subsequent preciousblock calls). */ + int32_t nBlockReverseSequenceId = -1; + /** chainwork for the last block that preciousblock has been applied to. */ + arith_uint256 nLastPreciousChainwork = 0; /** * Sources of received blocks, saved to be able to send them reject @@ -3107,6 +3111,36 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, return true; } + +bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) +{ + { + LOCK(cs_main); + if (pindex->nChainWork < chainActive.Tip()->nChainWork) { + // Nothing to do, this block is not at the tip. + return true; + } + if (chainActive.Tip()->nChainWork > nLastPreciousChainwork) { + // The chain has been extended since the last call, reset the counter. + nBlockReverseSequenceId = -1; + } + nLastPreciousChainwork = chainActive.Tip()->nChainWork; + setBlockIndexCandidates.erase(pindex); + pindex->nSequenceId = nBlockReverseSequenceId; + if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) { + // We can't keep reducing the counter if somebody really wants to + // call preciousblock 2**31-1 times on the same set of tips... + nBlockReverseSequenceId--; + } + if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->nChainTx) { + setBlockIndexCandidates.insert(pindex); + PruneBlockIndexCandidates(); + } + } + + return ActivateBestChain(state, params); +} + bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) { AssertLockHeld(cs_main); @@ -4501,7 +4535,7 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams) assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match. assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. } - if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked + if (pindex->nChainTx == 0) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock) // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred). // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred. if (!fHavePruned) { diff --git a/src/main.h b/src/main.h index e9106fccf7..f809f89812 100644 --- a/src/main.h +++ b/src/main.h @@ -499,6 +499,9 @@ public: /** Find the last common block between the parameter chain and a locator. */ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); +/** Mark a block as precious and reorganize. */ +bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex); + /** Mark a block as invalid. */ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index e3c32d905a..75f49e939b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1105,6 +1105,44 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp) return mempoolInfoToJSON(); } +UniValue preciousblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "preciousblock \"hash\"\n" + "\nTreats a block as if it were received before others with the same work.\n" + "\nA later preciousblock call can override the effect of an earlier one.\n" + "\nThe effects of preciousblock are not retained across restarts.\n" + "\nArguments:\n" + "1. hash (string, required) the hash of the block to mark as precious\n" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("preciousblock", "\"blockhash\"") + + HelpExampleRpc("preciousblock", "\"blockhash\"") + ); + + std::string strHash = params[0].get_str(); + uint256 hash(uint256S(strHash)); + CBlockIndex* pblockindex; + + { + LOCK(cs_main); + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + pblockindex = mapBlockIndex[hash]; + } + + CValidationState state; + PreciousBlock(state, Params(), pblockindex); + + if (!state.IsValid()) { + throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); + } + + return NullUniValue; +} + UniValue invalidateblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -1200,6 +1238,8 @@ static const CRPCCommand commands[] = { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, { "blockchain", "verifychain", &verifychain, true }, + { "blockchain", "preciousblock", &preciousblock, true }, + /* Not shown in help */ { "hidden", "invalidateblock", &invalidateblock, true }, { "hidden", "reconsiderblock", &reconsiderblock, true }, |