diff --git a/src/init.cpp b/src/init.cpp index 26ad148fe2..7cafa2b3ff 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -11,6 +11,7 @@ #include "addrman.h" #include "amount.h" +#include "callrpc.h" #include "chain.h" #include "chainparams.h" #include "checkpoints.h" @@ -1658,6 +1659,14 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 12: finished SetRPCWarmupFinished(); + + CScheduler::Function f2 = boost::bind(&BitcoindRPCCheck, false); + scheduler.scheduleEvery(f2, 120); + + if (!BitcoindRPCCheck(true)) { //Initial check, fail immediately + return InitError(_("ERROR: liquid-daemon is set to verify pegins but cannot get valid response from bitcoind. Please check debug.log for more information.")); + } + uiInterface.InitMessage(_("Done loading")); #ifdef ENABLE_WALLET diff --git a/src/txdb.cpp b/src/txdb.cpp index f4053806f0..4b0a8cbebb 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -20,6 +20,7 @@ static const char DB_TXINDEX = 't'; static const char DB_LOCKS = 'k'; static const char DB_BLOCK_INDEX = 'b'; static const char DB_WITHDRAW_FLAG = 'w'; +static const char DB_INVALID_BLOCK_Q = 'q'; static const char DB_BEST_BLOCK = 'B'; static const char DB_FLAG = 'F'; @@ -212,6 +213,14 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { return true; } +bool CBlockTreeDB::ReadInvalidBlockQueue(std::vector &vBlocks) { + return Read(std::make_pair(DB_INVALID_BLOCK_Q, uint256S("0")), vBlocks);//FIXME: why uint256 and not "" +} + +bool CBlockTreeDB::WriteInvalidBlockQueue(const std::vector &vBlocks) { + return Write(std::make_pair(DB_INVALID_BLOCK_Q, uint256S("0")), vBlocks); +} + bool CBlockTreeDB::LoadBlockIndexGuts(boost::function insertBlockIndex) { std::unique_ptr pcursor(NewIterator()); diff --git a/src/txdb.h b/src/txdb.h index 978a28e5a8..fa615981fc 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -127,6 +127,8 @@ public: bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts(boost::function insertBlockIndex); + bool ReadInvalidBlockQueue(std::vector &vBlocks); + bool WriteInvalidBlockQueue(const std::vector &vBlocks); }; #endif // BITCOIN_TXDB_H diff --git a/src/validation.cpp b/src/validation.cpp index cb58ce3a1d..8a6653cd34 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -6,6 +6,7 @@ #include "validation.h" #include "arith_uint256.h" +#include "callrpc.h" #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" @@ -1883,6 +1884,92 @@ void ThreadScriptCheck() { scriptcheckqueue.Thread(); } +bool BitcoindRPCCheck(bool init) +{ + //First, we can clear out any blocks thatsomehow are now deemed valid + //eg reconsiderblock rpc call manually + std::vector vblocksToReconsider; + pblocktree->ReadInvalidBlockQueue(vblocksToReconsider); + std::vector vblocksToReconsiderAgain; + BOOST_FOREACH(uint256& blockhash, vblocksToReconsider) { + 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 rpc + if (GetBoolArg("-validatepegin", false)) { + try { + UniValue params(UniValue::VARR); + params.push_back(UniValue(0)); + UniValue reply = CallRPC("getblockhash", params, GetArg("-mainchainrpcport", 18332), true); + if (!find_value(reply, "error").isNull()) { + LogPrintf("ERROR: Bitcoind RPC check returned 'error' response.\n"); + return false; + } + UniValue result = reply["result"]; + if (GetBoolArg("-testnet", false) && result.isStr() && result.get_str() != "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943") { //FIXME: Stick parent chain(s) genesis in chainparams + LogPrintf("ERROR: Invalid parent genesis block hash response via RPC. Contacting wrong parent daemon?"); + return false; + } + if (GetBoolArg("-regtest", false) && result.isStr() && result.get_str() != "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206") { + LogPrintf("ERROR: Invalid parent genesis block hash response via RPC. Contacting wrong parent daemon?"); + return false; + } + } catch (...) { + LogPrintf("ERROR: Failure connecting to bitcoind RPC.\n"); + return false; + } + } + + //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; + BOOST_FOREACH(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 + BOOST_FOREACH(const uint256& blockhash, vblocksToReconsider) { + 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; +} + // Protected by cs_main VersionBitsCache versionbitscache; diff --git a/src/validation.h b/src/validation.h index 6f3598d7fb..b2da86e0ab 100644 --- a/src/validation.h +++ b/src/validation.h @@ -263,6 +263,8 @@ bool LoadBlockIndex(const CChainParams& chainparams); void UnloadBlockIndex(); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); +/** Check if bitcoind connection via RPC is correctly working*/ +bool BitcoindRPCCheck(bool init); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core.