Require BufRead instead of Read

Our decoding code reads bytes in very small chunks. Which is not
efficient when dealing with the OS where the cost of a context switch is
significant. People could already buffer the data but it's easy to
forget it by accident.

This change requires the new `io::BufRead` trait instead of `io::Read`
in all bounds.

Code such as `Transaction::consensus_decode(&mut File::open(foo))` will
break after this is applied, uncovering the inefficiency.

This was originally Kix's work, done before we had the `io` crate.
Changes to `bitcoin` were originally his, any new mistakes are my own.
Changes to `io` are mine.

Co-developed-by: Martin Habovstiak <martin.habovstiak@gmail.com>
This commit is contained in:
Tobin C. Harding 2023-12-08 12:16:55 +11:00
parent 32d68fd1fa
commit 263a8b3603
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
22 changed files with 123 additions and 85 deletions

View File

@ -12,7 +12,7 @@ use std::error;
use hashes::{sha256, siphash24, Hash}; use hashes::{sha256, siphash24, Hash};
use internals::impl_array_newtype; use internals::impl_array_newtype;
use io::{Read, Write}; use io::{BufRead, Write};
use crate::consensus::encode::{self, Decodable, Encodable, VarInt}; use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding}; use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding};
@ -81,7 +81,7 @@ impl Encodable for PrefilledTransaction {
impl Decodable for PrefilledTransaction { impl Decodable for PrefilledTransaction {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let idx = VarInt::consensus_decode(r)?.0; let idx = VarInt::consensus_decode(r)?.0;
let idx = u16::try_from(idx) let idx = u16::try_from(idx)
.map_err(|_| encode::Error::ParseFailed("BIP152 prefilled tx index out of bounds"))?; .map_err(|_| encode::Error::ParseFailed("BIP152 prefilled tx index out of bounds"))?;
@ -137,7 +137,7 @@ impl Encodable for ShortId {
impl Decodable for ShortId { impl Decodable for ShortId {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
Ok(ShortId(Decodable::consensus_decode(r)?)) Ok(ShortId(Decodable::consensus_decode(r)?))
} }
} }
@ -273,7 +273,7 @@ impl Encodable for BlockTransactionsRequest {
} }
impl Decodable for BlockTransactionsRequest { impl Decodable for BlockTransactionsRequest {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(BlockTransactionsRequest { Ok(BlockTransactionsRequest {
block_hash: BlockHash::consensus_decode(r)?, block_hash: BlockHash::consensus_decode(r)?,
indexes: { indexes: {

View File

@ -43,7 +43,7 @@ use core::fmt::{self, Display, Formatter};
use hashes::{sha256d, siphash24, Hash}; use hashes::{sha256d, siphash24, Hash};
use internals::write_err; use internals::write_err;
use io::{Read, Write}; use io::{BufRead, Write};
use crate::blockdata::block::{Block, BlockHash}; use crate::blockdata::block::{Block, BlockHash};
use crate::blockdata::script::Script; use crate::blockdata::script::Script;
@ -245,7 +245,7 @@ impl BlockFilterReader {
where where
I: Iterator, I: Iterator,
I::Item: Borrow<[u8]>, I::Item: Borrow<[u8]>,
R: Read + ?Sized, R: BufRead + ?Sized,
{ {
self.reader.match_any(reader, query) self.reader.match_any(reader, query)
} }
@ -255,7 +255,7 @@ impl BlockFilterReader {
where where
I: Iterator, I: Iterator,
I::Item: Borrow<[u8]>, I::Item: Borrow<[u8]>,
R: Read + ?Sized, R: BufRead + ?Sized,
{ {
self.reader.match_all(reader, query) self.reader.match_all(reader, query)
} }
@ -278,7 +278,7 @@ impl GcsFilterReader {
where where
I: Iterator, I: Iterator,
I::Item: Borrow<[u8]>, I::Item: Borrow<[u8]>,
R: Read + ?Sized, R: BufRead + ?Sized,
{ {
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0)); let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
// map hashes to [0, n_elements << grp] // map hashes to [0, n_elements << grp]
@ -321,7 +321,7 @@ impl GcsFilterReader {
where where
I: Iterator, I: Iterator,
I::Item: Borrow<[u8]>, I::Item: Borrow<[u8]>,
R: Read + ?Sized, R: BufRead + ?Sized,
{ {
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0)); let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
// map hashes to [0, n_elements << grp] // map hashes to [0, n_elements << grp]
@ -447,7 +447,7 @@ impl GcsFilter {
/// Golomb-Rice decodes a number from a bit stream (parameter 2^k). /// Golomb-Rice decodes a number from a bit stream (parameter 2^k).
fn golomb_rice_decode<R>(&self, reader: &mut BitStreamReader<R>) -> Result<u64, io::Error> fn golomb_rice_decode<R>(&self, reader: &mut BitStreamReader<R>) -> Result<u64, io::Error>
where where
R: Read + ?Sized, R: BufRead + ?Sized,
{ {
let mut q = 0u64; let mut q = 0u64;
while reader.read(1)? == 1 { while reader.read(1)? == 1 {
@ -470,7 +470,7 @@ pub struct BitStreamReader<'a, R: ?Sized> {
reader: &'a mut R, reader: &'a mut R,
} }
impl<'a, R: Read + ?Sized> BitStreamReader<'a, R> { impl<'a, R: BufRead + ?Sized> BitStreamReader<'a, R> {
/// Creates a new [`BitStreamReader`] that reads bitwise from a given `reader`. /// Creates a new [`BitStreamReader`] that reads bitwise from a given `reader`.
pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> { pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> {
BitStreamReader { buffer: [0u8], reader, offset: 8 } BitStreamReader { buffer: [0u8], reader, offset: 8 }

View File

@ -11,7 +11,7 @@
use core::fmt; use core::fmt;
use hashes::{sha256d, Hash, HashEngine}; use hashes::{sha256d, Hash, HashEngine};
use io::{Read, Write}; use io::{BufRead, Write};
use super::Weight; use super::Weight;
use crate::blockdata::script; use crate::blockdata::script;
@ -207,7 +207,7 @@ impl Encodable for Version {
} }
impl Decodable for Version { impl Decodable for Version {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Version) Decodable::consensus_decode(r).map(Version)
} }
} }

View File

@ -10,7 +10,7 @@ use core::cmp::{Ordering, PartialOrd};
use core::{fmt, mem}; use core::{fmt, mem};
use internals::write_err; use internals::write_err;
use io::{Read, Write}; use io::{BufRead, Write};
#[cfg(all(test, mutate))] #[cfg(all(test, mutate))]
use mutagen::mutate; use mutagen::mutate;
@ -345,7 +345,7 @@ impl Encodable for LockTime {
impl Decodable for LockTime { impl Decodable for LockTime {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
u32::consensus_decode(r).map(LockTime::from_consensus) u32::consensus_decode(r).map(LockTime::from_consensus)
} }
} }

View File

@ -66,7 +66,7 @@ use core::fmt;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use hashes::{hash160, sha256}; use hashes::{hash160, sha256};
use io::{Read, Write}; use io::{BufRead, Write};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde; use serde;
@ -594,7 +594,7 @@ impl Encodable for ScriptBuf {
impl Decodable for ScriptBuf { impl Decodable for ScriptBuf {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, encode::Error> { ) -> Result<Self, encode::Error> {
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?)) Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))

View File

@ -16,7 +16,7 @@ use core::{cmp, fmt, str};
use hashes::{self, sha256d, Hash}; use hashes::{self, sha256d, Hash};
use internals::write_err; use internals::write_err;
use io::{Read, Write}; use io::{BufRead, Write};
use super::Weight; use super::Weight;
use crate::blockdata::fee_rate::FeeRate; use crate::blockdata::fee_rate::FeeRate;
@ -1025,7 +1025,7 @@ impl Encodable for Version {
} }
impl Decodable for Version { impl Decodable for Version {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Version) Decodable::consensus_decode(r).map(Version)
} }
} }
@ -1039,7 +1039,7 @@ impl Encodable for OutPoint {
} }
} }
impl Decodable for OutPoint { impl Decodable for OutPoint {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(OutPoint { Ok(OutPoint {
txid: Decodable::consensus_decode(r)?, txid: Decodable::consensus_decode(r)?,
vout: Decodable::consensus_decode(r)?, vout: Decodable::consensus_decode(r)?,
@ -1058,7 +1058,7 @@ impl Encodable for TxIn {
} }
impl Decodable for TxIn { impl Decodable for TxIn {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, encode::Error> { ) -> Result<Self, encode::Error> {
Ok(TxIn { Ok(TxIn {
@ -1077,7 +1077,7 @@ impl Encodable for Sequence {
} }
impl Decodable for Sequence { impl Decodable for Sequence {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Sequence) Decodable::consensus_decode(r).map(Sequence)
} }
} }
@ -1107,7 +1107,7 @@ impl Encodable for Transaction {
} }
impl Decodable for Transaction { impl Decodable for Transaction {
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, encode::Error> { ) -> Result<Self, encode::Error> {
let version = Version::consensus_decode_from_finite_reader(r)?; let version = Version::consensus_decode_from_finite_reader(r)?;

View File

@ -8,7 +8,7 @@
use core::fmt; use core::fmt;
use core::ops::Index; use core::ops::Index;
use io::{Read, Write}; use io::{BufRead, Write};
use crate::consensus::encode::{Error, MAX_VEC_SIZE}; use crate::consensus::encode::{Error, MAX_VEC_SIZE};
use crate::consensus::{Decodable, Encodable, WriteExt}; use crate::consensus::{Decodable, Encodable, WriteExt};
@ -124,7 +124,7 @@ pub struct Iter<'a> {
} }
impl Decodable for Witness { impl Decodable for Witness {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { 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 = VarInt::consensus_decode(r)?.0 as usize;
// Minimum size of witness element is 1 byte, so if the count is // Minimum size of witness element is 1 byte, so if the count is
// greater than MAX_VEC_SIZE we must return an error. // greater than MAX_VEC_SIZE we must return an error.

View File

@ -20,7 +20,7 @@ use core::{fmt, mem, u32};
use hashes::{sha256, sha256d, Hash}; use hashes::{sha256, sha256d, Hash};
use internals::write_err; use internals::write_err;
use io::{Cursor, Read, Write}; use io::{Cursor, BufRead, Read, Write};
use crate::bip152::{PrefilledTransaction, ShortId}; use crate::bip152::{PrefilledTransaction, ShortId};
use crate::bip158::{FilterHash, FilterHeader}; use crate::bip158::{FilterHash, FilterHeader};
@ -301,7 +301,7 @@ pub trait Decodable: Sized {
/// avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny /// avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny
/// performance hit. /// performance hit.
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
reader: &mut R, reader: &mut R,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
// This method is always strictly less general than, `consensus_decode`, so it's safe and // This method is always strictly less general than, `consensus_decode`, so it's safe and
@ -319,7 +319,7 @@ pub trait Decodable: Sized {
/// for types that override [`Self::consensus_decode_from_finite_reader`] /// for types that override [`Self::consensus_decode_from_finite_reader`]
/// instead. /// instead.
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, Error> {
Self::consensus_decode_from_finite_reader(&mut reader.take(MAX_VEC_SIZE as u64)) Self::consensus_decode_from_finite_reader(&mut reader.take(MAX_VEC_SIZE as u64))
} }
} }
@ -357,7 +357,7 @@ macro_rules! impl_int_encodable {
($ty:ident, $meth_dec:ident, $meth_enc:ident) => { ($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
impl Decodable for $ty { impl Decodable for $ty {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
ReadExt::$meth_dec(r) ReadExt::$meth_dec(r)
} }
} }
@ -440,7 +440,7 @@ impl Encodable for VarInt {
impl Decodable for VarInt { impl Decodable for VarInt {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let n = ReadExt::read_u8(r)?; let n = ReadExt::read_u8(r)?;
match n { match n {
0xFF => { 0xFF => {
@ -482,7 +482,7 @@ impl Encodable for bool {
impl Decodable for bool { impl Decodable for bool {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<bool, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<bool, Error> {
ReadExt::read_bool(r) ReadExt::read_bool(r)
} }
} }
@ -499,7 +499,7 @@ impl Encodable for String {
impl Decodable for String { impl Decodable for String {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<String, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<String, Error> {
String::from_utf8(Decodable::consensus_decode(r)?) String::from_utf8(Decodable::consensus_decode(r)?)
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
} }
@ -517,7 +517,7 @@ impl Encodable for Cow<'static, str> {
impl Decodable for Cow<'static, str> { impl Decodable for Cow<'static, str> {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> {
String::from_utf8(Decodable::consensus_decode(r)?) String::from_utf8(Decodable::consensus_decode(r)?)
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
.map(Cow::Owned) .map(Cow::Owned)
@ -539,7 +539,7 @@ macro_rules! impl_array {
impl Decodable for [u8; $size] { impl Decodable for [u8; $size] {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut ret = [0; $size]; let mut ret = [0; $size];
r.read_slice(&mut ret)?; r.read_slice(&mut ret)?;
Ok(ret) Ok(ret)
@ -560,7 +560,7 @@ impl_array!(33);
impl Decodable for [u16; 8] { impl Decodable for [u16; 8] {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut res = [0; 8]; let mut res = [0; 8];
for item in &mut res { for item in &mut res {
*item = Decodable::consensus_decode(r)?; *item = Decodable::consensus_decode(r)?;
@ -595,7 +595,7 @@ macro_rules! impl_vec {
impl Decodable for Vec<$type> { impl Decodable for Vec<$type> {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let len = VarInt::consensus_decode_from_finite_reader(r)?.0; let len = VarInt::consensus_decode_from_finite_reader(r)?.0;
@ -685,7 +685,7 @@ impl Encodable for Vec<u8> {
impl Decodable for Vec<u8> { impl Decodable for Vec<u8> {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { 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 = VarInt::consensus_decode(r)?.0 as usize;
// most real-world vec of bytes data, wouldn't be larger than 128KiB // most real-world vec of bytes data, wouldn't be larger than 128KiB
let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 }; let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 };
@ -702,7 +702,7 @@ impl Encodable for Box<[u8]> {
impl Decodable for Box<[u8]> { impl Decodable for Box<[u8]> {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
<Vec<u8>>::consensus_decode_from_finite_reader(r).map(From::from) <Vec<u8>>::consensus_decode_from_finite_reader(r).map(From::from)
} }
} }
@ -727,7 +727,7 @@ impl Encodable for CheckedData {
impl Decodable for CheckedData { impl Decodable for CheckedData {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let len = u32::consensus_decode_from_finite_reader(r)? as usize; let len = u32::consensus_decode_from_finite_reader(r)? as usize;
let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?; let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?;
@ -787,7 +787,7 @@ macro_rules! tuple_encode {
impl<$($x: Decodable),*> Decodable for ($($x),*) { impl<$($x: Decodable),*> Decodable for ($($x),*) {
#[inline] #[inline]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(($({let $x = Decodable::consensus_decode(r)?; $x }),*)) Ok(($({let $x = Decodable::consensus_decode(r)?; $x }),*))
} }
} }
@ -809,7 +809,7 @@ impl Encodable for sha256d::Hash {
} }
impl Decodable for sha256d::Hash { impl Decodable for sha256d::Hash {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?)) Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
} }
} }
@ -821,7 +821,7 @@ impl Encodable for sha256::Hash {
} }
impl Decodable for sha256::Hash { impl Decodable for sha256::Hash {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?)) Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
} }
} }
@ -833,7 +833,7 @@ impl Encodable for TapLeafHash {
} }
impl Decodable for TapLeafHash { impl Decodable for TapLeafHash {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?)) Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
} }
} }

View File

@ -12,7 +12,7 @@
use core::fmt; use core::fmt;
use core::marker::PhantomData; use core::marker::PhantomData;
use io::{Read, Write}; use io::{BufRead, Read, Write};
use serde::de::{SeqAccess, Unexpected, Visitor}; use serde::de::{SeqAccess, Unexpected, Visitor};
use serde::ser::SerializeSeq; use serde::ser::SerializeSeq;
use serde::{Deserializer, Serializer}; use serde::{Deserializer, Serializer};
@ -420,11 +420,12 @@ where
struct IterReader<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> { struct IterReader<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> {
iterator: core::iter::Fuse<I>, iterator: core::iter::Fuse<I>,
buf: Option<u8>,
error: Option<E>, error: Option<E>,
} }
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> { impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), error: None } } fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), buf: None, error: None } }
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> { fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
let result = T::consensus_decode(&mut self); let result = T::consensus_decode(&mut self);
@ -443,8 +444,17 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
} }
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> Read for IterReader<E, I> { impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> Read for IterReader<E, I> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
let mut count = 0; let mut count = 0;
if buf.is_empty() {
return Ok(0);
}
if let Some(first) = self.buf.take() {
buf[0] = first;
buf = &mut buf[1..];
count += 1;
}
for (dst, src) in buf.iter_mut().zip(&mut self.iterator) { for (dst, src) in buf.iter_mut().zip(&mut self.iterator) {
match src { match src {
Ok(byte) => *dst = byte, Ok(byte) => *dst = byte,
@ -460,6 +470,34 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> Read for IterReader<E, I>
} }
} }
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> BufRead for IterReader<E, I> {
fn fill_buf(&mut self) -> Result<&[u8], io::Error> {
// matching on reference rather than using `ref` confuses borrow checker
if let Some(ref byte) = self.buf {
Ok(core::slice::from_ref(byte))
} else {
match self.iterator.next() {
Some(Ok(byte)) => {
self.buf = Some(byte);
Ok(core::slice::from_ref(self.buf.as_ref().expect("we've just filled it")))
},
Some(Err(error)) => {
self.error = Some(error);
Err(io::ErrorKind::Other.into())
},
None => Ok(&[]),
}
}
}
fn consume(&mut self, len: usize) {
debug_assert!(len <= 1);
if len > 0 {
self.buf = None;
}
}
}
/// Helper for `#[serde(with = "")]`. /// Helper for `#[serde(with = "")]`.
/// ///
/// To (de)serialize a field using consensus encoding you can write e.g.: /// To (de)serialize a field using consensus encoding you can write e.g.:

View File

@ -22,7 +22,7 @@ macro_rules! impl_consensus_encoding {
impl $crate::consensus::Decodable for $thing { impl $crate::consensus::Decodable for $thing {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: $crate::io::Read + ?Sized>( fn consensus_decode_from_finite_reader<R: $crate::io::BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<$thing, $crate::consensus::encode::Error> { ) -> Result<$thing, $crate::consensus::encode::Error> {
Ok($thing { Ok($thing {
@ -31,7 +31,7 @@ macro_rules! impl_consensus_encoding {
} }
#[inline] #[inline]
fn consensus_decode<R: $crate::io::Read + ?Sized>( fn consensus_decode<R: $crate::io::BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<$thing, $crate::consensus::encode::Error> { ) -> Result<$thing, $crate::consensus::encode::Error> {
let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64); let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64);
@ -202,7 +202,7 @@ macro_rules! impl_hashencode {
} }
impl $crate::consensus::Decodable for $hashtype { impl $crate::consensus::Decodable for $hashtype {
fn consensus_decode<R: $crate::io::Read + ?Sized>(r: &mut R) -> Result<Self, $crate::consensus::encode::Error> { fn consensus_decode<R: $crate::io::BufRead + ?Sized>(r: &mut R) -> Result<Self, $crate::consensus::encode::Error> {
use $crate::hashes::Hash; use $crate::hashes::Hash;
Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?)) Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?))
} }

View File

@ -165,7 +165,7 @@ pub mod amount {
//! We refer to the documentation on the types for more information. //! We refer to the documentation on the types for more information.
use crate::consensus::{encode, Decodable, Encodable}; use crate::consensus::{encode, Decodable, Encodable};
use crate::io; use crate::io::{BufRead, Write};
#[rustfmt::skip] // Keep public re-exports separate. #[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)] #[doc(inline)]
@ -177,14 +177,14 @@ pub mod amount {
impl Decodable for Amount { impl Decodable for Amount {
#[inline] #[inline]
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(Amount::from_sat(Decodable::consensus_decode(r)?)) Ok(Amount::from_sat(Decodable::consensus_decode(r)?))
} }
} }
impl Encodable for Amount { impl Encodable for Amount {
#[inline] #[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.to_sat().consensus_encode(w) self.to_sat().consensus_encode(w)
} }
} }

View File

@ -41,7 +41,7 @@
use core::fmt; use core::fmt;
use hashes::Hash; use hashes::Hash;
use io::{Read, Write}; use io::{BufRead, Write};
use self::MerkleBlockError::*; use self::MerkleBlockError::*;
use crate::blockdata::block::{self, Block, TxMerkleNode}; use crate::blockdata::block::{self, Block, TxMerkleNode};
@ -151,7 +151,7 @@ impl Encodable for MerkleBlock {
} }
impl Decodable for MerkleBlock { impl Decodable for MerkleBlock {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(MerkleBlock { Ok(MerkleBlock {
header: Decodable::consensus_decode(r)?, header: Decodable::consensus_decode(r)?,
txn: Decodable::consensus_decode(r)?, txn: Decodable::consensus_decode(r)?,
@ -452,7 +452,7 @@ impl Encodable for PartialMerkleTree {
} }
impl Decodable for PartialMerkleTree { impl Decodable for PartialMerkleTree {
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, encode::Error> { ) -> Result<Self, encode::Error> {
let num_transactions: u32 = Decodable::consensus_decode(r)?; let num_transactions: u32 = Decodable::consensus_decode(r)?;

View File

@ -9,7 +9,7 @@
use core::{fmt, iter}; use core::{fmt, iter};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use io::{Read, Write}; use io::{BufRead, Read, Write};
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt}; use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt};
use crate::p2p::ServiceFlags; use crate::p2p::ServiceFlags;
@ -75,7 +75,7 @@ impl Encodable for Address {
impl Decodable for Address { impl Decodable for Address {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(Address { Ok(Address {
services: Decodable::consensus_decode(r)?, services: Decodable::consensus_decode(r)?,
address: read_be_address(r)?, address: read_be_address(r)?,
@ -167,7 +167,7 @@ impl Encodable for AddrV2 {
} }
impl Decodable for AddrV2 { impl Decodable for AddrV2 {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let network_id = u8::consensus_decode(r)?; let network_id = u8::consensus_decode(r)?;
let len = VarInt::consensus_decode(r)?.0; let len = VarInt::consensus_decode(r)?.0;
if len > 512 { if len > 512 {
@ -285,7 +285,7 @@ impl Encodable for AddrV2Message {
} }
impl Decodable for AddrV2Message { impl Decodable for AddrV2Message {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(AddrV2Message { Ok(AddrV2Message {
time: Decodable::consensus_decode(r)?, time: Decodable::consensus_decode(r)?,
services: ServiceFlags::from(VarInt::consensus_decode(r)?.0), services: ServiceFlags::from(VarInt::consensus_decode(r)?.0),

View File

@ -9,7 +9,7 @@
use core::{fmt, iter}; use core::{fmt, iter};
use hashes::{sha256d, Hash}; use hashes::{sha256d, Hash};
use io::{Read, Write}; use io::{BufRead, Write};
use crate::blockdata::{block, transaction}; use crate::blockdata::{block, transaction};
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt}; use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
@ -110,7 +110,7 @@ impl Encodable for CommandString {
impl Decodable for CommandString { impl Decodable for CommandString {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?; let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?;
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| { let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| {
if u > 0 { if u > 0 {
@ -407,7 +407,7 @@ struct HeaderDeserializationWrapper(Vec<block::Header>);
impl Decodable for HeaderDeserializationWrapper { impl Decodable for HeaderDeserializationWrapper {
#[inline] #[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, encode::Error> { ) -> Result<Self, encode::Error> {
let len = VarInt::consensus_decode(r)?.0; let len = VarInt::consensus_decode(r)?.0;
@ -426,13 +426,13 @@ impl Decodable for HeaderDeserializationWrapper {
} }
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64)) Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
} }
} }
impl Decodable for RawNetworkMessage { impl Decodable for RawNetworkMessage {
fn consensus_decode_from_finite_reader<R: Read + ?Sized>( fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, encode::Error> { ) -> Result<Self, encode::Error> {
let magic = Decodable::consensus_decode_from_finite_reader(r)?; let magic = Decodable::consensus_decode_from_finite_reader(r)?;
@ -442,7 +442,7 @@ impl Decodable for RawNetworkMessage {
let raw_payload = checked_data.into_data(); let raw_payload = checked_data.into_data();
let payload_len = raw_payload.len() as u32; let payload_len = raw_payload.len() as u32;
let mut mem_d = io::Cursor::new(raw_payload); let mut mem_d = raw_payload.as_slice();
let payload = match &cmd.0[..] { let payload = match &cmd.0[..] {
"version" => "version" =>
NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?), NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
@ -525,13 +525,13 @@ impl Decodable for RawNetworkMessage {
"addrv2" => "addrv2" =>
NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?), NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"sendaddrv2" => NetworkMessage::SendAddrV2, "sendaddrv2" => NetworkMessage::SendAddrV2,
_ => NetworkMessage::Unknown { command: cmd, payload: mem_d.into_inner() }, _ => NetworkMessage::Unknown { command: cmd, payload: raw_payload },
}; };
Ok(RawNetworkMessage { magic, payload, payload_len, checksum }) Ok(RawNetworkMessage { magic, payload, payload_len, checksum })
} }
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64)) Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
} }
} }

View File

@ -7,7 +7,7 @@
//! //!
use hashes::{sha256d, Hash as _}; use hashes::{sha256d, Hash as _};
use io::{Read, Write}; use io::{BufRead, Write};
use crate::blockdata::block::BlockHash; use crate::blockdata::block::BlockHash;
use crate::blockdata::transaction::{Txid, Wtxid}; use crate::blockdata::transaction::{Txid, Wtxid};
@ -83,7 +83,7 @@ impl Encodable for Inventory {
impl Decodable for Inventory { impl Decodable for Inventory {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let inv_type: u32 = Decodable::consensus_decode(r)?; let inv_type: u32 = Decodable::consensus_decode(r)?;
Ok(match inv_type { Ok(match inv_type {
0 => Inventory::Error, 0 => Inventory::Error,

View File

@ -5,7 +5,7 @@
//! This module describes BIP37 Connection Bloom filtering network messages. //! This module describes BIP37 Connection Bloom filtering network messages.
//! //!
use io::{Read, Write}; use io::{BufRead, Write};
use crate::consensus::{encode, Decodable, Encodable, ReadExt}; use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding; use crate::internal_macros::impl_consensus_encoding;
@ -48,7 +48,7 @@ impl Encodable for BloomFlags {
} }
impl Decodable for BloomFlags { impl Decodable for BloomFlags {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(match r.read_u8()? { Ok(match r.read_u8()? {
0 => BloomFlags::None, 0 => BloomFlags::None,
1 => BloomFlags::All, 1 => BloomFlags::All,

View File

@ -7,7 +7,7 @@
//! //!
use hashes::sha256d; use hashes::sha256d;
use io::{Read, Write}; use io::{BufRead, Write};
use crate::consensus::{encode, Decodable, Encodable, ReadExt}; use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding; use crate::internal_macros::impl_consensus_encoding;
@ -110,7 +110,7 @@ impl Encodable for RejectReason {
} }
impl Decodable for RejectReason { impl Decodable for RejectReason {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(match r.read_u8()? { Ok(match r.read_u8()? {
0x01 => RejectReason::Malformed, 0x01 => RejectReason::Malformed,
0x10 => RejectReason::Invalid, 0x10 => RejectReason::Invalid,

View File

@ -25,7 +25,7 @@ use core::{fmt, ops};
use hex::FromHex; use hex::FromHex;
use internals::{debug_from_display, write_err}; use internals::{debug_from_display, write_err};
use io::{Read, Write}; use io::{BufRead, Write};
use crate::consensus::encode::{self, Decodable, Encodable}; use crate::consensus::encode::{self, Decodable, Encodable};
use crate::prelude::{Borrow, BorrowMut, String, ToOwned}; use crate::prelude::{Borrow, BorrowMut, String, ToOwned};
@ -198,7 +198,7 @@ impl Encodable for ServiceFlags {
impl Decodable for ServiceFlags { impl Decodable for ServiceFlags {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ServiceFlags(Decodable::consensus_decode(r)?)) Ok(ServiceFlags(Decodable::consensus_decode(r)?))
} }
} }
@ -290,7 +290,7 @@ impl Encodable for Magic {
} }
impl Decodable for Magic { impl Decodable for Magic {
fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
Ok(Magic(Decodable::consensus_decode(reader)?)) Ok(Magic(Decodable::consensus_decode(reader)?))
} }
} }

View File

@ -9,7 +9,7 @@
use core::fmt::{self, LowerHex, UpperHex}; use core::fmt::{self, LowerHex, UpperHex};
use core::ops::{Add, Div, Mul, Not, Rem, Shl, Shr, Sub}; use core::ops::{Add, Div, Mul, Not, Rem, Shl, Shr, Sub};
use io::{Read, Write}; use io::{BufRead, Write};
#[cfg(all(test, mutate))] #[cfg(all(test, mutate))]
use mutagen::mutate; use mutagen::mutate;
@ -301,7 +301,7 @@ impl Encodable for CompactTarget {
impl Decodable for CompactTarget { impl Decodable for CompactTarget {
#[inline] #[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
u32::consensus_decode(r).map(CompactTarget) u32::consensus_decode(r).map(CompactTarget)
} }
} }

View File

@ -56,7 +56,7 @@ macro_rules! impl_psbtmap_deserialize {
macro_rules! impl_psbtmap_decoding { macro_rules! impl_psbtmap_decoding {
($thing:ty) => { ($thing:ty) => {
impl $thing { impl $thing {
pub(crate) fn decode<R: $crate::io::Read + ?Sized>( pub(crate) fn decode<R: $crate::io::BufRead + ?Sized>(
r: &mut R, r: &mut R,
) -> Result<Self, $crate::psbt::Error> { ) -> Result<Self, $crate::psbt::Error> {
let mut rv: Self = core::default::Default::default(); let mut rv: Self = core::default::Default::default();

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
use io::{Cursor, Read}; use io::{Cursor, BufRead, Read};
use crate::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpub}; use crate::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpub};
use crate::blockdata::transaction::Transaction; use crate::blockdata::transaction::Transaction;
@ -70,7 +70,7 @@ impl Map for Psbt {
} }
impl Psbt { impl Psbt {
pub(crate) fn decode_global<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { pub(crate) fn decode_global<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut r = r.take(MAX_VEC_SIZE as u64); let mut r = r.take(MAX_VEC_SIZE as u64);
let mut tx: Option<Transaction> = None; let mut tx: Option<Transaction> = None;
let mut version: Option<u32> = None; let mut version: Option<u32> = None;

View File

@ -8,7 +8,7 @@
use core::fmt; use core::fmt;
use io::{Read, Write}; use io::{BufRead, Read, Write};
use super::serialize::{Deserialize, Serialize}; use super::serialize::{Deserialize, Serialize};
use crate::consensus::encode::{ use crate::consensus::encode::{
@ -74,7 +74,7 @@ impl fmt::Display for Key {
} }
impl Key { impl Key {
pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let VarInt(byte_size): VarInt = Decodable::consensus_decode(r)?; let VarInt(byte_size): VarInt = Decodable::consensus_decode(r)?;
if byte_size == 0 { if byte_size == 0 {
@ -137,7 +137,7 @@ impl Deserialize for Pair {
} }
impl Pair { impl Pair {
pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> { pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? }) Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? })
} }
} }
@ -159,7 +159,7 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype>
where where
Subtype: Copy + From<u8> + Into<u8>, Subtype: Copy + From<u8> + Into<u8>,
{ {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let prefix = Vec::<u8>::consensus_decode(r)?; let prefix = Vec::<u8>::consensus_decode(r)?;
let subtype = Subtype::from(r.read_u8()?); let subtype = Subtype::from(r.read_u8()?);
let key = read_to_end(r)?; let key = read_to_end(r)?;