Add preciousblock RPC

Includes a bugfix by Luke-Jr.
This commit is contained in:
Pieter Wuille 2016-08-26 23:05:09 +02:00
parent c072b8fd95
commit 5127c4f21c
4 changed files with 80 additions and 3 deletions

View file

@ -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()
{

View file

@ -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) {

View file

@ -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);

View file

@ -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 },