Skip to content

Commit

Permalink
psbt: use sighash type field to determine whether to remove non-witne…
Browse files Browse the repository at this point in the history
…ss utxos

Since the sighash type field is written for atypical sighash types, we
can look at that field to figure out whether the psbt contains
unnecessary transactions.
  • Loading branch information
achow101 committed Feb 20, 2025
1 parent b1515fe commit a14daad
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 29 deletions.
56 changes: 30 additions & 26 deletions src/psbt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,37 +467,41 @@ PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransact
return sig_complete ? PSBTError::OK : PSBTError::INCOMPLETE;
}

void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, std::optional<int> sighash_type)
void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx)
{
if (!sighash_type) sighash_type = SIGHASH_DEFAULT;
// Only drop non_witness_utxos if sighash_type != SIGHASH_ANYONECANPAY
if ((*sighash_type & 0x80) != SIGHASH_ANYONECANPAY) {
// Figure out if any non_witness_utxos should be dropped
std::vector<unsigned int> to_drop;
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
const auto& input = psbtx.inputs.at(i);
int wit_ver;
std::vector<unsigned char> wit_prog;
if (input.witness_utxo.IsNull() || !input.witness_utxo.scriptPubKey.IsWitnessProgram(wit_ver, wit_prog)) {
// There's a non-segwit input or Segwit v0, so we cannot drop any witness_utxos
to_drop.clear();
break;
}
if (wit_ver == 0) {
// Segwit v0, so we cannot drop any non_witness_utxos
to_drop.clear();
break;
}
if (input.non_witness_utxo) {
to_drop.push_back(i);
}
// Figure out if any non_witness_utxos should be dropped
std::vector<unsigned int> to_drop;
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
const auto& input = psbtx.inputs.at(i);
int wit_ver;
std::vector<unsigned char> wit_prog;
if (input.witness_utxo.IsNull() || !input.witness_utxo.scriptPubKey.IsWitnessProgram(wit_ver, wit_prog)) {
// There's a non-segwit input, so we cannot drop any non_witness_utxos
to_drop.clear();
break;
}
if (wit_ver == 0) {
// Segwit v0, so we cannot drop any non_witness_utxos
to_drop.clear();
break;
}
// non_witness_utxos cannot be dropped if the sighash type includes SIGHASH_ANYONECANPAY
// Since callers should have called SignPSBTInput which updates the sighash type in the PSBT, we only
// need to look at that field. If it is not present, then we can assume SIGHASH_DEFAULT or SIGHASH_ALL.
if (input.sighash_type != std::nullopt && (*input.sighash_type & 0x80) == SIGHASH_ANYONECANPAY) {
to_drop.clear();
break;
}

// Drop the non_witness_utxos that we can drop
for (unsigned int i : to_drop) {
psbtx.inputs.at(i).non_witness_utxo = nullptr;
if (input.non_witness_utxo) {
to_drop.push_back(i);
}
}

// Drop the non_witness_utxos that we can drop
for (unsigned int i : to_drop) {
psbtx.inputs.at(i).non_witness_utxo = nullptr;
}
}

bool FinalizePSBT(PartiallySignedTransaction& psbtx)
Expand Down
2 changes: 1 addition & 1 deletion src/psbt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned
[[nodiscard]] PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, std::optional<int> sighash = std::nullopt, SignatureData* out_sigdata = nullptr, bool finalize = true);

/** Reduces the size of the PSBT by dropping unnecessary `non_witness_utxos` (i.e. complete previous transactions) from a psbt when all inputs are segwit v1. */
void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, std::optional<int> sighash_type);
void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx);

/** Counts the unsigned inputs of a PSBT. */
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt);
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std
UpdatePSBTOutput(provider, psbtx, i);
}

RemoveUnnecessaryTransactions(psbtx, /*sighash_type=*/std::nullopt);
RemoveUnnecessaryTransactions(psbtx);

return psbtx;
}
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2240,7 +2240,7 @@ std::optional<PSBTError> CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bo
}
}

RemoveUnnecessaryTransactions(psbtx, sighash_type);
RemoveUnnecessaryTransactions(psbtx);

// Complete if every input is now signed
complete = true;
Expand Down

0 comments on commit a14daad

Please sign in to comment.