mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
Dynafed RPC support, tests, and deployment for custom chains
This commit is contained in:
parent
aac354b5ba
commit
47db75e39f
15 changed files with 849 additions and 342 deletions
|
|
@ -141,6 +141,14 @@ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGen
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out block witness if dynamic federation is enabled
|
||||
// since we are assuming WSH(OP_TRUE)
|
||||
if (!pblock->m_dyna_params.IsNull()) {
|
||||
CScript op_true(OP_TRUE);
|
||||
pblock->m_signblock_witness.stack.push_back(std::vector<unsigned char>(op_true.begin(), op_true.end()));
|
||||
}
|
||||
|
||||
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
|
||||
if (!ProcessNewBlock(Params(), shared_pblock, true, nullptr))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
||||
|
|
@ -989,15 +997,27 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
|
|||
|
||||
UniValue getnewblockhex(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() > 1)
|
||||
if (request.fHelp || request.params.size() > 2)
|
||||
throw std::runtime_error(
|
||||
RPCHelpMan{"getnewblockhex",
|
||||
"\nGets hex representation of a proposed, unmined new block\n",
|
||||
{
|
||||
{"min_tx_age", RPCArg::Type::NUM, /* default */ "0", "How many seconds a transaction must have been in the mempool to be inluded in the block proposal. This may help with faster block convergence among functionaries using compact blocks."},
|
||||
{"proposed_parameters", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED , "Parameters to be used in dynamic federations blocks as proposals. During a period of `-dynamic_epoch_length` blocks, 4/5 of total blocks must signal these parameters for the proposal to become activated in the next epoch.",
|
||||
{
|
||||
{"signblockscript", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Hex-encoded block signing script to propose"},
|
||||
{"max_block_witness", RPCArg::Type::NUM, RPCArg::Optional::NO, "Total size in witness bytes that are allowed in the dynamic federations block witness for blocksigning"},
|
||||
{"fedpegscript", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Hex-encoded fedpegscript for dynamic block proposal"},
|
||||
{"extension_space", RPCArg::Type::ARR, RPCArg::Optional::NO, "Array of additional fields to embed in the dynamic blockheader. Has no consensus meaning aside from serialized size changes. This space is currently is only used for PAK enforcement.",
|
||||
{
|
||||
{"", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Hex encoded string for extension entries."},
|
||||
},
|
||||
},
|
||||
},
|
||||
"proposed_parameters"},
|
||||
},
|
||||
RPCResult{
|
||||
"blockhex (hex) The block hex\n"
|
||||
"blockhex (hex) The block hex\n"
|
||||
},
|
||||
RPCExamples{
|
||||
HelpExampleCli("getnewblockhex", ""),
|
||||
|
|
@ -1009,9 +1029,47 @@ UniValue getnewblockhex(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_INVALID_PARAMETER, "min_tx_age must be non-negative.");
|
||||
}
|
||||
|
||||
// Construct proposed parameter entry, if any
|
||||
ConsensusParamEntry proposed;
|
||||
if (!request.params[1].isNull()) {
|
||||
if (!IsDynaFedEnabled(chainActive.Tip(), Params().GetConsensus())) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Dynamic federations is not active on this network. Proposed parameters are not needed.");
|
||||
}
|
||||
|
||||
UniValue prop = request.params[1].get_obj();
|
||||
|
||||
std::string sbs_str = prop["signblockscript"].get_str();
|
||||
if (!IsHex(sbs_str)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "signblockscript must be hex");
|
||||
}
|
||||
std::vector<unsigned char> signblock_bytes = ParseHex(sbs_str);
|
||||
proposed.m_signblockscript = CScript(signblock_bytes.begin(), signblock_bytes.end());
|
||||
|
||||
int max_sbs_wit = prop["max_block_witness"].get_int();
|
||||
if (max_sbs_wit < 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "max_block_witness must be non-negative");
|
||||
}
|
||||
proposed.m_sbs_wit_limit = max_sbs_wit;
|
||||
|
||||
std::string fps_str = prop["fedpegscript"].get_str();
|
||||
if (!IsHex(fps_str)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "fedpegscript must be hex");
|
||||
}
|
||||
std::vector<unsigned char> fedpeg_bytes = ParseHex(fps_str);
|
||||
proposed.m_fedpegscript = CScript(fedpeg_bytes.begin(), fedpeg_bytes.end());
|
||||
|
||||
UniValue extension_array = prop["extension_space"].get_array();
|
||||
for (unsigned int i = 0; i < extension_array.size(); i++) {
|
||||
std::string extension_str = extension_array[i].get_str();
|
||||
proposed.m_extension_space.push_back(ParseHex(extension_str));
|
||||
}
|
||||
// All proposals are full serializations
|
||||
proposed.m_serialize_type = 2;
|
||||
}
|
||||
|
||||
CScript feeDestinationScript = Params().GetConsensus().mandatory_coinbase_destination;
|
||||
if (feeDestinationScript == CScript()) feeDestinationScript = CScript() << OP_TRUE;
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(feeDestinationScript, required_wait));
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(feeDestinationScript, required_wait, &proposed));
|
||||
if (!pblocktemplate.get()) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
|
||||
}
|
||||
|
|
@ -1023,6 +1081,13 @@ UniValue getnewblockhex(const JSONRPCRequest& request)
|
|||
IncrementExtraNonce(&pblocktemplate->block, chainActive.Tip(), nExtraNonce);
|
||||
}
|
||||
|
||||
// If WSH(OP_TRUE) block, fill in witness
|
||||
CScript op_true(OP_TRUE);
|
||||
if (pblocktemplate->block.m_dyna_params.m_current.m_signblockscript ==
|
||||
GetScriptForDestination(WitnessV0ScriptHash(op_true))) {
|
||||
pblocktemplate->block.m_signblock_witness.stack.push_back(std::vector<unsigned char>(op_true.begin(), op_true.end()));
|
||||
}
|
||||
|
||||
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssBlock << pblocktemplate->block;
|
||||
return HexStr(ssBlock.begin(), ssBlock.end());
|
||||
|
|
@ -1030,7 +1095,7 @@ UniValue getnewblockhex(const JSONRPCRequest& request)
|
|||
|
||||
UniValue combineblocksigs(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 2)
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
|
||||
throw std::runtime_error(
|
||||
RPCHelpMan{"combineblocksigs",
|
||||
"\nMerges signatures on a block proposal\n",
|
||||
|
|
@ -1046,6 +1111,7 @@ UniValue combineblocksigs(const JSONRPCRequest& request)
|
|||
},
|
||||
},
|
||||
},
|
||||
{"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded witnessScript for the signblockscript"},
|
||||
},
|
||||
RPCResult{
|
||||
"{\n"
|
||||
|
|
@ -1087,9 +1153,22 @@ UniValue combineblocksigs(const JSONRPCRequest& request)
|
|||
sig_data.signatures[pubkey.GetID()] = std::make_pair(pubkey, sig_bytes);
|
||||
}
|
||||
|
||||
// Finalizes the signatures, has no access to keys
|
||||
ProduceSignature(keystore, signature_creator, block.proof.challenge, sig_data, SCRIPT_NO_SIGHASH_BYTE);
|
||||
block.proof.solution = sig_data.scriptSig;
|
||||
if (!block.m_dyna_params.IsNull()) {
|
||||
if (request.params[2].isNull()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Signing dynamic blocks requires the witnessScript argument");
|
||||
}
|
||||
std::vector<unsigned char> witness_bytes(ParseHex(request.params[2].get_str()));
|
||||
if (!witness_bytes.empty()) {
|
||||
keystore.AddCScript(CScript(witness_bytes.begin(), witness_bytes.end()));
|
||||
}
|
||||
// Finalizes the signatures, has no access to keys
|
||||
ProduceSignature(keystore, signature_creator, block.m_dyna_params.m_current.m_signblockscript, sig_data, SCRIPT_NO_SIGHASH_BYTE);
|
||||
block.m_signblock_witness = sig_data.scriptWitness;
|
||||
} else {
|
||||
// Finalizes the signatures, has no access to keys
|
||||
ProduceSignature(keystore, signature_creator, block.proof.challenge, sig_data, SCRIPT_NO_SIGHASH_BYTE);
|
||||
block.proof.solution = sig_data.scriptSig;
|
||||
}
|
||||
|
||||
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
|
||||
ssBlock << block;
|
||||
|
|
@ -1350,25 +1429,6 @@ UniValue testproposedblock(const JSONRPCRequest& request)
|
|||
const CChainParams& chainparams = Params();
|
||||
const bool acceptnonstd = !request.params[1].isNull() ? request.params[1].get_bool() : gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
|
||||
if (!acceptnonstd) {
|
||||
|
||||
// Get PAK commitment, if any
|
||||
boost::optional<CPAKList> paklist_block = GetPAKKeysFromCommitment(*block.vtx[0]);
|
||||
|
||||
// Possible PAK commitment mismatch between blocks and config
|
||||
if (chainparams.GetEnforcePak() && g_paklist_config) {
|
||||
if(paklist_block) {
|
||||
if (*paklist_block != *g_paklist_config) {
|
||||
throw JSONRPCError(RPC_VERIFY_ERROR, "Proposal PAK commitment and config PAK do not match.");
|
||||
}
|
||||
// else it may be an unnecessary commitment but that's ok.
|
||||
} else {
|
||||
// Waiting for block that has commitment to config list
|
||||
if (*g_paklist_config != g_paklist_blockchain) {
|
||||
throw JSONRPCError(RPC_VERIFY_ERROR, "Proposal does not have required PAK commitment.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& transaction : block.vtx) {
|
||||
if (transaction->IsCoinBase()) continue;
|
||||
std::string reason;
|
||||
|
|
@ -1395,7 +1455,7 @@ static const CRPCCommand commands[] =
|
|||
{ "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
|
||||
{ "generating", "combineblocksigs", &combineblocksigs, {"blockhex","signatures"} },
|
||||
{ "mining", "submitheader", &submitheader, {"hexdata"} },
|
||||
{ "generating", "getnewblockhex", &getnewblockhex, {"min_tx_age"} },
|
||||
{ "generating", "getnewblockhex", &getnewblockhex, {"min_tx_age", "proposed_parameters"} },
|
||||
{ "generating", "getcompactsketch", &getcompactsketch, {"block_hex"} },
|
||||
{ "generating", "consumecompactsketch", &consumecompactsketch, {"sketch"} },
|
||||
{ "generating", "consumegetblocktxn", &consumegetblocktxn, {"full_block", "block_tx_req"} },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue