@@ -169,7 +169,7 @@ static std::vector<RPCArg> CreateTxDoc()
169
169
};
170
170
}
171
171
172
- // Update PSBT with information from the mempool, the UTXO set, and the provided descriptors
172
+ // Update PSBT with information from the mempool, the UTXO set, the txindex, and the provided descriptors
173
173
PartiallySignedTransaction ProcessPSBT (const std::string& psbt_string, const std::any& context, const HidingSigningProvider& provider)
174
174
{
175
175
// Unserialize the transactions
@@ -179,50 +179,78 @@ PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std
179
179
throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed %s" , error));
180
180
}
181
181
182
- // Fetch previous transactions (inputs):
183
- CCoinsView viewDummy;
184
- CCoinsViewCache view (&viewDummy);
185
- {
186
- NodeContext& node = EnsureAnyNodeContext (context);
187
- const CTxMemPool& mempool = EnsureMemPool (node);
188
- ChainstateManager& chainman = EnsureChainman (node);
189
- LOCK2 (cs_main, mempool.cs );
190
- CCoinsViewCache &viewChain = chainman.ActiveChainstate ().CoinsTip ();
191
- CCoinsViewMemPool viewMempool (&viewChain, mempool);
192
- view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
193
-
194
- for (const CTxIn& txin : psbtx.tx ->vin ) {
195
- view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
196
- }
182
+ if (g_txindex) g_txindex->BlockUntilSyncedToCurrentChain ();
183
+ const NodeContext& node = EnsureAnyNodeContext (context);
197
184
198
- view.SetBackend (viewDummy); // switch back to avoid locking mempool for too long
199
- }
185
+ // If we can't find the corresponding full transaction for all of our inputs,
186
+ // this will be used to find just the utxos for the segwit inputs for which
187
+ // the full transaction isn't found
188
+ std::map<COutPoint, Coin> coins;
200
189
201
- // Fill the inputs
202
- const PrecomputedTransactionData txdata = PrecomputePSBTData (psbtx);
190
+ // Fetch previous transactions:
191
+ // First, look in the txindex and the mempool
203
192
for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
204
- PSBTInput& input = psbtx.inputs .at (i);
193
+ PSBTInput& psbt_input = psbtx.inputs .at (i);
194
+ const CTxIn& tx_in = psbtx.tx ->vin .at (i);
205
195
206
- if (input.non_witness_utxo || !input.witness_utxo .IsNull ()) {
207
- continue ;
196
+ // The `non_witness_utxo` is the whole previous transaction
197
+ if (psbt_input.non_witness_utxo ) continue ;
198
+
199
+ CTransactionRef tx;
200
+
201
+ // Look in the txindex
202
+ if (g_txindex) {
203
+ uint256 block_hash;
204
+ g_txindex->FindTx (tx_in.prevout .hash , block_hash, tx);
205
+ }
206
+ // If we still don't have it look in the mempool
207
+ if (!tx) {
208
+ tx = node.mempool ->get (tx_in.prevout .hash );
209
+ }
210
+ if (tx) {
211
+ psbt_input.non_witness_utxo = tx;
212
+ } else {
213
+ coins[tx_in.prevout ]; // Create empty map entry keyed by prevout
214
+ }
215
+ }
216
+
217
+ // If we still haven't found all of the inputs, look for the missing ones in the utxo set
218
+ if (!coins.empty ()) {
219
+ FindCoins (node, coins);
220
+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
221
+ PSBTInput& input = psbtx.inputs .at (i);
222
+
223
+ // If there are still missing utxos, add them if they were found in the utxo set
224
+ if (!input.non_witness_utxo ) {
225
+ const CTxIn& tx_in = psbtx.tx ->vin .at (i);
226
+ const Coin& coin = coins.at (tx_in.prevout );
227
+ if (!coin.out .IsNull () && IsSegWitOutput (provider, coin.out .scriptPubKey )) {
228
+ input.witness_utxo = coin.out ;
229
+ }
230
+ }
208
231
}
232
+ }
209
233
210
- const Coin& coin = view. AccessCoin (psbtx. tx -> vin [i]. prevout );
234
+ const PrecomputedTransactionData& txdata = PrecomputePSBTData (psbtx);
211
235
212
- if (IsSegWitOutput (provider, coin.out .scriptPubKey )) {
213
- input.witness_utxo = coin.out ;
236
+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
237
+ if (PSBTInputSigned (psbtx.inputs .at (i))) {
238
+ continue ;
214
239
}
215
240
216
241
// Update script/keypath information using descriptor data.
217
242
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
218
243
// we don't actually care about those here, in fact.
219
- SignPSBTInput (provider, psbtx, i, &txdata, /* sighash=*/ 1 );
244
+ SignPSBTInput (provider, psbtx, /* index= */ i, &txdata, /* sighash=*/ 1 );
220
245
}
221
246
222
247
// Update script/keypath information using descriptor data.
223
248
for (unsigned int i = 0 ; i < psbtx.tx ->vout .size (); ++i) {
224
249
UpdatePSBTOutput (provider, psbtx, i);
225
250
}
251
+
252
+ RemoveUnnecessaryTransactions (psbtx, /* sighash_type=*/ 1 );
253
+
226
254
return psbtx;
227
255
}
228
256
@@ -1632,7 +1660,7 @@ static RPCHelpMan converttopsbt()
1632
1660
static RPCHelpMan utxoupdatepsbt ()
1633
1661
{
1634
1662
return RPCHelpMan{" utxoupdatepsbt" ,
1635
- " \n Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n " ,
1663
+ " \n Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set, txindex, or the mempool.\n " ,
1636
1664
{
1637
1665
{" psbt" , RPCArg::Type::STR, RPCArg::Optional::NO, " A base64 string of a PSBT" },
1638
1666
{" descriptors" , RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, " An array of either strings or objects" , {
0 commit comments