fix RPC documentation inconsistencies
What changed, and why it matters
This commit fixes mistakes in the text descriptions and type labels shown by several command-line/RPC commands. Most changes are cosmetic documentation corrections, such as fixing typos, marking fields as optional, and correcting error messages. The only functional change is a small update to the `combineblocksigs` command so its optional `witnessScript` argument behaves as documented for both old-style and dynamic-federation blocks, plus a regression test for that behavior. There is no direct security vulnerability being patched.
No urgent action required. Treat as a normal maintenance/documentation fix. Reviewers may want to verify the new `combineblocksigs` runtime check matches the documented behavior and that the regression test passes.
Security signals we found
Documentation-only fixes for RPC result schemas and argument types
Single behavior change: optional `witnessScript` argument handling in `combineblocksigs`
Regression test added for `combineblocksigs` witnessScript optionality under dynafed and non-dynafed states
No changes to consensus, cryptography, networking, or transaction validation logic
Evidence from the diff
The patch is almost entirely RPC help-text and result-schema consistency fixes across src/rpc/blockchain.cpp, src/rpc/mining.cpp, src/rpc/rawtransaction.cpp, and several wallet RPC files. It removes non-existent target fields from getblock/getblockheader docs, marks actually-optional fields as optional, corrects type annotations (e.g., STR -> STR_HEX), fixes typos (Uninforced -> Unenforced), and updates error strings to match what is really being validated. The single behavioral change is in combineblocksigs: the witnessScript argument is now truly optional for non-dynafed blocks and required for dynafed blocks, with an explicit runtime check and a regression test in feature_blocksign.py.
Changed components
RPC help systemsrc/rpc/blockchain.cppsrc/rpc/mining.cppsrc/rpc/rawtransaction.cppsrc/wallet/rpc/coins.cppsrc/wallet/rpc/elements.cppsrc/wallet/rpc/spend.cppsrc/wallet/rpc/wallet.cpptest/functional/feature_blocksign.pyInspect captured patch +77 / −41
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index aa80fb6..8f2ebb1 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -641,7 +641,6 @@ static RPCHelpMan getblockheader()
{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
{RPCResult::Type::NUM, "nonce", /*optional=*/true, "The nonce"},
{RPCResult::Type::STR_HEX, "bits", /*optional=*/true, "The bits"},
- {RPCResult::Type::STR_HEX, "target", /*optional=*/true, "The difficulty target"},
{RPCResult::Type::NUM, "difficulty", /*optional=*/true, "The difficulty"},
{RPCResult::Type::STR_HEX, "chainwork", /*optional=*/true, "Expected number of hashes required to produce the current chain"},
{RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
@@ -843,7 +842,6 @@ static RPCHelpMan getblock()
{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
{RPCResult::Type::NUM, "nonce", /*optional=*/true, "The nonce"},
{RPCResult::Type::STR_HEX, "bits", /*optional=*/true, "The bits"},
- {RPCResult::Type::STR_HEX, "target", /*optional=*/true, "The difficulty target"},
{RPCResult::Type::NUM, "difficulty", /*optional=*/true, "The difficulty"},
{RPCResult::Type::STR_HEX, "chainwork", /*optional=*/true, "Expected number of hashes required to produce the chain up to this block"},
{RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
@@ -867,7 +865,7 @@ static RPCHelpMan getblock()
{RPCResult::Type::ELISION, "", ""}
}},
}},
- {RPCResult::Type::OBJ, "proposed", "Proposed parameters. Uninforced. Must be published in full",
+ {RPCResult::Type::OBJ, "proposed", "Proposed parameters. Unenforced. Must be published in full",
{
{RPCResult::Type::ELISION, "", "same entries as \"current\""}
}},
@@ -2477,7 +2475,7 @@ static RPCHelpMan scantxoutset()
{RPCResult::Type::STR_HEX, "scriptPubKey", "The output script"},
{RPCResult::Type::STR, "desc", "A specialized descriptor for the matched output script"},
{RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
- {RPCResult::Type::STR_HEX, "asset", "The asset ID"},
+ {RPCResult::Type::STR_HEX, "asset", /*optional=*/true, "The asset ID"},
{RPCResult::Type::BOOL, "coinbase", "Whether this is a coinbase output"},
{RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
{RPCResult::Type::STR_HEX, "blockhash", "Blockhash of the unspent transaction output"},
@@ -2900,7 +2898,7 @@ static RPCHelpMan getdescriptoractivity()
{RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The blockhash this spend appears in (omitted if unconfirmed)"},
{RPCResult::Type::NUM, "height", /*optional=*/true, "Height of the spend (omitted if unconfirmed)"},
{RPCResult::Type::STR_HEX, "spend_txid", "The txid of the spending transaction"},
- {RPCResult::Type::NUM, "spend_vout", "The vout of the spend"},
+ {RPCResult::Type::NUM, "spend_vin", "The vin of the spend"},
{RPCResult::Type::STR_HEX, "prevout_txid", "The txid of the prevout"},
{RPCResult::Type::NUM, "prevout_vout", "The vout of the prevout"},
{RPCResult::Type::OBJ, "prevout_spk", "", ScriptPubKeyDoc()},
@@ -3679,10 +3677,10 @@ static RPCHelpMan getsidechaininfo()
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "fedpegscript", "The fedpegscript from genesis block"},
- {RPCResult::Type::ARR, "current_fedpegscripts", "The currently-enforced fedpegscripts in hex. Peg-ins for any entries on this list are honored by consensus and policy. Newest first. Two total entries are possible",
- {{RPCResult::Type::STR_HEX, "", "active fedpegscript"}}},
{RPCResult::Type::ARR, "current_fedpeg_programs", "The currently-enforced fedpegscript scriptPubKeys in hex. Prior to a transition this may be P2SH scriptpubkey, otherwise it will be a native segwit script. Results are paired in-order with current_fedpegscripts",
{{RPCResult::Type::STR_HEX, "", "active fedpegscript scriptPubKeys"}}},
+ {RPCResult::Type::ARR, "current_fedpegscripts", "The currently-enforced fedpegscripts in hex. Peg-ins for any entries on this list are honored by consensus and policy. Newest first. Two total entries are possible",
+ {{RPCResult::Type::STR_HEX, "", "active fedpegscript"}}},
{RPCResult::Type::STR_HEX, "pegged_asset", "Pegged asset type"},
{RPCResult::Type::STR, "min_peg_diff", "The minimum difficulty parent chain header target. Peg-in headers that have less work will be rejected as an anti-Dos measure"},
{RPCResult::Type::STR_HEX, "parent_blockhash", "The parent genesis blockhash as source of pegged-in funds"},
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index d620a28..40d7665 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -450,14 +450,14 @@ static RPCHelpMan getmininginfo()
{RPCResult::Type::NUM, "networkhashps", /*optional=*/true, "The network hashes per second"},
{RPCResult::Type::NUM, "pooledtx", "The size of the mempool"},
{RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
- {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "The block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
- {RPCResult::Type::OBJ, "next", "The next block",
+ {RPCResult::Type::OBJ, "next", /*optional=*/true, "The next block",
{
{RPCResult::Type::NUM, "height", "The next height"},
{RPCResult::Type::STR_HEX, "bits", "The next target nBits"},
{RPCResult::Type::NUM, "difficulty", "The next difficulty"},
{RPCResult::Type::STR_HEX, "target", "The next target"}
}},
+ {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "The block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
(IsDeprecatedRPCEnabled("warnings") ?
RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
@@ -663,6 +663,10 @@ static RPCHelpMan getblocktemplate()
RPCResult{"If the proposal was not accepted with mode=='proposal'", RPCResult::Type::STR, "", "According to BIP22"},
RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "",
{
+ {RPCResult::Type::ARR, "capabilities", "",
+ {
+ {RPCResult::Type::STR, "value", "A supported feature, for example 'proposal'"},
+ }},
{RPCResult::Type::NUM, "version", "The preferred block version"},
{RPCResult::Type::ARR, "rules", "specific block rules that are to be enforced",
{
@@ -672,10 +676,6 @@ static RPCHelpMan getblocktemplate()
{
{RPCResult::Type::NUM, "rulename", "identifies the bit number as indicating acceptance and readiness for the named softfork rule"},
}},
- {RPCResult::Type::ARR, "capabilities", "",
- {
- {RPCResult::Type::STR, "value", "A supported feature, for example 'proposal'"},
- }},
{RPCResult::Type::NUM, "vbrequired", "bit mask of versionbits the server requires set in submissions"},
{RPCResult::Type::STR, "previousblockhash", "The hash of current highest block"},
{RPCResult::Type::ARR, "transactions", "contents of non-coinbase transactions that should be included in the next block",
@@ -1262,7 +1262,7 @@ static RPCHelpMan getnewblockhex()
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), node.mempool.get(), options).CreateNewBlock());
if (!pblocktemplate.get()) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Block template empty");
}
{
@@ -1310,7 +1310,7 @@ static RPCHelpMan combineblocksigs()
},
},
},
- {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded witnessScript for the signblockscript"},
+ {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded witnessScript for the signblockscript. Required for dynafed blocks; omitted for non-dynafed blocks."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -1391,7 +1391,7 @@ static RPCHelpMan getcompactsketch()
{"block_hex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Hex serialized block proposal from `getnewblockhex`."},
},
RPCResult{
- RPCResult::Type::STR, "sketch", "serialized block sketch",
+ RPCResult::Type::STR_HEX, "sketch", "serialized block sketch",
},
RPCExamples{
HelpExampleCli("getcompactsketch", ""),
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index d339fa5..1877d08 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -343,7 +343,7 @@ static RPCHelpMan getrawtransaction()
},
{
RPCResult{"if verbosity is not set or set to 0",
- RPCResult::Type::STR, "data", "The serialized transaction as a hex-encoded string for 'txid'"
+ RPCResult::Type::STR_HEX, "data", "The serialized transaction as a hex-encoded string for 'txid'"
},
RPCResult{"if verbosity is set to 1",
RPCResult::Type::OBJ, "", "",
@@ -711,7 +711,7 @@ static RPCHelpMan combinerawtransaction()
},
},
RPCResult{
- RPCResult::Type::STR, "", "The hex-encoded raw transaction with signature(s)"
+ RPCResult::Type::STR_HEX, "", "The hex-encoded raw transaction with signature(s)"
},
RPCExamples{
HelpExampleCli("combinerawtransaction", R"('["myhex1", "myhex2", "myhex3"]')")
@@ -795,7 +795,7 @@ static RPCHelpMan signrawtransactionwithkey()
{"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
{"privkeys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base58-encoded private keys for signing",
{
- {"privatekey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "private key in base58-encoding"},
+ {"privatekey", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "private key in base58-encoding"},
},
},
{"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The previous dependent transaction outputs",
@@ -1171,9 +1171,8 @@ static RPCHelpMan decodepsbt()
}},
{RPCResult::Type::NUM, "tx_version", /*optional=*/true, "The version number of the unsigned transaction. Not to be confused with PSBT version"},
{RPCResult::Type::NUM, "fallback_locktime", /*optional=*/true, "The locktime to fallback to if no inputs specify a required locktime."},
- {RPCResult::Type::NUM, "fees", "The fees specified in this psbt.", {}, /*skip_type_check=*/true}, // ELEMENTS has an explicit fee output, bitcoin does not (they are implicit)
- {RPCResult::Type::NUM, "input_count", "The number of inputs in this psbt"},
- {RPCResult::Type::NUM, "output_count", "The number of outputs in this psbt."},
+ {RPCResult::Type::NUM, "input_count", /*optional=*/true, "The number of inputs in this psbt"},
+ {RPCResult::Type::NUM, "output_count", /*optional=*/true, "The number of outputs in this psbt."},
{RPCResult::Type::BOOL, "inputs_modifiable", /*optional=*/true, "Whether inputs can be modified"},
{RPCResult::Type::BOOL, "outputs_modifiable", /*optional=*/true, "Whether outputs can be modified"},
{RPCResult::Type::BOOL, "has_sighash_single", /*optional=*/true, "Whether this PSBT has SIGHASH_SINGLE inputs"},
@@ -2608,7 +2607,7 @@ static RPCHelpMan rawblindrawtransaction()
{"ignoreblindfail", RPCArg::Type::BOOL, RPCArg::Default{true}, "Return a transaction even when a blinding attempt fails due to number of blinded inputs/outputs."},
},
RPCResult{
- RPCResult::Type::STR, "transaction", "hex string of the transaction"
+ RPCResult::Type::STR_HEX, "transaction", "hex string of the transaction"
},
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
@@ -2642,7 +2641,7 @@ static RPCHelpMan rawblindrawtransaction()
}
if (inputAmounts.size() != tx.vin.size()) {
throw JSONRPCError(RPC_INVALID_PARAMETER,
- "Invalid parameter: one (potentially empty) input blind for each input must be provided");
+ "Invalid parameter: one (potentially empty) input amount for each input must be provided");
}
if (inputAssets.size() != tx.vin.size()) {
throw JSONRPCError(RPC_INVALID_PARAMETER,
@@ -2694,7 +2693,7 @@ static RPCHelpMan rawblindrawtransaction()
if (!IsHex(assetblind) || assetblind.length() != 32*2)
throw JSONRPCError(RPC_INVALID_PARAMETER, "input asset blinds must be an array of 32-byte hex-encoded strings");
if (!IsHex(asset) || asset.length() != 32*2)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "input asset blinds must be an array of 32-byte hex-encoded strings");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "input asset IDs must be an array of 32-byte hex-encoded strings");
input_blinds.push_back(uint256S(blind));
input_asset_blinds.push_back(uint256S(assetblind));
diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp
index fd3bddc..2b004eb 100644
--- a/src/wallet/rpc/coins.cpp
+++ b/src/wallet/rpc/coins.cpp
@@ -120,7 +120,7 @@ RPCHelpMan getreceivedbyaddress()
"\nThe amount with at least 6 confirmations\n"
+ HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6") +
"\nThe amount with at least 6 confirmations including immature coinbase outputs\n"
- + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6 true") +
+ + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6 \"\" true") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6")
},
@@ -178,9 +178,9 @@ RPCHelpMan getreceivedbylabel()
"\nThe amount with at least 6 confirmations\n"
+ HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
"\nThe amount with at least 6 confirmations including immature coinbase outputs\n"
- + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6 true") +
+ + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6 \"\" true") +
"\nAs a JSON-RPC call\n"
- + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6, true")
+ + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6, \"\", true")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
@@ -640,14 +640,14 @@ RPCHelpMan listunspent()
{RPCResult::Type::STR, "scriptPubKey", "the output script"},
{RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT},
{RPCResult::Type::STR_HEX, "amountcommitment", /*optional=*/true, "the transaction output commitment in hex"},
- {RPCResult::Type::STR_HEX, "asset", "the transaction output asset in hex"},
+ {RPCResult::Type::STR_HEX, "asset", /*optional=*/true, "the transaction output asset in hex"},
{RPCResult::Type::STR_HEX, "assetcommitment", /*optional=*/true, "the transaction output asset commitment in hex"},
- {RPCResult::Type::STR_HEX, "amountblinder", "the transaction output amount blinding factor in hex"},
- {RPCResult::Type::STR_HEX, "assetblinder", "the transaction output asset blinding factor in hex"},
+ {RPCResult::Type::STR_HEX, "amountblinder", /*optional=*/true, "the transaction output amount blinding factor in hex"},
+ {RPCResult::Type::STR_HEX, "assetblinder", /*optional=*/true, "the transaction output asset blinding factor in hex"},
{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
{RPCResult::Type::NUM, "ancestorcount", /*optional=*/true, "The number of in-mempool ancestor transactions, including this one (if transaction is in the mempool)"},
{RPCResult::Type::NUM, "ancestorsize", /*optional=*/true, "The virtual transaction size of in-mempool ancestors, including this one (if transaction is in the mempool)"},
- {RPCResult::Type::STR_AMOUNT, "ancestorfees", /*optional=*/true, "The total fees of in-mempool ancestors (including this one) with fee deltas used for mining priority in " + CURRENCY_ATOM + " (if transaction is in the mempool)"},
+ {RPCResult::Type::NUM, "ancestorfees", /*optional=*/true, "The total fees of in-mempool ancestors (including this one) with fee deltas used for mining priority in " + CURRENCY_ATOM + " (if transaction is in the mempool)"},
{RPCResult::Type::STR_HEX, "redeemScript", /*optional=*/true, "The redeem script if the output script is P2SH"},
{RPCResult::Type::STR, "witnessScript", /*optional=*/true, "witness script if the output script is P2WSH or P2SH-P2WSH"},
{RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
diff --git a/src/wallet/rpc/elements.cpp b/src/wallet/rpc/elements.cpp
index 455c559..3ae2400 100644
--- a/src/wallet/rpc/elements.cpp
+++ b/src/wallet/rpc/elements.cpp
@@ -1000,7 +1000,7 @@ RPCHelpMan createrawpegin()
RPCResult{
RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::STR, "hex", "raw transaction data"},
+ {RPCResult::Type::STR_HEX, "hex", "raw transaction data"},
{RPCResult::Type::BOOL, "mature", /*optional=*/true, "Whether the peg-in is mature (only included when validating peg-ins)"},
},
},
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index b044140..393d047 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -1001,7 +1001,7 @@ RPCHelpMan signrawtransactionwithwallet()
{"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
{"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
{"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The amount spent (required if non-confidential segwit output)"},
- {"amountcommitment", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The amount commitment spent (required if confidential segwit output)"},
+ {"amountcommitment", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The amount commitment spent (required if confidential segwit output)"},
},
},
},
@@ -1917,7 +1917,7 @@ RPCHelpMan walletcreatefundedpsbt()
FundTxDoc()),
RPCArgOptions{.oneline_description="options"}},
{"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
- {"psbt_version", RPCArg::Type::NUM, RPCArg::Default{2}, "The PSBT version number to use."},
+ {"psbt_version", RPCArg::Type::NUM, RPCArg::Default{2}, "The PSBT version number to use. Must be 2."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index f4d1400..14ee67f 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -52,16 +52,13 @@ static RPCHelpMan getwalletinfo()
{RPCResult::Type::NUM, "walletversion", "the wallet version"},
{RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"},
{RPCResult::Type::OBJ, "balance", "DEPRECATED. Identical to getbalances().mine.trusted", {
- // A different entry for each asset in the wallet
- {RPCResult::Type::STR_AMOUNT, "bitcoin", "amount of bitcoin in the wallet"},
+ {RPCResult::Type::ELISION, "", "the amount for each asset"},
}, /*skip_type_check=*/true},
{RPCResult::Type::OBJ, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending", {
- // A different entry for each asset in the wallet
- {RPCResult::Type::STR_AMOUNT, "bitcoin", "amount of bitcoin in the wallet"},
+ {RPCResult::Type::ELISION, "", "the amount for each asset"},
}, /*skip_type_check=*/true},
{RPCResult::Type::OBJ, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature", {
- // A different entry for each asset in the wallet
- {RPCResult::Type::STR_AMOUNT, "bitcoin", "amount of bitcoin in the wallet"},
+ {RPCResult::Type::ELISION, "", "the amount for each asset"},
}, /*skip_type_check=*/true},
{RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
{RPCResult::Type::NUM_TIME, "keypoololdest", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
diff --git a/test/functional/feature_blocksign.py b/test/functional/feature_blocksign.py
index 0306902..1dbd293 100755
--- a/test/functional/feature_blocksign.py
+++ b/test/functional/feature_blocksign.py
@@ -180,6 +180,39 @@ class BlockSignTest(BitcoinTestFramework):
for i in range(num_blocks):
self.mine_block(transactions)
+ def test_combineblocksigs_witnessscript_arg(self):
+ # Regression test for combineblocksigs witnessScript optionality.
+
+ node = self.nodes[0]
+ block = node.getnewblockhex()
+
+ is_dyna = node.getdeploymentinfo()['deployments']['dynafed']['bip9']['status'] == "active"
+
+ if is_dyna:
+ # no witnessScript must give RPC_INVALID_PARAMETER, not a help error from arg-count validation.
+ assert_raises_rpc_error(
+ -8,
+ "Signing dynamic blocks requires the witnessScript argument",
+ node.combineblocksigs,
+ block,
+ [],
+ )
+ # Supplying witnessScript must work normally.
+ result = node.combineblocksigs(block, [], self.witnessScript)
+ assert "hex" in result
+ assert "complete" in result
+ else:
+ # Non-dynafed: 2-argument call must not be rejected by arg-count validation.
+ try:
+ result = node.combineblocksigs(block, [])
+ assert "hex" in result
+ assert "complete" in result
+ except Exception as e:
+ # If exception it must not be the help string
+ assert "combineblocksigs" not in str(e), \
+ "Got help text — 2-arg call was rejected by arg-count validation"
+ raise
+
def run_test(self):
# Have every node except last import its block signing private key.
for i in range(self.num_keys):
@@ -211,6 +244,10 @@ class BlockSignTest(BitcoinTestFramework):
assert_equal(info['deployments']['dynafed']['bip9']['status'], "defined")
+ # Test combineblocksigs witnessScript optionality pre-dynafed
+ self.log.info("Testing combineblocksigs witnessScript argument (pre-dynafed)")
+ self.test_combineblocksigs_witnessscript_arg()
+
# Next let's activate dynafed
blocks_til_dynafed = 431 - self.nodes[0].getblockcount()
self.log.info("Activating dynafed")
@@ -221,6 +258,11 @@ class BlockSignTest(BitcoinTestFramework):
self.log.info("Mine some dynamic federation blocks without txns")
self.mine_blocks(10, False)
+
+ # Test combineblocksigs witnessScript optionality post-dynafed
+ self.log.info("Testing combineblocksigs witnessScript argument (post-dynafed)")
+ self.test_combineblocksigs_witnessscript_arg()
+
self.log.info("Mine some dynamic federation blocks with txns")
self.mine_blocks(10, True)
Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.