Merge rust-bitcoin/rust-bitcoin#2024: Add VarInt from implementations by way of macro

0419fa278b Add VarInt from implementations by way of macro (Tobin C. Harding)

Pull request description:

  Throughout the codebase we cast values to `u64` when constructing a `VarInt`. We can make the code marginally cleaner by adding `From<T>` impls for all unsigned integer types less than or equal to 64 bits. Also allows us to (possibly unnecessarily) comment the cast in a single place.

ACKs for top commit:
  sanket1729:
    utACK 0419fa278b
  apoelstra:
    ACK 0419fa278b

Tree-SHA512: 0cbcc7e9ec6a1a102693cb13685c348672fb13b098cbecd0a36bed0331165adb008f149f87f7b0c64f131974cfe513adbc12f508bc4853906adb2a65c0c647ee
This commit is contained in:
Andrew Poelstra 2023-08-24 15:35:12 +00:00
commit 407dec0bce
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
12 changed files with 36 additions and 23 deletions

View File

@ -74,7 +74,7 @@ impl convert::AsRef<Transaction> for PrefilledTransaction {
impl Encodable for PrefilledTransaction {
#[inline]
fn consensus_encode<S: io::Write + ?Sized>(&self, mut s: &mut S) -> Result<usize, io::Error> {
Ok(VarInt(self.idx as u64).consensus_encode(&mut s)? + self.tx.consensus_encode(&mut s)?)
Ok(VarInt::from(self.idx).consensus_encode(&mut s)? + self.tx.consensus_encode(&mut s)?)
}
}

View File

@ -391,7 +391,7 @@ impl<'a, W: io::Write> GcsFilterWriter<'a, W> {
mapped.sort_unstable();
// write number of elements as varint
let mut wrote = VarInt(mapped.len() as u64).consensus_encode(&mut self.writer)?;
let mut wrote = VarInt::from(mapped.len()).consensus_encode(&mut self.writer)?;
// write out deltas of sorted values into a Golonb-Rice coded bit stream
let mut writer = BitStreamWriter::new(self.writer);

View File

@ -276,7 +276,7 @@ impl Block {
}
/// base_size == size of header + size of encoded transaction count.
fn base_size(&self) -> usize { 80 + VarInt(self.txdata.len() as u64).len() }
fn base_size(&self) -> usize { 80 + VarInt::from(self.txdata.len()).len() }
/// Returns the size of the block.
///

View File

@ -227,7 +227,7 @@ impl TxIn {
// Size in vbytes:
// previous_output (36) + script_sig varint len + script_sig push + sequence (4)
Weight::from_non_witness_data_size(
(36 + VarInt(script_sig_size as u64).len() + script_sig_size + 4) as u64,
(36 + VarInt::from(script_sig_size).len() + script_sig_size + 4) as u64,
)
}
@ -501,9 +501,7 @@ impl TxOut {
let script_len = self.script_pubkey.len();
// In vbytes:
// value (8) + script varint len + script push
Weight::from_non_witness_data_size(
(8 + VarInt(script_len as u64).len() + script_len) as u64,
)
Weight::from_non_witness_data_size((8 + VarInt::from(script_len).len() + script_len) as u64)
}
/// Creates a `TxOut` with given script and the smallest possible `value` that is **not** dust

View File

@ -213,7 +213,7 @@ fn resize_if_needed(vec: &mut Vec<u8>, required_len: usize) {
impl Encodable for Witness {
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
let len = VarInt(self.witness_elements as u64);
let len = VarInt::from(self.witness_elements);
len.consensus_encode(w)?;
let content_with_indices_len = self.content.len();
let indices_size = self.witness_elements * 4;
@ -233,14 +233,14 @@ impl Witness {
let index_size = witness_elements * 4;
let content_size = slice
.iter()
.map(|elem| elem.as_ref().len() + VarInt(elem.as_ref().len() as u64).len())
.map(|elem| elem.as_ref().len() + VarInt::from(elem.as_ref().len()).len())
.sum();
let mut content = vec![0u8; content_size + index_size];
let mut cursor = 0usize;
for (i, elem) in slice.iter().enumerate() {
encode_cursor(&mut content, content_size, i, cursor);
let elem_len_varint = VarInt(elem.as_ref().len() as u64);
let elem_len_varint = VarInt::from(elem.as_ref().len());
elem_len_varint
.consensus_encode(&mut &mut content[cursor..cursor + elem_len_varint.len()])
.expect("writers on vec don't errors, space granted by content_size");
@ -268,8 +268,8 @@ impl Witness {
/// Returns the bytes required when this Witness is consensus encoded.
pub fn serialized_len(&self) -> usize {
self.iter().map(|el| VarInt(el.len() as u64).len() + el.len()).sum::<usize>()
+ VarInt(self.witness_elements as u64).len()
self.iter().map(|el| VarInt::from(el.len()).len() + el.len()).sum::<usize>()
+ VarInt::from(self.witness_elements).len()
}
/// Clear the witness.
@ -288,7 +288,7 @@ impl Witness {
fn push_slice(&mut self, new_element: &[u8]) {
self.witness_elements += 1;
let previous_content_end = self.indices_start;
let element_len_varint = VarInt(new_element.len() as u64);
let element_len_varint = VarInt::from(new_element.len());
let current_content_len = self.content.len();
let new_item_total_len = element_len_varint.len() + new_element.len();
self.content.resize(current_content_len + new_item_total_len + 4, 0);

View File

@ -399,6 +399,21 @@ impl VarInt {
}
}
/// Implements `From<T> for VarInt`.
///
/// `VarInt`s are consensus encoded as `u64`s so we store them as such. Casting from any integer size smaller than or equal to `u64` is always safe and the cast value is correctly handled by `consensus_encode`.
macro_rules! impl_var_int_from {
($($ty:tt),*) => {
$(
/// Creates a `VarInt` from a `usize` by casting the to a `u64`.
impl From<$ty> for VarInt {
fn from(x: $ty) -> Self { VarInt(x as u64) }
}
)*
}
}
impl_var_int_from!(u8, u16, u32, u64, usize);
impl Encodable for VarInt {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
@ -436,7 +451,7 @@ impl Decodable for VarInt {
if x < 0x100000000 {
Err(self::Error::NonMinimalVarInt)
} else {
Ok(VarInt(x))
Ok(VarInt::from(x))
}
}
0xFE => {
@ -444,7 +459,7 @@ impl Decodable for VarInt {
if x < 0x10000 {
Err(self::Error::NonMinimalVarInt)
} else {
Ok(VarInt(x as u64))
Ok(VarInt::from(x))
}
}
0xFD => {
@ -452,10 +467,10 @@ impl Decodable for VarInt {
if x < 0xFD {
Err(self::Error::NonMinimalVarInt)
} else {
Ok(VarInt(x as u64))
Ok(VarInt::from(x))
}
}
n => Ok(VarInt(n as u64)),
n => Ok(VarInt::from(n)),
}
}
}

View File

@ -436,7 +436,7 @@ impl Encodable for PartialMerkleTree {
ret += self.hashes.consensus_encode(w)?;
let nb_bytes_for_bits = (self.bits.len() + 7) / 8;
ret += encode::VarInt(nb_bytes_for_bits as u64).consensus_encode(w)?;
ret += encode::VarInt::from(nb_bytes_for_bits).consensus_encode(w)?;
for chunk in self.bits.chunks(8) {
let mut byte = 0u8;
for (i, bit) in chunk.iter().enumerate() {

View File

@ -148,7 +148,7 @@ impl Encodable for AddrV2 {
bytes: &[u8],
) -> Result<usize, io::Error> {
let len = network.consensus_encode(w)?
+ VarInt(bytes.len() as u64).consensus_encode(w)?
+ VarInt::from(bytes.len()).consensus_encode(w)?
+ bytes.len();
w.emit_slice(bytes)?;
Ok(len)

View File

@ -335,7 +335,7 @@ impl<'a> Encodable for HeaderSerializationWrapper<'a> {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
let mut len = 0;
len += VarInt(self.0.len() as u64).consensus_encode(w)?;
len += VarInt::from(self.0.len()).consensus_encode(w)?;
for header in self.0.iter() {
len += header.consensus_encode(w)?;
len += 0u8.consensus_encode(w)?;

View File

@ -104,7 +104,7 @@ impl Key {
impl Serialize for Key {
fn serialize(&self) -> Vec<u8> {
let mut buf = Vec::new();
VarInt((self.key.len() + 1) as u64)
VarInt::from(self.key.len() + 1)
.consensus_encode(&mut buf)
.expect("in-memory writers don't error");

View File

@ -342,7 +342,7 @@ impl Serialize for TapTree {
let capacity = self
.script_leaves()
.map(|l| {
l.script().len() + VarInt(l.script().len() as u64).len() // script version
l.script().len() + VarInt::from(l.script().len()).len() // script version
+ 1 // merkle branch
+ 1 // leaf version
})

View File

@ -198,7 +198,7 @@ mod message_signing {
pub fn signed_msg_hash(msg: &str) -> sha256d::Hash {
let mut engine = sha256d::Hash::engine();
engine.input(BITCOIN_SIGNED_MSG_PREFIX);
let msg_len = encode::VarInt(msg.len() as u64);
let msg_len = encode::VarInt::from(msg.len());
msg_len.consensus_encode(&mut engine).expect("engines don't error");
engine.input(msg.as_bytes());
sha256d::Hash::from_engine(engine)