mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
feat(rpc): submit chainlock signature if needed RPC (#5765)
## Issue being fixed or feature implemented Once Platform is live, there could be an edge case where the CL could arrive to an EvoNode faster through Platform quorum than regular P2P propagation. ## What was done? This PR introduces a new RPC `submitchainlock` with the following 3 mandatory parameters: - `blockHash`, `signature` and `height`. Besides some basic tests: - If the block is unknown then the RPC returns an error (could happen if the node is stucked) - If the signature is not verified then the RPC return an error. - If the node already has this CL, the RPC returns true. - If the node doesn't have this CL, it inserts it, broadcast it through the inv system and return true. ## How Has This Been Tested? `feature_llmq_chainlocks.py` was modified with the following scenario: 1. node0 is isolated from the rest of the network 2. node1 mines a new block and waits for CL 3. Make sure node0 doesn't know the new block/CL (by checking `getbestchainlock()`) 4. CL is submitted via the new RPC on node0 5. checking `getbestchainlock()` and make sure the CL was processed + 'known_block' is false 6. reconnect node0 ## Breaking Changes no ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ --------- Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com> Co-authored-by: thephez <thephez@users.noreply.github.com>
This commit is contained in:
parent
714be63de5
commit
3bc77a6e1d
5
doc/release-notes-5765.md
Normal file
5
doc/release-notes-5765.md
Normal file
@ -0,0 +1,5 @@
|
||||
Added RPC
|
||||
--------
|
||||
|
||||
- `submitchainlock` RPC allows the submission of a ChainLock signature.
|
||||
Note: This RPC is whitelisted for the Platform RPC user.
|
@ -986,6 +986,49 @@ static UniValue verifyislock(const JSONRPCRequest& request)
|
||||
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, 0) ||
|
||||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, signOffset);
|
||||
}
|
||||
|
||||
static void submitchainlock_help(const JSONRPCRequest& request)
|
||||
{
|
||||
RPCHelpMan{"submitchainlock",
|
||||
"Submit a ChainLock signature if needed\n",
|
||||
{
|
||||
{"blockHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash of the ChainLock."},
|
||||
{"signature", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The signature of the ChainLock."},
|
||||
{"blockHeight", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height of the ChainLock."},
|
||||
},
|
||||
RPCResults{},
|
||||
RPCExamples{""},
|
||||
}.Check(request);
|
||||
}
|
||||
|
||||
static UniValue submitchainlock(const JSONRPCRequest& request)
|
||||
{
|
||||
submitchainlock_help(request);
|
||||
|
||||
const uint256 nBlockHash(ParseHashV(request.params[0], "blockHash"));
|
||||
|
||||
const int nBlockHeight = ParseInt32V(request.params[2], "blockHeight");
|
||||
if (nBlockHeight <= 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid block height");
|
||||
}
|
||||
|
||||
CBLSSignature sig;
|
||||
if (!sig.SetHexStr(request.params[1].get_str(), false) && !sig.SetHexStr(request.params[1].get_str(), true)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid signature format");
|
||||
}
|
||||
|
||||
|
||||
const LLMQContext& llmq_ctx = EnsureLLMQContext(EnsureAnyNodeContext(request.context));
|
||||
auto clsig = llmq::CChainLockSig(nBlockHeight, nBlockHash, sig);
|
||||
if (!llmq_ctx.clhandler->VerifyChainLock(clsig)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid signature");
|
||||
}
|
||||
|
||||
llmq_ctx.clhandler->ProcessNewChainLock(-1, clsig, ::SerializeHash(clsig));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RegisterQuorumsRPCCommands(CRPCTable &tableRPC)
|
||||
{
|
||||
// clang-format off
|
||||
@ -993,6 +1036,7 @@ static const CRPCCommand commands[] =
|
||||
{ // category name actor (function)
|
||||
// --------------------- ------------------------ -----------------------
|
||||
{ "evo", "quorum", &_quorum, {} },
|
||||
{ "evo", "submitchainlock", &submitchainlock, {"blockHash", "signature", "blockHeight"} },
|
||||
{ "evo", "verifychainlock", &verifychainlock, {"blockHash", "signature", "blockHeight"} },
|
||||
{ "evo", "verifyislock", &verifyislock, {"id", "txid", "signature", "maxHeight"} },
|
||||
};
|
||||
|
@ -147,6 +147,7 @@ void CRPCTable::InitPlatformRestrictions()
|
||||
{"getbestchainlock", {}},
|
||||
{"quorum", {"sign", static_cast<uint8_t>(Params().GetConsensus().llmqTypePlatform)}},
|
||||
{"quorum", {"verify"}},
|
||||
{"submitchainlock", {}},
|
||||
{"verifyislock", {}},
|
||||
};
|
||||
}
|
||||
|
@ -98,6 +98,25 @@ class LLMQChainLocksTest(DashTestFramework):
|
||||
self.wait_for_chainlocked_block_all_nodes(self.nodes[1].getbestblockhash())
|
||||
self.test_coinbase_best_cl(self.nodes[0])
|
||||
|
||||
self.log.info("Isolate node, mine on another, reconnect and submit CL via RPC")
|
||||
self.isolate_node(0)
|
||||
self.nodes[1].generate(1)
|
||||
self.wait_for_chainlocked_block(self.nodes[1], self.nodes[1].getbestblockhash())
|
||||
best_0 = self.nodes[0].getbestchainlock()
|
||||
best_1 = self.nodes[1].getbestchainlock()
|
||||
assert best_0['blockhash'] != best_1['blockhash']
|
||||
assert best_0['height'] != best_1['height']
|
||||
assert best_0['signature'] != best_1['signature']
|
||||
assert_equal(best_0['known_block'], True)
|
||||
self.nodes[0].submitchainlock(best_1['blockhash'], best_1['signature'], best_1['height'])
|
||||
best_0 = self.nodes[0].getbestchainlock()
|
||||
assert_equal(best_0['blockhash'], best_1['blockhash'])
|
||||
assert_equal(best_0['height'], best_1['height'])
|
||||
assert_equal(best_0['signature'], best_1['signature'])
|
||||
assert_equal(best_0['known_block'], False)
|
||||
self.reconnect_isolated_node(0, 1)
|
||||
self.sync_all()
|
||||
|
||||
self.log.info("Isolate node, mine on both parts of the network, and reconnect")
|
||||
self.isolate_node(0)
|
||||
bad_tip = self.nodes[0].generate(5)[-1]
|
||||
|
@ -61,6 +61,7 @@ class HTTPBasicsTest(BitcoinTestFramework):
|
||||
"getblockcount",
|
||||
"getbestchainlock",
|
||||
"quorum",
|
||||
"submitchainlock",
|
||||
"verifyislock"]
|
||||
|
||||
help_output = self.nodes[0].help().split('\n')
|
||||
|
Loading…
Reference in New Issue
Block a user