From 9881861228d964a47471007f0a43356014a144f8 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Tue, 18 Jun 2024 21:06:39 +0100 Subject: [PATCH] Add `zcash_encoding::{CompactSize, Vector}::serialized_size` and `zcash_primitives::legacy::Script::serialized_size`. Use the latter in `zcash_primitives::transaction::fees::transparent::OutputView::serialized_size`. Signed-off-by: Daira-Emma Hopwood --- components/zcash_encoding/CHANGELOG.md | 3 +++ components/zcash_encoding/src/lib.rs | 25 ++++++++++++++++++- zcash_primitives/CHANGELOG.md | 5 ++++ zcash_primitives/src/legacy.rs | 5 ++++ .../src/transaction/fees/transparent.rs | 9 +++---- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/components/zcash_encoding/CHANGELOG.md b/components/zcash_encoding/CHANGELOG.md index da71b50f7..7b5976256 100644 --- a/components/zcash_encoding/CHANGELOG.md +++ b/components/zcash_encoding/CHANGELOG.md @@ -6,6 +6,9 @@ and this library adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `zcash_encoding::CompactSize::serialized_size` +- `zcash_encoding::Vector::serialized_size` ## [0.2.0] - 2022-10-19 ### Changed diff --git a/components/zcash_encoding/src/lib.rs b/components/zcash_encoding/src/lib.rs index 8e23f7b68..c90751449 100644 --- a/components/zcash_encoding/src/lib.rs +++ b/components/zcash_encoding/src/lib.rs @@ -93,6 +93,16 @@ impl CompactSize { } } } + + /// Returns the number of bytes needed to encode the given size in compact form. + pub fn serialized_size(size: usize) -> usize { + match size { + s if s < 253 => 1, + s if s <= 0xFFFF => 3, + s if s <= 0xFFFFFFFF => 5, + _ => 9, + } + } } /// Namespace for functions that perform encoding of vectors. @@ -171,6 +181,12 @@ impl Vector { CompactSize::write(&mut writer, items.len())?; items.try_for_each(|e| func(&mut writer, e)) } + + /// Returns the serialized size of a vector of `u8` as written by `[Vector::write]`. + pub fn serialized_size(vec: &[u8]) -> usize { + let length = vec.len(); + CompactSize::serialized_size(length) + length + } } /// Namespace for functions that perform encoding of array contents. @@ -279,8 +295,11 @@ mod tests { >::Error: Debug, { let mut data = vec![]; - CompactSize::write(&mut data, value.try_into().unwrap()).unwrap(); + let value_usize: usize = value.try_into().unwrap(); + CompactSize::write(&mut data, value_usize).unwrap(); assert_eq!(&data[..], expected); + let serialized_size = CompactSize::serialized_size(value_usize); + assert_eq!(serialized_size, expected.len()); let result: io::Result = CompactSize::read_t(&data[..]); match result { Ok(n) => assert_eq!(n, value), @@ -308,6 +327,8 @@ mod tests { let mut data = vec![]; CompactSize::write(&mut data, value).unwrap(); assert_eq!(&data[..], encoded); + let serialized_size = CompactSize::serialized_size(value); + assert_eq!(serialized_size, encoded.len()); assert!(CompactSize::read(encoded).is_err()); } } @@ -320,6 +341,8 @@ mod tests { let mut data = vec![]; Vector::write(&mut data, &$value, |w, e| w.write_u8(*e)).unwrap(); assert_eq!(&data[..], &$expected[..]); + let serialized_size = Vector::serialized_size(&$value); + assert_eq!(serialized_size, $expected.len()); match Vector::read(&data[..], |r| r.read_u8()) { Ok(v) => assert_eq!(v, $value), Err(e) => panic!("Unexpected error: {:?}", e), diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index fd28de023..9e2d78a6f 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -11,6 +11,11 @@ and this library adheres to Rust's notion of - `impl From for bip32::ChildNumber` - `impl From for bip32::ChildNumber` - `impl TryFrom for NonHardenedChildIndex` +- `zcash_primitives::legacy::Script::serialized_size` +- `zcash_primitives::transaction::fees::transparent`: + - `InputSize` + - `InputView::serialized_size` + - `OutputView::serialized_size` ### Changed - MSRV is now 1.70.0. diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index 398d9ab97..6992001d8 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -322,6 +322,11 @@ impl Script { Vector::write(&mut writer, &self.0, |w, e| w.write_u8(*e)) } + /// Returns the length of this script as encoded (including the initial CompactSize). + pub fn serialized_size(&self) -> usize { + Vector::serialized_size(&self.0) + } + /// Returns the address that this Script contains, if any. pub(crate) fn address(&self) -> Option { if self.0.len() == 25 diff --git a/zcash_primitives/src/transaction/fees/transparent.rs b/zcash_primitives/src/transaction/fees/transparent.rs index 188af54ff..beea5795c 100644 --- a/zcash_primitives/src/transaction/fees/transparent.rs +++ b/zcash_primitives/src/transaction/fees/transparent.rs @@ -77,12 +77,9 @@ pub trait OutputView: std::fmt::Debug { /// Returns the serialized size of the txout. fn serialized_size(&self) -> usize { - let mut buf: Vec = vec![]; - self.script_pubkey() - .write(&mut buf) - .expect("script does not exceed available memory"); - // The length of a transparent TxOut is the length of an amount plus the length of the serialized script pubkey. - 8 + buf.len() + // The serialized size of a transparent `TxOut` is the serialized size of an amount + // plus the serialized size of the script pubkey. + 8 + self.script_pubkey().serialized_size() } }