mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Add periodic RPC recheck and invalid block recheck
This commit is contained in:
parent
0e4e83474e
commit
4688e3eb8e
3 changed files with 150 additions and 1 deletions
15
src/init.cpp
15
src/init.cpp
|
|
@ -21,7 +21,6 @@
|
|||
#include <httprpc.h>
|
||||
#include <index/txindex.h>
|
||||
#include <key.h>
|
||||
#include <validation.h>
|
||||
#include <mainchainrpc.h>
|
||||
#include <miner.h>
|
||||
#include <netbase.h>
|
||||
|
|
@ -45,6 +44,7 @@
|
|||
#include <util.h>
|
||||
#include <utilmoneystr.h>
|
||||
#include <utilstrencodings.h>
|
||||
#include <validation.h>
|
||||
#include <validationinterface.h>
|
||||
#include <warnings.h>
|
||||
#include <walletinitinterface.h>
|
||||
|
|
@ -546,6 +546,7 @@ void SetupServerArgs()
|
|||
gArgs.AddArg("-mainchainrpccookiefile=<file>", "The bitcoind cookie auth path which the daemon will use to connect to the trusted bitcoind to validate peg-ins. (default: `<datadir>/regtest/.cookie`)", false, OptionsCategory::ELEMENTS);
|
||||
gArgs.AddArg("-mainchainrpctimeout=<n>", strprintf("Timeout in seconds during mainchain RPC requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), false, OptionsCategory::ELEMENTS);
|
||||
gArgs.AddArg("-peginconfirmationdepth=<n>", strprintf("Pegin claims must be this deep to be considered valid. (default: %d)", DEFAULT_PEGIN_CONFIRMATION_DEPTH), false, OptionsCategory::ELEMENTS);
|
||||
gArgs.AddArg("-recheckpeginblockinterval=<n>", strprintf("The interval in seconds at which a peg-in witness failing block is re-evaluated in case of intermittant peg-in witness failure. 0 means never. (default: %u)", 120), false, OptionsCategory::ELEMENTS);
|
||||
gArgs.AddArg("-parentpubkeyprefix", strprintf("The byte prefix, in decimal, of the parent chain's base58 pubkey address. (default: %d)", 111), false, OptionsCategory::CHAINPARAMS);
|
||||
gArgs.AddArg("-parentscriptprefix", strprintf("The byte prefix, in decimal, of the parent chain's base58 script address. (default: %d)", 196), false, OptionsCategory::CHAINPARAMS);
|
||||
gArgs.AddArg("-parent_bech32_hrp", strprintf("The human-readable part of the parent chain's bech32 encoding. (default: %s)", "bc"), false, OptionsCategory::CHAINPARAMS);
|
||||
|
|
@ -1762,6 +1763,18 @@ bool AppInitMain()
|
|||
// ********************************************************* Step 13: finished
|
||||
|
||||
SetRPCWarmupFinished();
|
||||
|
||||
// ELEMENTS:
|
||||
CScheduler::Function f2 = boost::bind(&BitcoindRPCCheck, false);
|
||||
unsigned int check_rpc_every = gArgs.GetArg("-recheckpeginblockinterval", 120);
|
||||
if (check_rpc_every) {
|
||||
scheduler.scheduleEvery(f2, check_rpc_every);
|
||||
}
|
||||
uiInterface.InitMessage(_("Awaiting bitcoind RPC warmup"));
|
||||
if (!BitcoindRPCCheck(true)) { //Initial check, fail immediately
|
||||
return InitError(_("ERROR: elementsd is set to verify pegins but cannot get valid response from bitcoind. Please check debug.log for more information."));
|
||||
}
|
||||
|
||||
uiInterface.InitMessage(_("Done loading"));
|
||||
|
||||
g_wallet_init_interface.Start(scheduler);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <cuckoocache.h>
|
||||
#include <hash.h>
|
||||
#include <index/txindex.h>
|
||||
#include <mainchainrpc.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/rbf.h>
|
||||
|
|
@ -4979,3 +4980,127 @@ public:
|
|||
mapBlockIndex.clear();
|
||||
}
|
||||
} instance_of_cmaincleanup;
|
||||
|
||||
// ELEMENTS:
|
||||
/* This function has two major purposes:
|
||||
* 1) Checks that the RPC connection to the parent chain node
|
||||
* can be attained, and is returning back reasonable answers.
|
||||
* 2) Re-evaluates a list of blocks that have been deemed "bad"
|
||||
* from the perspective of peg-in witness validation. Blocks are
|
||||
* added to this queue in ConnectTip based on the error code returned.
|
||||
*/
|
||||
bool BitcoindRPCCheck(const bool init)
|
||||
{
|
||||
// First, we can clear out any blocks thatsomehow are now deemed valid
|
||||
// eg reconsiderblock rpc call manually
|
||||
std::vector<uint256> vblocksToReconsider;
|
||||
pblocktree->ReadInvalidBlockQueue(vblocksToReconsider);
|
||||
std::vector<uint256> vblocksToReconsiderAgain;
|
||||
for(uint256& blockhash : vblocksToReconsider) {
|
||||
LOCK(cs_main);
|
||||
if (mapBlockIndex.count(blockhash)) {
|
||||
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
|
||||
if ((pblockindex->nStatus & BLOCK_FAILED_MASK)) {
|
||||
vblocksToReconsiderAgain.push_back(blockhash);
|
||||
}
|
||||
}
|
||||
}
|
||||
vblocksToReconsider = vblocksToReconsiderAgain;
|
||||
vblocksToReconsiderAgain.clear();
|
||||
pblocktree->WriteInvalidBlockQueue(vblocksToReconsider);
|
||||
|
||||
// Next, check for working and valid rpc
|
||||
if (gArgs.GetBoolArg("-validatepegin", DEFAULT_VALIDATE_PEGIN)) {
|
||||
// During init try until a non-RPC_IN_WARMUP result
|
||||
while (true) {
|
||||
try {
|
||||
// The first thing we have to check is the version of the node.
|
||||
UniValue params(UniValue::VARR);
|
||||
UniValue reply = CallMainChainRPC("getnetworkinfo", params);
|
||||
UniValue error = reply["error"];
|
||||
if (!error.isNull()) {
|
||||
// On the first call, it's possible to node is still in
|
||||
// warmup; in that case, just wait and retry.
|
||||
if (error["code"].get_int() == RPC_IN_WARMUP) {
|
||||
MilliSleep(1000);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
LogPrintf("ERROR: Bitcoind RPC check returned 'error' response.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
UniValue result = reply["result"];
|
||||
if (!result.isObject() || !result.get_obj()["version"].isNum() ||
|
||||
result.get_obj()["version"].get_int() < MIN_MAINCHAIN_NODE_VERSION) {
|
||||
LogPrintf("ERROR: Parent chain daemon too old; need Bitcoin Core version 0.16.3 or newer.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Then check the genesis block to correspond to parent chain.
|
||||
params.push_back(UniValue(0));
|
||||
reply = CallMainChainRPC("getblockhash", params);
|
||||
error = reply["error"];
|
||||
if (!error.isNull()) {
|
||||
LogPrintf("ERROR: Bitcoind RPC check returned 'error' response.\n");
|
||||
return false;
|
||||
}
|
||||
result = reply["result"];
|
||||
if (!result.isStr() || result.get_str() != Params().ParentGenesisBlockHash().GetHex()) {
|
||||
LogPrintf("ERROR: Invalid parent genesis block hash response via RPC. Contacting wrong parent daemon?\n");
|
||||
return false;
|
||||
}
|
||||
} catch (const std::runtime_error& re) {
|
||||
LogPrintf("ERROR: Failure connecting to bitcoind RPC: %s\n", std::string(re.what()));
|
||||
return false;
|
||||
}
|
||||
// Success
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Sanity startup check won't reconsider queued blocks
|
||||
if (init) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Getting this far means we either aren't validating pegins(so let's make sure that's why
|
||||
// it failed previously) or we successfully connected to bitcoind
|
||||
// Time to reconsider blocks
|
||||
if (vblocksToReconsider.size() > 0) {
|
||||
CValidationState state;
|
||||
for(const uint256& blockhash : vblocksToReconsider) {
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (mapBlockIndex.count(blockhash) == 0)
|
||||
continue;
|
||||
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
|
||||
ResetBlockFailureFlags(pblockindex);
|
||||
}
|
||||
}
|
||||
|
||||
//All blocks are now being reconsidered
|
||||
ActivateBestChain(state, Params());
|
||||
//This simply checks for DB errors
|
||||
if (!state.IsValid()) {
|
||||
//Something scary?
|
||||
}
|
||||
|
||||
//Now to clear out now-valid blocks
|
||||
for(const uint256& blockhash : vblocksToReconsider) {
|
||||
LOCK(cs_main);
|
||||
if (mapBlockIndex.count(blockhash)) {
|
||||
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
|
||||
|
||||
//Marked as invalid still, put back into queue
|
||||
if((pblockindex->nStatus & BLOCK_FAILED_MASK)) {
|
||||
vblocksToReconsiderAgain.push_back(blockhash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Write back remaining blocks
|
||||
pblocktree->WriteInvalidBlockQueue(vblocksToReconsiderAgain);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,13 @@ static const bool DEFAULT_PEERBLOOMFILTERS = true;
|
|||
/** Default for -stopatheight */
|
||||
static const int DEFAULT_STOPATHEIGHT = 0;
|
||||
|
||||
// ELEMENTS constants:
|
||||
/** The minimum version for the mainchain node.
|
||||
* We need v0.16.3 to get the nTx field in getblockheader and inflation fix.
|
||||
* Note that Elements-based parent chains may not have fixes based on this
|
||||
* version check! */
|
||||
static const int MIN_MAINCHAIN_NODE_VERSION = 160300; // 0.16.3
|
||||
|
||||
struct BlockHasher
|
||||
{
|
||||
size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); }
|
||||
|
|
@ -502,4 +509,8 @@ inline bool IsBlockPruned(const CBlockIndex* pblockindex)
|
|||
return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
|
||||
}
|
||||
|
||||
// ELEMENTS:
|
||||
/** Check if bitcoind connection via RPC is correctly working*/
|
||||
bool BitcoindRPCCheck(bool init);
|
||||
|
||||
#endif // BITCOIN_VALIDATION_H
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue