Introduce getbestchainlock rpc and fix llmq-is-cl-conflicts.py (#3094)

* Introduce getbestchainlock rpc and fix llmq-is-cl-conflicts.py

* Add `known_block` field and move `getbestchainlock` to `blockchain` rpc category

* Add CChainLockSig::IsNull() and throw an exception in getbestchainlock if there is no known chainlock yet

* drop blockHash initializer
This commit is contained in:
UdjinM6 2019-09-23 21:36:55 +03:00 committed by GitHub
parent ac0270871c
commit 1c74b668b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 4 deletions

View File

@ -23,6 +23,11 @@ static const std::string CLSIG_REQUESTID_PREFIX = "clsig";
CChainLocksHandler* chainLocksHandler; CChainLocksHandler* chainLocksHandler;
bool CChainLockSig::IsNull() const
{
return nHeight == -1 && blockHash == uint256();
}
std::string CChainLockSig::ToString() const std::string CChainLockSig::ToString() const
{ {
return strprintf("CChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString()); return strprintf("CChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString());
@ -72,6 +77,12 @@ bool CChainLocksHandler::GetChainLockByHash(const uint256& hash, llmq::CChainLoc
return true; return true;
} }
CChainLockSig CChainLocksHandler::GetBestChainLock()
{
LOCK(cs);
return bestChainLock;
}
void CChainLocksHandler::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) void CChainLocksHandler::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{ {
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) { if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
@ -101,7 +112,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock
return; return;
} }
if (bestChainLock.nHeight != -1 && clsig.nHeight <= bestChainLock.nHeight) { if (!bestChainLock.IsNull() && clsig.nHeight <= bestChainLock.nHeight) {
// no need to process/relay older CLSIGs // no need to process/relay older CLSIGs
return; return;
} }

View File

@ -38,6 +38,7 @@ public:
READWRITE(sig); READWRITE(sig);
} }
bool IsNull() const;
std::string ToString() const; std::string ToString() const;
}; };
@ -85,6 +86,7 @@ public:
bool AlreadyHave(const CInv& inv); bool AlreadyHave(const CInv& inv);
bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret); bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret);
CChainLockSig GetBestChainLock();
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
void ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, const uint256& hash); void ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, const uint256& hash);

View File

@ -207,6 +207,34 @@ UniValue getbestblockhash(const JSONRPCRequest& request)
return chainActive.Tip()->GetBlockHash().GetHex(); return chainActive.Tip()->GetBlockHash().GetHex();
} }
UniValue getbestchainlock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
"getbestchainlock\n"
"\nReturns the block hash of the best chainlock. Throws an error if there is no known chainlock yet.\n"
"\nResult:\n"
"{\n"
" \"blockhash\" : \"hash\", (string) The block hash hex encoded\n"
" \"height\" : n, (numeric) The block height or index\n"
" \"known_block\" : true|false (boolean) True if the block is known by our node\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getbestchainlock", "")
+ HelpExampleRpc("getbestchainlock", "")
);
UniValue result(UniValue::VOBJ);
llmq::CChainLockSig clsig = llmq::chainLocksHandler->GetBestChainLock();
if (clsig.IsNull()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to find any chainlock");
}
result.push_back(Pair("blockhash", clsig.blockHash.GetHex()));
result.push_back(Pair("height", clsig.nHeight));
LOCK(cs_main);
result.push_back(Pair("known_block", mapBlockIndex.count(clsig.blockHash) > 0));
return result;
}
void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex) void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
{ {
if(pindex) { if(pindex) {
@ -2161,6 +2189,7 @@ static const CRPCCommand commands[] =
{ "blockchain", "getchaintxstats", &getchaintxstats, true, {"nblocks", "blockhash"} }, { "blockchain", "getchaintxstats", &getchaintxstats, true, {"nblocks", "blockhash"} },
{ "blockchain", "getblockstats", &getblockstats, true, {"hash_or_height", "stats"} }, { "blockchain", "getblockstats", &getblockstats, true, {"hash_or_height", "stats"} },
{ "blockchain", "getbestblockhash", &getbestblockhash, true, {} }, { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
{ "blockchain", "getbestchainlock", &getbestchainlock, true, {} },
{ "blockchain", "getblockcount", &getblockcount, true, {} }, { "blockchain", "getblockcount", &getblockcount, true, {} },
{ "blockchain", "getblock", &getblock, true, {"blockhash","verbosity|verbose"} }, { "blockchain", "getblock", &getblock, true, {"blockhash","verbosity|verbose"} },
{ "blockchain", "getblockhashes", &getblockhashes, true, {"high","low"} }, { "blockchain", "getblockhashes", &getblockhashes, true, {"high","low"} },

View File

@ -112,9 +112,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
cl = self.create_chainlock(self.nodes[0].getblockcount() + 1, block.sha256) cl = self.create_chainlock(self.nodes[0].getblockcount() + 1, block.sha256)
self.test_node.send_clsig(cl) self.test_node.send_clsig(cl)
# Give the CLSIG some time to propagate. We unfortunately can't check propagation here as "getblock/getblockheader" self.wait_for_best_chainlock(self.nodes[1], "%064x" % block.sha256)
# is required to check for CLSIGs, but this requires the block header to be propagated already
time.sleep(1)
# The block should get accepted now, and at the same time prune the conflicting ISLOCKs # The block should get accepted now, and at the same time prune the conflicting ISLOCKs
submit_result = self.nodes[1].submitblock(ToHex(block)) submit_result = self.nodes[1].submitblock(ToHex(block))
@ -223,6 +221,17 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
time.sleep(0.1) time.sleep(0.1)
raise AssertionError("wait_for_chainlock timed out") raise AssertionError("wait_for_chainlock timed out")
def wait_for_best_chainlock(self, node, block_hash):
t = time.time()
while time.time() - t < 15:
try:
if node.getbestchainlock()["blockhash"] == block_hash:
return
except:
pass
time.sleep(0.1)
raise AssertionError("wait_for_best_chainlock timed out")
def create_block(self, node, vtx=[]): def create_block(self, node, vtx=[]):
bt = node.getblocktemplate() bt = node.getblocktemplate()
height = bt['height'] height = bt['height']