diff options
Diffstat (limited to 'src/rpc/rawtransaction.cpp')
-rw-r--r-- | src/rpc/rawtransaction.cpp | 249 |
1 files changed, 155 insertions, 94 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 9b6ef15785..c6d7fea443 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -67,9 +67,9 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& } } -static UniValue getrawtransaction(const JSONRPCRequest& request) +static RPCHelpMan getrawtransaction() { - RPCHelpMan{ + return RPCHelpMan{ "getrawtransaction", "\nReturn the raw transaction data.\n" @@ -155,8 +155,8 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"") + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureNodeContext(request.context); bool in_active_chain = true; @@ -191,7 +191,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) } uint256 hash_block; - const CTransactionRef tx = GetTransaction(blockindex, node.mempool, hash, Params().GetConsensus(), hash_block); + const CTransactionRef tx = GetTransaction(blockindex, node.mempool.get(), hash, Params().GetConsensus(), hash_block); if (!tx) { std::string errmsg; if (blockindex) { @@ -217,11 +217,13 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) if (blockindex) result.pushKV("in_active_chain", in_active_chain); TxToJSON(*tx, hash_block, result); return result; +}, + }; } -static UniValue gettxoutproof(const JSONRPCRequest& request) +static RPCHelpMan gettxoutproof() { - RPCHelpMan{"gettxoutproof", + return RPCHelpMan{"gettxoutproof", "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" "\nNOTE: By default this function only works sometimes. This is when there is an\n" "unspent output in the utxo for this transaction. To make it always work,\n" @@ -239,8 +241,8 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) RPCResult::Type::STR, "data", "A string that is a serialized, hex-encoded data for the proof." }, RPCExamples{""}, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::set<uint256> setTxids; uint256 oneTxid; UniValue txids = request.params[0].get_array(); @@ -315,11 +317,13 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) ssMB << mb; std::string strHex = HexStr(ssMB); return strHex; +}, + }; } -static UniValue verifytxoutproof(const JSONRPCRequest& request) +static RPCHelpMan verifytxoutproof() { - RPCHelpMan{"verifytxoutproof", + return RPCHelpMan{"verifytxoutproof", "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" "and throwing an RPC error if the block is not in our best chain\n", { @@ -332,8 +336,8 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) } }, RPCExamples{""}, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); CMerkleBlock merkleBlock; ssMB >> merkleBlock; @@ -360,11 +364,13 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) } return res; +}, + }; } -static UniValue createrawtransaction(const JSONRPCRequest& request) +static RPCHelpMan createrawtransaction() { - RPCHelpMan{"createrawtransaction", + return RPCHelpMan{"createrawtransaction", "\nCreate a transaction spending the given inputs and creating new outputs.\n" "Outputs can be addresses or data.\n" "Returns hex-encoded raw transaction.\n" @@ -412,8 +418,8 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VARR, UniValueType(), // ARR or OBJ, checked later @@ -429,11 +435,13 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf); return EncodeHexTx(CTransaction(rawTx)); +}, + }; } -static UniValue decoderawtransaction(const JSONRPCRequest& request) +static RPCHelpMan decoderawtransaction() { - RPCHelpMan{"decoderawtransaction", + return RPCHelpMan{"decoderawtransaction", "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"}, @@ -498,8 +506,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) HelpExampleCli("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); CMutableTransaction mtx; @@ -515,6 +523,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false); return result; +}, + }; } static std::string GetAllOutputTypes() @@ -527,9 +537,9 @@ static std::string GetAllOutputTypes() return Join(ret, ", "); } -static UniValue decodescript(const JSONRPCRequest& request) +static RPCHelpMan decodescript() { - RPCHelpMan{"decodescript", + return RPCHelpMan{"decodescript", "\nDecode a hex-encoded script.\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"}, @@ -563,8 +573,8 @@ static UniValue decodescript(const JSONRPCRequest& request) HelpExampleCli("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); UniValue r(UniValue::VOBJ); @@ -616,18 +626,20 @@ static UniValue decodescript(const JSONRPCRequest& request) } return r; +}, + }; } -static UniValue combinerawtransaction(const JSONRPCRequest& request) +static RPCHelpMan combinerawtransaction() { - RPCHelpMan{"combinerawtransaction", + return RPCHelpMan{"combinerawtransaction", "\nCombine multiple partially signed transactions into one transaction.\n" "The combined transaction may be another partially signed transaction or a \n" "fully signed transaction.", { {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The hex strings of partially signed transactions", { - {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"}, + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A hex-encoded raw transaction"}, }, }, }, @@ -637,15 +649,15 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("combinerawtransaction", R"('["myhex1", "myhex2", "myhex3"]')") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ UniValue txs = request.params[0].get_array(); std::vector<CMutableTransaction> txVariants(txs.size()); for (unsigned int idx = 0; idx < txs.size(); idx++) { - if (!DecodeHexTx(txVariants[idx], txs[idx].get_str(), true)) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d", idx)); + if (!DecodeHexTx(txVariants[idx], txs[idx].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d. Make sure the tx has at least one input.", idx)); } } @@ -699,11 +711,13 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) } return EncodeHexTx(CTransaction(mergedTx)); +}, + }; } -static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) +static RPCHelpMan signrawtransactionwithkey() { - RPCHelpMan{"signrawtransactionwithkey", + return RPCHelpMan{"signrawtransactionwithkey", "\nSign inputs for raw transaction (serialized, hex-encoded).\n" "The second argument is an array of base58-encoded private\n" "keys that will be the only keys used to sign the transaction.\n" @@ -744,7 +758,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) { {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"}, {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"}, - {RPCResult::Type::ARR, "errors", "Script verification errors (if there are any)", + {RPCResult::Type::ARR, "errors", /* optional */ true, "Script verification errors (if there are any)", { {RPCResult::Type::OBJ, "", "", { @@ -761,13 +775,13 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"") + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); CMutableTransaction mtx; - if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(mtx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); } FillableSigningProvider keystore; @@ -795,11 +809,13 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); SignTransaction(mtx, &keystore, coins, request.params[3], result); return result; +}, + }; } -static UniValue sendrawtransaction(const JSONRPCRequest& request) +static RPCHelpMan sendrawtransaction() { - RPCHelpMan{"sendrawtransaction", + return RPCHelpMan{"sendrawtransaction", "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n" "\nNote that the transaction will be sent unconditionally to all peers, so using this\n" "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n" @@ -824,17 +840,17 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VSTR, UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() }); - // parse hex string from parameter CMutableTransaction mtx; - if (!DecodeHexTx(mtx, request.params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(mtx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); + } CTransactionRef tx(MakeTransactionRef(std::move(mtx))); const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? @@ -853,11 +869,13 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) } return tx->GetHash().GetHex(); +}, + }; } -static UniValue testmempoolaccept(const JSONRPCRequest& request) +static RPCHelpMan testmempoolaccept() { - RPCHelpMan{"testmempoolaccept", + return RPCHelpMan{"testmempoolaccept", "\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n" "\nThis checks if the transaction violates the consensus or policy rules.\n" "\nSee sendrawtransaction call.\n", @@ -878,6 +896,11 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) { {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, {RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"}, + {RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"}, + {RPCResult::Type::OBJ, "fees", "Transaction fees (only present if 'allowed' is true)", + { + {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, + }}, {RPCResult::Type::STR, "reject-reason", "Rejection string (only present when 'allowed' is false)"}, }}, } @@ -892,8 +915,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VARR, UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() @@ -905,7 +928,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) CMutableTransaction mtx; if (!DecodeHexTx(mtx, request.params[0].get_array()[0].get_str())) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); } CTransactionRef tx(MakeTransactionRef(std::move(mtx))); const uint256& tx_hash = tx->GetHash(); @@ -924,13 +947,30 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) TxValidationState state; bool test_accept_res; + CAmount fee{0}; { LOCK(cs_main); test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx), - nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true); + nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee); + } + + // Check that fee does not exceed maximum fee + if (test_accept_res && max_raw_tx_fee && fee > max_raw_tx_fee) { + result_0.pushKV("allowed", false); + result_0.pushKV("reject-reason", "max-fee-exceeded"); + result.push_back(std::move(result_0)); + return result; } result_0.pushKV("allowed", test_accept_res); - if (!test_accept_res) { + + // Only return the fee and vsize if the transaction would pass ATMP. + // These can be used to calculate the feerate. + if (test_accept_res) { + result_0.pushKV("vsize", virtual_size); + UniValue fees(UniValue::VOBJ); + fees.pushKV("base", ValueFromAmount(fee)); + result_0.pushKV("fees", fees); + } else { if (state.IsInvalid()) { if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { result_0.pushKV("reject-reason", "missing-inputs"); @@ -944,11 +984,13 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) result.push_back(std::move(result_0)); return result; +}, + }; } -UniValue decodepsbt(const JSONRPCRequest& request) +static RPCHelpMan decodepsbt() { - RPCHelpMan{"decodepsbt", + return RPCHelpMan{"decodepsbt", "\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"}, @@ -1060,8 +1102,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("decodepsbt", "\"psbt\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); // Unserialize the transactions @@ -1253,11 +1295,13 @@ UniValue decodepsbt(const JSONRPCRequest& request) } return result; +}, + }; } -UniValue combinepsbt(const JSONRPCRequest& request) +static RPCHelpMan combinepsbt() { - RPCHelpMan{"combinepsbt", + return RPCHelpMan{"combinepsbt", "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n" "Implements the Combiner role.\n", { @@ -1273,8 +1317,8 @@ UniValue combinepsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("combinepsbt", R"('["mybase64_1", "mybase64_2", "mybase64_3"]')") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VARR}, true); // Unserialize the transactions @@ -1300,12 +1344,14 @@ UniValue combinepsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << merged_psbt; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); +}, + }; } -UniValue finalizepsbt(const JSONRPCRequest& request) +static RPCHelpMan finalizepsbt() { - RPCHelpMan{"finalizepsbt", + return RPCHelpMan{"finalizepsbt", "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n" "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n" "created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n" @@ -1326,8 +1372,8 @@ UniValue finalizepsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("finalizepsbt", "\"psbt\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); // Unserialize the transactions @@ -1358,11 +1404,13 @@ UniValue finalizepsbt(const JSONRPCRequest& request) result.pushKV("complete", complete); return result; +}, + }; } -UniValue createpsbt(const JSONRPCRequest& request) +static RPCHelpMan createpsbt() { - RPCHelpMan{"createpsbt", + return RPCHelpMan{"createpsbt", "\nCreates a transaction in the Partially Signed Transaction format.\n" "Implements the Creator role.\n", { @@ -1404,8 +1452,8 @@ UniValue createpsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VARR, @@ -1435,12 +1483,14 @@ UniValue createpsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); +}, + }; } -UniValue converttopsbt(const JSONRPCRequest& request) +static RPCHelpMan converttopsbt() { - RPCHelpMan{"converttopsbt", + return RPCHelpMan{"converttopsbt", "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n" "createpsbt and walletcreatefundedpsbt should be used for new applications.\n", { @@ -1464,8 +1514,8 @@ UniValue converttopsbt(const JSONRPCRequest& request) "\nConvert the transaction to a PSBT\n" + HelpExampleCli("converttopsbt", "\"rawtransaction\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true); // parse hex string from parameter @@ -1502,12 +1552,14 @@ UniValue converttopsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); +}, + }; } -UniValue utxoupdatepsbt(const JSONRPCRequest& request) +static RPCHelpMan utxoupdatepsbt() { - RPCHelpMan{"utxoupdatepsbt", + return RPCHelpMan{"utxoupdatepsbt", "\nUpdates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}, @@ -1524,8 +1576,9 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) }, RPCExamples { HelpExampleCli("utxoupdatepsbt", "\"psbt\"") - }}.Check(request); - + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true); // Unserialize the transactions @@ -1590,12 +1643,14 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); +}, + }; } -UniValue joinpsbts(const JSONRPCRequest& request) +static RPCHelpMan joinpsbts() { - RPCHelpMan{"joinpsbts", + return RPCHelpMan{"joinpsbts", "\nJoins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs\n" "No input in any of the PSBTs can be in more than one of the PSBTs.\n", { @@ -1609,8 +1664,9 @@ UniValue joinpsbts(const JSONRPCRequest& request) }, RPCExamples { HelpExampleCli("joinpsbts", "\"psbt\"") - }}.Check(request); - + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VARR}, true); // Unserialize the transactions @@ -1683,12 +1739,14 @@ UniValue joinpsbts(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << shuffled_psbt; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); +}, + }; } -UniValue analyzepsbt(const JSONRPCRequest& request) +static RPCHelpMan analyzepsbt() { - RPCHelpMan{"analyzepsbt", + return RPCHelpMan{"analyzepsbt", "\nAnalyzes and provides information about the current status of a PSBT and its inputs\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} @@ -1722,13 +1780,14 @@ UniValue analyzepsbt(const JSONRPCRequest& request) {RPCResult::Type::STR_AMOUNT, "estimated_feerate", /* optional */ true, "Estimated feerate of the final signed transaction in " + CURRENCY_UNIT + "/kB. Shown only if all UTXO slots in the PSBT have been filled"}, {RPCResult::Type::STR_AMOUNT, "fee", /* optional */ true, "The transaction fee paid. Shown only if all UTXO slots in the PSBT have been filled"}, {RPCResult::Type::STR, "next", "Role of the next person that this psbt needs to go to"}, - {RPCResult::Type::STR, "error", "Error message if there is one"}, + {RPCResult::Type::STR, "error", /* optional */ true, "Error message (if there is one)"}, } }, RPCExamples { HelpExampleCli("analyzepsbt", "\"psbt\"") - }}.Check(request); - + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); // Unserialize the transaction @@ -1792,6 +1851,8 @@ UniValue analyzepsbt(const JSONRPCRequest& request) } return result; +}, + }; } void RegisterRawTransactionRPCCommands(CRPCTable &t) @@ -1821,7 +1882,7 @@ static const CRPCCommand commands[] = { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, }; // clang-format on - - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - t.appendCommand(commands[vcidx].name, &commands[vcidx]); + for (const auto& c : commands) { + t.appendCommand(c.name, &c); + } } |