Skip to content

Commit bbdbe80

Browse files
committed
Add iswitness parameter to decode- and fundrawtransaction RPCs
1 parent 28485c7 commit bbdbe80

File tree

6 files changed

+45
-29
lines changed

6 files changed

+45
-29
lines changed

src/core_io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class UniValue;
2020
// core_read.cpp
2121
CScript ParseScript(const std::string& s);
2222
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
23-
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
23+
bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
2424
bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
2525
uint256 ParseHashUV(const UniValue& v, const std::string& strName);
2626
uint256 ParseHashStr(const std::string&, const std::string& strName);

src/core_read.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,39 +108,39 @@ bool CheckTxScriptsSanity(const CMutableTransaction& tx)
108108
return true;
109109
}
110110

111-
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)
111+
bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness)
112112
{
113-
if (!IsHex(strHexTx)) {
113+
if (!IsHex(hex_tx)) {
114114
return false;
115115
}
116116

117-
std::vector<unsigned char> txData(ParseHex(strHexTx));
117+
std::vector<unsigned char> txData(ParseHex(hex_tx));
118118

119-
if (fTryNoWitness) {
119+
if (try_no_witness) {
120120
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
121121
try {
122122
ssData >> tx;
123-
if (ssData.eof() && CheckTxScriptsSanity(tx)) {
123+
if (ssData.eof() && (!try_witness || CheckTxScriptsSanity(tx))) {
124124
return true;
125125
}
126-
}
127-
catch (const std::exception&) {
126+
} catch (const std::exception&) {
128127
// Fall through.
129128
}
130129
}
131130

132-
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
133-
try {
134-
ssData >> tx;
135-
if (!ssData.empty()) {
136-
return false;
131+
if (try_witness) {
132+
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
133+
try {
134+
ssData >> tx;
135+
if (ssData.empty()) {
136+
return true;
137+
}
138+
} catch (const std::exception&) {
139+
// Fall through.
137140
}
138141
}
139-
catch (const std::exception&) {
140-
return false;
141-
}
142-
143-
return true;
142+
143+
return false;
144144
}
145145

146146
bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)

src/rpc/client.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,13 @@ static const CRPCConvertParam vRPCConvertParams[] =
9393
{ "createrawtransaction", 1, "outputs" },
9494
{ "createrawtransaction", 2, "locktime" },
9595
{ "createrawtransaction", 3, "replaceable" },
96+
{ "decoderawtransaction", 1, "iswitness" },
9697
{ "signrawtransaction", 1, "prevtxs" },
9798
{ "signrawtransaction", 2, "privkeys" },
9899
{ "sendrawtransaction", 1, "allowhighfees" },
99100
{ "combinerawtransaction", 0, "txs" },
100101
{ "fundrawtransaction", 1, "options" },
102+
{ "fundrawtransaction", 2, "iswitness" },
101103
{ "gettxout", 1, "n" },
102104
{ "gettxout", 2, "include_mempool" },
103105
{ "gettxoutproof", 0, "txids" },

src/rpc/rawtransaction.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -419,13 +419,15 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
419419

420420
UniValue decoderawtransaction(const JSONRPCRequest& request)
421421
{
422-
if (request.fHelp || request.params.size() != 1)
422+
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
423423
throw std::runtime_error(
424-
"decoderawtransaction \"hexstring\"\n"
424+
"decoderawtransaction \"hexstring\" ( iswitness )\n"
425425
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
426426

427427
"\nArguments:\n"
428428
"1. \"hexstring\" (string, required) The transaction hex string\n"
429+
"2. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction\n"
430+
" If iswitness is not present, heuristic tests will be used in decoding\n"
429431

430432
"\nResult:\n"
431433
"{\n"
@@ -473,12 +475,16 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
473475
);
474476

475477
LOCK(cs_main);
476-
RPCTypeCheck(request.params, {UniValue::VSTR});
478+
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
477479

478480
CMutableTransaction mtx;
479481

480-
if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
482+
bool try_witness = request.params[1].isNull() ? true : request.params[1].get_bool();
483+
bool try_no_witness = request.params[1].isNull() ? true : !request.params[1].get_bool();
484+
485+
if (!DecodeHexTx(mtx, request.params[0].get_str(), try_no_witness, try_witness)) {
481486
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
487+
}
482488

483489
UniValue result(UniValue::VOBJ);
484490
TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false);
@@ -966,7 +972,7 @@ static const CRPCCommand commands[] =
966972
// --------------------- ------------------------ ----------------------- ----------
967973
{ "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose"} },
968974
{ "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
969-
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
975+
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring","iswitness"} },
970976
{ "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
971977
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
972978
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },

src/test/rpc_tests.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
6565
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193);
6666
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
6767
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
68-
BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error);
68+
BOOST_CHECK_THROW(CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error);
69+
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false"));
70+
BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false extra"), std::runtime_error);
6971

7072
BOOST_CHECK_THROW(CallRPC("signrawtransaction"), std::runtime_error);
7173
BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), std::runtime_error);

src/wallet/rpcwallet.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2812,9 +2812,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
28122812
return NullUniValue;
28132813
}
28142814

2815-
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
2815+
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
28162816
throw std::runtime_error(
2817-
"fundrawtransaction \"hexstring\" ( options )\n"
2817+
"fundrawtransaction \"hexstring\" ( options iswitness )\n"
28182818
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
28192819
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
28202820
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
@@ -2849,6 +2849,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
28492849
" \"CONSERVATIVE\"\n"
28502850
" }\n"
28512851
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"
2852+
"3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction \n"
2853+
" If iswitness is not present, heuristic tests will be used in decoding\n"
2854+
28522855
"\nResult:\n"
28532856
"{\n"
28542857
" \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
@@ -2881,7 +2884,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
28812884
coinControl.fAllowWatchOnly = request.params[1].get_bool();
28822885
}
28832886
else {
2884-
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
2887+
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ, UniValue::VBOOL});
28852888

28862889
UniValue options = request.params[1];
28872890

@@ -2949,8 +2952,11 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
29492952

29502953
// parse hex string from parameter
29512954
CMutableTransaction tx;
2952-
if (!DecodeHexTx(tx, request.params[0].get_str(), true))
2955+
bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
2956+
bool try_no_witness = request.params[2].isNull() ? true : !request.params[2].get_bool();
2957+
if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
29532958
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2959+
}
29542960

29552961
if (tx.vout.size() == 0)
29562962
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
@@ -3183,7 +3189,7 @@ extern UniValue importmulti(const JSONRPCRequest& request);
31833189
static const CRPCCommand commands[] =
31843190
{ // category name actor (function) argNames
31853191
// --------------------- ------------------------ ----------------------- ----------
3186-
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options"} },
3192+
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
31873193
{ "hidden", "resendwallettransactions", &resendwallettransactions, {} },
31883194
{ "wallet", "abandontransaction", &abandontransaction, {"txid"} },
31893195
{ "wallet", "abortrescan", &abortrescan, {} },

0 commit comments

Comments
 (0)