rust-bitcoin-unsafe-fast/p2p/src/consensus.rs

98 lines
3.5 KiB
Rust

use bitcoin::consensus::encode::WriteExt;
use io::Write;
pub(crate) fn consensus_encode_with_size<W: Write + ?Sized>(
data: &[u8],
w: &mut W,
) -> Result<usize, io::Error> {
Ok(w.emit_compact_size(data.len())? + w.emit_slice(data)?)
}
pub(crate) fn parse_failed_error(msg: &'static str) -> bitcoin::consensus::encode::Error {
bitcoin::consensus::encode::Error::Parse(bitcoin::consensus::encode::ParseError::ParseFailed(
msg,
))
}
macro_rules! impl_consensus_encoding {
($thing:ident, $($field:ident),+) => (
impl bitcoin::consensus::Encodable for $thing {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(
&self,
w: &mut W,
) -> core::result::Result<usize, io::Error> {
let mut len = 0;
$(len += self.$field.consensus_encode(w)?;)+
Ok(len)
}
}
impl bitcoin::consensus::Decodable for $thing {
#[inline]
fn consensus_decode_from_finite_reader<R: io::BufRead + ?Sized>(
r: &mut R,
) -> core::result::Result<$thing, bitcoin::consensus::encode::Error> {
Ok($thing {
$($field: bitcoin::consensus::Decodable::consensus_decode_from_finite_reader(r)?),+
})
}
#[inline]
fn consensus_decode<R: io::BufRead + ?Sized>(
r: &mut R,
) -> core::result::Result<$thing, bitcoin::consensus::encode::Error> {
let mut r = r.take(internals::ToU64::to_u64(bitcoin::consensus::encode::MAX_VEC_SIZE));
Ok($thing {
$($field: bitcoin::consensus::Decodable::consensus_decode(&mut r)?),+
})
}
}
);
}
pub(crate) use impl_consensus_encoding;
macro_rules! impl_vec_wrapper {
($wrapper: ident, $type: ty) => {
impl bitcoin::consensus::encode::Encodable for $wrapper {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(
&self,
w: &mut W,
) -> core::result::Result<usize, io::Error> {
let mut len = 0;
len += w.emit_compact_size(self.0.len())?;
for c in self.0.iter() {
len += c.consensus_encode(w)?;
}
Ok(len)
}
}
impl bitcoin::consensus::encode::Decodable for $wrapper {
#[inline]
fn consensus_decode_from_finite_reader<R: io::BufRead + ?Sized>(
r: &mut R,
) -> core::result::Result<$wrapper, bitcoin::consensus::encode::Error> {
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
// reallocate.
// Note: OOM protection relies on reader eventually running out of
// data to feed us.
let max_capacity =
bitcoin::consensus::encode::MAX_VEC_SIZE / 4 / core::mem::size_of::<$type>();
let mut ret = Vec::with_capacity(core::cmp::min(len as usize, max_capacity));
for _ in 0..len {
ret.push(Decodable::consensus_decode_from_finite_reader(r)?);
}
Ok($wrapper(ret))
}
}
};
}
pub(crate) use impl_vec_wrapper;