Skip to content

Commit d5b929c

Browse files
committed
Merge #13932: Additional utility RPCs for PSBT
540729e Implement analyzepsbt RPC and tests (Andrew Chow) 77542cf Move PSBT UTXO fetching to a separate method (Andrew Chow) cb40b3a Figure out what is missing during signing (Andrew Chow) 08f749c Implement joinpsbts RPC and tests (Andrew Chow) 7344a7b Implement utxoupdatepsbt RPC and tests (Andrew Chow) Pull request description: This PR adds 3 new utility RPCs for interacting with PSBTs. `utxoupdatepsbt` updates a PSBT with UTXO information from the node. It only works with witness UTXOs because full transactions (as would be needed for non-witness UTXOs) are not available unless txindex is enabled. `joinpsbts` joins the inputs from multiple distinct PSBTs into one PSBT. e.g. if PSBT 1 has inputs 1 and 2, and PSBT 2 has inputs 3 and 4, `joinpsbts` would create a new PSBT with inputs 1, 2, 3, and 4. `analyzepsbt` analyzes a PSBT and determines the current state of it and all of its inputs, and the next step that needs to be done. Tree-SHA512: 3c1fa302201abca76a8901d0c2be7b4ccbce334d989533c215f8b3e50e22f2f018ce6209544b26789f58f5980a253c0655111e1e20d47d5656e0414c64891a5c
2 parents f9d50e8 + 540729e commit d5b929c

File tree

7 files changed

+487
-9
lines changed

7 files changed

+487
-9
lines changed

src/psbt.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,40 @@ bool PartiallySignedTransaction::IsSane() const
4242
return true;
4343
}
4444

45+
bool PartiallySignedTransaction::AddInput(const CTxIn& txin, PSBTInput& psbtin)
46+
{
47+
if (std::find(tx->vin.begin(), tx->vin.end(), txin) != tx->vin.end()) {
48+
return false;
49+
}
50+
tx->vin.push_back(txin);
51+
psbtin.partial_sigs.clear();
52+
psbtin.final_script_sig.clear();
53+
psbtin.final_script_witness.SetNull();
54+
inputs.push_back(psbtin);
55+
return true;
56+
}
57+
58+
bool PartiallySignedTransaction::AddOutput(const CTxOut& txout, const PSBTOutput& psbtout)
59+
{
60+
tx->vout.push_back(txout);
61+
outputs.push_back(psbtout);
62+
return true;
63+
}
64+
65+
bool PartiallySignedTransaction::GetInputUTXO(CTxOut& utxo, int input_index) const
66+
{
67+
PSBTInput input = inputs[input_index];
68+
int prevout_index = tx->vin[input_index].prevout.n;
69+
if (input.non_witness_utxo) {
70+
utxo = input.non_witness_utxo->vout[prevout_index];
71+
} else if (!input.witness_utxo.IsNull()) {
72+
utxo = input.witness_utxo;
73+
} else {
74+
return false;
75+
}
76+
return true;
77+
}
78+
4579
bool PSBTInput::IsNull() const
4680
{
4781
return !non_witness_utxo && witness_utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty() && witness_script.empty();
@@ -171,13 +205,12 @@ void PSBTOutput::Merge(const PSBTOutput& output)
171205
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
172206
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
173207
}
174-
175208
bool PSBTInputSigned(PSBTInput& input)
176209
{
177210
return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
178211
}
179212

180-
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash)
213+
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash, SignatureData* out_sigdata, bool use_dummy)
181214
{
182215
PSBTInput& input = psbt.inputs.at(index);
183216
const CMutableTransaction& tx = *psbt.tx;
@@ -217,9 +250,14 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
217250
return false;
218251
}
219252

220-
MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash);
221253
sigdata.witness = false;
222-
bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
254+
bool sig_complete;
255+
if (use_dummy) {
256+
sig_complete = ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, utxo.scriptPubKey, sigdata);
257+
} else {
258+
MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash);
259+
sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
260+
}
223261
// Verify that a witness signature was produced in case one was required.
224262
if (require_witness_sig && !sigdata.witness) return false;
225263
input.FromSignatureData(sigdata);
@@ -230,6 +268,14 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
230268
input.non_witness_utxo = nullptr;
231269
}
232270

271+
// Fill in the missing info
272+
if (out_sigdata) {
273+
out_sigdata->missing_pubkeys = sigdata.missing_pubkeys;
274+
out_sigdata->missing_sigs = sigdata.missing_sigs;
275+
out_sigdata->missing_redeem_script = sigdata.missing_redeem_script;
276+
out_sigdata->missing_witness_script = sigdata.missing_witness_script;
277+
}
278+
233279
return sig_complete;
234280
}
235281

src/psbt.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,19 @@ struct PartiallySignedTransaction
389389
* same actual Bitcoin transaction.) Returns true if the merge succeeded, false otherwise. */
390390
NODISCARD bool Merge(const PartiallySignedTransaction& psbt);
391391
bool IsSane() const;
392+
bool AddInput(const CTxIn& txin, PSBTInput& psbtin);
393+
bool AddOutput(const CTxOut& txout, const PSBTOutput& psbtout);
392394
PartiallySignedTransaction() {}
393395
PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {}
394396
explicit PartiallySignedTransaction(const CMutableTransaction& tx);
397+
/**
398+
* Finds the UTXO for a given input index
399+
*
400+
* @param[out] utxo The UTXO of the input if found
401+
* @param[in] input_index Index of the input to retrieve the UTXO of
402+
* @return Whether the UTXO for the specified input was found
403+
*/
404+
bool GetInputUTXO(CTxOut& utxo, int input_index) const;
395405

396406
template <typename Stream>
397407
inline void Serialize(Stream& s) const {
@@ -542,7 +552,7 @@ struct PartiallySignedTransaction
542552
bool PSBTInputSigned(PSBTInput& input);
543553

544554
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
545-
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL);
555+
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool use_dummy = false);
546556

547557
/**
548558
* Finalizes a PSBT if possible, combining partial signatures.

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
112112
{ "createpsbt", 2, "locktime" },
113113
{ "createpsbt", 3, "replaceable" },
114114
{ "combinepsbt", 0, "txs"},
115+
{ "joinpsbts", 0, "txs"},
115116
{ "finalizepsbt", 1, "extract"},
116117
{ "converttopsbt", 1, "permitsigdata"},
117118
{ "converttopsbt", 2, "iswitness"},

0 commit comments

Comments
 (0)