@@ -172,6 +172,91 @@ static std::vector<RPCArg> CreateTxDoc()
172
172
};
173
173
}
174
174
175
+ // Update PSBT with information from the mempool, the UTXO set, the txindex, and the provided descriptors
176
+ PartiallySignedTransaction ProcessPSBT (const std::string& psbt_string, const std::any& context, const HidingSigningProvider& provider)
177
+ {
178
+ // Unserialize the transactions
179
+ PartiallySignedTransaction psbtx;
180
+ std::string error;
181
+ if (!DecodeBase64PSBT (psbtx, psbt_string, error)) {
182
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed %s" , error));
183
+ }
184
+
185
+ if (g_txindex) g_txindex->BlockUntilSyncedToCurrentChain ();
186
+ const NodeContext& node = EnsureAnyNodeContext (context);
187
+
188
+ // If we can't find the corresponding full transaction for all of our inputs,
189
+ // this will be used to find just the utxos for the segwit inputs for which
190
+ // the full transaction isn't found
191
+ std::map<COutPoint, Coin> coins;
192
+
193
+ // Fetch previous transactions:
194
+ // First, look in the txindex and the mempool
195
+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
196
+ PSBTInput& psbt_input = psbtx.inputs .at (i);
197
+ const CTxIn& tx_in = psbtx.tx ->vin .at (i);
198
+
199
+ // The `non_witness_utxo` is the whole previous transaction
200
+ if (psbt_input.non_witness_utxo ) continue ;
201
+
202
+ CTransactionRef tx;
203
+
204
+ // Look in the txindex
205
+ if (g_txindex) {
206
+ uint256 block_hash;
207
+ g_txindex->FindTx (tx_in.prevout .hash , block_hash, tx);
208
+ }
209
+ // If we still don't have it look in the mempool
210
+ if (!tx) {
211
+ tx = node.mempool ->get (tx_in.prevout .hash );
212
+ }
213
+ if (tx) {
214
+ psbt_input.non_witness_utxo = tx;
215
+ } else {
216
+ coins[tx_in.prevout ]; // Create empty map entry keyed by prevout
217
+ }
218
+ }
219
+
220
+ // If we still haven't found all of the inputs, look for the missing ones in the utxo set
221
+ if (!coins.empty ()) {
222
+ FindCoins (node, coins);
223
+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
224
+ PSBTInput& input = psbtx.inputs .at (i);
225
+
226
+ // If there are still missing utxos, add them if they were found in the utxo set
227
+ if (!input.non_witness_utxo ) {
228
+ const CTxIn& tx_in = psbtx.tx ->vin .at (i);
229
+ const Coin& coin = coins.at (tx_in.prevout );
230
+ if (!coin.out .IsNull () && IsSegWitOutput (provider, coin.out .scriptPubKey )) {
231
+ input.witness_utxo = coin.out ;
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ const PrecomputedTransactionData& txdata = PrecomputePSBTData (psbtx);
238
+
239
+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
240
+ if (PSBTInputSigned (psbtx.inputs .at (i))) {
241
+ continue ;
242
+ }
243
+
244
+ // Update script/keypath information using descriptor data.
245
+ // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
246
+ // we don't actually care about those here, in fact.
247
+ SignPSBTInput (provider, psbtx, /* index=*/ i, &txdata, /* sighash=*/ 1 );
248
+ }
249
+
250
+ // Update script/keypath information using descriptor data.
251
+ for (unsigned int i = 0 ; i < psbtx.tx ->vout .size (); ++i) {
252
+ UpdatePSBTOutput (provider, psbtx, i);
253
+ }
254
+
255
+ RemoveUnnecessaryTransactions (psbtx, /* sighash_type=*/ 1 );
256
+
257
+ return psbtx;
258
+ }
259
+
175
260
static RPCHelpMan getrawtransaction ()
176
261
{
177
262
return RPCHelpMan{
@@ -1580,7 +1665,7 @@ static RPCHelpMan converttopsbt()
1580
1665
static RPCHelpMan utxoupdatepsbt ()
1581
1666
{
1582
1667
return RPCHelpMan{" utxoupdatepsbt" ,
1583
- " \n Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n " ,
1668
+ " \n Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set, txindex, or the mempool.\n " ,
1584
1669
{
1585
1670
{" psbt" , RPCArg::Type::STR, RPCArg::Optional::NO, " A base64 string of a PSBT" },
1586
1671
{" descriptors" , RPCArg::Type::ARR, RPCArg::Optional::OMITTED, " An array of either strings or objects" , {
@@ -1599,13 +1684,6 @@ static RPCHelpMan utxoupdatepsbt()
1599
1684
},
1600
1685
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1601
1686
{
1602
- // Unserialize the transactions
1603
- PartiallySignedTransaction psbtx;
1604
- std::string error;
1605
- if (!DecodeBase64PSBT (psbtx, request.params [0 ].get_str (), error)) {
1606
- throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed %s" , error));
1607
- }
1608
-
1609
1687
// Parse descriptors, if any.
1610
1688
FlatSigningProvider provider;
1611
1689
if (!request.params [1 ].isNull ()) {
@@ -1614,53 +1692,12 @@ static RPCHelpMan utxoupdatepsbt()
1614
1692
EvalDescriptorStringOrObject (descs[i], provider);
1615
1693
}
1616
1694
}
1617
- // We don't actually need private keys further on; hide them as a precaution.
1618
- HidingSigningProvider public_provider (&provider, /* hide_secret=*/ true , /* hide_origin=*/ false );
1619
-
1620
- // Fetch previous transactions (inputs):
1621
- CCoinsView viewDummy;
1622
- CCoinsViewCache view (&viewDummy);
1623
- {
1624
- NodeContext& node = EnsureAnyNodeContext (request.context );
1625
- const CTxMemPool& mempool = EnsureMemPool (node);
1626
- ChainstateManager& chainman = EnsureChainman (node);
1627
- LOCK2 (cs_main, mempool.cs );
1628
- CCoinsViewCache &viewChain = chainman.ActiveChainstate ().CoinsTip ();
1629
- CCoinsViewMemPool viewMempool (&viewChain, mempool);
1630
- view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
1631
-
1632
- for (const CTxIn& txin : psbtx.tx ->vin ) {
1633
- view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
1634
- }
1635
-
1636
- view.SetBackend (viewDummy); // switch back to avoid locking mempool for too long
1637
- }
1638
-
1639
- // Fill the inputs
1640
- const PrecomputedTransactionData txdata = PrecomputePSBTData (psbtx);
1641
- for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
1642
- PSBTInput& input = psbtx.inputs .at (i);
1643
1695
1644
- if (input.non_witness_utxo || !input.witness_utxo .IsNull ()) {
1645
- continue ;
1646
- }
1647
-
1648
- const Coin& coin = view.AccessCoin (psbtx.tx ->vin [i].prevout );
1649
-
1650
- if (IsSegWitOutput (provider, coin.out .scriptPubKey )) {
1651
- input.witness_utxo = coin.out ;
1652
- }
1653
-
1654
- // Update script/keypath information using descriptor data.
1655
- // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
1656
- // we don't actually care about those here, in fact.
1657
- SignPSBTInput (public_provider, psbtx, i, &txdata, /* sighash=*/ 1 );
1658
- }
1659
-
1660
- // Update script/keypath information using descriptor data.
1661
- for (unsigned int i = 0 ; i < psbtx.tx ->vout .size (); ++i) {
1662
- UpdatePSBTOutput (public_provider, psbtx, i);
1663
- }
1696
+ // We don't actually need private keys further on; hide them as a precaution.
1697
+ const PartiallySignedTransaction& psbtx = ProcessPSBT (
1698
+ request.params [0 ].get_str (),
1699
+ request.context ,
1700
+ HidingSigningProvider (&provider, /* hide_secret=*/ true , /* hide_origin=*/ false ));
1664
1701
1665
1702
CDataStream ssTx (SER_NETWORK, PROTOCOL_VERSION);
1666
1703
ssTx << psbtx;
0 commit comments