mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
rpc: extract psbt updating logic into ProcessPSBT
This function is called from utxoupdatepsbt and will be modified in a following commit to allow for updating inputs with the `non_witness_utxo` as well.
This commit is contained in:
parent
8ae2808a43
commit
a5b4883fb4
1 changed files with 62 additions and 53 deletions
|
@ -169,6 +169,63 @@ static std::vector<RPCArg> CreateTxDoc()
|
|||
};
|
||||
}
|
||||
|
||||
// Update PSBT with information from the mempool, the UTXO set, and the provided descriptors
|
||||
PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std::any& context, const HidingSigningProvider& provider)
|
||||
{
|
||||
// Unserialize the transactions
|
||||
PartiallySignedTransaction psbtx;
|
||||
std::string error;
|
||||
if (!DecodeBase64PSBT(psbtx, psbt_string, error)) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
|
||||
}
|
||||
|
||||
// Fetch previous transactions (inputs):
|
||||
CCoinsView viewDummy;
|
||||
CCoinsViewCache view(&viewDummy);
|
||||
{
|
||||
NodeContext& node = EnsureAnyNodeContext(context);
|
||||
const CTxMemPool& mempool = EnsureMemPool(node);
|
||||
ChainstateManager& chainman = EnsureChainman(node);
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip();
|
||||
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
|
||||
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
|
||||
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);
|
||||
|
||||
if (IsSegWitOutput(provider, coin.out.scriptPubKey)) {
|
||||
input.witness_utxo = coin.out;
|
||||
}
|
||||
|
||||
// Update script/keypath information using descriptor data.
|
||||
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
|
||||
// we don't actually care about those here, in fact.
|
||||
SignPSBTInput(provider, psbtx, i, &txdata, /*sighash=*/1);
|
||||
}
|
||||
|
||||
// Update script/keypath information using descriptor data.
|
||||
for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
|
||||
UpdatePSBTOutput(provider, psbtx, i);
|
||||
}
|
||||
return psbtx;
|
||||
}
|
||||
|
||||
static RPCHelpMan getrawtransaction()
|
||||
{
|
||||
return RPCHelpMan{
|
||||
|
@ -1594,13 +1651,6 @@ static RPCHelpMan utxoupdatepsbt()
|
|||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
|
||||
// Parse descriptors, if any.
|
||||
FlatSigningProvider provider;
|
||||
if (!request.params[1].isNull()) {
|
||||
|
@ -1609,53 +1659,12 @@ static RPCHelpMan utxoupdatepsbt()
|
|||
EvalDescriptorStringOrObject(descs[i], provider);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't actually need private keys further on; hide them as a precaution.
|
||||
HidingSigningProvider public_provider(&provider, /*hide_secret=*/true, /*hide_origin=*/false);
|
||||
|
||||
// Fetch previous transactions (inputs):
|
||||
CCoinsView viewDummy;
|
||||
CCoinsViewCache view(&viewDummy);
|
||||
{
|
||||
NodeContext& node = EnsureAnyNodeContext(request.context);
|
||||
const CTxMemPool& mempool = EnsureMemPool(node);
|
||||
ChainstateManager& chainman = EnsureChainman(node);
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip();
|
||||
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
|
||||
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
|
||||
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);
|
||||
|
||||
if (IsSegWitOutput(provider, coin.out.scriptPubKey)) {
|
||||
input.witness_utxo = coin.out;
|
||||
}
|
||||
|
||||
// Update script/keypath information using descriptor data.
|
||||
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
|
||||
// we don't actually care about those here, in fact.
|
||||
SignPSBTInput(public_provider, psbtx, i, &txdata, /*sighash=*/1);
|
||||
}
|
||||
|
||||
// Update script/keypath information using descriptor data.
|
||||
for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
|
||||
UpdatePSBTOutput(public_provider, psbtx, i);
|
||||
}
|
||||
const PartiallySignedTransaction& psbtx = ProcessPSBT(
|
||||
request.params[0].get_str(),
|
||||
request.context,
|
||||
HidingSigningProvider(&provider, /*hide_secret=*/true, /*hide_origin=*/false));
|
||||
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssTx << psbtx;
|
||||
|
|
Loading…
Add table
Reference in a new issue