Skip to content

Commit e9d86a4

Browse files
committed
Methods for interacting with PSBT structs
Added methods which move data to/from SignaturData objects to PSBTInput and PSBTOutput objects. Added sanity checks for PSBTs as a whole which are done immediately after deserialization. Added Merge methods to merge a PSBT into another one.
1 parent 12bcc64 commit e9d86a4

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

src/script/sign.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,12 +447,144 @@ bool PartiallySignedTransaction::IsNull() const
447447
return !tx && inputs.empty() && outputs.empty() && unknown.empty();
448448
}
449449

450+
void PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt)
451+
{
452+
for (unsigned int i = 0; i < inputs.size(); ++i) {
453+
inputs[i].Merge(psbt.inputs[i]);
454+
}
455+
for (unsigned int i = 0; i < outputs.size(); ++i) {
456+
outputs[i].Merge(psbt.outputs[i]);
457+
}
458+
}
459+
460+
bool PartiallySignedTransaction::IsSane() const
461+
{
462+
for (PSBTInput input : inputs) {
463+
if (!input.IsSane()) return false;
464+
}
465+
return true;
466+
}
467+
450468
bool PSBTInput::IsNull() const
451469
{
452470
return !non_witness_utxo && witness_utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty() && witness_script.empty();
453471
}
454472

473+
void PSBTInput::FillSignatureData(SignatureData& sigdata) const
474+
{
475+
if (!final_script_sig.empty()) {
476+
sigdata.scriptSig = final_script_sig;
477+
sigdata.complete = true;
478+
}
479+
if (!final_script_witness.IsNull()) {
480+
sigdata.scriptWitness = final_script_witness;
481+
sigdata.complete = true;
482+
}
483+
if (sigdata.complete) {
484+
return;
485+
}
486+
487+
sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end());
488+
if (!redeem_script.empty()) {
489+
sigdata.redeem_script = redeem_script;
490+
}
491+
if (!witness_script.empty()) {
492+
sigdata.witness_script = witness_script;
493+
}
494+
for (const auto& key_pair : hd_keypaths) {
495+
sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
496+
}
497+
}
498+
499+
void PSBTInput::FromSignatureData(const SignatureData& sigdata)
500+
{
501+
if (sigdata.complete) {
502+
partial_sigs.clear();
503+
hd_keypaths.clear();
504+
redeem_script.clear();
505+
witness_script.clear();
506+
507+
if (!sigdata.scriptSig.empty()) {
508+
final_script_sig = sigdata.scriptSig;
509+
}
510+
if (!sigdata.scriptWitness.IsNull()) {
511+
final_script_witness = sigdata.scriptWitness;
512+
}
513+
return;
514+
}
515+
516+
partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end());
517+
if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
518+
redeem_script = sigdata.redeem_script;
519+
}
520+
if (witness_script.empty() && !sigdata.witness_script.empty()) {
521+
witness_script = sigdata.witness_script;
522+
}
523+
}
524+
525+
void PSBTInput::Merge(const PSBTInput& input)
526+
{
527+
if (!non_witness_utxo && input.non_witness_utxo) non_witness_utxo = input.non_witness_utxo;
528+
if (witness_utxo.IsNull() && !input.witness_utxo.IsNull()) {
529+
witness_utxo = input.witness_utxo;
530+
non_witness_utxo = nullptr; // Clear out any non-witness utxo when we set a witness one.
531+
}
532+
533+
partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end());
534+
hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end());
535+
unknown.insert(input.unknown.begin(), input.unknown.end());
536+
537+
if (redeem_script.empty() && !input.redeem_script.empty()) redeem_script = input.redeem_script;
538+
if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script;
539+
if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig;
540+
if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness;
541+
}
542+
543+
bool PSBTInput::IsSane() const
544+
{
545+
// Cannot have both witness and non-witness utxos
546+
if (!witness_utxo.IsNull() && non_witness_utxo) return false;
547+
548+
// If we have a witness_script or a scriptWitness, we must also have a witness utxo
549+
if (!witness_script.empty() && witness_utxo.IsNull()) return false;
550+
if (!final_script_witness.IsNull() && witness_utxo.IsNull()) return false;
551+
552+
return true;
553+
}
554+
555+
void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
556+
{
557+
if (!redeem_script.empty()) {
558+
sigdata.redeem_script = redeem_script;
559+
}
560+
if (!witness_script.empty()) {
561+
sigdata.witness_script = witness_script;
562+
}
563+
for (const auto& key_pair : hd_keypaths) {
564+
sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
565+
}
566+
}
567+
568+
void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
569+
{
570+
if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
571+
redeem_script = sigdata.redeem_script;
572+
}
573+
if (witness_script.empty() && !sigdata.witness_script.empty()) {
574+
witness_script = sigdata.witness_script;
575+
}
576+
}
577+
455578
bool PSBTOutput::IsNull() const
456579
{
457580
return redeem_script.empty() && witness_script.empty() && hd_keypaths.empty() && unknown.empty();
458581
}
582+
583+
void PSBTOutput::Merge(const PSBTOutput& output)
584+
{
585+
hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end());
586+
unknown.insert(output.unknown.begin(), output.unknown.end());
587+
588+
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
589+
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
590+
}

src/script/sign.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ struct PSBTInput
187187
int sighash_type = 0;
188188

189189
bool IsNull() const;
190+
void FillSignatureData(SignatureData& sigdata) const;
191+
void FromSignatureData(const SignatureData& sigdata);
192+
void Merge(const PSBTInput& input);
193+
bool IsSane() const;
190194
PSBTInput() {}
191195

192196
template <typename Stream>
@@ -375,6 +379,10 @@ struct PSBTOutput
375379
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
376380

377381
bool IsNull() const;
382+
void FillSignatureData(SignatureData& sigdata) const;
383+
void FromSignatureData(const SignatureData& sigdata);
384+
void Merge(const PSBTOutput& output);
385+
bool IsSane() const;
378386
PSBTOutput() {}
379387

380388
template <typename Stream>
@@ -472,6 +480,8 @@ struct PartiallySignedTransaction
472480
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
473481

474482
bool IsNull() const;
483+
void Merge(const PartiallySignedTransaction& psbt);
484+
bool IsSane() const;
475485
PartiallySignedTransaction() {}
476486
PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {}
477487

@@ -605,6 +615,10 @@ struct PartiallySignedTransaction
605615
if (outputs.size() != tx->vout.size()) {
606616
throw std::ios_base::failure("Outputs provided does not match the number of outputs in transaction.");
607617
}
618+
// Sanity check
619+
if (!IsSane()) {
620+
throw std::ios_base::failure("PSBT is not sane.");
621+
}
608622
}
609623

610624
template <typename Stream>

0 commit comments

Comments
 (0)