@@ -220,6 +220,78 @@ static std::vector<RPCArg> CreateTxDoc()
220220 };
221221}
222222
223+ // Update PSBT with information from the mempool, the UTXO set, the txindex, and the provided descriptors
224+ PartiallySignedTransaction ProcessPSBT (const std::string& psbt_string, const CoreContext& context, const HidingSigningProvider& provider)
225+ {
226+ // Unserialize the transactions
227+ PartiallySignedTransaction psbtx;
228+ std::string error;
229+ if (!DecodeBase64PSBT (psbtx, psbt_string, error)) {
230+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed %s" , error));
231+ }
232+
233+ if (g_txindex) g_txindex->BlockUntilSyncedToCurrentChain ();
234+ const NodeContext& node = EnsureAnyNodeContext (context);
235+
236+ // If we can't find the corresponding full transaction for all of our inputs,
237+ // this will be used to find just the utxos for the segwit inputs for which
238+ // the full transaction isn't found
239+ std::map<COutPoint, Coin> coins;
240+
241+ // Fetch previous transactions:
242+ // First, look in the txindex and the mempool
243+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
244+ PSBTInput& psbt_input = psbtx.inputs .at (i);
245+ const CTxIn& tx_in = psbtx.tx ->vin .at (i);
246+
247+ // The `non_witness_utxo` is the whole previous transaction
248+ if (psbt_input.non_witness_utxo ) continue ;
249+
250+ CTransactionRef tx;
251+
252+ // Look in the txindex
253+ if (g_txindex) {
254+ uint256 block_hash;
255+ g_txindex->FindTx (tx_in.prevout .hash , block_hash, tx);
256+ }
257+ // If we still don't have it look in the mempool
258+ if (!tx) {
259+ tx = node.mempool ->get (tx_in.prevout .hash );
260+ }
261+ if (tx) {
262+ psbt_input.non_witness_utxo = tx;
263+ } else {
264+ coins[tx_in.prevout ]; // Create empty map entry keyed by prevout
265+ }
266+ }
267+
268+ // In Bitcoin, if we still haven't found all of the inputs, the utxo set
269+ // is searched and segwit inputs are updated with just the utxo. Dash does
270+ // not support segwit, so this fallback is not applicable.
271+
272+ const PrecomputedTransactionData& txdata = PrecomputePSBTData (psbtx);
273+
274+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
275+ if (PSBTInputSigned (psbtx.inputs .at (i))) {
276+ continue ;
277+ }
278+
279+ // Update script/keypath information using descriptor data.
280+ // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
281+ // we don't actually care about those here, in fact.
282+ SignPSBTInput (provider, psbtx, /* index=*/ i, &txdata, /* sighash=*/ 1 );
283+ }
284+
285+ // Update script/keypath information using descriptor data.
286+ for (unsigned int i = 0 ; i < psbtx.tx ->vout .size (); ++i) {
287+ UpdatePSBTOutput (provider, psbtx, i);
288+ }
289+
290+ RemoveUnnecessaryTransactions (psbtx, /* sighash_type=*/ 1 );
291+
292+ return psbtx;
293+ }
294+
223295static RPCHelpMan getrawtransaction ()
224296{
225297 return RPCHelpMan{
@@ -1659,7 +1731,7 @@ static RPCHelpMan converttopsbt()
16591731static RPCHelpMan utxoupdatepsbt ()
16601732{
16611733 return RPCHelpMan{" utxoupdatepsbt" ,
1662- " \n Updates a PSBT with data from output descriptors, UTXOs retrieved from the UTXO set or the mempool.\n " ,
1734+ " \n Updates a PSBT with data from output descriptors, the UTXO set, txindex, or the mempool.\n " ,
16631735 {
16641736 {" psbt" , RPCArg::Type::STR, RPCArg::Optional::NO, " A base64 string of a PSBT" },
16651737 {" descriptors" , RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, " An array of either strings or objects" , {
@@ -1680,12 +1752,6 @@ static RPCHelpMan utxoupdatepsbt()
16801752{
16811753 RPCTypeCheck (request.params , {UniValue::VSTR, UniValue::VARR}, true );
16821754
1683- // Unserialize the transactions
1684- PartiallySignedTransaction psbtx;
1685- std::string error;
1686- if (!DecodeBase64PSBT (psbtx, request.params [0 ].get_str (), error)) {
1687- throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed %s" , error));
1688- }
16891755
16901756 // Parse descriptors, if any.
16911757 FlatSigningProvider provider;
@@ -1695,47 +1761,12 @@ static RPCHelpMan utxoupdatepsbt()
16951761 EvalDescriptorStringOrObject (descs[i], provider);
16961762 }
16971763 }
1698- // We don't actually need private keys further on; hide them as a precaution.
1699- HidingSigningProvider public_provider (&provider, /* hide_secret=*/ true , /* hide_origin=*/ false );
1700-
1701- // Fetch previous transactions (inputs):
1702- CCoinsView viewDummy;
1703- CCoinsViewCache view (&viewDummy);
1704- {
1705- const NodeContext& node = EnsureAnyNodeContext (request.context );
1706- const CTxMemPool& mempool = EnsureMemPool (node);
1707- ChainstateManager& chainman = EnsureChainman (node);
1708- LOCK2 (cs_main, mempool.cs );
1709- CCoinsViewCache &viewChain = chainman.ActiveChainstate ().CoinsTip ();
1710- CCoinsViewMemPool viewMempool (&viewChain, mempool);
1711- view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
17121764
1713- for (const CTxIn& txin : psbtx.tx ->vin ) {
1714- view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
1715- }
1716-
1717- view.SetBackend (viewDummy); // switch back to avoid locking mempool for too long
1718- }
1719-
1720- // Fill the inputs
1721- const PrecomputedTransactionData txdata = PrecomputePSBTData (psbtx);
1722- for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
1723- PSBTInput& input = psbtx.inputs .at (i);
1724-
1725- if (input.non_witness_utxo ) {
1726- continue ;
1727- }
1728-
1729- // Update script/keypath information using descriptor data.
1730- // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
1731- // we don't actually care about those here, in fact.
1732- SignPSBTInput (public_provider, psbtx, i, &txdata, /* sighash=*/ SIGHASH_ALL);
1733- }
1734-
1735- // Update script/keypath information using descriptor data.
1736- for (unsigned int i = 0 ; i < psbtx.tx ->vout .size (); ++i) {
1737- UpdatePSBTOutput (public_provider, psbtx, i);
1738- }
1765+ // We don't actually need private keys further on; hide them as a precaution.
1766+ const PartiallySignedTransaction& psbtx = ProcessPSBT (
1767+ request.params [0 ].get_str (),
1768+ request.context ,
1769+ HidingSigningProvider (&provider, /* hide_secret=*/ true , /* hide_origin=*/ false ));
17391770
17401771 CDataStream ssTx (SER_NETWORK, PROTOCOL_VERSION);
17411772 ssTx << psbtx;
0 commit comments