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:
parent
ac0270871c
commit
1c74b668b6
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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"} },
|
||||||
|
@ -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']
|
||||||
|
Loading…
Reference in New Issue
Block a user