Skip to content

Commit 22b6c4e

Browse files
committed
Merge #15899: rpc: Document iswitness flag and fix bug in converttopsbt
fa499b5 rpc: bugfix: Properly use iswitness in converttopsbt (MarcoFalke) fa5c5cd rpc: Switch touched RPCs to IsValidNumArgs (MarcoFalke) Pull request description: When a serialized transaction has inputs, there is no risk in only trying to deserialize it with witness allowed. (This is how all transactions from p2p are deserialized.) In fact, it would avoid a common issue where a transaction with inputs can be deserialized in two ways: * Fixes #12989 * Fixes #15872 * Fixes #15701 * Fixes #13738 * ... When a serialized transaction has no inputs, there is no risk in only trying to deserialze it with witness disallowed. (A transaction without inputs can't have corresponding witness data) ACKs for commit fa499b: meshcollider: utACK bitcoin/bitcoin@fa499b5 ryanofsky: utACK fa499b5. Changes since last review: consolidating commits and making iswitness documentation the same across methods. PastaPastaPasta: utACK fa499b5 Tree-SHA512: a64423a3131f3f0222a40da557c8b590c9ff01b45bcd40796f77a1a64ae74c6680a6be9d01ece95c492dfbcc7e2810409d2c2b336c2894af00bb213972fc85c6
2 parents 98958c8 + fa499b5 commit 22b6c4e

File tree

3 files changed

+43
-24
lines changed

3 files changed

+43
-24
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -426,14 +426,17 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
426426

427427
static UniValue decoderawtransaction(const JSONRPCRequest& request)
428428
{
429-
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
430-
throw std::runtime_error(
431-
RPCHelpMan{"decoderawtransaction",
429+
const RPCHelpMan help{"decoderawtransaction",
432430
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
433431
{
434432
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
435-
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n"
436-
" If iswitness is not present, heuristic tests will be used in decoding"},
433+
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
434+
"If iswitness is not present, heuristic tests will be used in decoding.\n"
435+
"If true, only witness deserialization will be tried.\n"
436+
"If false, only non-witness deserialization will be tried.\n"
437+
"This boolean should reflect whether the transaction has inputs\n"
438+
"(e.g. fully valid, or on-chain transactions), if known by the caller."
439+
},
437440
},
438441
RPCResult{
439442
"{\n"
@@ -480,7 +483,11 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
480483
HelpExampleCli("decoderawtransaction", "\"hexstring\"")
481484
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
482485
},
483-
}.ToString());
486+
};
487+
488+
if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
489+
throw std::runtime_error(help.ToString());
490+
}
484491

485492
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
486493

@@ -1417,19 +1424,20 @@ UniValue createpsbt(const JSONRPCRequest& request)
14171424

14181425
UniValue converttopsbt(const JSONRPCRequest& request)
14191426
{
1420-
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
1421-
throw std::runtime_error(
1422-
RPCHelpMan{"converttopsbt",
1427+
const RPCHelpMan help{"converttopsbt",
14231428
"\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
14241429
"createpsbt and walletcreatefundedpsbt should be used for new applications.\n",
14251430
{
14261431
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"},
1427-
{"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion.\n"
1432+
{"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion\n"
14281433
" will continue. If false, RPC will fail if any signatures are present."},
14291434
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
1430-
" If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"
1431-
" will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n"
1432-
" permitsigdata is true."},
1435+
"If iswitness is not present, heuristic tests will be used in decoding.\n"
1436+
"If true, only witness deserialization will be tried.\n"
1437+
"If false, only non-witness deserialization will be tried.\n"
1438+
"This boolean should reflect whether the transaction has inputs\n"
1439+
"(e.g. fully valid, or on-chain transactions), if known by the caller."
1440+
},
14331441
},
14341442
RPCResult{
14351443
" \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n"
@@ -1440,8 +1448,11 @@ UniValue converttopsbt(const JSONRPCRequest& request)
14401448
"\nConvert the transaction to a PSBT\n"
14411449
+ HelpExampleCli("converttopsbt", "\"rawtransaction\"")
14421450
},
1443-
}.ToString());
1451+
};
14441452

1453+
if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
1454+
throw std::runtime_error(help.ToString());
1455+
}
14451456

14461457
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
14471458

@@ -1450,8 +1461,8 @@ UniValue converttopsbt(const JSONRPCRequest& request)
14501461
bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool();
14511462
bool witness_specified = !request.params[2].isNull();
14521463
bool iswitness = witness_specified ? request.params[2].get_bool() : false;
1453-
bool try_witness = permitsigdata ? (witness_specified ? iswitness : true) : false;
1454-
bool try_no_witness = permitsigdata ? (witness_specified ? !iswitness : true) : true;
1464+
const bool try_witness = witness_specified ? iswitness : true;
1465+
const bool try_no_witness = witness_specified ? !iswitness : true;
14551466
if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
14561467
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
14571468
}

src/wallet/rpcwallet.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3106,9 +3106,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
31063106
return NullUniValue;
31073107
}
31083108

3109-
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
3110-
throw std::runtime_error(
3111-
RPCHelpMan{"fundrawtransaction",
3109+
const RPCHelpMan help{"fundrawtransaction",
31123110
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
31133111
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
31143112
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
@@ -3147,8 +3145,13 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
31473145
" \"CONSERVATIVE\""},
31483146
},
31493147
"options"},
3150-
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction \n"
3151-
" If iswitness is not present, heuristic tests will be used in decoding"},
3148+
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
3149+
"If iswitness is not present, heuristic tests will be used in decoding.\n"
3150+
"If true, only witness deserialization will be tried.\n"
3151+
"If false, only non-witness deserialization will be tried.\n"
3152+
"This boolean should reflect whether the transaction has inputs\n"
3153+
"(e.g. fully valid, or on-chain transactions), if known by the caller."
3154+
},
31523155
},
31533156
RPCResult{
31543157
"{\n"
@@ -3167,7 +3170,11 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
31673170
"\nSend the transaction\n"
31683171
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
31693172
},
3170-
}.ToString());
3173+
};
3174+
3175+
if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
3176+
throw std::runtime_error(help.ToString());
3177+
}
31713178

31723179
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
31733180

test/functional/rpc_psbt.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,10 @@ def run_test(self):
152152

153153
# Make sure that a non-psbt with signatures cannot be converted
154154
# Error could be either "TX decode failed" (segwit inputs causes parsing to fail) or "Inputs must not have scriptSigs and scriptWitnesses"
155+
# We must set iswitness=True because the serialized transaction has inputs and is therefore a witness transaction
155156
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])
156-
assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, signedtx['hex'])
157-
assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, signedtx['hex'], False)
157+
assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], iswitness=True)
158+
assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], permitsigdata=False, iswitness=True)
158159
# Unless we allow it to convert and strip signatures
159160
self.nodes[0].converttopsbt(signedtx['hex'], True)
160161

0 commit comments

Comments
 (0)