Merge rust-bitcoin/rust-bitcoin#4637: psbt: check that non-witness UTXOs' txids match the input txid
53b93321c8
psbt: add test vector where non-witness UTXO TXID does not match input txid (Andrew Poelstra)74f22a0a67
psbt: validate that non_witness_utxo txids match the input txids (Andrew Poelstra)3337b7a030
psbt: introduce IncorrectNonWitnessUtxo error variant (Andrew Poelstra) Pull request description: Fixes #4617 ACKs for top commit: tcharding: ACK53b93321c8
Tree-SHA512: bf841708493fe38a37c7448cc02a26061ea66fd3c7acdbf9df4bbdfe07d8611075dceed20813de2b7cd63864ad80a9f66eaf8b869249c3a2028e1be25b48c5ae
This commit is contained in:
commit
2c18ec2c9f
|
@ -80,6 +80,16 @@ pub enum Error {
|
||||||
NegativeFee,
|
NegativeFee,
|
||||||
/// Integer overflow in fee calculation
|
/// Integer overflow in fee calculation
|
||||||
FeeOverflow,
|
FeeOverflow,
|
||||||
|
/// Non-witness UTXO (which is a complete transaction) has [`crate::Txid`] that
|
||||||
|
/// does not match the transaction input.
|
||||||
|
IncorrectNonWitnessUtxo {
|
||||||
|
/// The index of the input in question.
|
||||||
|
index: usize,
|
||||||
|
/// The outpoint of the input, as it appears in the unsigned transaction.
|
||||||
|
input_outpoint: crate::OutPoint,
|
||||||
|
/// The ['crate::Txid`] of the non-witness UTXO.
|
||||||
|
non_witness_utxo_txid: crate::Txid,
|
||||||
|
},
|
||||||
/// Parsing error indicating invalid public keys
|
/// Parsing error indicating invalid public keys
|
||||||
InvalidPublicKey(crate::crypto::key::FromSliceError),
|
InvalidPublicKey(crate::crypto::key::FromSliceError),
|
||||||
/// Parsing error indicating invalid secp256k1 public keys
|
/// Parsing error indicating invalid secp256k1 public keys
|
||||||
|
@ -154,6 +164,13 @@ impl fmt::Display for Error {
|
||||||
write_err!(f, "error parsing bitcoin consensus encoded object"; e),
|
write_err!(f, "error parsing bitcoin consensus encoded object"; e),
|
||||||
NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
|
NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
|
||||||
FeeOverflow => f.write_str("integer overflow in fee calculation"),
|
FeeOverflow => f.write_str("integer overflow in fee calculation"),
|
||||||
|
IncorrectNonWitnessUtxo { index, input_outpoint, non_witness_utxo_txid } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"non-witness utxo txid is {}, which does not match input {}'s outpoint {}",
|
||||||
|
non_witness_utxo_txid, index, input_outpoint
|
||||||
|
)
|
||||||
|
}
|
||||||
InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
|
InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
|
||||||
InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e),
|
InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e),
|
||||||
InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"),
|
InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"),
|
||||||
|
@ -200,6 +217,7 @@ impl std::error::Error for Error {
|
||||||
| CombineInconsistentKeySources(_)
|
| CombineInconsistentKeySources(_)
|
||||||
| NegativeFee
|
| NegativeFee
|
||||||
| FeeOverflow
|
| FeeOverflow
|
||||||
|
| IncorrectNonWitnessUtxo { .. }
|
||||||
| InvalidPublicKey(_)
|
| InvalidPublicKey(_)
|
||||||
| InvalidSecp256k1PublicKey(_)
|
| InvalidSecp256k1PublicKey(_)
|
||||||
| InvalidXOnlyPublicKey
|
| InvalidXOnlyPublicKey
|
||||||
|
|
|
@ -1666,6 +1666,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
unsigned_tx: {
|
unsigned_tx: {
|
||||||
let mut unsigned = tx.clone();
|
let mut unsigned = tx.clone();
|
||||||
|
unsigned.input[0].previous_output.txid = tx.compute_txid();
|
||||||
unsigned.input[0].script_sig = ScriptBuf::new();
|
unsigned.input[0].script_sig = ScriptBuf::new();
|
||||||
unsigned.input[0].witness = Witness::default();
|
unsigned.input[0].witness = Witness::default();
|
||||||
unsigned
|
unsigned
|
||||||
|
@ -2111,6 +2112,28 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_vector_4617() {
|
||||||
|
let err = hex_psbt("70736274ff01007374ff0103010000000000000000002e2873007374ff0107736205000000000000000000000000000000000006060005feffffff74ff01000a000000000000002cc760008530b38dac0100030500000074ff01070100000000000000000000000000c0316888e006000600050000736274ff00d90001007374ff41030100000000000a0a06002e2873007374ff01070100000000000000000000000000000000ff0000060600050000736274ff01000a0080000000000024c7600005193b1e400700030500000074ff0107010000000000a9c7df3f07000570ed62c76004c3ca95c5f90200010742420a0a000000000000").unwrap_err();
|
||||||
|
match err {
|
||||||
|
Error::IncorrectNonWitnessUtxo { index: 0, input_outpoint, non_witness_utxo_txid } => {
|
||||||
|
assert_eq!(
|
||||||
|
input_outpoint,
|
||||||
|
"00000000000000000000000562730701ff74730073282e000000000000000000:0"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
non_witness_utxo_txid,
|
||||||
|
"9ed45fd3f73b038649bee6e763dbd70868745c48a0d2b0299f42c68f957995f4"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => panic!("expected output hash mismatch error, got {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_and_deserialize_preimage_psbt() {
|
fn serialize_and_deserialize_preimage_psbt() {
|
||||||
// create a sha preimage map
|
// create a sha preimage map
|
||||||
|
|
|
@ -103,8 +103,20 @@ impl Psbt {
|
||||||
|
|
||||||
let mut inputs: Vec<Input> = Vec::with_capacity(inputs_len);
|
let mut inputs: Vec<Input> = Vec::with_capacity(inputs_len);
|
||||||
|
|
||||||
for _ in 0..inputs_len {
|
for i in 0..inputs_len {
|
||||||
inputs.push(Input::decode(r)?);
|
let input = Input::decode(r)?;
|
||||||
|
if let Some(ref tx) = input.non_witness_utxo {
|
||||||
|
let input_outpoint = global.unsigned_tx.input[i].previous_output;
|
||||||
|
let txid = tx.compute_txid();
|
||||||
|
if txid != input_outpoint.txid {
|
||||||
|
return Err(Error::IncorrectNonWitnessUtxo {
|
||||||
|
index: i,
|
||||||
|
input_outpoint,
|
||||||
|
non_witness_utxo_txid: txid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inputs.push(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs
|
inputs
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
"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"
|
Binary file not shown.
|
@ -285,6 +285,7 @@ fn serde_regression_psbt() {
|
||||||
},
|
},
|
||||||
unsigned_tx: {
|
unsigned_tx: {
|
||||||
let mut unsigned = tx.clone();
|
let mut unsigned = tx.clone();
|
||||||
|
unsigned.input[0].previous_output.txid = tx.compute_txid();
|
||||||
unsigned.input[0].script_sig = ScriptBuf::new();
|
unsigned.input[0].script_sig = ScriptBuf::new();
|
||||||
unsigned.input[0].witness = Witness::default();
|
unsigned.input[0].witness = Witness::default();
|
||||||
unsigned
|
unsigned
|
||||||
|
|
Loading…
Reference in New Issue