aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2018-07-20 17:08:25 -0700
committerAndrew Chow <achow101-github@achow101.com>2019-02-16 00:04:27 -0500
commit7344a7b9984b99882e136efc8ad48fb31740df93 (patch)
treea3f3914903f06d765ca78ed072a875bd9081da9d /src
parente3b1c7a9d6aefcf5c6022dde6956aec6cbc7f205 (diff)
Implement utxoupdatepsbt RPC and tests
Diffstat (limited to 'src')
-rw-r--r--src/rpc/rawtransaction.cpp65
1 files changed, 65 insertions, 0 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 7fe73e56da..2adfd0c0fc 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1691,6 +1691,70 @@ UniValue converttopsbt(const JSONRPCRequest& request)
return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
}
+UniValue utxoupdatepsbt(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1) {
+ throw std::runtime_error(
+ RPCHelpMan{"utxoupdatepsbt",
+ "\nUpdates a PSBT with witness UTXOs retrieved from the UTXO set or the mempool.\n",
+ {
+ {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}
+ },
+ RPCResult {
+ " \"psbt\" (string) The base64-encoded partially signed transaction with inputs updated\n"
+ },
+ RPCExamples {
+ HelpExampleCli("utxoupdatepsbt", "\"psbt\"")
+ }}.ToString());
+ }
+
+ RPCTypeCheck(request.params, {UniValue::VSTR}, true);
+
+ // Unserialize the transactions
+ PartiallySignedTransaction psbtx;
+ std::string error;
+ if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
+ }
+
+ // Fetch previous transactions (inputs):
+ CCoinsView viewDummy;
+ CCoinsViewCache view(&viewDummy);
+ {
+ LOCK2(cs_main, mempool.cs);
+ CCoinsViewCache &viewChain = *pcoinsTip;
+ CCoinsViewMemPool viewMempool(&viewChain, mempool);
+ view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
+
+ for (const CTxIn& txin : psbtx.tx->vin) {
+ view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
+ }
+
+ view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
+ }
+
+ // Fill the inputs
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ PSBTInput& input = psbtx.inputs.at(i);
+
+ if (input.non_witness_utxo || !input.witness_utxo.IsNull()) {
+ continue;
+ }
+
+ const Coin& coin = view.AccessCoin(psbtx.tx->vin[i].prevout);
+
+ std::vector<std::vector<unsigned char>> solutions_data;
+ txnouttype which_type = Solver(coin.out.scriptPubKey, solutions_data);
+ if (which_type == TX_WITNESS_V0_SCRIPTHASH || which_type == TX_WITNESS_V0_KEYHASH || which_type == TX_WITNESS_UNKNOWN) {
+ input.witness_utxo = coin.out;
+ }
+ }
+
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ ssTx << psbtx;
+ return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
+}
+
// clang-format off
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
@@ -1709,6 +1773,7 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },
{ "rawtransactions", "createpsbt", &createpsbt, {"inputs","outputs","locktime","replaceable"} },
{ "rawtransactions", "converttopsbt", &converttopsbt, {"hexstring","permitsigdata","iswitness"} },
+ { "rawtransactions", "utxoupdatepsbt", &utxoupdatepsbt, {"psbt"} },
{ "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} },
{ "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} },