Skip to content

Commit 250c8e5

Browse files
committed
Merge #1030: [forward port] When validation is waiting for parent chain daemon, "stall"
b2e1cc3 Regression test for pegin validation issues during sync (Glenn Willen) d5042b4 Finish removing 'recheckpeginblockinterval'; move MainchainRPCCheck (Glenn Willen) 313f73d When validation is waiting for parent chain daemon, "stall". (Andrew Poelstra) Pull request description: Forward-port of #1022 ACKs for top commit: gwillen: utACK b2e1cc3, verified that it contains only the requested changes from da11d7b. Tree-SHA512: 971b6a137efdc54f84995b17595346bf3d3ebd5a04eef1676225c664923e0b52393550bc51ea366c4d3010aa35a9de16da0643bb5bfb40c7eb788a180c99b1a0
2 parents 1240172 + b2e1cc3 commit 250c8e5

File tree

10 files changed

+163
-203
lines changed

10 files changed

+163
-203
lines changed

src/init.cpp

Lines changed: 80 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,6 @@ void SetupServerArgs(NodeContext& node)
627627
argsman.AddArg("-mainchainrpccookiefile=<file>", "The bitcoind cookie auth path which the daemon will use to connect to the trusted mainchain daemon to validate peg-ins. (default: `<datadir>/regtest/.cookie`)", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
628628
argsman.AddArg("-mainchainrpctimeout=<n>", strprintf("Timeout in seconds during mainchain RPC requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
629629
argsman.AddArg("-peginconfirmationdepth=<n>", strprintf("Pegin claims must be this deep to be considered valid. (default: %d)", DEFAULT_PEGIN_CONFIRMATION_DEPTH), ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
630-
argsman.AddArg("-recheckpeginblockinterval=<n>", strprintf("The interval in seconds at which a peg-in witness failing block is re-evaluated in case of intermittent peg-in witness failure. 0 means never. (default: %u)", 120), ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
631630
argsman.AddArg("-parentpubkeyprefix", strprintf("The byte prefix, in decimal, of the parent chain's base58 pubkey address. (default: %d)", 111), ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
632631
argsman.AddArg("-parentscriptprefix", strprintf("The byte prefix, in decimal, of the parent chain's base58 script address. (default: %d)", 196), ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
633632
argsman.AddArg("-parent_bech32_hrp", strprintf("The human-readable part of the parent chain's bech32 encoding. (default: %s)", "bc"), ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
@@ -1299,6 +1298,61 @@ bool AppInitLockDataDirectory()
12991298
return true;
13001299
}
13011300

1301+
/* This function checks that the RPC connection to the parent chain node
1302+
* can be attained, and is returning back reasonable answers.
1303+
*/
1304+
bool MainchainRPCCheck()
1305+
{
1306+
// Check for working and valid rpc
1307+
// Retry until a non-RPC_IN_WARMUP result
1308+
while (true) {
1309+
try {
1310+
// The first thing we have to check is the version of the node.
1311+
UniValue params(UniValue::VARR);
1312+
UniValue reply = CallMainChainRPC("getnetworkinfo", params);
1313+
UniValue error = reply["error"];
1314+
if (!error.isNull()) {
1315+
// On the first call, it's possible to node is still in
1316+
// warmup; in that case, just wait and retry.
1317+
if (error["code"].get_int() == RPC_IN_WARMUP) {
1318+
UninterruptibleSleep(std::chrono::milliseconds{1000});
1319+
continue;
1320+
}
1321+
else {
1322+
LogPrintf("ERROR: Mainchain daemon RPC check returned 'error' response.\n");
1323+
return false;
1324+
}
1325+
}
1326+
UniValue result = reply["result"];
1327+
if (!result.isObject() || !result.get_obj()["version"].isNum() ||
1328+
result.get_obj()["version"].get_int() < MIN_MAINCHAIN_NODE_VERSION) {
1329+
LogPrintf("ERROR: Parent chain daemon too old; need Bitcoin Core version 0.16.3 or newer.\n");
1330+
return false;
1331+
}
1332+
1333+
// Then check the genesis block to correspond to parent chain.
1334+
params.push_back(UniValue(0));
1335+
reply = CallMainChainRPC("getblockhash", params);
1336+
error = reply["error"];
1337+
if (!error.isNull()) {
1338+
LogPrintf("ERROR: Mainchain daemon RPC check returned 'error' response.\n");
1339+
return false;
1340+
}
1341+
result = reply["result"];
1342+
if (!result.isStr() || result.get_str() != Params().ParentGenesisBlockHash().GetHex()) {
1343+
LogPrintf("ERROR: Invalid parent genesis block hash response via RPC. Contacting wrong parent daemon?\n");
1344+
return false;
1345+
}
1346+
} catch (const std::runtime_error& re) {
1347+
LogPrintf("ERROR: Failure connecting to mainchain daemon RPC: %s\n", std::string(re.what()));
1348+
return false;
1349+
}
1350+
1351+
// Success
1352+
return true;
1353+
}
1354+
}
1355+
13021356
bool AppInitInterfaces(NodeContext& node)
13031357
{
13041358
node.chain = interfaces::MakeChain(node);
@@ -2079,29 +2133,34 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
20792133
// ELEMENTS:
20802134
if (gArgs.GetBoolArg("-validatepegin", Params().GetConsensus().has_parent_chain)) {
20812135
uiInterface.InitMessage(_("Awaiting mainchain RPC warmup").translated);
2082-
}
2083-
if (!MainchainRPCCheck(true)) { //Initial check only
2084-
const std::string err_msg = "ERROR: elements is set to verify pegins but cannot get a valid response from the mainchain daemon. Please check debug.log for more information.\n\nIf you haven't setup a bitcoind please get the latest stable version from https://bitcoincore.org/en/download/ or if you do not need to validate pegins set in your elements configuration validatepegin=0";
2085-
// We fail immediately if this node has RPC server enabled
2086-
if (gArgs.GetBoolArg("-server", false)) {
2087-
InitError(Untranslated(err_msg));
2088-
return false;
2089-
} else {
2090-
// Or gently warn the user, and continue
2091-
InitError(Untranslated(err_msg));
2092-
gArgs.SoftSetArg("-validatepegin", "0");
2136+
if (!MainchainRPCCheck()) {
2137+
const std::string err_msg = "ERROR: elements is set to verify pegins but cannot get a valid response from the mainchain daemon. Please check debug.log for more information.\n\nIf you haven't setup a bitcoind please get the latest stable version from https://bitcoincore.org/en/download/ or if you do not need to validate pegins set in your elements configuration validatepegin=0";
2138+
// We fail immediately if this node has RPC server enabled
2139+
if (gArgs.GetBoolArg("-server", false)) {
2140+
InitError(Untranslated(err_msg));
2141+
return false;
2142+
} else {
2143+
// Or gently warn the user, and continue
2144+
InitError(Untranslated(err_msg));
2145+
gArgs.SoftSetArg("-validatepegin", "0");
2146+
}
20932147
}
20942148
}
20952149

2096-
// Start the lightweight block re-evaluation scheduler thread
2097-
CScheduler::Function reevaluationLoop = [&node]{ node.reverification_scheduler->serviceQueue(); };
2098-
threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>, "reevaluation_scheduler", reevaluationLoop));
2099-
2100-
CScheduler::Function f2 = std::bind(&MainchainRPCCheck, false);
2101-
unsigned int check_rpc_every = gArgs.GetArg("-recheckpeginblockinterval", 120);
2102-
if (check_rpc_every) {
2103-
node.reverification_scheduler->scheduleEvery(f2, std::chrono::seconds(check_rpc_every));
2104-
}
2150+
// Call ActivateBestChain every 30 seconds. This is almost always a
2151+
// harmless no-op. It is necessary in the unusual case where:
2152+
// (1) Our connection to bitcoind is lost, and
2153+
// (2) we build up a queue of blocks to validate in the meantime, and then
2154+
// (3) our connection to bitcoind is restored, but
2155+
// (4) nothing after that causes ActivateBestChain to be called, including
2156+
// no further blocks arriving for us to validate.
2157+
// Unfortunately, this unusual case happens in the functional test suite.
2158+
node.reverification_scheduler->scheduleEvery([]{
2159+
BlockValidationState state;
2160+
if (!ActivateBestChain(state, Params())) {
2161+
LogPrintf("Failed to periodically activate best chain (%s)\n", state.ToString());
2162+
}
2163+
}, std::chrono::seconds{30});
21052164

21062165
uiInterface.InitMessage(_("Done loading").translated);
21072166

src/mainchainrpc.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,18 +153,24 @@ UniValue CallMainChainRPC(const std::string& strMethod, const UniValue& params)
153153

154154
bool IsConfirmedBitcoinBlock(const uint256& hash, const int nMinConfirmationDepth, const int nbTxs)
155155
{
156+
LogPrintf("Checking for confirmed bitcoin block with hash %s, mindepth %d, nbtxs %d\n", hash.ToString().c_str(), nMinConfirmationDepth, nbTxs);
156157
try {
157158
UniValue params(UniValue::VARR);
158159
params.push_back(hash.GetHex());
159160
UniValue reply = CallMainChainRPC("getblockheader", params);
160-
if (!find_value(reply, "error").isNull())
161+
if (!find_value(reply, "error").isNull()) {
162+
LogPrintf("ERROR: Got error reply from bitcoind getblockheader.\n");
161163
return false;
164+
}
162165
UniValue result = find_value(reply, "result");
163-
if (!result.isObject())
166+
if (!result.isObject()) {
167+
LogPrintf("ERROR: bitcoind getblockheader result was malformed (not object).\n");
164168
return false;
169+
}
165170

166171
UniValue confirmations = find_value(result.get_obj(), "confirmations");
167172
if (!confirmations.isNum() || confirmations.get_int64() < nMinConfirmationDepth) {
173+
LogPrintf("Insufficient confirmations (got %s).\n", confirmations.write());
168174
return false;
169175
}
170176

src/pegins.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,11 @@ bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::P
240240
return true;
241241
}
242242

243-
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector<std::pair<CScript, CScript>>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth) {
243+
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector<std::pair<CScript, CScript>>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth, bool* depth_failed) {
244+
if (depth_failed) {
245+
*depth_failed = false;
246+
}
247+
244248
// 0) Return false if !consensus.has_parent_chain
245249
if (!Params().GetConsensus().has_parent_chain) {
246250
err_msg = "Parent chain is not enabled on this network.";
@@ -372,6 +376,9 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector<
372376
LogPrintf("Required depth: %d\n", required_depth);
373377
if (!IsConfirmedBitcoinBlock(block_hash, required_depth, num_txs)) {
374378
err_msg = "Needs more confirmations.";
379+
if (depth_failed) {
380+
*depth_failed = true;
381+
}
375382
return false;
376383
}
377384
}

src/pegins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ bool GetAmountFromParentChainPegin(CAmount& amount, const CTransaction& txBTC, u
2323
/** Check whether a parent chain block hash satisfies the proof-of-work requirement specified by nBits */
2424
bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
2525
/** Checks pegin witness for validity */
26-
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector<std::pair<CScript, CScript>>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth);
26+
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector<std::pair<CScript, CScript>>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth, bool* depth_failed = nullptr);
2727

2828
/* Consensus-critical. Matching against telescoped multisig used on Liquid v1:
2929
* Pseudo-structure:

src/rpc/rawtransaction_util.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,9 @@ bool ValidateTransactionPeginInputs(const CMutableTransaction& mtx, std::map<int
545545
continue;
546546
}
547547
// Report warning about immature peg-in though
548-
if(txin.m_is_pegin && !IsValidPeginWitness(mtx.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, txin.prevout, err, true)) {
549-
CHECK_NONFATAL(err == "Needs more confirmations.");
548+
bool depth_failed = false;
549+
if(txin.m_is_pegin && !IsValidPeginWitness(mtx.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, txin.prevout, err, true, &depth_failed)) {
550+
CHECK_NONFATAL(depth_failed);
550551
immature_pegin = true;
551552
}
552553
}

src/txdb.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static const char DB_LAST_BLOCK = 'l';
3333

3434
// ELEMENTS:
3535
static const char DB_PEGIN_FLAG = 'w';
36-
static const char DB_INVALID_BLOCK_Q = 'q';
36+
// static const char DB_INVALID_BLOCK_Q = 'q'; // No longer used, but avoid reuse.
3737
static const char DB_PAK = 'p';
3838

3939
namespace {
@@ -269,14 +269,6 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
269269
return true;
270270
}
271271

272-
// ELEMENTS:
273-
bool CBlockTreeDB::ReadInvalidBlockQueue(std::vector<uint256> &vBlocks) {
274-
return Read(std::make_pair(DB_INVALID_BLOCK_Q, uint256S("0")), vBlocks);//FIXME: why uint 56 and not ""
275-
}
276-
bool CBlockTreeDB::WriteInvalidBlockQueue(const std::vector<uint256> &vBlocks) {
277-
return Write(std::make_pair(DB_INVALID_BLOCK_Q, uint256S("0")), vBlocks);
278-
}
279-
280272
bool CBlockTreeDB::ReadPAKList(std::vector<std::vector<unsigned char> >& offline_list, std::vector<std::vector<unsigned char> >& online_list, bool& reject)
281273
{
282274
return Read(std::make_pair(DB_PAK, uint256S("1")), offline_list) && Read(std::make_pair(DB_PAK, uint256S("2")), online_list) && Read(std::make_pair(DB_PAK, uint256S("3")), reject);

src/txdb.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ class CBlockTreeDB : public CDBWrapper
109109
bool ReadFlag(const std::string &name, bool &fValue);
110110
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex);
111111
// ELEMENTS:
112-
bool ReadInvalidBlockQueue(std::vector<uint256> &vBlocks);
113-
bool WriteInvalidBlockQueue(const std::vector<uint256> &vBlocks);
114112
bool ReadPAKList(std::vector<std::vector<unsigned char> >& offline_list, std::vector<std::vector<unsigned char> >& online_list, bool& reject);
115113
bool WritePAKList(const std::vector<std::vector<unsigned char> >& offline_list, const std::vector<std::vector<unsigned char> >& online_list, bool reject);
116114
};

0 commit comments

Comments
 (0)