aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/rawtransaction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/rawtransaction.cpp')
-rw-r--r--src/rpc/rawtransaction.cpp260
1 files changed, 103 insertions, 157 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index cce62bacef..4d8a1b87fc 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -13,10 +13,11 @@
#include <key_io.h>
#include <keystore.h>
#include <merkleblock.h>
-#include <net.h>
+#include <node/transaction.h>
#include <policy/policy.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
+#include <psbt.h>
#include <rpc/rawtransaction.h>
#include <rpc/server.h>
#include <rpc/util.h>
@@ -24,13 +25,12 @@
#include <script/script_error.h>
#include <script/sign.h>
#include <script/standard.h>
-#include <txmempool.h>
#include <uint256.h>
+#include <util/bip32.h>
#include <util/strencodings.h>
#include <validation.h>
#include <validationinterface.h>
-#include <future>
#include <stdint.h>
#include <univalue.h>
@@ -82,9 +82,9 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
"\nIf verbose is 'true', returns an Object with information about 'txid'.\n"
"If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n",
{
- {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
- {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If false, return a string, otherwise return a json object"},
- {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "The block in which to look for the transaction"},
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+ {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If false, return a string, otherwise return a json object"},
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The block in which to look for the transaction"},
},
{
RPCResult{"if verbose is not set or set to false",
@@ -218,12 +218,12 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
"you need to maintain a transaction index, using the -txindex command line option or\n"
"specify the block in which the transaction is included manually (by blockhash).\n",
{
- {"txids", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of txids to filter",
+ {"txids", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of txids to filter",
{
- {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A transaction hash"},
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
},
},
- {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "If specified, looks for txid in the block with this hash"},
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "If specified, looks for txid in the block with this hash"},
},
RPCResult{
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
@@ -311,7 +311,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
"\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",
{
- {"proof", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded proof generated by gettxoutproof"},
+ {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"},
},
RPCResult{
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n"
@@ -472,36 +472,36 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
"Note that the transaction's inputs are not signed, and\n"
"it is not stored in the wallet or transmitted to the network.\n",
{
- {"inputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of json objects",
+ {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of json objects",
{
- {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
- {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
- {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"},
- {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+ {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
+ {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
},
},
},
},
- {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
+ {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
"That is, each address can only appear once and there can only be one 'data' object.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.",
{
- {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
- {"address", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT},
+ {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT},
},
},
- {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
- {"data", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
+ {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
},
},
},
},
- {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125-replaceable.\n"
+ {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
+ {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125-replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
},
RPCResult{
@@ -536,8 +536,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
RPCHelpMan{"decoderawtransaction",
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
{
- {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction hex string"},
- {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n"
+ {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
+ {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n"
" If iswitness is not present, heuristic tests will be used in decoding"},
},
RPCResult{
@@ -611,7 +611,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
RPCHelpMan{"decodescript",
"\nDecode a hex-encoded script.\n",
{
- {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded script"},
+ {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"},
},
RPCResult{
"{\n"
@@ -711,9 +711,9 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
"The combined transaction may be another partially signed transaction or a \n"
"fully signed transaction.",
{
- {"txs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of hex strings of partially signed transactions",
+ {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of hex strings of partially signed transactions",
{
- {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A transaction hash"},
+ {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
},
},
},
@@ -856,15 +856,25 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
RPCTypeCheckObj(prevOut,
{
{"redeemScript", UniValueType(UniValue::VSTR)},
- });
- UniValue v = find_value(prevOut, "redeemScript");
- if (!v.isNull()) {
- std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
+ {"witnessScript", UniValueType(UniValue::VSTR)},
+ }, true);
+ UniValue rs = find_value(prevOut, "redeemScript");
+ if (!rs.isNull()) {
+ std::vector<unsigned char> rsData(ParseHexV(rs, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
keystore->AddCScript(redeemScript);
// Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
+ // This is only for compatibility, it is encouraged to use the explicit witnessScript field instead.
keystore->AddCScript(GetScriptForWitness(redeemScript));
}
+ UniValue ws = find_value(prevOut, "witnessScript");
+ if (!ws.isNull()) {
+ std::vector<unsigned char> wsData(ParseHexV(ws, "witnessScript"));
+ CScript witnessScript(wsData.begin(), wsData.end());
+ keystore->AddCScript(witnessScript);
+ // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
+ keystore->AddCScript(GetScriptForWitness(witnessScript));
+ }
}
}
}
@@ -936,26 +946,27 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
"The third optional argument (may be null) is an array of previous transaction outputs that\n"
"this transaction depends on but may not yet be in the block chain.\n",
{
- {"hexstring", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction hex string"},
- {"privkeys", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of base58-encoded private keys for signing",
+ {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
+ {"privkeys", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of base58-encoded private keys for signing",
{
- {"privatekey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "private key in base58-encoding"},
+ {"privatekey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "private key in base58-encoding"},
},
},
- {"prevtxs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of previous dependent transaction outputs",
+ {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of previous dependent transaction outputs",
{
- {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
- {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
- {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"},
- {"scriptPubKey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "script key"},
- {"redeemScript", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "omitted", "(required for P2SH or P2WSH) redeem script"},
- {"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The amount spent"},
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+ {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
+ {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
+ {"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::NO, "The amount spent"},
},
},
},
},
- {"sighashtype", RPCArg::Type::STR, /* opt */ true, /* default_val */ "ALL", "The signature hash type. Must be one of:\n"
+ {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of:\n"
" \"ALL\"\n"
" \"NONE\"\n"
" \"SINGLE\"\n"
@@ -1023,8 +1034,8 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n",
{
- {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of the raw transaction"},
- {"allowhighfees", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Allow high fees"},
+ {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
+ {"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"},
},
RPCResult{
"\"hex\" (string) The transaction hash in hex\n"
@@ -1041,8 +1052,6 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
},
}.ToString());
- std::promise<void> promise;
-
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
// parse hex string from parameter
@@ -1050,67 +1059,17 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
if (!DecodeHexTx(mtx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
- const uint256& hashTx = tx->GetHash();
-
- CAmount nMaxRawTxFee = maxTxFee;
- if (!request.params[1].isNull() && request.params[1].get_bool())
- nMaxRawTxFee = 0;
- { // cs_main scope
- LOCK(cs_main);
- CCoinsViewCache &view = *pcoinsTip;
- bool fHaveChain = false;
- for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
- const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
- fHaveChain = !existingCoin.IsSpent();
- }
- bool fHaveMempool = mempool.exists(hashTx);
- if (!fHaveMempool && !fHaveChain) {
- // push to local node and sync with wallets
- CValidationState state;
- bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
- nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
- if (state.IsInvalid()) {
- throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state));
- } else {
- if (fMissingInputs) {
- throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
- }
- throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state));
- }
- } else {
- // If wallet is enabled, ensure that the wallet has been made aware
- // of the new transaction prior to returning. This prevents a race
- // where a user might call sendrawtransaction with a transaction
- // to/from their wallet, immediately call some wallet RPC, and get
- // a stale result because callbacks have not yet been processed.
- CallFunctionInValidationInterfaceQueue([&promise] {
- promise.set_value();
- });
- }
- } else if (fHaveChain) {
- throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
- } else {
- // Make sure we don't block forever if re-sending
- // a transaction already in mempool.
- promise.set_value();
+ bool allowhighfees = false;
+ if (!request.params[1].isNull()) allowhighfees = request.params[1].get_bool();
+ uint256 txid;
+ TransactionError err;
+ std::string err_string;
+ if (!BroadcastTransaction(tx, txid, err, err_string, allowhighfees)) {
+ throw JSONRPCTransactionError(err, err_string);
}
- } // cs_main
-
- promise.get_future().wait();
-
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
-
- CInv inv(MSG_TX, hashTx);
- g_connman->ForEachNode([&inv](CNode* pnode)
- {
- pnode->PushInventory(inv);
- });
-
- return hashTx.GetHex();
+ return txid.GetHex();
}
static UniValue testmempoolaccept(const JSONRPCRequest& request)
@@ -1122,13 +1081,13 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
"\nThis checks if the transaction violates the consensus or policy rules.\n"
"\nSee sendrawtransaction call.\n",
{
- {"rawtxs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "An array of hex strings of raw transactions.\n"
+ {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.\n"
" Length must be one for now.",
{
- {"rawtx", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", ""},
+ {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
},
},
- {"allowhighfees", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Allow high fees"},
+ {"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"},
},
RPCResult{
"[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n"
@@ -1223,7 +1182,7 @@ UniValue decodepsbt(const JSONRPCRequest& request)
RPCHelpMan{"decodepsbt",
"\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n",
{
- {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The PSBT base64 string"},
+ {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"},
},
RPCResult{
"{\n"
@@ -1323,7 +1282,7 @@ UniValue decodepsbt(const JSONRPCRequest& request)
// Unserialize the transactions
PartiallySignedTransaction psbtx;
std::string error;
- if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) {
+ if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
@@ -1499,9 +1458,9 @@ UniValue combinepsbt(const JSONRPCRequest& request)
"\nCombine multiple partially signed Bitcoin transactions into one transaction.\n"
"Implements the Combiner role.\n",
{
- {"txs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of base64 strings of partially signed transactions",
+ {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of base64 strings of partially signed transactions",
{
- {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "A base64 string of a PSBT"},
+ {"psbt", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A base64 string of a PSBT"},
},
},
},
@@ -1524,23 +1483,16 @@ UniValue combinepsbt(const JSONRPCRequest& request)
for (unsigned int i = 0; i < txs.size(); ++i) {
PartiallySignedTransaction psbtx;
std::string error;
- if (!DecodePSBT(psbtx, txs[i].get_str(), error)) {
+ if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
psbtxs.push_back(psbtx);
}
- PartiallySignedTransaction merged_psbt(psbtxs[0]); // Copy the first one
-
- // Merge
- for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) {
- if (*it != merged_psbt) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "PSBTs do not refer to the same transactions.");
- }
- merged_psbt.Merge(*it);
- }
- if (!merged_psbt.IsSane()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Merged PSBT is inconsistent");
+ PartiallySignedTransaction merged_psbt;
+ TransactionError error;
+ if (!CombinePSBTs(merged_psbt, error, psbtxs)) {
+ throw JSONRPCTransactionError(error);
}
UniValue result(UniValue::VOBJ);
@@ -1559,8 +1511,8 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
"created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n"
"Implements the Finalizer and Extractor roles.\n",
{
- {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "A base64 string of a PSBT"},
- {"extract", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "If true and the transaction is complete,\n"
+ {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
+ {"extract", RPCArg::Type::BOOL, /* default */ "true", "If true and the transaction is complete,\n"
" extract and return the complete transaction in normal network serialization instead of the PSBT."},
},
RPCResult{
@@ -1581,33 +1533,27 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
// Unserialize the transactions
PartiallySignedTransaction psbtx;
std::string error;
- if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) {
+ if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
- // Finalize input signatures -- in case we have partial signatures that add up to a complete
- // signature, but have not combined them yet (e.g. because the combiner that created this
- // PartiallySignedTransaction did not understand them), this will combine them into a final
- // script.
- bool complete = true;
- for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, SIGHASH_ALL);
- }
+ bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool());
+
+ CMutableTransaction mtx;
+ bool complete = FinalizeAndExtractPSBT(psbtx, mtx);
UniValue result(UniValue::VOBJ);
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
- bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool());
+ std::string result_str;
+
if (complete && extract) {
- CMutableTransaction mtx(*psbtx.tx);
- for (unsigned int i = 0; i < mtx.vin.size(); ++i) {
- mtx.vin[i].scriptSig = psbtx.inputs[i].final_script_sig;
- mtx.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness;
- }
ssTx << mtx;
- result.pushKV("hex", HexStr(ssTx.str()));
+ result_str = HexStr(ssTx.str());
+ result.pushKV("hex", result_str);
} else {
ssTx << psbtx;
- result.pushKV("psbt", EncodeBase64(ssTx.str()));
+ result_str = EncodeBase64(ssTx.str());
+ result.pushKV("psbt", result_str);
}
result.pushKV("complete", complete);
@@ -1622,36 +1568,36 @@ UniValue createpsbt(const JSONRPCRequest& request)
"\nCreates a transaction in the Partially Signed Transaction format.\n"
"Implements the Creator role.\n",
{
- {"inputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of json objects",
+ {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of json objects",
{
- {"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
- {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
- {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"},
- {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+ {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
+ {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
},
},
},
},
- {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
+ {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
"That is, each address can only appear once and there can only be one 'data' object.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.",
{
- {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
- {"address", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT},
+ {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT},
},
},
- {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
- {"data", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
+ {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
},
},
},
},
- {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125 replaceable.\n"
+ {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
+ {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
},
RPCResult{
@@ -1698,10 +1644,10 @@ UniValue converttopsbt(const JSONRPCRequest& request)
"\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",
{
- {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of a raw transaction"},
- {"permitsigdata", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If true, any signatures in the input will be discarded and conversion.\n"
+ {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"},
+ {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion.\n"
" will continue. If false, RPC will fail if any signatures are present."},
- {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
" If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"
" will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n"
" permitsigdata is true."},