-
Notifications
You must be signed in to change notification settings - Fork 387
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move PSBT definitions and code to separate files
Move non-wallet PSBT code to src/psbt.{h,cpp}, and PSBT wallet code to src/wallet/psbtwallet.{h,cpp}. This commit contains only code movement (and adjustments to includes and Makefile.am.)
- Loading branch information
Showing
12 changed files
with
862 additions
and
816 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
// Copyright (c) 2009-2018 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#include <psbt.h> | ||
#include <util/strencodings.h> | ||
|
||
PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx) | ||
{ | ||
inputs.resize(tx.vin.size()); | ||
outputs.resize(tx.vout.size()); | ||
} | ||
|
||
bool PartiallySignedTransaction::IsNull() const | ||
{ | ||
return !tx && inputs.empty() && outputs.empty() && unknown.empty(); | ||
} | ||
|
||
void PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt) | ||
{ | ||
for (unsigned int i = 0; i < inputs.size(); ++i) { | ||
inputs[i].Merge(psbt.inputs[i]); | ||
} | ||
for (unsigned int i = 0; i < outputs.size(); ++i) { | ||
outputs[i].Merge(psbt.outputs[i]); | ||
} | ||
unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); | ||
} | ||
|
||
bool PartiallySignedTransaction::IsSane() const | ||
{ | ||
for (PSBTInput input : inputs) { | ||
if (!input.IsSane()) return false; | ||
} | ||
return true; | ||
} | ||
|
||
bool PSBTInput::IsNull() const | ||
{ | ||
return !non_witness_utxo && witness_utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty() && witness_script.empty(); | ||
} | ||
|
||
void PSBTInput::FillSignatureData(SignatureData& sigdata) const | ||
{ | ||
if (!final_script_sig.empty()) { | ||
sigdata.scriptSig = final_script_sig; | ||
sigdata.complete = true; | ||
} | ||
if (!final_script_witness.IsNull()) { | ||
sigdata.scriptWitness = final_script_witness; | ||
sigdata.complete = true; | ||
} | ||
if (sigdata.complete) { | ||
return; | ||
} | ||
|
||
sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end()); | ||
if (!redeem_script.empty()) { | ||
sigdata.redeem_script = redeem_script; | ||
} | ||
if (!witness_script.empty()) { | ||
sigdata.witness_script = witness_script; | ||
} | ||
for (const auto& key_pair : hd_keypaths) { | ||
sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); | ||
} | ||
} | ||
|
||
void PSBTInput::FromSignatureData(const SignatureData& sigdata) | ||
{ | ||
if (sigdata.complete) { | ||
partial_sigs.clear(); | ||
hd_keypaths.clear(); | ||
redeem_script.clear(); | ||
witness_script.clear(); | ||
|
||
if (!sigdata.scriptSig.empty()) { | ||
final_script_sig = sigdata.scriptSig; | ||
} | ||
if (!sigdata.scriptWitness.IsNull()) { | ||
final_script_witness = sigdata.scriptWitness; | ||
} | ||
return; | ||
} | ||
|
||
partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end()); | ||
if (redeem_script.empty() && !sigdata.redeem_script.empty()) { | ||
redeem_script = sigdata.redeem_script; | ||
} | ||
if (witness_script.empty() && !sigdata.witness_script.empty()) { | ||
witness_script = sigdata.witness_script; | ||
} | ||
for (const auto& entry : sigdata.misc_pubkeys) { | ||
hd_keypaths.emplace(entry.second); | ||
} | ||
} | ||
|
||
void PSBTInput::Merge(const PSBTInput& input) | ||
{ | ||
if (!non_witness_utxo && input.non_witness_utxo) non_witness_utxo = input.non_witness_utxo; | ||
if (witness_utxo.IsNull() && !input.witness_utxo.IsNull()) { | ||
witness_utxo = input.witness_utxo; | ||
non_witness_utxo = nullptr; // Clear out any non-witness utxo when we set a witness one. | ||
} | ||
|
||
partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end()); | ||
hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end()); | ||
unknown.insert(input.unknown.begin(), input.unknown.end()); | ||
|
||
if (redeem_script.empty() && !input.redeem_script.empty()) redeem_script = input.redeem_script; | ||
if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script; | ||
if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig; | ||
if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness; | ||
} | ||
|
||
bool PSBTInput::IsSane() const | ||
{ | ||
// Cannot have both witness and non-witness utxos | ||
if (!witness_utxo.IsNull() && non_witness_utxo) return false; | ||
|
||
// If we have a witness_script or a scriptWitness, we must also have a witness utxo | ||
if (!witness_script.empty() && witness_utxo.IsNull()) return false; | ||
if (!final_script_witness.IsNull() && witness_utxo.IsNull()) return false; | ||
|
||
return true; | ||
} | ||
|
||
void PSBTOutput::FillSignatureData(SignatureData& sigdata) const | ||
{ | ||
if (!redeem_script.empty()) { | ||
sigdata.redeem_script = redeem_script; | ||
} | ||
if (!witness_script.empty()) { | ||
sigdata.witness_script = witness_script; | ||
} | ||
for (const auto& key_pair : hd_keypaths) { | ||
sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); | ||
} | ||
} | ||
|
||
void PSBTOutput::FromSignatureData(const SignatureData& sigdata) | ||
{ | ||
if (redeem_script.empty() && !sigdata.redeem_script.empty()) { | ||
redeem_script = sigdata.redeem_script; | ||
} | ||
if (witness_script.empty() && !sigdata.witness_script.empty()) { | ||
witness_script = sigdata.witness_script; | ||
} | ||
for (const auto& entry : sigdata.misc_pubkeys) { | ||
hd_keypaths.emplace(entry.second); | ||
} | ||
} | ||
|
||
bool PSBTOutput::IsNull() const | ||
{ | ||
return redeem_script.empty() && witness_script.empty() && hd_keypaths.empty() && unknown.empty(); | ||
} | ||
|
||
void PSBTOutput::Merge(const PSBTOutput& output) | ||
{ | ||
hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end()); | ||
unknown.insert(output.unknown.begin(), output.unknown.end()); | ||
|
||
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script; | ||
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script; | ||
} | ||
|
||
bool PSBTInputSigned(PSBTInput& input) | ||
{ | ||
return !input.final_script_sig.empty() || !input.final_script_witness.IsNull(); | ||
} | ||
|
||
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash) | ||
{ | ||
PSBTInput& input = psbt.inputs.at(index); | ||
const CMutableTransaction& tx = *psbt.tx; | ||
|
||
if (PSBTInputSigned(input)) { | ||
return true; | ||
} | ||
|
||
// Fill SignatureData with input info | ||
SignatureData sigdata; | ||
input.FillSignatureData(sigdata); | ||
|
||
// Get UTXO | ||
bool require_witness_sig = false; | ||
CTxOut utxo; | ||
|
||
// Verify input sanity, which checks that at most one of witness or non-witness utxos is provided. | ||
if (!input.IsSane()) { | ||
return false; | ||
} | ||
|
||
if (input.non_witness_utxo) { | ||
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout. | ||
COutPoint prevout = tx.vin[index].prevout; | ||
if (input.non_witness_utxo->GetHash() != prevout.hash) { | ||
return false; | ||
} | ||
utxo = input.non_witness_utxo->vout[prevout.n]; | ||
} else if (!input.witness_utxo.IsNull()) { | ||
utxo = input.witness_utxo; | ||
// When we're taking our information from a witness UTXO, we can't verify it is actually data from | ||
// the output being spent. This is safe in case a witness signature is produced (which includes this | ||
// information directly in the hash), but not for non-witness signatures. Remember that we require | ||
// a witness signature in this situation. | ||
require_witness_sig = true; | ||
} else { | ||
return false; | ||
} | ||
|
||
MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash); | ||
sigdata.witness = false; | ||
bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata); | ||
// Verify that a witness signature was produced in case one was required. | ||
if (require_witness_sig && !sigdata.witness) return false; | ||
input.FromSignatureData(sigdata); | ||
|
||
// If we have a witness signature, use the smaller witness UTXO. | ||
if (sigdata.witness) { | ||
input.witness_utxo = utxo; | ||
input.non_witness_utxo = nullptr; | ||
} | ||
|
||
return sig_complete; | ||
} |
Oops, something went wrong.