@@ -169,6 +169,63 @@ 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
173
+ PartiallySignedTransaction ProcessPSBT (const std::string& psbt_string, const std::any& context, const HidingSigningProvider& provider)
174
+ {
175
+ // Unserialize the transactions
176
+ PartiallySignedTransaction psbtx;
177
+ std::string error;
178
+ if (!DecodeBase64PSBT (psbtx, psbt_string, error)) {
179
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed %s" , error));
180
+ }
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
+ }
197
+
198
+ view.SetBackend (viewDummy); // switch back to avoid locking mempool for too long
199
+ }
200
+
201
+ // Fill the inputs
202
+ const PrecomputedTransactionData txdata = PrecomputePSBTData (psbtx);
203
+ for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
204
+ PSBTInput& input = psbtx.inputs .at (i);
205
+
206
+ if (input.non_witness_utxo || !input.witness_utxo .IsNull ()) {
207
+ continue ;
208
+ }
209
+
210
+ const Coin& coin = view.AccessCoin (psbtx.tx ->vin [i].prevout );
211
+
212
+ if (IsSegWitOutput (provider, coin.out .scriptPubKey )) {
213
+ input.witness_utxo = coin.out ;
214
+ }
215
+
216
+ // Update script/keypath information using descriptor data.
217
+ // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
218
+ // we don't actually care about those here, in fact.
219
+ SignPSBTInput (provider, psbtx, i, &txdata, /* sighash=*/ 1 );
220
+ }
221
+
222
+ // Update script/keypath information using descriptor data.
223
+ for (unsigned int i = 0 ; i < psbtx.tx ->vout .size (); ++i) {
224
+ UpdatePSBTOutput (provider, psbtx, i);
225
+ }
226
+ return psbtx;
227
+ }
228
+
172
229
static RPCHelpMan getrawtransaction ()
173
230
{
174
231
return RPCHelpMan{
@@ -1594,13 +1651,6 @@ static RPCHelpMan utxoupdatepsbt()
1594
1651
},
1595
1652
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1596
1653
{
1597
- // Unserialize the transactions
1598
- PartiallySignedTransaction psbtx;
1599
- std::string error;
1600
- if (!DecodeBase64PSBT (psbtx, request.params [0 ].get_str (), error)) {
1601
- throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed %s" , error));
1602
- }
1603
-
1604
1654
// Parse descriptors, if any.
1605
1655
FlatSigningProvider provider;
1606
1656
if (!request.params [1 ].isNull ()) {
@@ -1609,53 +1659,12 @@ static RPCHelpMan utxoupdatepsbt()
1609
1659
EvalDescriptorStringOrObject (descs[i], provider);
1610
1660
}
1611
1661
}
1612
- // We don't actually need private keys further on; hide them as a precaution.
1613
- HidingSigningProvider public_provider (&provider, /* hide_secret=*/ true , /* hide_origin=*/ false );
1614
-
1615
- // Fetch previous transactions (inputs):
1616
- CCoinsView viewDummy;
1617
- CCoinsViewCache view (&viewDummy);
1618
- {
1619
- NodeContext& node = EnsureAnyNodeContext (request.context );
1620
- const CTxMemPool& mempool = EnsureMemPool (node);
1621
- ChainstateManager& chainman = EnsureChainman (node);
1622
- LOCK2 (cs_main, mempool.cs );
1623
- CCoinsViewCache &viewChain = chainman.ActiveChainstate ().CoinsTip ();
1624
- CCoinsViewMemPool viewMempool (&viewChain, mempool);
1625
- view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
1626
-
1627
- for (const CTxIn& txin : psbtx.tx ->vin ) {
1628
- view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
1629
- }
1630
-
1631
- view.SetBackend (viewDummy); // switch back to avoid locking mempool for too long
1632
- }
1633
-
1634
- // Fill the inputs
1635
- const PrecomputedTransactionData txdata = PrecomputePSBTData (psbtx);
1636
- for (unsigned int i = 0 ; i < psbtx.tx ->vin .size (); ++i) {
1637
- PSBTInput& input = psbtx.inputs .at (i);
1638
-
1639
- if (input.non_witness_utxo || !input.witness_utxo .IsNull ()) {
1640
- continue ;
1641
- }
1642
-
1643
- const Coin& coin = view.AccessCoin (psbtx.tx ->vin [i].prevout );
1644
-
1645
- if (IsSegWitOutput (provider, coin.out .scriptPubKey )) {
1646
- input.witness_utxo = coin.out ;
1647
- }
1648
-
1649
- // Update script/keypath information using descriptor data.
1650
- // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
1651
- // we don't actually care about those here, in fact.
1652
- SignPSBTInput (public_provider, psbtx, i, &txdata, /* sighash=*/ 1 );
1653
- }
1654
1662
1655
- // Update script/keypath information using descriptor data.
1656
- for (unsigned int i = 0 ; i < psbtx.tx ->vout .size (); ++i) {
1657
- UpdatePSBTOutput (public_provider, psbtx, i);
1658
- }
1663
+ // We don't actually need private keys further on; hide them as a precaution.
1664
+ const PartiallySignedTransaction& psbtx = ProcessPSBT (
1665
+ request.params [0 ].get_str (),
1666
+ request.context ,
1667
+ HidingSigningProvider (&provider, /* hide_secret=*/ true , /* hide_origin=*/ false ));
1659
1668
1660
1669
CDataStream ssTx (SER_NETWORK, PROTOCOL_VERSION);
1661
1670
ssTx << psbtx;
0 commit comments