Browse Source

Add 'invalidateblock' and 'reconsiderblock' RPC commands.

These can be used for testing reorganizations or for manual intervention in case of
chain forks.
tags/v0.15.1
Pieter Wuille 6 years ago
parent
commit
9b0a8d3152
5 changed files with 159 additions and 0 deletions
  1. 73
    0
      src/main.cpp
  2. 6
    0
      src/main.h
  3. 76
    0
      src/rpcblockchain.cpp
  4. 2
    0
      src/rpcserver.cpp
  5. 2
    0
      src/rpcserver.h

+ 73
- 0
src/main.cpp View File

@@ -2135,6 +2135,79 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
return true;
}

bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) {
AssertLockHeld(cs_main);

// Mark the block itself as invalid.
pindex->nStatus |= BLOCK_FAILED_VALID;
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) {
return state.Abort("Failed to update block index");
}
setBlockIndexCandidates.erase(pindex);

while (chainActive.Contains(pindex)) {
CBlockIndex *pindexWalk = chainActive.Tip();
pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexWalk))) {
return state.Abort("Failed to update block index");
}
setBlockIndexCandidates.erase(pindexWalk);
// ActivateBestChain considers blocks already in chainActive
// unconditionally valid already, so force disconnect away from it.
if (!DisconnectTip(state)) {
return false;
}
}

// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
// add them again.
BlockMap::iterator it = mapBlockIndex.begin();
while (it != mapBlockIndex.end()) {
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) {
setBlockIndexCandidates.insert(pindex);
}
it++;
}

InvalidChainFound(pindex);
return true;
}

bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) {
AssertLockHeld(cs_main);

int nHeight = pindex->nHeight;

// Remove the invalidity flag from this block and all its descendants.
BlockMap::iterator it = mapBlockIndex.begin();
while (it != mapBlockIndex.end()) {
if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) {
it->second->nStatus &= ~BLOCK_FAILED_MASK;
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) {
return state.Abort("Failed to update block index");
}
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) {
setBlockIndexCandidates.insert(it->second);
}
if (it->second == pindexBestInvalid) {
// Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = NULL;
}
}
it++;
}

// Remove the invalidity flag from all ancestors too.
while (pindex != NULL) {
pindex->nStatus &= ~BLOCK_FAILED_MASK;
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) {
return state.Abort("Failed to update block index");
}
pindex = pindex->pprev;
}
return true;
}

CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
{
// Check for duplicate

+ 6
- 0
src/main.h View File

@@ -609,6 +609,12 @@ 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 invalid. */
bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex);

/** Remove invalidity status from a block and its descendants. */
bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex);

/** The currently-connected chain of blocks. */
extern CChain chainActive;


+ 76
- 0
src/rpcblockchain.cpp View File

@@ -561,3 +561,79 @@ Value getmempoolinfo(const Array& params, bool fHelp)
return ret;
}

Value invalidateblock(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"invalidateblock \"hash\"\n"
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
"\nArguments:\n"
"1. hash (string, required) the hash of the block to mark as invalid\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("invalidateblock", "\"blockhash\"")
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
);

std::string strHash = params[0].get_str();
uint256 hash(strHash);
CValidationState state;

{
LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

CBlockIndex* pblockindex = mapBlockIndex[hash];
InvalidateBlock(state, pblockindex);
}

if (state.IsValid()) {
ActivateBestChain(state);
}

if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
}

return Value::null;
}

Value reconsiderblock(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"reconsiderblock \"hash\"\n"
"\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
"This can be used to undo the effects of invalidateblock.\n"
"\nArguments:\n"
"1. hash (string, required) the hash of the block to reconsider\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
);

std::string strHash = params[0].get_str();
uint256 hash(strHash);
CValidationState state;

{
LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

CBlockIndex* pblockindex = mapBlockIndex[hash];
ReconsiderBlock(state, pblockindex);
}

if (state.IsValid()) {
ActivateBestChain(state);
}

if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
}

return Value::null;
}

+ 2
- 0
src/rpcserver.cpp View File

@@ -270,6 +270,8 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "gettxout", &gettxout, true, false, false },
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
{ "blockchain", "verifychain", &verifychain, true, false, false },
{ "blockchain", "invalidateblock", &invalidateblock, true, true, false },
{ "blockchain", "reconsiderblock", &reconsiderblock, true, true, false },

/* Mining */
{ "mining", "getblocktemplate", &getblocktemplate, true, false, false },

+ 2
- 0
src/rpcserver.h View File

@@ -222,6 +222,8 @@ extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool
extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value invalidateblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool fHelp);

// in rest.cpp
extern bool HTTPReq_REST(AcceptedConnection *conn,

Loading…
Cancel
Save