Merge ElementsProject/elements#1559: rpc: use null for optional parameters

14a52bf188 rpc: use null for optional parameters (Ruslan Kasheparov)

Pull request description:

  Fixes: #1558

ACKs for top commit:
  tomt1664:
    Tested ACK 14a52bf188

Tree-SHA512: 161da840bb23c8573dca19b3216e1da03924d65a2ac17075e37c2fb8697994fe9a14b82ee8453f6122692409cb417c5dfe1f726fa0710458c20d207c153a124c
This commit is contained in:
merge-script 2026-07-06 13:22:18 +01:00 committed by Tom Trevethan
parent df752b810c
commit cda99dbfea
No known key found for this signature in database
11 changed files with 56 additions and 13 deletions

View file

@ -2776,7 +2776,7 @@ static RPCHelpMan scantxoutset()
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
}
if (request.params.size() < 2) {
if (request.params[1].isNull()) {
throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
}

View file

@ -145,7 +145,7 @@ static RPCHelpMan help()
[&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue
{
std::string strCommand;
if (jsonRequest.params.size() > 0) {
if (!jsonRequest.params[0].isNull()) {
strCommand = jsonRequest.params[0].get_str();
}
if (strCommand == "dump_all_command_conversions") {

View file

@ -330,7 +330,7 @@ RPCHelpMan initpegoutwallet()
// Generate a new key that is added to wallet or set from argument
CPubKey online_pubkey;
if (request.params.size() < 3) {
if (request.params[2].isNull()) {
std::string error;
if (!pwallet->GetOnlinePakKey(online_pubkey, error)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
@ -347,7 +347,7 @@ RPCHelpMan initpegoutwallet()
// Parse offline counter
int counter = 0;
if (request.params.size() > 1) {
if (!request.params[1].isNull()) {
counter = request.params[1].get_int();
if (counter < 0 || counter > 1000000000) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "bip32_counter must be between 0 and 1,000,000,000, inclusive.");
@ -502,7 +502,7 @@ RPCHelpMan sendtomainchain_base()
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
bool subtract_fee = false;
if (request.params.size() > 2) {
if (!request.params[2].isNull()) {
subtract_fee = request.params[2].get_bool();
}
@ -523,7 +523,7 @@ RPCHelpMan sendtomainchain_base()
EnsureWalletIsUnlocked(*pwallet);
bool verbose = request.params[3].isNull() ? false: request.params[3].get_bool();
bool verbose = request.params[3].isNull() ? false : request.params[3].get_bool();
mapValue_t mapValue;
CCoinControl no_coin_control; // This is a deprecated API
return SendMoney(*pwallet, no_coin_control, recipients, std::move(mapValue), verbose, true /* ignore_blind_fail */);
@ -615,7 +615,7 @@ RPCHelpMan sendtomainchain_pak()
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount for send, must send more than 0.00100000 BTC");
bool subtract_fee = false;
if (request.params.size() > 2) {
if (!request.params[2].isNull()) {
subtract_fee = request.params[2].get_bool();
}
@ -827,7 +827,7 @@ static UniValue createrawpegin(const JSONRPCRequest& request, T_tx_ref& txBTCRef
std::vector<unsigned char> txOutProofData = ParseHex(request.params[1].get_str());
std::set<CScript> claim_scripts;
if (request.params.size() > 2) {
if (!request.params[2].isNull()) {
const std::string claim_script = request.params[2].get_str();
if (!IsHex(claim_script)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Given claim_script is not hex.");
@ -1273,12 +1273,12 @@ RPCHelpMan blindrawtransaction()
}
bool ignore_blind_fail = true;
if (request.params.size() > 1) {
if (!request.params[1].isNull()) {
ignore_blind_fail = request.params[1].get_bool();
}
std::vector<std::vector<unsigned char> > auxiliary_generators;
if (request.params.size() > 2) {
if (!request.params[2].isNull()) {
UniValue assetCommitments = request.params[2].get_array();
if (assetCommitments.size() != 0 && assetCommitments.size() < tx.vin.size()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Asset commitment array must have at least as many entries as transaction inputs.");
@ -1542,11 +1542,11 @@ RPCHelpMan issueasset()
throw JSONRPCError(RPC_TYPE_ERROR, "Issuance must have one non-zero component");
}
bool blind_issuances = request.params.size() < 3 || request.params[2].get_bool();
bool blind_issuances = request.params[2].isNull() || request.params[2].get_bool();
// Check for optional contract to hash into definition
uint256 contract_hash;
if (request.params.size() >= 4) {
if (!request.params[3].isNull()) {
contract_hash = ParseHashV(request.params[3], "contract_hash");
}
@ -1733,7 +1733,7 @@ RPCHelpMan listissuances()
std::string assetstr;
CAsset asset_filter;
if (request.params.size() > 0) {
if (!request.params[0].isNull()) {
assetstr = request.params[0].get_str();
asset_filter = GetAssetFromString(assetstr);
}

View file

@ -600,6 +600,12 @@ class FedPegTest(BitcoinTestFramework):
peg_out_txid = sidechain.sendtomainchain(some_btc_addr, 1)
self.log.info("sendtomainchain with null argument")
verbose_result = sidechain.sendtomainchain(some_btc_addr, 1, None, True)
assert isinstance(verbose_result, dict)
assert 'txid' in verbose_result
assert 'fee_reason' in verbose_result
peg_out_details = sidechain.decoderawtransaction(sidechain.getrawtransaction(peg_out_txid))
# peg-out, change, fee
assert len(peg_out_details["vout"]) == 3

View file

@ -112,12 +112,19 @@ class IssuanceTest(BitcoinTestFramework):
# Make sure test starts with no initial issuance.
assert_equal(len(self.nodes[0].listissuances()), 0)
self.log.info("listissuances with null argument")
assert_equal(self.nodes[0].listissuances(None), [])
# Unblinded issuance of asset
contract_hash = "deadbeef"*8
issued = self.nodes[0].issueasset(1, 1, False, contract_hash)
balance = self.nodes[0].getwalletinfo()["balance"]
assert_equal(balance[issued["asset"]], 1)
assert_equal(balance[issued["token"]], 1)
self.log.info("issueasset with null argument")
assert_equal(len(self.nodes[0].listissuances(None)), len(self.nodes[0].listissuances()))
# Quick unblinded reissuance check, making 2*COIN total
self.nodes[0].reissueasset(issued["asset"], 1)

View file

@ -71,6 +71,11 @@ class PAKTest (BitcoinTestFramework):
assert_equal(new_init["address_lookahead"][0], init_results[1]["address_lookahead"][2])
assert(new_init["liquid_pak"] != init_results[1]["liquid_pak"])
self.log.info("initpegoutwallet with null argument")
null_pak_init = self.nodes[2].initpegoutwallet(xpub, 5, None)
assert_equal(self.nodes[2].getwalletpakinfo()["bip32_counter"], "5")
assert null_pak_init["liquid_pak"]
# Restart and connect peers to check wallet persistence
self.stop_nodes()
self.start_nodes()
@ -187,6 +192,12 @@ class PAKTest (BitcoinTestFramework):
wpkh_stmc = self.nodes[1].sendtomainchain("", 1)
wpkh_txid = wpkh_stmc['txid']
self.log.info("sendtomainchain with null argument")
verbose_stmc = self.nodes[1].sendtomainchain("", 1, None, True)
assert isinstance(verbose_stmc, dict)
assert 'txid' in verbose_stmc
assert 'fee_reason' in verbose_stmc
# Also check some basic return fields of sendtomainchain with pak
assert_equal(wpkh_stmc["bitcoin_address"], wpkh_info["address_lookahead"][0])
validata = self.nodes[1].validateaddress(wpkh_stmc["bitcoin_address"])

View file

@ -339,6 +339,16 @@ class PeginSubsidyTest(BitcoinTestFramework):
assert_equal(len(pegin_tx["decoded"]["vout"]), 2)
self.generate(sidechain2, 1, sync_fun=sync_sidechain)
self.log.info("createrawpegin with null argument")
txid, vout, txoutproof, bitcoin_txhex, claim_script = parent_pegin(parent, sidechain2, amount=1.0, feerate=2.0)
pegintx = sidechain2.createrawpegin(bitcoin_txhex, txoutproof, None, 2.0)
signed = sidechain2.signrawtransactionwithwallet(pegintx["hex"])
assert_equal(signed["complete"], True)
pegin_txid = sidechain2.sendrawtransaction(signed["hex"])
pegin_tx = sidechain2.gettransaction(pegin_txid, True, True)
assert_equal(len(pegin_tx["decoded"]["vout"]), 2)
self.generate(sidechain2, 1, sync_fun=sync_sidechain)
self.log.info("claimpegin before enforcement, with validatepegin, below threshold")
txid, vout, txoutproof, bitcoin_txhex, claim_script = parent_pegin(parent, sidechain, amount=1.0, feerate=2.0)
pegin_txid = sidechain.claimpegin(bitcoin_txhex, txoutproof, claim_script)

View file

@ -17,6 +17,7 @@ class DeriveaddressesTest(BitcoinTestFramework):
descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)#t6wfjs64"
address = "ert1qjqmxmkpmxt80xz4y3746zgt0q3u3ferrfpgxn5"
assert_equal(self.nodes[0].deriveaddresses(descriptor), [address])
assert_equal(self.nodes[0].deriveaddresses(descriptor, None), [address])
descriptor = descriptor[:-9]
assert_raises_rpc_error(-5, "Missing checksum", self.nodes[0].deriveaddresses, descriptor)

View file

@ -649,6 +649,10 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
fundedTx = self.nodes[1].fundrawtransaction(rawtx)
blindedTx = self.nodes[1].blindrawtransaction(fundedTx['hex'])
assert fundedTx["changepos"] != -1
self.log.info("blindrawtransaction with null argument")
blindedTx_null_commitments = self.nodes[1].blindrawtransaction(fundedTx['hex'], None, None, False)
assert blindedTx_null_commitments
# Now we need to unlock.
self.nodes[1].walletpassphrase("test", 600)

View file

@ -94,6 +94,9 @@ class HelpRpcTest(BitcoinTestFramework):
# invalid argument
assert_raises_rpc_error(-1, 'JSON value is not a string as expected', node.help, 0)
# null argument
assert_equal(node.help(None), node.help())
# help of unknown command
assert_equal(node.help('foo'), 'help: unknown command: foo')

View file

@ -126,6 +126,7 @@ class ScantxoutsetTest(BitcoinTestFramework):
# Check that second arg is needed for start
assert_raises_rpc_error(-1, "scanobjects argument is required for the start action", self.nodes[0].scantxoutset, "start")
assert_raises_rpc_error(-1, "scanobjects argument is required for the start action", self.nodes[0].scantxoutset, "start", None)
if __name__ == "__main__":