From a109969a6bb1f75214ca98dc7417dbaac9eea602 Mon Sep 17 00:00:00 2001 From: Jasper van der Maarel Date: Sun, 22 Nov 2020 19:24:14 +0100 Subject: [PATCH 1/4] Define PIBD segment p2p messages --- p2p/src/codec.rs | 8 ++++ p2p/src/msg.rs | 110 +++++++++++++++++++++++++++++++++++++++++++- p2p/src/protocol.rs | 10 ++++ 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/p2p/src/codec.rs b/p2p/src/codec.rs index 9fd6043c43..293613f47f 100644 --- a/p2p/src/codec.rs +++ b/p2p/src/codec.rs @@ -237,6 +237,14 @@ fn decode_message( Type::PeerAddrs => Message::PeerAddrs(msg.body()?), Type::TxHashSetRequest => Message::TxHashSetRequest(msg.body()?), Type::TxHashSetArchive => Message::TxHashSetArchive(msg.body()?), + Type::GetOutputBitmapSegment => Message::GetOutputBitmapSegment(msg.body()?), + Type::OutputBitmapSegment => Message::OutputBitmapSegment(msg.body()?), + Type::GetOutputSegment => Message::GetOutputSegment(msg.body()?), + Type::OutputSegment => Message::OutputSegment(msg.body()?), + Type::GetRangeProofSegment => Message::GetRangeProofSegment(msg.body()?), + Type::RangeProofSegment => Message::RangeProofSegment(msg.body()?), + Type::GetKernelSegment => Message::GetKernelSegment(msg.body()?), + Type::KernelSegment => Message::KernelSegment(msg.body()?), Type::Error | Type::Hand | Type::Shake | Type::Headers => { return Err(Error::UnexpectedMessage) } diff --git a/p2p/src/msg.rs b/p2p/src/msg.rs index 796817ad0c..b658e70948 100644 --- a/p2p/src/msg.rs +++ b/p2p/src/msg.rs @@ -14,10 +14,13 @@ //! Message types that transit over the network and related serialization code. +use crate::chain::txhashset::BitmapChunk; use crate::conn::Tracker; use crate::core::core::hash::Hash; +use crate::core::core::transaction::{OutputIdentifier, TxKernel}; use crate::core::core::{ - BlockHeader, Transaction, UntrustedBlock, UntrustedBlockHeader, UntrustedCompactBlock, + BlockHeader, Segment, SegmentIdentifier, Transaction, UntrustedBlock, UntrustedBlockHeader, + UntrustedCompactBlock, }; use crate::core::pow::Difficulty; use crate::core::ser::{ @@ -28,6 +31,7 @@ use crate::types::{ AttachmentMeta, AttachmentUpdate, Capabilities, Error, PeerAddr, ReasonForBan, MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS, }; +use crate::util::secp::pedersen::RangeProof; use bytes::Bytes; use num::FromPrimitive; use std::fmt; @@ -70,6 +74,14 @@ enum_from_primitive! { BanReason = 18, GetTransaction = 19, TransactionKernel = 20, + GetOutputBitmapSegment = 21, + OutputBitmapSegment = 22, + GetOutputSegment = 23, + OutputSegment = 24, + GetRangeProofSegment = 25, + RangeProofSegment = 26, + GetKernelSegment = 27, + KernelSegment = 28, } } @@ -107,6 +119,14 @@ fn max_msg_size(msg_type: Type) -> u64 { Type::BanReason => 64, Type::GetTransaction => 32, Type::TransactionKernel => 32, + Type::GetOutputBitmapSegment => 41, + Type::OutputBitmapSegment => 2 * max_block_size(), + Type::GetOutputSegment => 41, + Type::OutputSegment => 2 * max_block_size(), + Type::GetRangeProofSegment => 41, + Type::RangeProofSegment => 2 * max_block_size(), + Type::GetKernelSegment => 41, + Type::KernelSegment => 2 * max_block_size(), } } @@ -710,6 +730,78 @@ impl Readable for TxHashSetArchive { } } +/// Request to get a segment of a (P)MMR at a particular block. +pub struct SegmentRequest { + /// The hash of the block the MMR is associated with + pub block_hash: Hash, + /// The identifier of the requested segment + pub identifier: SegmentIdentifier, +} + +impl Readable for SegmentRequest { + fn read(reader: &mut R) -> Result { + let block_hash = Readable::read(reader)?; + let identifier = Readable::read(reader)?; + Ok(Self { + block_hash, + identifier, + }) + } +} + +impl Writeable for SegmentRequest { + fn write(&self, writer: &mut W) -> Result<(), ser::Error> { + Writeable::write(&self.block_hash, writer)?; + Writeable::write(&self.identifier, writer) + } +} + +/// Response to a (P)MMR segment request. +pub struct SegmentResponse { + /// The hash of the block the MMR is associated with + pub block_hash: Hash, + /// The MMR segment + pub segment: Segment, +} + +impl Readable for SegmentResponse { + fn read(reader: &mut R) -> Result { + let block_hash = Readable::read(reader)?; + let segment = Readable::read(reader)?; + Ok(Self { + block_hash, + segment, + }) + } +} + +impl Writeable for SegmentResponse { + fn write(&self, writer: &mut W) -> Result<(), ser::Error> { + Writeable::write(&self.block_hash, writer)?; + Writeable::write(&self.segment, writer) + } +} + +pub struct SegmentResponseWithRoot { + pub response: SegmentResponse, + pub root: Hash, +} + +impl Readable for SegmentResponseWithRoot { + fn read(reader: &mut R) -> Result { + let response = Readable::read(reader)?; + let root = Readable::read(reader)?; + Ok(Self { response, root }) + } +} + +impl Writeable for SegmentResponseWithRoot { + fn write(&self, writer: &mut W) -> Result<(), ser::Error> { + Writeable::write(&self.response, writer)?; + Writeable::write(&self.root, writer) + } +} + pub enum Message { Unknown(u8), Ping(Ping), @@ -731,6 +823,14 @@ pub enum Message { TxHashSetRequest(TxHashSetRequest), TxHashSetArchive(TxHashSetArchive), Attachment(AttachmentUpdate, Option), + GetOutputBitmapSegment(SegmentRequest), + OutputBitmapSegment(SegmentResponseWithRoot), + GetOutputSegment(SegmentRequest), + OutputSegment(SegmentResponseWithRoot), + GetRangeProofSegment(SegmentRequest), + RangeProofSegment(SegmentResponse), + GetKernelSegment(SegmentRequest), + KernelSegment(SegmentResponse), } impl fmt::Display for Message { @@ -756,6 +856,14 @@ impl fmt::Display for Message { Message::TxHashSetRequest(_) => write!(f, "tx hash set request"), Message::TxHashSetArchive(_) => write!(f, "tx hash set"), Message::Attachment(_, _) => write!(f, "attachment"), + Message::GetOutputBitmapSegment(_) => write!(f, "get output bitmap segment"), + Message::OutputBitmapSegment(_) => write!(f, "output bitmap segment"), + Message::GetOutputSegment(_) => write!(f, "get output segment"), + Message::OutputSegment(_) => write!(f, "output segment"), + Message::GetRangeProofSegment(_) => write!(f, "get range proof segment"), + Message::RangeProofSegment(_) => write!(f, "range proof segment"), + Message::GetKernelSegment(_) => write!(f, "get kernel segment"), + Message::KernelSegment(_) => write!(f, "kernel segment"), } } } diff --git a/p2p/src/protocol.rs b/p2p/src/protocol.rs index 15f869497d..7d77d93662 100644 --- a/p2p/src/protocol.rs +++ b/p2p/src/protocol.rs @@ -287,6 +287,16 @@ impl MessageHandler for Protocol { Consumed::Attachment(Arc::new(meta), file) } + + Message::GetOutputBitmapSegment(_) + | Message::OutputBitmapSegment(_) + | Message::GetOutputSegment(_) + | Message::OutputSegment(_) + | Message::GetRangeProofSegment(_) + | Message::RangeProofSegment(_) + | Message::GetKernelSegment(_) + | Message::KernelSegment(_) => Consumed::None, + Message::Unknown(_) => Consumed::None, }; Ok(consumed) From 87df71835e1fb1105134c3669f61834630c927c6 Mon Sep 17 00:00:00 2001 From: Jasper van der Maarel Date: Sun, 22 Nov 2020 20:48:24 +0100 Subject: [PATCH 2/4] Respond to segment requests --- chain/src/chain.rs | 7 ++- chain/src/error.rs | 6 +++ chain/src/txhashset.rs | 2 + chain/src/txhashset/segmenter.rs | 47 +++++++++++++++++ p2p/src/peer.rs | 35 ++++++++++++ p2p/src/peers.rs | 35 ++++++++++++ p2p/src/protocol.rs | 91 +++++++++++++++++++++++++++++--- p2p/src/serv.rs | 35 ++++++++++++ p2p/src/types.rs | 27 ++++++++++ servers/src/common/adapters.rs | 67 ++++++++++++++++++++++- 10 files changed, 344 insertions(+), 8 deletions(-) create mode 100644 chain/src/txhashset/segmenter.rs diff --git a/chain/src/chain.rs b/chain/src/chain.rs index cd0d14e0ea..c3799427d5 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -29,7 +29,7 @@ use crate::error::{Error, ErrorKind}; use crate::pipe; use crate::store; use crate::txhashset; -use crate::txhashset::{PMMRHandle, TxHashSet}; +use crate::txhashset::{PMMRHandle, Segmenter, TxHashSet}; use crate::types::{ BlockStatus, ChainAdapter, CommitPos, NoStatus, Options, Tip, TxHashsetWriteStatus, }; @@ -815,6 +815,11 @@ impl Chain { }) } + /// PLACEHOLDER + pub fn segmenter(&self) -> Result { + Ok(Segmenter::new()) + } + /// To support the ability to download the txhashset from multiple peers in parallel, /// the peers must all agree on the exact binary representation of the txhashset. /// This means compacting and rewinding to the exact same header. diff --git a/chain/src/error.rs b/chain/src/error.rs index d4d7dba529..56e8948a7b 100644 --- a/chain/src/error.rs +++ b/chain/src/error.rs @@ -149,6 +149,12 @@ pub enum ErrorKind { /// Error during chain sync #[fail(display = "Sync error")] SyncError(String), + /// The segmenter is associated to a different block header + #[fail(display = "Segmenter header mismatch")] + SegmenterHeaderMismatch, + /// Segment height not within allowed range + #[fail(display = "Invalid segment height")] + InvalidSegmentHeight, } impl Display for Error { diff --git a/chain/src/txhashset.rs b/chain/src/txhashset.rs index 094df1cb96..1926d7d79a 100644 --- a/chain/src/txhashset.rs +++ b/chain/src/txhashset.rs @@ -17,10 +17,12 @@ mod bitmap_accumulator; mod rewindable_kernel_view; +mod segmenter; mod txhashset; mod utxo_view; pub use self::bitmap_accumulator::*; pub use self::rewindable_kernel_view::*; +pub use self::segmenter::*; pub use self::txhashset::*; pub use self::utxo_view::*; diff --git a/chain/src/txhashset/segmenter.rs b/chain/src/txhashset/segmenter.rs new file mode 100644 index 0000000000..614c3042aa --- /dev/null +++ b/chain/src/txhashset/segmenter.rs @@ -0,0 +1,47 @@ +use crate::core::core::hash::Hash; +use crate::core::core::{BlockHeader, OutputIdentifier, Segment, SegmentIdentifier, TxKernel}; +use crate::error::Error; +use crate::txhashset::BitmapChunk; +use crate::util::secp::pedersen::RangeProof; + +/// PLACEHOLDER +#[derive(Clone)] +pub struct Segmenter {} + +impl Segmenter { + /// PLACEHOLDER + pub fn new() -> Segmenter { + Segmenter {} + } + + /// PLACEHOLDER + pub fn header(&self) -> &BlockHeader { + unimplemented!() + } + + /// PLACEHOLDER + pub fn kernel_segment(&self, _id: SegmentIdentifier) -> Result, Error> { + unimplemented!() + } + + /// PLACEHOLDER + pub fn bitmap_segment( + &self, + _id: SegmentIdentifier, + ) -> Result<(Segment, Hash), Error> { + unimplemented!() + } + + /// PLACEHOLDER + pub fn output_segment( + &self, + _id: SegmentIdentifier, + ) -> Result<(Segment, Hash), Error> { + unimplemented!() + } + + /// PLACEHOLDER + pub fn rangeproof_segment(&self, _id: SegmentIdentifier) -> Result, Error> { + unimplemented!() + } +} diff --git a/p2p/src/peer.rs b/p2p/src/peer.rs index 6907a85274..617a9172b2 100644 --- a/p2p/src/peer.rs +++ b/p2p/src/peer.rs @@ -23,8 +23,10 @@ use std::sync::Arc; use lru_cache::LruCache; use crate::chain; +use crate::chain::txhashset::BitmapChunk; use crate::conn; use crate::core::core::hash::{Hash, Hashed}; +use crate::core::core::{OutputIdentifier, Segment, SegmentIdentifier, TxKernel}; use crate::core::pow::Difficulty; use crate::core::ser::Writeable; use crate::core::{core, global}; @@ -35,6 +37,7 @@ use crate::types::{ Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan, TxHashSetRead, }; +use crate::util::secp::pedersen::RangeProof; use chrono::prelude::{DateTime, Utc}; const MAX_TRACK_SIZE: usize = 30; @@ -565,6 +568,38 @@ impl ChainAdapter for TrackingAdapter { fn get_tmpfile_pathname(&self, tmpfile_name: String) -> PathBuf { self.adapter.get_tmpfile_pathname(tmpfile_name) } + + fn get_kernel_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error> { + self.adapter.get_kernel_segment(hash, id) + } + + fn get_bitmap_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + self.adapter.get_bitmap_segment(hash, id) + } + + fn get_output_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + self.adapter.get_output_segment(hash, id) + } + + fn get_rangeproof_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error> { + self.adapter.get_rangeproof_segment(hash, id) + } } impl NetAdapter for TrackingAdapter { diff --git a/p2p/src/peers.rs b/p2p/src/peers.rs index 9c6dd2c59d..520a7c356f 100644 --- a/p2p/src/peers.rs +++ b/p2p/src/peers.rs @@ -21,8 +21,10 @@ use std::sync::Arc; use rand::prelude::*; use crate::chain; +use crate::chain::txhashset::BitmapChunk; use crate::core::core; use crate::core::core::hash::{Hash, Hashed}; +use crate::core::core::{OutputIdentifier, Segment, SegmentIdentifier, TxKernel}; use crate::core::global; use crate::core::pow::Difficulty; use crate::peer::Peer; @@ -31,6 +33,7 @@ use crate::types::{ Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan, TxHashSetRead, MAX_PEER_ADDRS, }; +use crate::util::secp::pedersen::RangeProof; use chrono::prelude::*; use chrono::Duration; @@ -625,6 +628,38 @@ impl ChainAdapter for Peers { fn get_tmpfile_pathname(&self, tmpfile_name: String) -> PathBuf { self.adapter.get_tmpfile_pathname(tmpfile_name) } + + fn get_kernel_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error> { + self.adapter.get_kernel_segment(hash, id) + } + + fn get_bitmap_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + self.adapter.get_bitmap_segment(hash, id) + } + + fn get_output_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + self.adapter.get_output_segment(hash, id) + } + + fn get_rangeproof_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error> { + self.adapter.get_rangeproof_segment(hash, id) + } } impl NetAdapter for Peers { diff --git a/p2p/src/protocol.rs b/p2p/src/protocol.rs index 7d77d93662..d6903c24cd 100644 --- a/p2p/src/protocol.rs +++ b/p2p/src/protocol.rs @@ -16,7 +16,10 @@ use crate::chain; use crate::conn::MessageHandler; use crate::core::core::{hash::Hashed, CompactBlock}; -use crate::msg::{Consumed, Headers, Message, Msg, PeerAddrs, Pong, TxHashSetArchive, Type}; +use crate::msg::{ + Consumed, Headers, Message, Msg, PeerAddrs, Pong, SegmentRequest, SegmentResponse, + SegmentResponseWithRoot, TxHashSetArchive, Type, +}; use crate::types::{AttachmentMeta, Error, NetAdapter, PeerInfo}; use chrono::prelude::Utc; use rand::{thread_rng, Rng}; @@ -288,13 +291,89 @@ impl MessageHandler for Protocol { Consumed::Attachment(Arc::new(meta), file) } - Message::GetOutputBitmapSegment(_) - | Message::OutputBitmapSegment(_) - | Message::GetOutputSegment(_) + Message::GetOutputBitmapSegment(req) => { + let SegmentRequest { + block_hash, + identifier, + } = req; + if let Ok((segment, root)) = self.adapter.get_bitmap_segment(block_hash, identifier) + { + Consumed::Response(Msg::new( + Type::OutputBitmapSegment, + SegmentResponseWithRoot { + response: SegmentResponse { + block_hash, + segment, + }, + root, + }, + self.peer_info.version, + )?) + } else { + Consumed::None + } + } + Message::GetOutputSegment(req) => { + let SegmentRequest { + block_hash, + identifier, + } = req; + if let Ok((segment, root)) = self.adapter.get_output_segment(block_hash, identifier) + { + Consumed::Response(Msg::new( + Type::OutputSegment, + SegmentResponseWithRoot { + response: SegmentResponse { + block_hash, + segment, + }, + root, + }, + self.peer_info.version, + )?) + } else { + Consumed::None + } + } + Message::GetRangeProofSegment(req) => { + let SegmentRequest { + block_hash, + identifier, + } = req; + if let Ok(segment) = self.adapter.get_rangeproof_segment(block_hash, identifier) { + Consumed::Response(Msg::new( + Type::RangeProofSegment, + SegmentResponse { + block_hash, + segment, + }, + self.peer_info.version, + )?) + } else { + Consumed::None + } + } + Message::GetKernelSegment(req) => { + let SegmentRequest { + block_hash, + identifier, + } = req; + if let Ok(segment) = self.adapter.get_kernel_segment(block_hash, identifier) { + Consumed::Response(Msg::new( + Type::KernelSegment, + SegmentResponse { + block_hash, + segment, + }, + self.peer_info.version, + )?) + } else { + Consumed::None + } + } + Message::OutputBitmapSegment(_) | Message::OutputSegment(_) - | Message::GetRangeProofSegment(_) | Message::RangeProofSegment(_) - | Message::GetKernelSegment(_) | Message::KernelSegment(_) => Consumed::None, Message::Unknown(_) => Consumed::None, diff --git a/p2p/src/serv.rs b/p2p/src/serv.rs index 19fcab93b4..d4714b09d1 100644 --- a/p2p/src/serv.rs +++ b/p2p/src/serv.rs @@ -21,8 +21,10 @@ use std::thread; use std::time::Duration; use crate::chain; +use crate::chain::txhashset::BitmapChunk; use crate::core::core; use crate::core::core::hash::Hash; +use crate::core::core::{OutputIdentifier, Segment, SegmentIdentifier, TxKernel}; use crate::core::global; use crate::core::pow::Difficulty; use crate::handshake::Handshake; @@ -33,6 +35,7 @@ use crate::types::{ Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan, TxHashSetRead, }; +use crate::util::secp::pedersen::RangeProof; use crate::util::StopState; use chrono::prelude::{DateTime, Utc}; @@ -375,6 +378,38 @@ impl ChainAdapter for DummyAdapter { fn get_tmpfile_pathname(&self, _tmpfile_name: String) -> PathBuf { unimplemented!() } + + fn get_kernel_segment( + &self, + _hash: Hash, + _id: SegmentIdentifier, + ) -> Result, chain::Error> { + unimplemented!() + } + + fn get_bitmap_segment( + &self, + _hash: Hash, + _id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + unimplemented!() + } + + fn get_output_segment( + &self, + _hash: Hash, + _id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + unimplemented!() + } + + fn get_rangeproof_segment( + &self, + _hash: Hash, + _id: SegmentIdentifier, + ) -> Result, chain::Error> { + unimplemented!() + } } impl NetAdapter for DummyAdapter { diff --git a/p2p/src/types.rs b/p2p/src/types.rs index faf2d1dfeb..476a954e1d 100644 --- a/p2p/src/types.rs +++ b/p2p/src/types.rs @@ -28,12 +28,15 @@ use serde::{Deserialize, Deserializer}; use grin_store; use crate::chain; +use crate::chain::txhashset::BitmapChunk; use crate::core::core; use crate::core::core::hash::Hash; +use crate::core::core::{OutputIdentifier, Segment, SegmentIdentifier, TxKernel}; use crate::core::global; use crate::core::pow::Difficulty; use crate::core::ser::{self, ProtocolVersion, Readable, Reader, Writeable, Writer}; use crate::msg::PeerAddrs; +use crate::util::secp::pedersen::RangeProof; use crate::util::RwLock; /// Maximum number of block headers a peer should ever send @@ -642,6 +645,30 @@ pub trait ChainAdapter: Sync + Send { /// Get a tmp file path in above specific tmp dir (create tmp dir if not exist) /// Delete file if tmp file already exists fn get_tmpfile_pathname(&self, tmpfile_name: String) -> PathBuf; + + fn get_kernel_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error>; + + fn get_bitmap_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error>; + + fn get_output_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error>; + + fn get_rangeproof_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error>; } /// Additional methods required by the protocol that don't need to be diff --git a/servers/src/common/adapters.rs b/servers/src/common/adapters.rs index e9b51ed686..8be95a85b1 100644 --- a/servers/src/common/adapters.rs +++ b/servers/src/common/adapters.rs @@ -22,6 +22,7 @@ use std::sync::{Arc, Weak}; use std::thread; use std::time::Instant; +use crate::chain::txhashset::BitmapChunk; use crate::chain::{ self, BlockStatus, ChainAdapter, Options, SyncState, SyncStatus, TxHashsetDownloadStats, }; @@ -30,13 +31,17 @@ use crate::common::types::{ChainValidationMode, DandelionEpoch, ServerConfig}; use crate::core::core::hash::{Hash, Hashed}; use crate::core::core::transaction::Transaction; use crate::core::core::verifier_cache::VerifierCache; -use crate::core::core::{BlockHeader, BlockSums, CompactBlock, Inputs, OutputIdentifier}; +use crate::core::core::{ + BlockHeader, BlockSums, CompactBlock, Inputs, OutputIdentifier, Segment, SegmentIdentifier, + TxKernel, +}; use crate::core::pow::Difficulty; use crate::core::ser::ProtocolVersion; use crate::core::{core, global}; use crate::p2p; use crate::p2p::types::PeerInfo; use crate::pool::{self, BlockChain, PoolAdapter}; +use crate::util::secp::pedersen::RangeProof; use crate::util::OneTime; use chrono::prelude::*; use chrono::Duration; @@ -477,6 +482,66 @@ where fn get_tmpfile_pathname(&self, tmpfile_name: String) -> PathBuf { self.chain().get_tmpfile_pathname(tmpfile_name) } + + fn get_kernel_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error> { + if id.height < 9 || id.height > 13 { + return Err(chain::ErrorKind::InvalidSegmentHeight.into()); + } + let segmenter = self.chain().segmenter()?; + if segmenter.header().hash() != hash { + return Err(chain::ErrorKind::SegmenterHeaderMismatch.into()); + } + segmenter.kernel_segment(id) + } + + fn get_bitmap_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + if id.height < 9 || id.height > 13 { + return Err(chain::ErrorKind::InvalidSegmentHeight.into()); + } + let segmenter = self.chain().segmenter()?; + if segmenter.header().hash() != hash { + return Err(chain::ErrorKind::SegmenterHeaderMismatch.into()); + } + segmenter.bitmap_segment(id) + } + + fn get_output_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result<(Segment, Hash), chain::Error> { + if id.height < 11 || id.height > 15 { + return Err(chain::ErrorKind::InvalidSegmentHeight.into()); + } + let segmenter = self.chain().segmenter()?; + if segmenter.header().hash() != hash { + return Err(chain::ErrorKind::SegmenterHeaderMismatch.into()); + } + segmenter.output_segment(id) + } + + fn get_rangeproof_segment( + &self, + hash: Hash, + id: SegmentIdentifier, + ) -> Result, chain::Error> { + if id.height < 7 || id.height > 11 { + return Err(chain::ErrorKind::InvalidSegmentHeight.into()); + } + let segmenter = self.chain().segmenter()?; + if segmenter.header().hash() != hash { + return Err(chain::ErrorKind::SegmenterHeaderMismatch.into()); + } + segmenter.rangeproof_segment(id) + } } impl NetToChainAdapter From db1925c188fab722364df7e41b04c630929cd6c2 Mon Sep 17 00:00:00 2001 From: Jasper van der Maarel Date: Tue, 24 Nov 2020 15:37:57 +0100 Subject: [PATCH 3/4] Use specialized (de)ser for output bitmap segments --- p2p/src/msg.rs | 59 ++++++++++++++++++++++++++++++++++++--------- p2p/src/protocol.rs | 24 +++++++++--------- 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/p2p/src/msg.rs b/p2p/src/msg.rs index b658e70948..d0ac2e6597 100644 --- a/p2p/src/msg.rs +++ b/p2p/src/msg.rs @@ -14,7 +14,7 @@ //! Message types that transit over the network and related serialization code. -use crate::chain::txhashset::BitmapChunk; +use crate::chain::txhashset::BitmapSegment; use crate::conn::Tracker; use crate::core::core::hash::Hash; use crate::core::core::transaction::{OutputIdentifier, TxKernel}; @@ -782,23 +782,60 @@ impl Writeable for SegmentResponse { } } -pub struct SegmentResponseWithRoot { - pub response: SegmentResponse, - pub root: Hash, +/// Response to an output PMMR segment request. +pub struct OutputSegmentResponse { + /// The segment response + pub response: SegmentResponse, + /// The root hash of the output bitmap MMR + pub output_bitmap_root: Hash, } -impl Readable for SegmentResponseWithRoot { +impl Readable for OutputSegmentResponse { fn read(reader: &mut R) -> Result { let response = Readable::read(reader)?; - let root = Readable::read(reader)?; - Ok(Self { response, root }) + let output_bitmap_root = Readable::read(reader)?; + Ok(Self { + response, + output_bitmap_root, + }) } } -impl Writeable for SegmentResponseWithRoot { +impl Writeable for OutputSegmentResponse { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { Writeable::write(&self.response, writer)?; - Writeable::write(&self.root, writer) + Writeable::write(&self.output_bitmap_root, writer) + } +} + +/// Response to an output bitmap MMR segment request. +pub struct OutputBitmapSegmentResponse { + /// The hash of the block the MMR is associated with + pub block_hash: Hash, + /// The MMR segment + pub segment: BitmapSegment, + /// The root hash of the output PMMR + pub output_root: Hash, +} + +impl Readable for OutputBitmapSegmentResponse { + fn read(reader: &mut R) -> Result { + let block_hash = Readable::read(reader)?; + let segment = Readable::read(reader)?; + let output_root = Readable::read(reader)?; + Ok(Self { + block_hash, + segment, + output_root, + }) + } +} + +impl Writeable for OutputBitmapSegmentResponse { + fn write(&self, writer: &mut W) -> Result<(), ser::Error> { + Writeable::write(&self.block_hash, writer)?; + Writeable::write(&self.segment, writer)?; + Writeable::write(&self.output_root, writer) } } @@ -824,9 +861,9 @@ pub enum Message { TxHashSetArchive(TxHashSetArchive), Attachment(AttachmentUpdate, Option), GetOutputBitmapSegment(SegmentRequest), - OutputBitmapSegment(SegmentResponseWithRoot), + OutputBitmapSegment(OutputBitmapSegmentResponse), GetOutputSegment(SegmentRequest), - OutputSegment(SegmentResponseWithRoot), + OutputSegment(OutputSegmentResponse), GetRangeProofSegment(SegmentRequest), RangeProofSegment(SegmentResponse), GetKernelSegment(SegmentRequest), diff --git a/p2p/src/protocol.rs b/p2p/src/protocol.rs index d6903c24cd..0b35ec4a6e 100644 --- a/p2p/src/protocol.rs +++ b/p2p/src/protocol.rs @@ -17,8 +17,8 @@ use crate::conn::MessageHandler; use crate::core::core::{hash::Hashed, CompactBlock}; use crate::msg::{ - Consumed, Headers, Message, Msg, PeerAddrs, Pong, SegmentRequest, SegmentResponse, - SegmentResponseWithRoot, TxHashSetArchive, Type, + Consumed, Headers, Message, Msg, OutputBitmapSegmentResponse, OutputSegmentResponse, PeerAddrs, + Pong, SegmentRequest, SegmentResponse, TxHashSetArchive, Type, }; use crate::types::{AttachmentMeta, Error, NetAdapter, PeerInfo}; use chrono::prelude::Utc; @@ -296,16 +296,15 @@ impl MessageHandler for Protocol { block_hash, identifier, } = req; - if let Ok((segment, root)) = self.adapter.get_bitmap_segment(block_hash, identifier) + if let Ok((segment, output_root)) = + self.adapter.get_bitmap_segment(block_hash, identifier) { Consumed::Response(Msg::new( Type::OutputBitmapSegment, - SegmentResponseWithRoot { - response: SegmentResponse { - block_hash, - segment, - }, - root, + OutputBitmapSegmentResponse { + block_hash, + segment: segment.into(), + output_root, }, self.peer_info.version, )?) @@ -318,16 +317,17 @@ impl MessageHandler for Protocol { block_hash, identifier, } = req; - if let Ok((segment, root)) = self.adapter.get_output_segment(block_hash, identifier) + if let Ok((segment, output_bitmap_root)) = + self.adapter.get_output_segment(block_hash, identifier) { Consumed::Response(Msg::new( Type::OutputSegment, - SegmentResponseWithRoot { + OutputSegmentResponse { response: SegmentResponse { block_hash, segment, }, - root, + output_bitmap_root, }, self.peer_info.version, )?) From 6160b313ff68aff1cc094d767b2c7b43d2216d3a Mon Sep 17 00:00:00 2001 From: Jasper van der Maarel Date: Wed, 25 Nov 2020 15:00:19 +0100 Subject: [PATCH 4/4] Allowed segment height ranges in const --- servers/src/common/adapters.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/servers/src/common/adapters.rs b/servers/src/common/adapters.rs index 8be95a85b1..726a9b7796 100644 --- a/servers/src/common/adapters.rs +++ b/servers/src/common/adapters.rs @@ -46,6 +46,12 @@ use crate::util::OneTime; use chrono::prelude::*; use chrono::Duration; use rand::prelude::*; +use std::ops::Range; + +const KERNEL_SEGMENT_HEIGHT_RANGE: Range = 9..14; +const BITMAP_SEGMENT_HEIGHT_RANGE: Range = 9..14; +const OUTPUT_SEGMENT_HEIGHT_RANGE: Range = 11..16; +const RANGEPROOF_SEGMENT_HEIGHT_RANGE: Range = 7..12; /// Implementation of the NetAdapter for the . Gets notified when new /// blocks and transactions are received and forwards to the chain and pool @@ -488,7 +494,7 @@ where hash: Hash, id: SegmentIdentifier, ) -> Result, chain::Error> { - if id.height < 9 || id.height > 13 { + if !KERNEL_SEGMENT_HEIGHT_RANGE.contains(&id.height) { return Err(chain::ErrorKind::InvalidSegmentHeight.into()); } let segmenter = self.chain().segmenter()?; @@ -503,7 +509,7 @@ where hash: Hash, id: SegmentIdentifier, ) -> Result<(Segment, Hash), chain::Error> { - if id.height < 9 || id.height > 13 { + if !BITMAP_SEGMENT_HEIGHT_RANGE.contains(&id.height) { return Err(chain::ErrorKind::InvalidSegmentHeight.into()); } let segmenter = self.chain().segmenter()?; @@ -518,7 +524,7 @@ where hash: Hash, id: SegmentIdentifier, ) -> Result<(Segment, Hash), chain::Error> { - if id.height < 11 || id.height > 15 { + if !OUTPUT_SEGMENT_HEIGHT_RANGE.contains(&id.height) { return Err(chain::ErrorKind::InvalidSegmentHeight.into()); } let segmenter = self.chain().segmenter()?; @@ -533,7 +539,7 @@ where hash: Hash, id: SegmentIdentifier, ) -> Result, chain::Error> { - if id.height < 7 || id.height > 11 { + if RANGEPROOF_SEGMENT_HEIGHT_RANGE.contains(&id.height) { return Err(chain::ErrorKind::InvalidSegmentHeight.into()); } let segmenter = self.chain().segmenter()?;