Browse Source

Add 'invalidateblock' and 'reconsiderblock' RPC commands.

These can be used for testing reorganizations or for manual intervention in case of
chain forks.
0.10
Pieter Wuille 10 years ago
parent
commit
9b0a8d3152
  1. 73
      src/main.cpp
  2. 6
      src/main.h
  3. 76
      src/rpcblockchain.cpp
  4. 2
      src/rpcserver.cpp
  5. 2
      src/rpcserver.h

73
src/main.cpp

@ -2135,6 +2135,79 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
return true; 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) CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
{ {
// Check for duplicate // Check for duplicate

6
src/main.h

@ -609,6 +609,12 @@ public:
/** Find the last common block between the parameter chain and a locator. */ /** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& 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. */ /** The currently-connected chain of blocks. */
extern CChain chainActive; extern CChain chainActive;

76
src/rpcblockchain.cpp

@ -561,3 +561,79 @@ Value getmempoolinfo(const Array& params, bool fHelp)
return ret; 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
src/rpcserver.cpp

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

2
src/rpcserver.h

@ -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 gettxout(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value verifychain(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 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 // in rest.cpp
extern bool HTTPReq_REST(AcceptedConnection *conn, extern bool HTTPReq_REST(AcceptedConnection *conn,

Loading…
Cancel
Save