Skip to content

Commit 1ecb6b5

Browse files
committed
feat: add param verbose=0|1 to RPC getbestchainlock
It adds ability to receive raw chainlock in hex format (compatible with ZMQ subscription)
1 parent 3edc738 commit 1ecb6b5

File tree

3 files changed

+45
-19
lines changed

3 files changed

+45
-19
lines changed

src/rpc/blockchain.cpp

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -232,39 +232,61 @@ static RPCHelpMan getbestblockhash()
232232
static RPCHelpMan getbestchainlock()
233233
{
234234
return RPCHelpMan{"getbestchainlock",
235-
"\nReturns information about the best ChainLock. Throws an error if there is no known ChainLock yet.",
236-
{},
237-
RPCResult{
238-
RPCResult::Type::OBJ, "", "",
239-
{
240-
{RPCResult::Type::STR_HEX, "hash", "The block hash hex-encoded"},
241-
{RPCResult::Type::NUM, "height", "The block height or index"},
242-
{RPCResult::Type::STR_HEX, "signature", "The ChainLock's BLS signature"},
243-
{RPCResult::Type::BOOL, "known_block", "True if the block is known by our node"},
244-
}},
235+
"\nIf verbose is 0, returns a string that is serialized, hex-encoded data for the best ChainLock.\n"
236+
"If verbose is 1, returns information about the best ChainLock.\n"
237+
"Throws an error if there is no known ChainLock yet.",
238+
{
239+
{"verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a json object"},
240+
},
241+
{
242+
RPCResult{"for verbose = 0",
243+
RPCResult::Type::STR, "data", "The serialized, hex-encoded data for best ChainLock"},
244+
RPCResult{"for verbose = 1",
245+
RPCResult::Type::OBJ, "", "",
246+
{
247+
{RPCResult::Type::STR_HEX, "hash", "The block hash hex-encoded"},
248+
{RPCResult::Type::NUM, "height", "The block height or index"},
249+
{RPCResult::Type::STR_HEX, "signature", "The ChainLock's BLS signature"},
250+
{RPCResult::Type::BOOL, "known_block", "True if the block is known by our node"},
251+
}},
252+
},
245253
RPCExamples{
246254
HelpExampleCli("getbestchainlock", "")
247255
+ HelpExampleRpc("getbestchainlock", "")
248256
},
249257
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
250258
{
251-
UniValue result(UniValue::VOBJ);
252-
259+
int verbose = 1;
260+
if (!request.params[0].isNull()) {
261+
if (request.params[0].isBool()) {
262+
verbose = request.params[0].get_bool() ? 1 : 0;
263+
} else {
264+
verbose = request.params[0].get_int();
265+
}
266+
}
253267
const NodeContext& node = EnsureAnyNodeContext(request.context);
254268

255269
const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
256270
const llmq::CChainLockSig clsig = llmq_ctx.clhandler->GetBestChainLock();
257271
if (clsig.IsNull()) {
258272
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to find any ChainLock");
259273
}
260-
result.pushKV("blockhash", clsig.getBlockHash().GetHex());
261-
result.pushKV("height", clsig.getHeight());
262-
result.pushKV("signature", clsig.getSig().ToString());
274+
if (verbose) {
275+
UniValue result(UniValue::VOBJ);
263276

264-
const ChainstateManager& chainman = EnsureChainman(node);
265-
LOCK(cs_main);
266-
result.pushKV("known_block", chainman.m_blockman.LookupBlockIndex(clsig.getBlockHash()) != nullptr);
267-
return result;
277+
result.pushKV("blockhash", clsig.getBlockHash().GetHex());
278+
result.pushKV("height", clsig.getHeight());
279+
result.pushKV("signature", clsig.getSig().ToString());
280+
281+
const ChainstateManager& chainman = EnsureChainman(node);
282+
LOCK(cs_main);
283+
result.pushKV("known_block", chainman.m_blockman.LookupBlockIndex(clsig.getBlockHash()) != nullptr);
284+
return result;
285+
} else {
286+
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
287+
ssTx << clsig;
288+
return HexStr(ssTx);
289+
}
268290
},
269291
};
270292
}

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
112112
{ "getblockheaders", 2, "verbose" },
113113
{ "getchaintxstats", 0, "nblocks" },
114114
{ "getmerkleblocks", 2, "count" },
115+
{ "getbestchainlock", 0, "verbose" },
115116
{ "gettransaction", 1, "include_watchonly" },
116117
{ "gettransaction", 2, "verbose" },
117118
{ "getrawtransaction", 1, "verbose" },

test/functional/interface_zmq_dash.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ def run_test(self):
136136
self.zmq_context = zmq.Context()
137137
# Initialize the network
138138
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0)
139+
self.log.info("Test RPC hex getbestchainlock before any CL appeared")
140+
assert_raises_rpc_error(-32603, "Unable to find any ChainLock", self.nodes[0].getbestchainlock, 0)
139141
self.wait_for_sporks_same()
140142
self.activate_v19(expected_activation_height=900)
141143
self.log.info("Activated v19 at height:" + str(self.nodes[0].getblockcount()))
@@ -263,6 +265,7 @@ def test_chainlock_publishers(self):
263265
assert_equal(uint256_to_string(zmq_chain_lock.blockHash), rpc_chain_lock_hash)
264266
assert_equal(zmq_chain_locked_block.hash, rpc_chain_lock_hash)
265267
assert_equal(zmq_chain_lock.sig.hex(), rpc_best_chain_lock_sig)
268+
assert_equal(zmq_chain_lock.serialize().hex(), self.nodes[0].getbestchainlock(0))
266269
# Unsubscribe from ChainLock messages
267270
self.unsubscribe(chain_lock_publishers)
268271

0 commit comments

Comments
 (0)