aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2016-10-18 21:35:27 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2016-10-18 21:36:38 +0200
commit7f71a3c591945769ad33e5734105219062311d1e (patch)
treefe9c4008eeeb0f912630ecf80b7342072f15e353 /src
parentdf7519cbc1a9613a557bf84ad3c124795155f287 (diff)
parent5805ac836c5847bc54cbef3e71154d022ca18eda (diff)
Merge #6996: Add preciousblock RPC
5805ac8 Add preciousblock tests (Pieter Wuille) 5127c4f Add preciousblock RPC (Pieter Wuille)
Diffstat (limited to 'src')
-rw-r--r--src/chain.h2
-rw-r--r--src/main.cpp38
-rw-r--r--src/main.h3
-rw-r--r--src/rpc/blockchain.cpp40
4 files changed, 80 insertions, 3 deletions
diff --git a/src/chain.h b/src/chain.h
index 6588e8f57d..e2f8c56522 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 9f3116e358..cb3e771602 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -169,7 +169,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
@@ -3137,6 +3141,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);
@@ -4531,7 +4565,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 db58b27487..49768f21c1 100644
--- a/src/main.h
+++ b/src/main.h
@@ -509,6 +509,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 1e04fcc01c..1ca4a7c6d7 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1251,6 +1251,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)
@@ -1346,6 +1384,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 },