Merge rust-bitcoin/rust-bitcoin#2931: Remove `VarInt` and use `ReadExt` and `WriteExt` trait methods instead
18d8b0e469
Replace VarInt type with ReadExt and WriteExt functions (Steven Roose)003db025c1
Return encoded length from WriteExt::emit_slice (Steven Roose) Pull request description: This the meat and potatoes out of Steven's work in #2133 and also closes #1016 ACKs for top commit: apoelstra: ACK18d8b0e469
successfully ran local tests Tree-SHA512: 2df96c91e0fbfdc87158bde9bbdd9565f67e3f66601697d0e22341416c0cd45dd69d09637393993f350354a44031bead99fd0d2f006b4fc6e7613aedc4b0a832
This commit is contained in:
commit
dfa8692169
|
@ -12,7 +12,7 @@ use hashes::{sha256, siphash24};
|
|||
use internals::{impl_array_newtype, ToU64 as _};
|
||||
use io::{BufRead, Write};
|
||||
|
||||
use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
|
||||
use crate::consensus::encode::{self, Decodable, Encodable, WriteExt, ReadExt};
|
||||
use crate::internal_macros::{impl_array_newtype_stringify, impl_consensus_encoding};
|
||||
use crate::prelude::Vec;
|
||||
use crate::transaction::TxIdentifier;
|
||||
|
@ -76,14 +76,14 @@ impl convert::AsRef<Transaction> for PrefilledTransaction {
|
|||
impl Encodable for PrefilledTransaction {
|
||||
#[inline]
|
||||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
Ok(VarInt::from(self.idx).consensus_encode(w)? + self.tx.consensus_encode(w)?)
|
||||
Ok(w.emit_compact_size(self.idx)? + self.tx.consensus_encode(w)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for PrefilledTransaction {
|
||||
#[inline]
|
||||
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||
let idx = VarInt::consensus_decode(r)?.0;
|
||||
let idx = r.read_compact_size()?;
|
||||
let idx = u16::try_from(idx)
|
||||
.map_err(|_| encode::Error::ParseFailed("BIP152 prefilled tx index out of bounds"))?;
|
||||
let tx = Transaction::consensus_decode(r)?;
|
||||
|
@ -289,10 +289,10 @@ impl Encodable for BlockTransactionsRequest {
|
|||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
let mut len = self.block_hash.consensus_encode(w)?;
|
||||
// Manually encode indexes because they are differentially encoded VarInts.
|
||||
len += VarInt(self.indexes.len().to_u64()).consensus_encode(w)?;
|
||||
len += w.emit_compact_size(self.indexes.len())?;
|
||||
let mut last_idx = 0;
|
||||
for idx in &self.indexes {
|
||||
len += VarInt(*idx - last_idx).consensus_encode(w)?;
|
||||
len += w.emit_compact_size(*idx - last_idx)?;
|
||||
last_idx = *idx + 1; // can panic here
|
||||
}
|
||||
Ok(len)
|
||||
|
@ -305,12 +305,12 @@ impl Decodable for BlockTransactionsRequest {
|
|||
block_hash: BlockHash::consensus_decode(r)?,
|
||||
indexes: {
|
||||
// Manually decode indexes because they are differentially encoded VarInts.
|
||||
let nb_indexes = VarInt::consensus_decode(r)?.0 as usize;
|
||||
let nb_indexes = r.read_compact_size()? as usize;
|
||||
|
||||
// Since the number of indices ultimately represent transactions,
|
||||
// we can limit the number of indices to the maximum number of
|
||||
// transactions that would be allowed in a vector.
|
||||
let byte_size = (nb_indexes)
|
||||
let byte_size = nb_indexes
|
||||
.checked_mul(mem::size_of::<Transaction>())
|
||||
.ok_or(encode::Error::ParseFailed("invalid length"))?;
|
||||
if byte_size > encode::MAX_VEC_SIZE {
|
||||
|
@ -323,8 +323,8 @@ impl Decodable for BlockTransactionsRequest {
|
|||
let mut indexes = Vec::with_capacity(nb_indexes);
|
||||
let mut last_index: u64 = 0;
|
||||
for _ in 0..nb_indexes {
|
||||
let differential: VarInt = Decodable::consensus_decode(r)?;
|
||||
last_index = match last_index.checked_add(differential.0) {
|
||||
let differential = r.read_compact_size()?;
|
||||
last_index = match last_index.checked_add(differential) {
|
||||
Some(i) => i,
|
||||
None => return Err(encode::Error::ParseFailed("block index overflow")),
|
||||
};
|
||||
|
|
|
@ -45,8 +45,7 @@ use internals::{write_err, ToU64 as _};
|
|||
use io::{BufRead, Write};
|
||||
|
||||
use crate::block::{Block, BlockHash};
|
||||
use crate::consensus::encode::VarInt;
|
||||
use crate::consensus::{Decodable, Encodable};
|
||||
use crate::consensus::{ReadExt, WriteExt};
|
||||
use crate::internal_macros::impl_hashencode;
|
||||
use crate::prelude::{BTreeSet, Borrow, Vec};
|
||||
use crate::script::{Script, ScriptExt as _};
|
||||
|
@ -286,9 +285,9 @@ impl GcsFilterReader {
|
|||
I::Item: Borrow<[u8]>,
|
||||
R: BufRead + ?Sized,
|
||||
{
|
||||
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
|
||||
let n_elements = reader.read_compact_size().unwrap_or(0);
|
||||
// map hashes to [0, n_elements << grp]
|
||||
let nm = n_elements.0 * self.m;
|
||||
let nm = n_elements * self.m;
|
||||
let mut mapped =
|
||||
query.map(|e| map_to_range(self.filter.hash(e.borrow()), nm)).collect::<Vec<_>>();
|
||||
// sort
|
||||
|
@ -296,14 +295,14 @@ impl GcsFilterReader {
|
|||
if mapped.is_empty() {
|
||||
return Ok(true);
|
||||
}
|
||||
if n_elements.0 == 0 {
|
||||
if n_elements == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// find first match in two sorted arrays in one read pass
|
||||
let mut reader = BitStreamReader::new(reader);
|
||||
let mut data = self.filter.golomb_rice_decode(&mut reader)?;
|
||||
let mut remaining = n_elements.0 - 1;
|
||||
let mut remaining = n_elements - 1;
|
||||
for p in mapped {
|
||||
loop {
|
||||
match data.cmp(&p) {
|
||||
|
@ -329,9 +328,9 @@ impl GcsFilterReader {
|
|||
I::Item: Borrow<[u8]>,
|
||||
R: BufRead + ?Sized,
|
||||
{
|
||||
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
|
||||
let n_elements = reader.read_compact_size().unwrap_or(0);
|
||||
// map hashes to [0, n_elements << grp]
|
||||
let nm = n_elements.0 * self.m;
|
||||
let nm = n_elements * self.m;
|
||||
let mut mapped =
|
||||
query.map(|e| map_to_range(self.filter.hash(e.borrow()), nm)).collect::<Vec<_>>();
|
||||
// sort
|
||||
|
@ -340,14 +339,14 @@ impl GcsFilterReader {
|
|||
if mapped.is_empty() {
|
||||
return Ok(true);
|
||||
}
|
||||
if n_elements.0 == 0 {
|
||||
if n_elements == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// figure if all mapped are there in one read pass
|
||||
let mut reader = BitStreamReader::new(reader);
|
||||
let mut data = self.filter.golomb_rice_decode(&mut reader)?;
|
||||
let mut remaining = n_elements.0 - 1;
|
||||
let mut remaining = n_elements - 1;
|
||||
for p in mapped {
|
||||
loop {
|
||||
match data.cmp(&p) {
|
||||
|
@ -404,7 +403,7 @@ impl<'a, W: Write> GcsFilterWriter<'a, W> {
|
|||
mapped.sort_unstable();
|
||||
|
||||
// write number of elements as varint
|
||||
let mut wrote = VarInt::from(mapped.len()).consensus_encode(self.writer)?;
|
||||
let mut wrote = self.writer.emit_compact_size(mapped.len())?;
|
||||
|
||||
// write out deltas of sorted values into a Golomb-Rice coded bit stream
|
||||
let mut writer = BitStreamWriter::new(self.writer);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
use core::fmt;
|
||||
|
||||
use hashes::{sha256d, HashEngine};
|
||||
use internals::compact_size;
|
||||
use io::{BufRead, Write};
|
||||
|
||||
use super::Weight;
|
||||
|
@ -21,7 +22,6 @@ use crate::pow::{CompactTarget, Target, Work};
|
|||
use crate::prelude::Vec;
|
||||
use crate::script::{self, ScriptExt as _};
|
||||
use crate::transaction::{Transaction, Wtxid};
|
||||
use crate::VarInt;
|
||||
|
||||
hashes::hash_newtype! {
|
||||
/// A bitcoin block hash.
|
||||
|
@ -330,7 +330,7 @@ impl Block {
|
|||
fn base_size(&self) -> usize {
|
||||
let mut size = Header::SIZE;
|
||||
|
||||
size += VarInt::from(self.txdata.len()).size();
|
||||
size += compact_size::encoded_size(self.txdata.len());
|
||||
size += self.txdata.iter().map(|tx| tx.base_size()).sum::<usize>();
|
||||
|
||||
size
|
||||
|
@ -343,7 +343,7 @@ impl Block {
|
|||
pub fn total_size(&self) -> usize {
|
||||
let mut size = Header::SIZE;
|
||||
|
||||
size += VarInt::from(self.txdata.len()).size();
|
||||
size += compact_size::encoded_size(self.txdata.len());
|
||||
size += self.txdata.iter().map(|tx| tx.total_size()).sum::<usize>();
|
||||
|
||||
size
|
||||
|
|
|
@ -15,7 +15,7 @@ use core::{cmp, fmt, str};
|
|||
#[cfg(feature = "arbitrary")]
|
||||
use arbitrary::{Arbitrary, Unstructured};
|
||||
use hashes::sha256d;
|
||||
use internals::{write_err, ToU64 as _};
|
||||
use internals::{compact_size, write_err, ToU64};
|
||||
use io::{BufRead, Write};
|
||||
use primitives::Sequence;
|
||||
use units::parse;
|
||||
|
@ -29,7 +29,7 @@ use crate::script::{Script, ScriptBuf, ScriptExt as _, ScriptExtPriv as _};
|
|||
#[cfg(doc)]
|
||||
use crate::sighash::{EcdsaSighashType, TapSighashType};
|
||||
use crate::witness::Witness;
|
||||
use crate::{Amount, FeeRate, SignedAmount, VarInt};
|
||||
use crate::{Amount, FeeRate, SignedAmount};
|
||||
|
||||
#[rustfmt::skip] // Keep public re-exports separate.
|
||||
#[doc(inline)]
|
||||
|
@ -305,7 +305,7 @@ impl TxIn {
|
|||
pub fn base_size(&self) -> usize {
|
||||
let mut size = OutPoint::SIZE;
|
||||
|
||||
size += VarInt::from(self.script_sig.len()).size();
|
||||
size += compact_size::encoded_size(self.script_sig.len());
|
||||
size += self.script_sig.len();
|
||||
|
||||
size + Sequence::SIZE
|
||||
|
@ -407,7 +407,7 @@ impl<'a> Arbitrary<'a> for TxOut {
|
|||
/// Returns the total number of bytes that this script pubkey would contribute to a transaction.
|
||||
fn size_from_script_pubkey(script_pubkey: &Script) -> usize {
|
||||
let len = script_pubkey.len();
|
||||
Amount::SIZE + VarInt::from(len).size() + len
|
||||
Amount::SIZE + compact_size::encoded_size(len) + len
|
||||
}
|
||||
|
||||
/// Bitcoin transaction.
|
||||
|
@ -609,10 +609,10 @@ impl Transaction {
|
|||
pub fn base_size(&self) -> usize {
|
||||
let mut size: usize = 4; // Serialized length of a u32 for the version number.
|
||||
|
||||
size += VarInt::from(self.input.len()).size();
|
||||
size += compact_size::encoded_size(self.input.len());
|
||||
size += self.input.iter().map(|input| input.base_size()).sum::<usize>();
|
||||
|
||||
size += VarInt::from(self.output.len()).size();
|
||||
size += compact_size::encoded_size(self.output.len());
|
||||
size += self.output.iter().map(|output| output.size()).sum::<usize>();
|
||||
|
||||
size + absolute::LockTime::SIZE
|
||||
|
@ -631,14 +631,14 @@ impl Transaction {
|
|||
size += 2; // 1 byte for the marker and 1 for the flag.
|
||||
}
|
||||
|
||||
size += VarInt::from(self.input.len()).size();
|
||||
size += compact_size::encoded_size(self.input.len());
|
||||
size += self
|
||||
.input
|
||||
.iter()
|
||||
.map(|input| if uses_segwit { input.total_size() } else { input.base_size() })
|
||||
.sum::<usize>();
|
||||
|
||||
size += VarInt::from(self.output.len()).size();
|
||||
size += compact_size::encoded_size(self.output.len());
|
||||
size += self.output.iter().map(|output| output.size()).sum::<usize>();
|
||||
|
||||
size + absolute::LockTime::SIZE
|
||||
|
@ -1169,7 +1169,7 @@ where
|
|||
let (output_count, output_scripts_size) = output_script_lens.into_iter().fold(
|
||||
(0, 0),
|
||||
|(output_count, total_scripts_size), script_len| {
|
||||
let script_size = script_len + VarInt(script_len.to_u64()).size();
|
||||
let script_size = script_len + compact_size::encoded_size(script_len);
|
||||
(output_count + 1, total_scripts_size + script_size)
|
||||
},
|
||||
);
|
||||
|
@ -1199,8 +1199,8 @@ const fn predict_weight_internal(
|
|||
// version:
|
||||
4 +
|
||||
// count varints:
|
||||
VarInt(input_count as u64).size() +
|
||||
VarInt(output_count as u64).size() +
|
||||
compact_size::encoded_size_const(input_count as u64) +
|
||||
compact_size::encoded_size_const(output_count as u64) +
|
||||
output_size +
|
||||
// lock_time
|
||||
4;
|
||||
|
@ -1240,7 +1240,7 @@ pub const fn predict_weight_from_slices(
|
|||
i = 0;
|
||||
while i < output_script_lens.len() {
|
||||
let script_len = output_script_lens[i];
|
||||
output_scripts_size += script_len + VarInt(script_len as u64).size();
|
||||
output_scripts_size += script_len + compact_size::encoded_size_const(script_len as u64);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
|
@ -1359,13 +1359,13 @@ impl InputWeightPrediction {
|
|||
T::Item: Borrow<usize>,
|
||||
{
|
||||
let (count, total_size) =
|
||||
witness_element_lengths.into_iter().fold((0, 0), |(count, total_size), elem_len| {
|
||||
witness_element_lengths.into_iter().fold((0usize, 0), |(count, total_size), elem_len| {
|
||||
let elem_len = *elem_len.borrow();
|
||||
let elem_size = elem_len + VarInt(elem_len.to_u64()).size();
|
||||
let elem_size = elem_len + compact_size::encoded_size(elem_len);
|
||||
(count + 1, total_size + elem_size)
|
||||
});
|
||||
let witness_size = if count > 0 { total_size + VarInt(count as u64).size() } else { 0 };
|
||||
let script_size = input_script_len + VarInt(input_script_len.to_u64()).size();
|
||||
let witness_size = if count > 0 { total_size + compact_size::encoded_size(count) } else { 0 };
|
||||
let script_size = input_script_len + compact_size::encoded_size(input_script_len);
|
||||
|
||||
InputWeightPrediction { script_size, witness_size }
|
||||
}
|
||||
|
@ -1381,16 +1381,16 @@ impl InputWeightPrediction {
|
|||
// for loops not supported in const fn
|
||||
while i < witness_element_lengths.len() {
|
||||
let elem_len = witness_element_lengths[i];
|
||||
let elem_size = elem_len + VarInt(elem_len as u64).size();
|
||||
let elem_size = elem_len + compact_size::encoded_size_const(elem_len as u64);
|
||||
total_size += elem_size;
|
||||
i += 1;
|
||||
}
|
||||
let witness_size = if !witness_element_lengths.is_empty() {
|
||||
total_size + VarInt(witness_element_lengths.len() as u64).size()
|
||||
total_size + compact_size::encoded_size_const(witness_element_lengths.len() as u64)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let script_size = input_script_len + VarInt(input_script_len as u64).size();
|
||||
let script_size = input_script_len + compact_size::encoded_size_const(input_script_len as u64);
|
||||
|
||||
InputWeightPrediction { script_size, witness_size }
|
||||
}
|
||||
|
|
|
@ -12,14 +12,14 @@ use arbitrary::{Arbitrary, Unstructured};
|
|||
use internals::compact_size;
|
||||
use io::{BufRead, Write};
|
||||
|
||||
use crate::consensus::encode::{Error, MAX_VEC_SIZE};
|
||||
use crate::consensus::encode::{Error, ReadExt, MAX_VEC_SIZE};
|
||||
use crate::consensus::{Decodable, Encodable, WriteExt};
|
||||
use crate::crypto::ecdsa;
|
||||
use crate::prelude::Vec;
|
||||
#[cfg(doc)]
|
||||
use crate::script::ScriptExt as _;
|
||||
use crate::taproot::{self, TAPROOT_ANNEX_PREFIX};
|
||||
use crate::{Script, VarInt};
|
||||
use crate::Script;
|
||||
|
||||
/// The Witness is the data used to unlock bitcoin since the [segwit upgrade].
|
||||
///
|
||||
|
@ -137,7 +137,7 @@ pub struct Iter<'a> {
|
|||
|
||||
impl Decodable for Witness {
|
||||
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
||||
let witness_elements = VarInt::consensus_decode(r)?.0 as usize;
|
||||
let witness_elements = r.read_compact_size()? as usize;
|
||||
// Minimum size of witness element is 1 byte, so if the count is
|
||||
// greater than MAX_VEC_SIZE we must return an error.
|
||||
if witness_elements > MAX_VEC_SIZE {
|
||||
|
@ -159,16 +159,15 @@ impl Decodable for Witness {
|
|||
let mut content = vec![0u8; cursor + 128];
|
||||
|
||||
for i in 0..witness_elements {
|
||||
let element_size_varint = VarInt::consensus_decode(r)?;
|
||||
let element_size_varint_len = element_size_varint.size();
|
||||
let element_size = element_size_varint.0 as usize;
|
||||
let element_size = r.read_compact_size()? as usize;
|
||||
let element_size_len = compact_size::encoded_size(element_size);
|
||||
let required_len = cursor
|
||||
.checked_add(element_size)
|
||||
.ok_or(self::Error::OversizedVectorAllocation {
|
||||
requested: usize::MAX,
|
||||
max: MAX_VEC_SIZE,
|
||||
})?
|
||||
.checked_add(element_size_varint_len)
|
||||
.checked_add(element_size_len)
|
||||
.ok_or(self::Error::OversizedVectorAllocation {
|
||||
requested: usize::MAX,
|
||||
max: MAX_VEC_SIZE,
|
||||
|
@ -186,10 +185,7 @@ impl Decodable for Witness {
|
|||
encode_cursor(&mut content, 0, i, cursor - witness_index_space);
|
||||
|
||||
resize_if_needed(&mut content, required_len);
|
||||
element_size_varint.consensus_encode(
|
||||
&mut &mut content[cursor..cursor + element_size_varint_len],
|
||||
)?;
|
||||
cursor += element_size_varint_len;
|
||||
cursor += (&mut content[cursor..cursor + element_size_len]).emit_compact_size(element_size)?;
|
||||
r.read_exact(&mut content[cursor..cursor + element_size])?;
|
||||
cursor += element_size;
|
||||
}
|
||||
|
@ -234,13 +230,10 @@ fn resize_if_needed(vec: &mut Vec<u8>, required_len: usize) {
|
|||
impl Encodable for Witness {
|
||||
// `self.content` includes the varints so encoding here includes them, as expected.
|
||||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
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;
|
||||
let content_len = content_with_indices_len - indices_size;
|
||||
w.emit_slice(&self.content[..content_len])?;
|
||||
Ok(content_len + len.size())
|
||||
Ok(w.emit_compact_size(self.witness_elements)? + w.emit_slice(&self.content[..content_len])?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use core::{fmt, mem};
|
|||
|
||||
use hashes::{sha256, sha256d, GeneralHash, Hash};
|
||||
use hex::error::{InvalidCharError, OddLengthStringError};
|
||||
use internals::{write_err, ToU64 as _};
|
||||
use internals::{compact_size, write_err, ToU64};
|
||||
use io::{BufRead, Cursor, Read, Write};
|
||||
|
||||
use crate::bip152::{PrefilledTransaction, ShortId};
|
||||
|
@ -205,11 +205,16 @@ pub trait WriteExt: Write {
|
|||
/// Outputs an 8-bit signed integer.
|
||||
fn emit_i8(&mut self, v: i8) -> Result<(), io::Error>;
|
||||
|
||||
/// Outputs a variable sized integer ([`CompactSize`]).
|
||||
///
|
||||
/// [`CompactSize`]: <https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer>
|
||||
fn emit_compact_size(&mut self, v: impl ToU64) -> Result<usize, io::Error>;
|
||||
|
||||
/// Outputs a boolean.
|
||||
fn emit_bool(&mut self, v: bool) -> Result<(), io::Error>;
|
||||
|
||||
/// Outputs a byte slice.
|
||||
fn emit_slice(&mut self, v: &[u8]) -> Result<(), io::Error>;
|
||||
fn emit_slice(&mut self, v: &[u8]) -> Result<usize, io::Error>;
|
||||
}
|
||||
|
||||
/// Extensions of `Read` to decode data as per Bitcoin consensus.
|
||||
|
@ -232,6 +237,11 @@ pub trait ReadExt: Read {
|
|||
/// Reads an 8-bit signed integer.
|
||||
fn read_i8(&mut self) -> Result<i8, Error>;
|
||||
|
||||
/// Reads a variable sized integer ([`CompactSize`]).
|
||||
///
|
||||
/// [`CompactSize`]: <https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer>
|
||||
fn read_compact_size(&mut self) -> Result<u64, Error>;
|
||||
|
||||
/// Reads a boolean.
|
||||
fn read_bool(&mut self) -> Result<bool, Error>;
|
||||
|
||||
|
@ -274,7 +284,16 @@ impl<W: Write + ?Sized> WriteExt for W {
|
|||
#[inline]
|
||||
fn emit_bool(&mut self, v: bool) -> Result<(), io::Error> { self.write_all(&[v as u8]) }
|
||||
#[inline]
|
||||
fn emit_slice(&mut self, v: &[u8]) -> Result<(), io::Error> { self.write_all(v) }
|
||||
fn emit_slice(&mut self, v: &[u8]) -> Result<usize, io::Error> {
|
||||
self.write_all(v)?;
|
||||
Ok(v.len())
|
||||
}
|
||||
#[inline]
|
||||
fn emit_compact_size(&mut self, v: impl ToU64) -> Result<usize, io::Error> {
|
||||
let encoded = compact_size::encode(v.to_u64());
|
||||
self.emit_slice(&encoded)?;
|
||||
Ok(encoded.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + ?Sized> ReadExt for R {
|
||||
|
@ -303,6 +322,36 @@ impl<R: Read + ?Sized> ReadExt for R {
|
|||
fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error> {
|
||||
self.read_exact(slice).map_err(Error::Io)
|
||||
}
|
||||
#[inline]
|
||||
fn read_compact_size(&mut self) -> Result<u64, Error> {
|
||||
match self.read_u8()? {
|
||||
0xFF => {
|
||||
let x = self.read_u64()?;
|
||||
if x < 0x1_0000_0000 { // I.e., would have fit in a `u32`.
|
||||
Err(Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(x)
|
||||
}
|
||||
}
|
||||
0xFE => {
|
||||
let x = self.read_u32()?;
|
||||
if x < 0x1_0000 { // I.e., would have fit in a `u16`.
|
||||
Err(Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(x as u64)
|
||||
}
|
||||
}
|
||||
0xFD => {
|
||||
let x = self.read_u16()?;
|
||||
if x < 0xFD { // Could have been encoded as a `u8`.
|
||||
Err(Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(x as u64)
|
||||
}
|
||||
}
|
||||
n => Ok(n as u64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximum size, in bytes, of a vector we are allowed to decode.
|
||||
|
@ -373,10 +422,6 @@ pub trait Decodable: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
/// A variable-length unsigned integer.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
|
||||
pub struct VarInt(pub u64);
|
||||
|
||||
/// Data and a 4-byte checksum.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct CheckedData {
|
||||
|
@ -434,96 +479,21 @@ impl_int_encodable!(i16, read_i16, emit_i16);
|
|||
impl_int_encodable!(i32, read_i32, emit_i32);
|
||||
impl_int_encodable!(i64, read_i64, emit_i64);
|
||||
|
||||
#[allow(clippy::len_without_is_empty)] // VarInt has no concept of 'is_empty'.
|
||||
impl VarInt {
|
||||
/// Returns the number of bytes this varint contributes to a transaction size.
|
||||
///
|
||||
/// Returns 1 for 0..=0xFC, 3 for 0xFD..=(2^16-1), 5 for 0x10000..=(2^32-1), and 9 otherwise.
|
||||
#[inline]
|
||||
pub const fn size(&self) -> usize {
|
||||
match self.0 {
|
||||
0..=0xFC => 1,
|
||||
0xFD..=0xFFFF => 3,
|
||||
0x10000..=0xFFFFFFFF => 5,
|
||||
_ => 9,
|
||||
}
|
||||
/// Returns 1 for 0..=0xFC, 3 for 0xFD..=(2^16-1), 5 for 0x10000..=(2^32-1), and 9 otherwise.
|
||||
#[inline]
|
||||
pub const fn varint_size_u64(v: u64) -> usize {
|
||||
match v {
|
||||
0..=0xFC => 1,
|
||||
0xFD..=0xFFFF => 3,
|
||||
0x10000..=0xFFFFFFFF => 5,
|
||||
_ => 9,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.to_u64()) }
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
impl_var_int_from!(u8, u16, u32, u64, usize);
|
||||
|
||||
impl Encodable for VarInt {
|
||||
#[inline]
|
||||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
match self.0 {
|
||||
0..=0xFC => {
|
||||
(self.0 as u8).consensus_encode(w)?;
|
||||
Ok(1)
|
||||
}
|
||||
0xFD..=0xFFFF => {
|
||||
w.emit_u8(0xFD)?;
|
||||
(self.0 as u16).consensus_encode(w)?;
|
||||
Ok(3)
|
||||
}
|
||||
0x10000..=0xFFFFFFFF => {
|
||||
w.emit_u8(0xFE)?;
|
||||
(self.0 as u32).consensus_encode(w)?;
|
||||
Ok(5)
|
||||
}
|
||||
_ => {
|
||||
w.emit_u8(0xFF)?;
|
||||
self.0.consensus_encode(w)?;
|
||||
Ok(9)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for VarInt {
|
||||
#[inline]
|
||||
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
||||
let n = ReadExt::read_u8(r)?;
|
||||
match n {
|
||||
0xFF => {
|
||||
let x = ReadExt::read_u64(r)?;
|
||||
if x < 0x100000000 {
|
||||
Err(self::Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(VarInt::from(x))
|
||||
}
|
||||
}
|
||||
0xFE => {
|
||||
let x = ReadExt::read_u32(r)?;
|
||||
if x < 0x10000 {
|
||||
Err(self::Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(VarInt::from(x))
|
||||
}
|
||||
}
|
||||
0xFD => {
|
||||
let x = ReadExt::read_u16(r)?;
|
||||
if x < 0xFD {
|
||||
Err(self::Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(VarInt::from(x))
|
||||
}
|
||||
}
|
||||
n => Ok(VarInt::from(n)),
|
||||
}
|
||||
}
|
||||
/// Returns 1 for 0..=0xFC, 3 for 0xFD..=(2^16-1), 5 for 0x10000..=(2^32-1), and 9 otherwise.
|
||||
#[inline]
|
||||
pub fn varint_size(v: impl ToU64) -> usize {
|
||||
varint_size_u64(v.to_u64())
|
||||
}
|
||||
|
||||
impl Encodable for bool {
|
||||
|
@ -544,10 +514,7 @@ impl Decodable for bool {
|
|||
impl Encodable for String {
|
||||
#[inline]
|
||||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
let b = self.as_bytes();
|
||||
let vi_len = VarInt(b.len().to_u64()).consensus_encode(w)?;
|
||||
w.emit_slice(b)?;
|
||||
Ok(vi_len + b.len())
|
||||
consensus_encode_with_size(self.as_bytes(), w)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,10 +529,7 @@ impl Decodable for String {
|
|||
impl Encodable for Cow<'static, str> {
|
||||
#[inline]
|
||||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
let b = self.as_bytes();
|
||||
let vi_len = VarInt(b.len().to_u64()).consensus_encode(w)?;
|
||||
w.emit_slice(b)?;
|
||||
Ok(vi_len + b.len())
|
||||
consensus_encode_with_size(self.as_bytes(), w)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,8 +550,8 @@ macro_rules! impl_array {
|
|||
&self,
|
||||
w: &mut W,
|
||||
) -> core::result::Result<usize, io::Error> {
|
||||
w.emit_slice(&self[..])?;
|
||||
Ok(self.len())
|
||||
let n = w.emit_slice(&self[..])?;
|
||||
Ok(n)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,7 +608,7 @@ macro_rules! impl_vec {
|
|||
w: &mut W,
|
||||
) -> core::result::Result<usize, io::Error> {
|
||||
let mut len = 0;
|
||||
len += VarInt(self.len().to_u64()).consensus_encode(w)?;
|
||||
len += w.emit_compact_size(self.len())?;
|
||||
for c in self.iter() {
|
||||
len += c.consensus_encode(w)?;
|
||||
}
|
||||
|
@ -657,7 +621,7 @@ macro_rules! impl_vec {
|
|||
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
|
||||
r: &mut R,
|
||||
) -> core::result::Result<Self, Error> {
|
||||
let len = VarInt::consensus_decode_from_finite_reader(r)?.0;
|
||||
let len = r.read_compact_size()?;
|
||||
// Do not allocate upfront more items than if the sequence of type
|
||||
// occupied roughly quarter a block. This should never be the case
|
||||
// for normal data, but even if that's not true - `push` will just
|
||||
|
@ -685,7 +649,6 @@ impl_vec!(TxIn);
|
|||
impl_vec!(Vec<u8>);
|
||||
impl_vec!(u64);
|
||||
impl_vec!(TapLeafHash);
|
||||
impl_vec!(VarInt);
|
||||
impl_vec!(ShortId);
|
||||
impl_vec!(PrefilledTransaction);
|
||||
|
||||
|
@ -700,9 +663,7 @@ pub(crate) fn consensus_encode_with_size<W: Write + ?Sized>(
|
|||
data: &[u8],
|
||||
w: &mut W,
|
||||
) -> Result<usize, io::Error> {
|
||||
let vi_len = VarInt(data.len().to_u64()).consensus_encode(w)?;
|
||||
w.emit_slice(data)?;
|
||||
Ok(vi_len + data.len())
|
||||
Ok(w.emit_compact_size(data.len())? + w.emit_slice(data)?)
|
||||
}
|
||||
|
||||
struct ReadBytesFromFiniteReaderOpts {
|
||||
|
@ -745,7 +706,7 @@ impl Encodable for Vec<u8> {
|
|||
impl Decodable for Vec<u8> {
|
||||
#[inline]
|
||||
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
||||
let len = VarInt::consensus_decode(r)?.0 as usize;
|
||||
let len = r.read_compact_size()? as usize;
|
||||
// most real-world vec of bytes data, wouldn't be larger than 128KiB
|
||||
let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 };
|
||||
read_bytes_from_finite_reader(r, opts)
|
||||
|
@ -779,8 +740,7 @@ impl Encodable for CheckedData {
|
|||
.expect("network message use u32 as length")
|
||||
.consensus_encode(w)?;
|
||||
self.checksum().consensus_encode(w)?;
|
||||
w.emit_slice(&self.data)?;
|
||||
Ok(8 + self.data.len())
|
||||
Ok(8 + w.emit_slice(&self.data)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -902,6 +862,8 @@ mod tests {
|
|||
use core::mem::discriminant;
|
||||
|
||||
use super::*;
|
||||
#[cfg(feature = "std")]
|
||||
use crate::p2p::{message_blockdata::Inventory, Address};
|
||||
|
||||
#[test]
|
||||
fn serialize_int_test() {
|
||||
|
@ -952,46 +914,51 @@ mod tests {
|
|||
assert_eq!(serialize(&723401728380766730i64), [10u8, 10, 10, 10, 10, 10, 10, 10]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_varint_test() {
|
||||
assert_eq!(serialize(&VarInt(10)), [10u8]);
|
||||
assert_eq!(serialize(&VarInt(0xFC)), [0xFCu8]);
|
||||
assert_eq!(serialize(&VarInt(0xFD)), [0xFDu8, 0xFD, 0]);
|
||||
assert_eq!(serialize(&VarInt(0xFFF)), [0xFDu8, 0xFF, 0xF]);
|
||||
assert_eq!(serialize(&VarInt(0xF0F0F0F)), [0xFEu8, 0xF, 0xF, 0xF, 0xF]);
|
||||
assert_eq!(
|
||||
serialize(&VarInt(0xF0F0F0F0F0E0)),
|
||||
[0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]
|
||||
);
|
||||
assert_eq!(
|
||||
test_varint_encode(0xFF, &0x100000000_u64.to_le_bytes()).unwrap(),
|
||||
VarInt(0x100000000)
|
||||
);
|
||||
assert_eq!(test_varint_encode(0xFE, &0x10000_u64.to_le_bytes()).unwrap(), VarInt(0x10000));
|
||||
assert_eq!(test_varint_encode(0xFD, &0xFD_u64.to_le_bytes()).unwrap(), VarInt(0xFD));
|
||||
|
||||
// Test that length calc is working correctly
|
||||
test_varint_len(VarInt(0), 1);
|
||||
test_varint_len(VarInt(0xFC), 1);
|
||||
test_varint_len(VarInt(0xFD), 3);
|
||||
test_varint_len(VarInt(0xFFFF), 3);
|
||||
test_varint_len(VarInt(0x10000), 5);
|
||||
test_varint_len(VarInt(0xFFFFFFFF), 5);
|
||||
test_varint_len(VarInt(0xFFFFFFFF + 1), 9);
|
||||
test_varint_len(VarInt(u64::MAX), 9);
|
||||
}
|
||||
|
||||
fn test_varint_len(varint: VarInt, expected: usize) {
|
||||
let mut encoder = vec![];
|
||||
assert_eq!(varint.consensus_encode(&mut encoder).unwrap(), expected);
|
||||
assert_eq!(varint.size(), expected);
|
||||
}
|
||||
|
||||
fn test_varint_encode(n: u8, x: &[u8]) -> Result<VarInt, Error> {
|
||||
fn test_varint_encode(n: u8, x: &[u8]) -> Result<u64, Error> {
|
||||
let mut input = [0u8; 9];
|
||||
input[0] = n;
|
||||
input[1..x.len() + 1].copy_from_slice(x);
|
||||
deserialize_partial::<VarInt>(&input).map(|t| t.0)
|
||||
(&input[..]).read_compact_size()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_varint_test() {
|
||||
fn encode(v: u64) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
buf.emit_compact_size(v).unwrap();
|
||||
buf
|
||||
}
|
||||
|
||||
assert_eq!(encode(10), [10u8]);
|
||||
assert_eq!(encode(0xFC), [0xFCu8]);
|
||||
assert_eq!(encode(0xFD), [0xFDu8, 0xFD, 0]);
|
||||
assert_eq!(encode(0xFFF), [0xFDu8, 0xFF, 0xF]);
|
||||
assert_eq!(encode(0xF0F0F0F), [0xFEu8, 0xF, 0xF, 0xF, 0xF]);
|
||||
assert_eq!(
|
||||
encode(0xF0F0F0F0F0E0),
|
||||
vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0],
|
||||
);
|
||||
assert_eq!(
|
||||
test_varint_encode(0xFF, &0x100000000_u64.to_le_bytes()).unwrap(),
|
||||
0x100000000,
|
||||
);
|
||||
assert_eq!(test_varint_encode(0xFE, &0x10000_u64.to_le_bytes()).unwrap(), 0x10000);
|
||||
assert_eq!(test_varint_encode(0xFD, &0xFD_u64.to_le_bytes()).unwrap(), 0xFD);
|
||||
|
||||
// Test that length calc is working correctly
|
||||
fn test_varint_len(varint: u64, expected: usize) {
|
||||
let mut encoder = vec![];
|
||||
assert_eq!(encoder.emit_compact_size(varint).unwrap(), expected);
|
||||
assert_eq!(varint_size(varint), expected);
|
||||
}
|
||||
test_varint_len(0, 1);
|
||||
test_varint_len(0xFC, 1);
|
||||
test_varint_len(0xFD, 3);
|
||||
test_varint_len(0xFFFF, 3);
|
||||
test_varint_len(0x10000, 5);
|
||||
test_varint_len(0xFFFFFFFF, 5);
|
||||
test_varint_len(0xFFFFFFFF + 1, 9);
|
||||
test_varint_len(u64::MAX, 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1199,8 +1166,9 @@ mod tests {
|
|||
T: fmt::Debug,
|
||||
{
|
||||
let rand_io_err = Error::Io(io::Error::new(io::ErrorKind::Other, ""));
|
||||
let varint = VarInt((super::MAX_VEC_SIZE / mem::size_of::<T>()).to_u64());
|
||||
let err = deserialize::<Vec<T>>(&serialize(&varint)).unwrap_err();
|
||||
let mut buf = Vec::new();
|
||||
buf.emit_compact_size(super::MAX_VEC_SIZE / mem::size_of::<T>()).unwrap();
|
||||
let err = deserialize::<Vec<T>>(&buf).unwrap_err();
|
||||
assert_eq!(discriminant(&err), discriminant(&rand_io_err));
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,6 @@ pub use crate::{
|
|||
blockdata::transaction::{self, OutPoint, Transaction, TxIn, TxOut, Txid, Wtxid},
|
||||
blockdata::weight::Weight,
|
||||
blockdata::witness::{self, Witness},
|
||||
consensus::encode::VarInt,
|
||||
crypto::ecdsa,
|
||||
crypto::key::{self, PrivateKey, PubkeyHash, PublicKey, CompressedPublicKey, WPubkeyHash, XOnlyPublicKey},
|
||||
crypto::sighash::{self, LegacySighash, SegwitV0Sighash, TapSighash, TapSighashTag},
|
||||
|
|
|
@ -16,7 +16,7 @@ use io::{BufRead, Write};
|
|||
|
||||
use self::MerkleBlockError::*;
|
||||
use crate::block::{self, Block};
|
||||
use crate::consensus::encode::{self, Decodable, Encodable, MAX_VEC_SIZE};
|
||||
use crate::consensus::encode::{self, Decodable, Encodable, MAX_VEC_SIZE, WriteExt, ReadExt};
|
||||
use crate::merkle_tree::{MerkleNode as _, TxMerkleNode};
|
||||
use crate::prelude::Vec;
|
||||
use crate::transaction::{Transaction, Txid};
|
||||
|
@ -405,7 +405,7 @@ impl Encodable for PartialMerkleTree {
|
|||
ret += self.hashes.consensus_encode(w)?;
|
||||
|
||||
let nb_bytes_for_bits = (self.bits.len() + 7) / 8;
|
||||
ret += encode::VarInt::from(nb_bytes_for_bits).consensus_encode(w)?;
|
||||
ret += w.emit_compact_size(nb_bytes_for_bits)?;
|
||||
for chunk in self.bits.chunks(8) {
|
||||
let mut byte = 0u8;
|
||||
for (i, bit) in chunk.iter().enumerate() {
|
||||
|
@ -424,7 +424,7 @@ impl Decodable for PartialMerkleTree {
|
|||
let num_transactions: u32 = Decodable::consensus_decode(r)?;
|
||||
let hashes: Vec<TxMerkleNode> = Decodable::consensus_decode(r)?;
|
||||
|
||||
let nb_bytes_for_bits = encode::VarInt::consensus_decode(r)?.0 as usize;
|
||||
let nb_bytes_for_bits = r.read_compact_size()? as usize;
|
||||
if nb_bytes_for_bits > MAX_VEC_SIZE {
|
||||
return Err(encode::Error::OversizedVectorAllocation {
|
||||
requested: nb_bytes_for_bits,
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSoc
|
|||
|
||||
use io::{BufRead, Read, Write};
|
||||
|
||||
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt};
|
||||
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt};
|
||||
use crate::p2p::ServiceFlags;
|
||||
|
||||
/// A message which can be sent on the Bitcoin network
|
||||
|
@ -146,11 +146,7 @@ impl Encodable for AddrV2 {
|
|||
network: u8,
|
||||
bytes: &[u8],
|
||||
) -> Result<usize, io::Error> {
|
||||
let len = network.consensus_encode(w)?
|
||||
+ VarInt::from(bytes.len()).consensus_encode(w)?
|
||||
+ bytes.len();
|
||||
w.emit_slice(bytes)?;
|
||||
Ok(len)
|
||||
Ok(network.consensus_encode(w)? + encode::consensus_encode_with_size(bytes, w)?)
|
||||
}
|
||||
Ok(match *self {
|
||||
AddrV2::Ipv4(ref addr) => encode_addr(w, 1, &addr.octets())?,
|
||||
|
@ -167,7 +163,7 @@ impl Encodable for AddrV2 {
|
|||
impl Decodable for AddrV2 {
|
||||
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||
let network_id = u8::consensus_decode(r)?;
|
||||
let len = VarInt::consensus_decode(r)?.0;
|
||||
let len = r.read_compact_size()?;
|
||||
if len > 512 {
|
||||
return Err(encode::Error::ParseFailed("IP must be <= 512 bytes"));
|
||||
}
|
||||
|
@ -272,7 +268,7 @@ impl Encodable for AddrV2Message {
|
|||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
let mut len = 0;
|
||||
len += self.time.consensus_encode(w)?;
|
||||
len += VarInt(self.services.to_u64()).consensus_encode(w)?;
|
||||
len += w.emit_compact_size(self.services.to_u64())?;
|
||||
len += self.addr.consensus_encode(w)?;
|
||||
|
||||
w.write_all(&self.port.to_be_bytes())?;
|
||||
|
@ -286,7 +282,7 @@ impl Decodable for AddrV2Message {
|
|||
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||
Ok(AddrV2Message {
|
||||
time: Decodable::consensus_decode(r)?,
|
||||
services: ServiceFlags::from(VarInt::consensus_decode(r)?.0),
|
||||
services: ServiceFlags::from(r.read_compact_size()?),
|
||||
addr: Decodable::consensus_decode(r)?,
|
||||
port: u16::swap_bytes(Decodable::consensus_decode(r)?),
|
||||
})
|
||||
|
|
|
@ -11,7 +11,7 @@ use hashes::sha256d;
|
|||
use internals::ToU64 as _;
|
||||
use io::{BufRead, Write};
|
||||
|
||||
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
|
||||
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, WriteExt, ReadExt};
|
||||
use crate::merkle_tree::MerkleBlock;
|
||||
use crate::p2p::address::{AddrV2Message, Address};
|
||||
use crate::p2p::{
|
||||
|
@ -337,7 +337,7 @@ impl<'a> Encodable for HeaderSerializationWrapper<'a> {
|
|||
#[inline]
|
||||
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||
let mut len = 0;
|
||||
len += VarInt::from(self.0.len()).consensus_encode(w)?;
|
||||
len += w.emit_compact_size(self.0.len())?;
|
||||
for header in self.0.iter() {
|
||||
len += header.consensus_encode(w)?;
|
||||
len += 0u8.consensus_encode(w)?;
|
||||
|
@ -410,7 +410,7 @@ impl Decodable for HeaderDeserializationWrapper {
|
|||
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
|
||||
r: &mut R,
|
||||
) -> Result<Self, encode::Error> {
|
||||
let len = VarInt::consensus_decode(r)?.0;
|
||||
let len = r.read_compact_size()?;
|
||||
// should be above usual number of items to avoid
|
||||
// allocation
|
||||
let mut ret = Vec::with_capacity(core::cmp::min(1024 * 16, len as usize));
|
||||
|
|
|
@ -12,7 +12,7 @@ use io::{BufRead, Write};
|
|||
|
||||
use super::serialize::{Deserialize, Serialize};
|
||||
use crate::consensus::encode::{
|
||||
self, deserialize, serialize, Decodable, Encodable, ReadExt, VarInt, WriteExt, MAX_VEC_SIZE,
|
||||
self, deserialize, serialize, Decodable, Encodable, ReadExt, WriteExt, MAX_VEC_SIZE,
|
||||
};
|
||||
use crate::prelude::{DisplayHex, Vec};
|
||||
use crate::psbt::Error;
|
||||
|
@ -73,7 +73,7 @@ impl fmt::Display for Key {
|
|||
|
||||
impl Key {
|
||||
pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
||||
let VarInt(byte_size): VarInt = Decodable::consensus_decode(r)?;
|
||||
let byte_size = r.read_compact_size()?;
|
||||
|
||||
if byte_size == 0 {
|
||||
return Err(Error::NoMorePairs);
|
||||
|
@ -103,9 +103,7 @@ impl Key {
|
|||
impl Serialize for Key {
|
||||
fn serialize(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
VarInt::from(self.key_data.len() + 1)
|
||||
.consensus_encode(&mut buf)
|
||||
.expect("in-memory writers don't error");
|
||||
buf.emit_compact_size(self.key_data.len() + 1).expect("in-memory writers don't error");
|
||||
|
||||
self.type_value.consensus_encode(&mut buf).expect("in-memory writers don't error");
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//! according to the BIP-174 specification.
|
||||
|
||||
use hashes::{hash160, ripemd160, sha256, sha256d};
|
||||
use internals::compact_size;
|
||||
use secp256k1::XOnlyPublicKey;
|
||||
|
||||
use super::map::{Input, Map, Output, PsbtSighashType};
|
||||
|
@ -22,7 +23,7 @@ use crate::taproot::{
|
|||
};
|
||||
use crate::transaction::{Transaction, TxOut};
|
||||
use crate::witness::Witness;
|
||||
use crate::VarInt;
|
||||
|
||||
/// A trait for serializing a value as raw data for insertion into PSBT
|
||||
/// key-value maps.
|
||||
pub(crate) trait Serialize {
|
||||
|
@ -355,8 +356,8 @@ impl Serialize for TapTree {
|
|||
let capacity = self
|
||||
.script_leaves()
|
||||
.map(|l| {
|
||||
l.script().len() + VarInt::from(l.script().len()).size() // script version
|
||||
+ 1 // Merkle branch
|
||||
l.script().len() + compact_size::encoded_size(l.script().len()) // script version
|
||||
+ 1 // merkle branch
|
||||
+ 1 // leaf version
|
||||
})
|
||||
.sum::<usize>();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
use hashes::{sha256d, HashEngine};
|
||||
|
||||
use crate::consensus::{encode, Encodable};
|
||||
use crate::consensus::encode::WriteExt;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[doc(inline)]
|
||||
|
@ -209,8 +209,7 @@ pub fn signed_msg_hash(msg: impl AsRef<[u8]>) -> sha256d::Hash {
|
|||
let msg_bytes = msg.as_ref();
|
||||
let mut engine = sha256d::Hash::engine();
|
||||
engine.input(BITCOIN_SIGNED_MSG_PREFIX);
|
||||
let msg_len = encode::VarInt::from(msg_bytes.len());
|
||||
msg_len.consensus_encode(&mut engine).expect("engines don't error");
|
||||
engine.emit_compact_size(msg_bytes.len()).expect("engines don't error");
|
||||
engine.input(msg_bytes);
|
||||
sha256d::Hash::from_engine(engine)
|
||||
}
|
||||
|
|
|
@ -1153,8 +1153,8 @@ impl ControlBlock {
|
|||
/// Serializes the control block.
|
||||
///
|
||||
/// This would be required when using [`ControlBlock`] as a witness element while spending an
|
||||
/// output via script path. This serialization does not include the [`crate::VarInt`] prefix that would
|
||||
/// be applied when encoding this element as a witness.
|
||||
/// output via script path. This serialization does not include the varint prefix that would be
|
||||
/// applied when encoding this element as a witness.
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(self.size());
|
||||
self.encode(&mut buf).expect("writers don't error");
|
||||
|
|
|
@ -30,7 +30,20 @@ const MAX_ENCODING_SIZE: usize = 9;
|
|||
/// - 9 otherwise.
|
||||
#[inline]
|
||||
pub fn encoded_size(value: impl ToU64) -> usize {
|
||||
match value.to_u64() {
|
||||
encoded_size_const(value.to_u64())
|
||||
}
|
||||
|
||||
/// Returns the number of bytes used to encode this `CompactSize` value (in const context).
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - 1 for 0..=0xFC
|
||||
/// - 3 for 0xFD..=(2^16-1)
|
||||
/// - 5 for 0x10000..=(2^32-1)
|
||||
/// - 9 otherwise.
|
||||
#[inline]
|
||||
pub const fn encoded_size_const(value: u64) -> usize {
|
||||
match value {
|
||||
0..=0xFC => 1,
|
||||
0xFD..=0xFFFF => 3,
|
||||
0x10000..=0xFFFFFFFF => 5,
|
||||
|
|
Loading…
Reference in New Issue