Merge rust-bitcoin/rust-bitcoin#2040: Use weight for block size function

a68c42e113 Remove test from Transaction test names (yancy)
f796d6fef9 Use Weight type for scaled_size (yancy)
e746341f33 Add tests for scaled_size (yancy)
97b7a2dee9 Use Weight type for block base_size (yancy)
9536a9947c Add base_size test (yancy)

Pull request description:

  Use Weight type for `base_size` in Transaction.  Also a small re-factor to remove `test_` and `_tests` from the testname for transaction tests.

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

Tree-SHA512: f4ab54143cbd9b1439912390f1e0857069a32b715477a4bc08692c5e32860a7090c95a92f78b118b17c1295c45a3bbdd209ba1d68c3a934341269235040e6911
This commit is contained in:
Andrew Poelstra 2023-09-06 14:02:42 +00:00
commit f8d7bcfce2
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
2 changed files with 46 additions and 40 deletions

View File

@ -276,14 +276,16 @@ impl Block {
}
/// base_size == size of header + size of encoded transaction count.
fn base_size(&self) -> usize { 80 + VarInt::from(self.txdata.len()).len() }
fn base_size(&self) -> Weight {
Weight::from_wu_usize(80 + VarInt::from(self.txdata.len()).len())
}
/// Returns the size of the block.
///
/// size == size of header + size of encoded transaction count + total size of transactions.
pub fn size(&self) -> usize {
let txs_size: usize = self.txdata.iter().map(Transaction::size).sum();
self.base_size() + txs_size
self.base_size().to_wu() as usize + txs_size
}
/// Returns the stripped size of the block.
@ -296,12 +298,12 @@ impl Block {
/// Returns the stripped size of the block.
pub fn stripped_size(&self) -> Weight {
let txs_size: Weight = self.txdata.iter().map(Transaction::stripped_size).sum();
Weight::from_wu_usize(self.base_size()) + txs_size
self.base_size() + txs_size
}
/// Returns the weight of the block.
pub fn weight(&self) -> Weight {
let base_weight = Weight::from_non_witness_data_size(self.base_size() as u64);
let base_weight = self.base_size() * Weight::WITNESS_SCALE_FACTOR;
let txs_weight: Weight = self.txdata.iter().map(Transaction::weight).sum();
base_weight + txs_weight
}
@ -487,6 +489,7 @@ mod tests {
assert_eq!(real_decode.header.difficulty_float(), 1.0);
// [test] TODO: check the transaction data
assert_eq!(real_decode.base_size(), Weight::from_wu(81));
assert_eq!(real_decode.size(), some_block.len());
assert_eq!(real_decode.stripped_size(), Weight::from_wu_usize(some_block.len()));
assert_eq!(

View File

@ -693,7 +693,7 @@ impl Transaction {
/// Returns the regular byte-wise consensus-serialized size of this transaction.
#[inline]
pub fn size(&self) -> usize { self.scaled_size(1) }
pub fn size(&self) -> usize { self.scaled_size(1).to_wu() as usize }
/// Returns the "virtual size" (vsize) of this transaction.
///
@ -741,39 +741,40 @@ impl Transaction {
}
/// Internal utility function for size/weight functions.
fn scaled_size(&self, scale_factor: usize) -> usize {
let mut input_weight = 0;
fn scaled_size(&self, scale_factor: u64) -> Weight {
let mut input_weight: Weight = Weight::ZERO;
let mut inputs_with_witnesses = 0;
for input in &self.input {
input_weight += scale_factor
* (TxIn::BASE_WEIGHT.to_wu() as usize
+ VarInt(input.script_sig.len() as u64).len()
+ input.script_sig.len());
let non_scaled_input_weight: Weight = TxIn::BASE_WEIGHT
+ Weight::from_wu_usize(VarInt(input.script_sig.len() as u64).len())
+ Weight::from_wu_usize(input.script_sig.len());
input_weight += non_scaled_input_weight * scale_factor;
if !input.witness.is_empty() {
inputs_with_witnesses += 1;
input_weight += input.witness.serialized_len();
input_weight += Weight::from_wu_usize(input.witness.serialized_len());
}
}
let mut output_size = 0;
let mut output_size = Weight::ZERO;
for output in &self.output {
output_size += 8 + // value
VarInt(output.script_pubkey.len() as u64).len() +
output.script_pubkey.len();
output_size += Weight::from_wu(8)+ // value
Weight::from_wu_usize(VarInt(output.script_pubkey.len() as u64).len()) +
Weight::from_wu_usize(output.script_pubkey.len());
}
let non_input_size =
// version:
4 +
Weight::from_wu(4) +
// count varints:
VarInt(self.input.len() as u64).len() +
VarInt(self.output.len() as u64).len() +
Weight::from_wu_usize(VarInt(self.input.len() as u64).len()) +
Weight::from_wu_usize(VarInt(self.output.len() as u64).len()) +
output_size +
// lock_time
4;
Weight::from_wu(4);
if inputs_with_witnesses == 0 {
non_input_size * scale_factor + input_weight
non_input_size.checked_mul(scale_factor).unwrap() + input_weight
} else {
non_input_size * scale_factor + input_weight + self.input.len() - inputs_with_witnesses
+ 2
non_input_size.checked_mul(scale_factor).unwrap()
+ input_weight
+ Weight::from_wu_usize(self.input.len() - inputs_with_witnesses + 2)
}
}
@ -1262,7 +1263,7 @@ mod tests {
}
#[test]
fn test_outpoint() {
fn outpoint() {
assert_eq!(OutPoint::from_str("i don't care"), Err(ParseOutPointError::Format));
assert_eq!(
OutPoint::from_str(
@ -1338,13 +1339,13 @@ mod tests {
}
#[test]
fn test_txin() {
fn txin() {
let txin: Result<TxIn, _> = deserialize(&hex!("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff"));
assert!(txin.is_ok());
}
#[test]
fn test_txin_default() {
fn txin_default() {
let txin = TxIn::default();
assert_eq!(txin.previous_output, OutPoint::default());
assert_eq!(txin.script_sig, ScriptBuf::new());
@ -1354,7 +1355,7 @@ mod tests {
}
#[test]
fn test_is_coinbase() {
fn is_coinbase() {
use crate::blockdata::constants;
use crate::network::Network;
@ -1366,7 +1367,7 @@ mod tests {
}
#[test]
fn test_nonsegwit_transaction() {
fn nonsegwit_transaction() {
let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
let tx: Result<Transaction, _> = deserialize(&tx_bytes);
assert!(tx.is_ok());
@ -1397,10 +1398,11 @@ mod tests {
assert_eq!(realtx.size(), tx_bytes.len());
assert_eq!(realtx.vsize(), tx_bytes.len());
assert_eq!(realtx.stripped_size(), Weight::from_wu_usize(tx_bytes.len()));
assert_eq!(realtx.scaled_size(4), Weight::from_wu(772));
}
#[test]
fn test_segwit_transaction() {
fn segwit_transaction() {
let tx_bytes = hex!(
"02000000000101595895ea20179de87052b4046dfe6fd515860505d6511a9004cf12a1f93cac7c01000000\
00ffffffff01deb807000000000017a9140f3444e271620c736808aa7b33e370bd87cb5a078702483045022\
@ -1457,12 +1459,13 @@ mod tests {
assert_eq!(Weight::from_wu_usize(tx_without_witness.size()), expected_strippedsize);
assert_eq!(Weight::from_wu_usize(tx_without_witness.vsize()), expected_strippedsize);
assert_eq!(tx_without_witness.stripped_size(), expected_strippedsize);
assert_eq!(tx_without_witness.scaled_size(1), Weight::from_wu(83));
}
// We temporarily abuse `Transaction` for testing consensus serde adapter.
#[cfg(feature = "serde")]
#[test]
fn test_consensus_serde() {
fn consensus_serde() {
use crate::consensus::serde as con_serde;
let json = "\"010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000\"";
let mut deserializer = serde_json::Deserializer::from_str(json);
@ -1479,7 +1482,7 @@ mod tests {
}
#[test]
fn test_transaction_version() {
fn transaction_version() {
let tx_bytes = hex!("ffffff7f0100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000");
let tx: Result<Transaction, _> = deserialize(&tx_bytes);
assert!(tx.is_ok());
@ -1508,7 +1511,7 @@ mod tests {
}
#[test]
fn test_ntxid() {
fn ntxid() {
let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
let mut tx: Transaction = deserialize(&tx_bytes).unwrap();
@ -1526,7 +1529,7 @@ mod tests {
}
#[test]
fn test_txid() {
fn txid() {
// segwit tx from Liquid integration tests, txid/hash from Core decoderawtransaction
let tx_bytes = hex!(
"01000000000102ff34f95a672bb6a4f6ff4a7e90fa8c7b3be7e70ffc39bc99be3bda67942e836c00000000\
@ -1593,7 +1596,7 @@ mod tests {
#[test]
#[cfg(feature = "serde")]
fn test_txn_encode_decode() {
fn txn_encode_decode() {
let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
let tx: Transaction = deserialize(&tx_bytes).unwrap();
serde_round_trip!(tx);
@ -1603,7 +1606,7 @@ mod tests {
// from testnet, which is the first BIP144-encoded transaction I encountered.
#[test]
#[cfg(feature = "serde")]
fn test_segwit_tx_decode() {
fn segwit_tx_decode() {
let tx_bytes = hex!("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000");
let tx: Transaction = deserialize(&tx_bytes).unwrap();
assert_eq!(tx.weight(), Weight::from_wu(780));
@ -1614,7 +1617,7 @@ mod tests {
}
#[test]
fn test_sighashtype_fromstr_display() {
fn sighashtype_fromstr_display() {
let sighashtypes = vec![
("SIGHASH_ALL", EcdsaSighashType::All),
("SIGHASH_NONE", EcdsaSighashType::None),
@ -1648,14 +1651,14 @@ mod tests {
}
#[test]
fn test_huge_witness() {
fn huge_witness() {
deserialize::<Transaction>(&hex!(include_str!("../../tests/data/huge_witness.hex").trim()))
.unwrap();
}
#[test]
#[cfg(feature = "bitcoinconsensus")]
fn test_transaction_verify() {
fn transaction_verify() {
use std::collections::HashMap;
use crate::blockdata::witness::Witness;
@ -1720,7 +1723,7 @@ mod tests {
}
#[test]
fn sequence_number_tests() {
fn sequence_number() {
let seq_final = Sequence::from_consensus(0xFFFFFFFF);
let seq_non_rbf = Sequence::from_consensus(0xFFFFFFFE);
let block_time_lock = Sequence::from_consensus(0xFFFF);
@ -1760,7 +1763,7 @@ mod tests {
}
#[test]
fn txin_txout_weight_tests() {
fn txin_txout_weight() {
// [(is_segwit, tx_hex, expected_weight)]
let txs = [
// one segwit input (P2WPKH)