Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-write the weight/size API #2076

Merged
merged 3 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions bitcoin/src/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,8 @@ impl Amount {
pub const MIN: Amount = Amount::ZERO;
/// The maximum value of an amount.
pub const MAX: Amount = Amount(u64::MAX);
/// The number of bytes that an amount contributes to the size of a transaction.
pub const SIZE: usize = 8; // Serialized length of a u64.

/// Create an [Amount] with satoshi precision and the given number of satoshis.
pub const fn from_sat(satoshi: u64) -> Amount { Amount(satoshi) }
Expand Down
67 changes: 38 additions & 29 deletions bitcoin/src/blockdata/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ pub struct Header {
impl_consensus_encoding!(Header, version, prev_blockhash, merkle_root, time, bits, nonce);

impl Header {
/// The number of bytes that the block header contributes to the size of a block.
// Serialized length of fields (version, prev_blockhash, merkle_root, time, bits, nonce)
pub const SIZE: usize = 4 + 32 + 32 + 4 + 4 + 4; // 80

/// Returns the block hash.
pub fn block_hash(&self) -> BlockHash {
let mut engine = BlockHash::engine();
Expand Down Expand Up @@ -275,39 +279,45 @@ impl Block {
merkle_tree::calculate_root(hashes).map(|h| h.into())
}

/// base_size == size of header + size of encoded transaction count.
fn base_size(&self) -> Weight {
Weight::from_wu_usize(80 + VarInt::from(self.txdata.len()).len())
/// Returns the weight of the block.
///
/// > Block weight is defined as Base size * 3 + Total size.
pub fn weight(&self) -> Weight {
// This is the exact definition of a weight unit, as defined by BIP-141 (quote above).
let wu = self.base_size() * 3 + self.total_size();
Weight::from_wu_usize(wu)
}

/// Returns the size of the block.
/// Returns the base block size.
///
/// 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().to_wu() as usize + txs_size
}
/// > Base size is the block size in bytes with the original transaction serialization without
/// > any witness-related data, as seen by a non-upgraded node.
fn base_size(&self) -> usize {
let mut size = Header::SIZE;

/// Returns the stripped size of the block.
#[deprecated(
since = "0.31.0",
note = "Truncates on 32-bit machines, Use Block::stripped_size() instead"
)]
pub fn strippedsize(&self) -> usize { Self::stripped_size(self).to_wu() as usize }
size += VarInt::from(self.txdata.len()).size();
size += self.txdata.iter().map(|tx| tx.base_size()).sum::<usize>();

/// 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();
self.base_size() + txs_size
size
}

/// Returns the weight of the block.
pub fn weight(&self) -> Weight {
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
/// Returns the total block size.
///
/// > Total size is the block size in bytes with transactions serialized as described in BIP144,
/// > including base data and witness data.
pub fn total_size(&self) -> usize {
let mut size = Header::SIZE;

size += VarInt::from(self.txdata.len()).size();
size += self.txdata.iter().map(|tx| tx.total_size()).sum::<usize>();

size
}

/// Returns the stripped size of the block.
#[deprecated(since = "0.31.0", note = "use Block::base_size() instead")]
pub fn strippedsize(&self) -> usize { self.base_size() }

/// Returns the coinbase transaction, if one is present.
pub fn coinbase(&self) -> Option<&Transaction> { self.txdata.first() }

Expand Down Expand Up @@ -489,9 +499,8 @@ 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!(real_decode.total_size(), some_block.len());
assert_eq!(real_decode.base_size(), some_block.len());
assert_eq!(
real_decode.weight(),
Weight::from_non_witness_data_size(some_block.len() as u64)
Expand Down Expand Up @@ -532,8 +541,8 @@ mod tests {
assert_eq!(real_decode.header.difficulty_float(), 2456598.4399242126);
// [test] TODO: check the transaction data

assert_eq!(real_decode.size(), segwit_block.len());
assert_eq!(real_decode.stripped_size(), Weight::from_wu(4283));
assert_eq!(real_decode.total_size(), segwit_block.len());
assert_eq!(real_decode.base_size(), 4283);
assert_eq!(real_decode.weight(), Weight::from_wu(17168));

assert!(real_decode.check_witness_commitment());
Expand Down
3 changes: 3 additions & 0 deletions bitcoin/src/blockdata/locktime/absolute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ impl LockTime {
/// transaction with nLocktime==0 is able to be included immediately in any block.
pub const ZERO: LockTime = LockTime::Blocks(Height::ZERO);

/// The number of bytes that the locktime contributes to the size of a transaction.
pub const SIZE: usize = 4; // Serialized length of a u32.

/// Constructs a `LockTime` from an nLockTime value or the argument to OP_CHEKCLOCKTIMEVERIFY.
///
/// # Examples
Expand Down