[2.x.x] deserialization now protocol version aware (#2824)
* introduce protocol version to deserialize and read * thread protocol version through our reader * example protocol version access in kernel read * fix our StreamingReader impl (WouldBlock woes) * debug log progress of txhashset download
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
use crate::core::hash::Hash;
|
||||
use crate::core::pmmr;
|
||||
use crate::ser;
|
||||
use crate::ser::{PMMRIndexHashable, Readable, Reader, Writeable, Writer};
|
||||
use crate::ser::{PMMRIndexHashable, ProtocolVersion, Readable, Reader, Writeable, Writer};
|
||||
use crate::util;
|
||||
|
||||
/// Merkle proof errors.
|
||||
@@ -85,7 +85,7 @@ impl MerkleProof {
|
||||
/// Convert hex string representation back to a Merkle proof instance
|
||||
pub fn from_hex(hex: &str) -> Result<MerkleProof, String> {
|
||||
let bytes = util::from_hex(hex.to_string()).unwrap();
|
||||
let res = ser::deserialize(&mut &bytes[..])
|
||||
let res = ser::deserialize(&mut &bytes[..], ProtocolVersion::default())
|
||||
.map_err(|_| "failed to deserialize a Merkle Proof".to_string())?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
@@ -202,6 +202,12 @@ impl Writeable for TxKernel {
|
||||
|
||||
impl Readable for TxKernel {
|
||||
fn read(reader: &mut dyn Reader) -> Result<TxKernel, ser::Error> {
|
||||
// We have access to the protocol version here.
|
||||
// This may be a protocol version based on a peer connection
|
||||
// or the version used locally for db storage.
|
||||
// We can handle version specific deserialization here.
|
||||
let _version = reader.protocol_version();
|
||||
|
||||
Ok(TxKernel {
|
||||
features: KernelFeatures::read(reader)?,
|
||||
fee: reader.read_u64()?,
|
||||
@@ -338,7 +344,7 @@ impl Writeable for TxKernelEntry {
|
||||
}
|
||||
|
||||
impl Readable for TxKernelEntry {
|
||||
fn read(reader: &mut Reader) -> Result<TxKernelEntry, ser::Error> {
|
||||
fn read(reader: &mut dyn Reader) -> Result<TxKernelEntry, ser::Error> {
|
||||
let kernel = TxKernel::read(reader)?;
|
||||
Ok(TxKernelEntry { kernel })
|
||||
}
|
||||
@@ -1523,7 +1529,7 @@ mod test {
|
||||
|
||||
let mut vec = vec![];
|
||||
ser::serialize(&mut vec, &kernel).expect("serialized failed");
|
||||
let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap();
|
||||
let kernel2: TxKernel = ser::deserialize_default(&mut &vec[..]).unwrap();
|
||||
assert_eq!(kernel2.features, KernelFeatures::Plain);
|
||||
assert_eq!(kernel2.lock_height, 0);
|
||||
assert_eq!(kernel2.excess, commit);
|
||||
@@ -1541,7 +1547,7 @@ mod test {
|
||||
|
||||
let mut vec = vec![];
|
||||
ser::serialize(&mut vec, &kernel).expect("serialized failed");
|
||||
let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap();
|
||||
let kernel2: TxKernel = ser::deserialize_default(&mut &vec[..]).unwrap();
|
||||
assert_eq!(kernel2.features, KernelFeatures::HeightLocked);
|
||||
assert_eq!(kernel2.lock_height, 100);
|
||||
assert_eq!(kernel2.excess, commit);
|
||||
|
||||
+91
-5
@@ -31,11 +31,11 @@ use crate::util::secp::pedersen::{Commitment, RangeProof};
|
||||
use crate::util::secp::Signature;
|
||||
use crate::util::secp::{ContextFlag, Secp256k1};
|
||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::marker;
|
||||
use std::time::Duration;
|
||||
use std::{cmp, error, fmt};
|
||||
use std::{cmp, error};
|
||||
|
||||
/// Possible errors deriving from serializing or deserializing.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||
@@ -209,6 +209,9 @@ pub trait Reader {
|
||||
/// Consumes a byte from the reader, producing an error if it doesn't have
|
||||
/// the expected value
|
||||
fn expect_u8(&mut self, val: u8) -> Result<u8, Error>;
|
||||
/// Access to underlying protocol version to support
|
||||
/// version specific deserialization logic.
|
||||
fn protocol_version(&self) -> ProtocolVersion;
|
||||
}
|
||||
|
||||
/// Trait that every type that can be serialized as binary must implement.
|
||||
@@ -275,6 +278,54 @@ where
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Protocol version for serialization/deserialization.
|
||||
/// Note: This is used in various places including but limited to
|
||||
/// the p2p layer and our local db storage layer.
|
||||
/// We may speak multiple versions to various peers and a potentially *different*
|
||||
/// version for our local db.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialOrd, PartialEq, Serialize)]
|
||||
pub struct ProtocolVersion(pub u32);
|
||||
|
||||
impl Default for ProtocolVersion {
|
||||
fn default() -> ProtocolVersion {
|
||||
ProtocolVersion(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ProtocolVersion {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolVersion {
|
||||
/// We need to specify a protocol version for our local database.
|
||||
/// Regardless of specific version used when sending/receiving data between peers
|
||||
/// we need to take care with serialization/deserialization of data locally in the db.
|
||||
pub fn local_db() -> ProtocolVersion {
|
||||
ProtocolVersion(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProtocolVersion> for u32 {
|
||||
fn from(v: ProtocolVersion) -> u32 {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for ProtocolVersion {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
writer.write_u32(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for ProtocolVersion {
|
||||
fn read(reader: &mut dyn Reader) -> Result<ProtocolVersion, Error> {
|
||||
let version = reader.read_u32()?;
|
||||
Ok(ProtocolVersion(version))
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait that every type that can be deserialized from binary must implement.
|
||||
/// Reads directly to a Reader, a utility type thinly wrapping an
|
||||
/// underlying Read implementation.
|
||||
@@ -287,11 +338,24 @@ where
|
||||
}
|
||||
|
||||
/// Deserializes a Readable from any std::io::Read implementation.
|
||||
pub fn deserialize<T: Readable>(source: &mut dyn Read) -> Result<T, Error> {
|
||||
let mut reader = BinReader { source };
|
||||
pub fn deserialize<T: Readable>(
|
||||
source: &mut dyn Read,
|
||||
version: ProtocolVersion,
|
||||
) -> Result<T, Error> {
|
||||
let mut reader = BinReader::new(source, version);
|
||||
T::read(&mut reader)
|
||||
}
|
||||
|
||||
/// Deserialize a Readable based on our local db version protocol.
|
||||
pub fn deserialize_db<T: Readable>(source: &mut dyn Read) -> Result<T, Error> {
|
||||
deserialize(source, ProtocolVersion::local_db())
|
||||
}
|
||||
|
||||
/// Deserialize a Readable based on our local "default" version protocol.
|
||||
pub fn deserialize_default<T: Readable>(source: &mut dyn Read) -> Result<T, Error> {
|
||||
deserialize(source, ProtocolVersion::default())
|
||||
}
|
||||
|
||||
/// Serializes a Writeable into any std::io::Write implementation.
|
||||
pub fn serialize<W: Writeable>(sink: &mut dyn Write, thing: &W) -> Result<(), Error> {
|
||||
let mut writer = BinWriter { sink };
|
||||
@@ -309,6 +373,14 @@ pub fn ser_vec<W: Writeable>(thing: &W) -> Result<Vec<u8>, Error> {
|
||||
/// Utility to read from a binary source
|
||||
pub struct BinReader<'a> {
|
||||
source: &'a mut dyn Read,
|
||||
version: ProtocolVersion,
|
||||
}
|
||||
|
||||
impl<'a> BinReader<'a> {
|
||||
/// Constructor for a new BinReader for the provided source and protocol version.
|
||||
pub fn new(source: &'a mut dyn Read, version: ProtocolVersion) -> BinReader<'a> {
|
||||
BinReader { source, version }
|
||||
}
|
||||
}
|
||||
|
||||
fn map_io_err(err: io::Error) -> Error {
|
||||
@@ -366,12 +438,17 @@ impl<'a> Reader for BinReader<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn protocol_version(&self) -> ProtocolVersion {
|
||||
self.version
|
||||
}
|
||||
}
|
||||
|
||||
/// A reader that reads straight off a stream.
|
||||
/// Tracks total bytes read so we can verify we read the right number afterwards.
|
||||
pub struct StreamingReader<'a> {
|
||||
total_bytes_read: u64,
|
||||
version: ProtocolVersion,
|
||||
stream: &'a mut dyn Read,
|
||||
timeout: Duration,
|
||||
}
|
||||
@@ -379,9 +456,14 @@ pub struct StreamingReader<'a> {
|
||||
impl<'a> StreamingReader<'a> {
|
||||
/// Create a new streaming reader with the provided underlying stream.
|
||||
/// Also takes a duration to be used for each individual read_exact call.
|
||||
pub fn new(stream: &'a mut dyn Read, timeout: Duration) -> StreamingReader<'a> {
|
||||
pub fn new(
|
||||
stream: &'a mut dyn Read,
|
||||
version: ProtocolVersion,
|
||||
timeout: Duration,
|
||||
) -> StreamingReader<'a> {
|
||||
StreamingReader {
|
||||
total_bytes_read: 0,
|
||||
version,
|
||||
stream,
|
||||
timeout,
|
||||
}
|
||||
@@ -450,6 +532,10 @@ impl<'a> Reader for StreamingReader<'a> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn protocol_version(&self) -> ProtocolVersion {
|
||||
self.version
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for Commitment {
|
||||
|
||||
Reference in New Issue
Block a user