Merge rust-bitcoin/rust-bitcoin#1926: Refactor transaction weight

f5591d8dee Use weight instead of checked_weight (yancy)
80a4d692c4 Change weight to call predict_weight (yancy)

Pull request description:

  Followup from https://github.com/rust-bitcoin/rust-bitcoin/pull/1835.  Call `predict_weight` from `weight` instead of `scaled_size()` https://github.com/rust-bitcoin/rust-bitcoin/pull/1835#issuecomment-1543687210.  I think we could also deprecate `scaled_size()` and `strippedsize()` in a future refactor.

ACKs for top commit:
  apoelstra:
    ACK f5591d8dee
  tcharding:
    ACK f5591d8dee

Tree-SHA512: 73d719a98bd0e7e1b9b667d4a613db86a97cb16c70201ad039094bd8025e16984e74ea5110a02eedd10604663461682b7fd527023a0b0c7c94989e6f79603997
This commit is contained in:
Andrew Poelstra 2023-06-29 01:05:49 +00:00
commit 83cf389a02
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
1 changed files with 12 additions and 22 deletions

View File

@ -19,7 +19,6 @@ use hashes::{self, sha256d, Hash};
use internals::write_err; use internals::write_err;
use super::Weight; use super::Weight;
use crate::blockdata::constants::WITNESS_SCALE_FACTOR;
use crate::blockdata::locktime::absolute::{self, Height, Time}; use crate::blockdata::locktime::absolute::{self, Height, Time};
use crate::blockdata::locktime::relative; use crate::blockdata::locktime::relative;
#[cfg(feature = "bitcoinconsensus")] #[cfg(feature = "bitcoinconsensus")]
@ -838,17 +837,6 @@ impl Transaction {
/// and can therefore avoid this ambiguity. /// and can therefore avoid this ambiguity.
#[inline] #[inline]
pub fn weight(&self) -> Weight { pub fn weight(&self) -> Weight {
Weight::from_wu(self.scaled_size(WITNESS_SCALE_FACTOR) as u64)
}
/// Returns the regular byte-wise consensus-serialized size of this transaction.
#[inline]
pub fn size(&self) -> usize { self.scaled_size(1) }
/// Computes the weight and checks that it matches the output of `predict_weight`.
#[cfg(test)]
fn check_weight(&self) -> Weight {
let weight1 = self.weight();
let inputs = self.input.iter().map(|txin| { let inputs = self.input.iter().map(|txin| {
InputWeightPrediction::new( InputWeightPrediction::new(
txin.script_sig.len(), txin.script_sig.len(),
@ -856,11 +844,13 @@ impl Transaction {
) )
}); });
let outputs = self.output.iter().map(|txout| txout.script_pubkey.len()); let outputs = self.output.iter().map(|txout| txout.script_pubkey.len());
let weight2 = predict_weight(inputs, outputs); predict_weight(inputs, outputs)
assert_eq!(weight1, weight2);
weight1
} }
/// Returns the regular byte-wise consensus-serialized size of this transaction.
#[inline]
pub fn size(&self) -> usize { self.scaled_size(1) }
/// Returns the "virtual size" (vsize) of this transaction. /// Returns the "virtual size" (vsize) of this transaction.
/// ///
/// Will be `ceil(weight / 4.0)`. Note this implements the virtual size as per [`BIP141`], which /// Will be `ceil(weight / 4.0)`. Note this implements the virtual size as per [`BIP141`], which
@ -1585,7 +1575,7 @@ mod tests {
format!("{:x}", realtx.wtxid()), format!("{:x}", realtx.wtxid()),
"a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string() "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()
); );
assert_eq!(realtx.check_weight().to_wu() as usize, tx_bytes.len() * WITNESS_SCALE_FACTOR); assert_eq!(realtx.weight().to_wu() as usize, tx_bytes.len() * WITNESS_SCALE_FACTOR);
assert_eq!(realtx.size(), tx_bytes.len()); assert_eq!(realtx.size(), tx_bytes.len());
assert_eq!(realtx.vsize(), tx_bytes.len()); assert_eq!(realtx.vsize(), tx_bytes.len());
assert_eq!(realtx.strippedsize(), tx_bytes.len()); assert_eq!(realtx.strippedsize(), tx_bytes.len());
@ -1626,7 +1616,7 @@ mod tests {
"80b7d8a82d5d5bf92905b06f2014dd699e03837ca172e3a59d51426ebbe3e7f5".to_string() "80b7d8a82d5d5bf92905b06f2014dd699e03837ca172e3a59d51426ebbe3e7f5".to_string()
); );
const EXPECTED_WEIGHT: Weight = Weight::from_wu(442); const EXPECTED_WEIGHT: Weight = Weight::from_wu(442);
assert_eq!(realtx.check_weight(), EXPECTED_WEIGHT); assert_eq!(realtx.weight(), EXPECTED_WEIGHT);
assert_eq!(realtx.size(), tx_bytes.len()); assert_eq!(realtx.size(), tx_bytes.len());
assert_eq!(realtx.vsize(), 111); assert_eq!(realtx.vsize(), 111);
// Since // Since
@ -1641,7 +1631,7 @@ mod tests {
let mut tx_without_witness = realtx; let mut tx_without_witness = realtx;
tx_without_witness.input.iter_mut().for_each(|input| input.witness.clear()); tx_without_witness.input.iter_mut().for_each(|input| input.witness.clear());
assert_eq!( assert_eq!(
tx_without_witness.check_weight().to_wu() as usize, tx_without_witness.weight().to_wu() as usize,
expected_strippedsize * WITNESS_SCALE_FACTOR expected_strippedsize * WITNESS_SCALE_FACTOR
); );
assert_eq!(tx_without_witness.size(), expected_strippedsize); assert_eq!(tx_without_witness.size(), expected_strippedsize);
@ -1758,7 +1748,7 @@ mod tests {
format!("{:x}", tx.txid()), format!("{:x}", tx.txid()),
"9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec" "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec"
); );
assert_eq!(tx.check_weight(), Weight::from_wu(2718)); assert_eq!(tx.weight(), Weight::from_wu(2718));
// non-segwit tx from my mempool // non-segwit tx from my mempool
let tx_bytes = hex!( let tx_bytes = hex!(
@ -1796,7 +1786,7 @@ mod tests {
fn test_segwit_tx_decode() { fn test_segwit_tx_decode() {
let tx_bytes = hex!("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000"); let tx_bytes = hex!("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000");
let tx: Transaction = deserialize(&tx_bytes).unwrap(); let tx: Transaction = deserialize(&tx_bytes).unwrap();
assert_eq!(tx.check_weight(), Weight::from_wu(780)); assert_eq!(tx.weight(), Weight::from_wu(780));
serde_round_trip!(tx); serde_round_trip!(tx);
let consensus_encoded = serialize(&tx); let consensus_encoded = serialize(&tx);
@ -1974,7 +1964,7 @@ mod tests {
input: vec![], input: vec![],
output: vec![], output: vec![],
} }
.check_weight(); .weight();
for (is_segwit, tx, expected_wu) in &txs { for (is_segwit, tx, expected_wu) in &txs {
let txin_weight = if *is_segwit { TxIn::segwit_weight } else { TxIn::legacy_weight }; let txin_weight = if *is_segwit { TxIn::segwit_weight } else { TxIn::legacy_weight };
@ -1986,7 +1976,7 @@ mod tests {
+ segwit_marker_weight + segwit_marker_weight
+ tx.input.iter().fold(0, |sum, i| sum + txin_weight(i)) + tx.input.iter().fold(0, |sum, i| sum + txin_weight(i))
+ tx.output.iter().fold(0, |sum, o| sum + o.weight()); + tx.output.iter().fold(0, |sum, o| sum + o.weight());
assert_eq!(calculated_size, tx.check_weight().to_wu() as usize); assert_eq!(calculated_size, tx.weight().to_wu() as usize);
assert_eq!(tx.weight().to_wu(), *expected_wu); assert_eq!(tx.weight().to_wu(), *expected_wu);
} }