Skip to content

Commit

Permalink
grin v5.3 (0020) PIBD segment p2p messages (mimblewimble#3496)
Browse files Browse the repository at this point in the history
* Define PIBD segment p2p messages

* Respond to segment requests

* Use specialized (de)ser for output bitmap segments

* Allowed segment height ranges in const
  • Loading branch information
bayk committed Jun 10, 2024
1 parent e5944df commit 7dc4125
Show file tree
Hide file tree
Showing 17 changed files with 1,158 additions and 346 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions chain/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ pub enum ErrorKind {
/// PIBD segment related error
#[fail(display = "Segment error")]
SegmentError(segment::SegmentError),
/// 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 {
Expand Down
1 change: 1 addition & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ siphasher = "0.3"
log = "0.4"
chrono = { version = "0.4.11", features = ["serde"] }
zeroize = { version = "1.1", features =["zeroize_derive"] }
bytes = "0.5"

keychain = { package = "grin_keychain", path = "../keychain", version = "4.4.2" }
util = { package = "grin_util", path = "../util", version = "4.4.2" }
Expand Down
50 changes: 49 additions & 1 deletion core/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::consensus::{
DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, MAX_BLOCK_WEIGHT, PROOFSIZE,
SECOND_POW_EDGE_BITS, STATE_SYNC_THRESHOLD,
};
use crate::pow::{self, new_cuckarood_ctx, new_cuckatoo_ctx, PoWContext};
use crate::pow::{self, new_cuckarood_ctx, new_cuckatoo_ctx, BitVec, PoWContext};
use crate::ser::ProtocolVersion;
use std::cell::Cell;
use std::sync::atomic::{AtomicBool, Ordering};
Expand Down Expand Up @@ -446,6 +446,54 @@ where
last_n
}

/// Calculates the size of a header (in bytes) given a number of edge bits in the PoW
#[inline]
pub fn header_size_bytes(edge_bits: u8) -> usize {
let size = 2 + 2 * 8 + 5 * 32 + 32 + 2 * 8;
let proof_size = 8 + 4 + 8 + 1 + BitVec::bytes_len(edge_bits as usize * proofsize());
size + proof_size
}

#[cfg(test)]
mod test {
use super::*;
use crate::core::Block;
use crate::genesis::*;
use crate::pow::mine_genesis_block;
use crate::ser::{BinWriter, Writeable};

fn test_header_len(genesis: Block) {
let mut raw = Vec::<u8>::with_capacity(1_024);
let mut writer = BinWriter::new(&mut raw, ProtocolVersion::local());
genesis.header.write(&mut writer).unwrap();
assert_eq!(raw.len(), header_size_bytes(genesis.header.pow.edge_bits()));
}

#[test]
fn automated_testing_header_len() {
set_local_chain_type(ChainTypes::AutomatedTesting);
test_header_len(mine_genesis_block().unwrap());
}

#[test]
fn user_testing_header_len() {
set_local_chain_type(ChainTypes::UserTesting);
test_header_len(mine_genesis_block().unwrap());
}

#[test]
fn floonet_header_len() {
set_local_chain_type(ChainTypes::Floonet);
test_header_len(genesis_floo());
}

#[test]
fn mainnet_header_len() {
set_local_chain_type(ChainTypes::Mainnet);
test_header_len(genesis_main());
}
}

/// Checking running status if the server
pub fn is_server_running() -> bool {
SERVER_RUNNING.load(Ordering::SeqCst)
Expand Down
6 changes: 4 additions & 2 deletions core/src/pow/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,15 +477,17 @@ impl Writeable for Proof {
}
}

/// A bit vector
// TODO this could likely be optimized by writing whole bytes (or even words)
// in the `BitVec` at once, dealing with the truncation, instead of bits by bits
struct BitVec {
pub struct BitVec {
bits: Vec<u8>,
}

impl BitVec {
/// Number of bytes required to store the provided number of bits
fn bytes_len(bits_len: usize) -> usize {
#[inline]
pub fn bytes_len(bits_len: usize) -> usize {
(bits_len + 7) / 8
}

Expand Down
113 changes: 113 additions & 0 deletions core/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use crate::core::hash::{DefaultHashable, Hash, Hashed};
use crate::global::PROTOCOL_VERSION;
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
use bytes::Buf;
use keychain::{BlindingFactor, Identifier, IDENTIFIER_SIZE};
use serde::__private::from_utf8_lossy;
use std::convert::TryInto;
Expand Down Expand Up @@ -109,6 +110,12 @@ impl From<io::Error> for Error {
}
}

impl From<io::ErrorKind> for Error {
fn from(e: io::ErrorKind) -> Error {
Error::IOErr(format!("{}", io::Error::from(e)), e)
}
}

impl From<util::secp::Error> for Error {
fn from(e: util::secp::Error) -> Error {
Error::SecpError(e)
Expand Down Expand Up @@ -583,6 +590,112 @@ impl<'a> Reader for StreamingReader<'a> {
}
}

/// Protocol version-aware wrapper around a `Buf` impl
pub struct BufReader<'a, B: Buf> {
inner: &'a mut B,
version: ProtocolVersion,
bytes_read: usize,
}

impl<'a, B: Buf> BufReader<'a, B> {
/// Construct a new BufReader
pub fn new(buf: &'a mut B, version: ProtocolVersion) -> Self {
Self {
inner: buf,
version,
bytes_read: 0,
}
}

/// Check whether the buffer has enough bytes remaining to perform a read
fn has_remaining(&mut self, len: usize) -> Result<(), Error> {
if self.inner.remaining() >= len {
self.bytes_read += len;
Ok(())
} else {
Err(io::ErrorKind::UnexpectedEof.into())
}
}

/// The total bytes read
pub fn bytes_read(&self) -> u64 {
self.bytes_read as u64
}

/// Convenience function to read from the buffer and deserialize
pub fn body<T: Readable>(&mut self) -> Result<T, Error> {
T::read(self)
}
}

impl<'a, B: Buf> Reader for BufReader<'a, B> {
fn read_u8(&mut self) -> Result<u8, Error> {
self.has_remaining(1)?;
Ok(self.inner.get_u8())
}

fn read_u16(&mut self) -> Result<u16, Error> {
self.has_remaining(2)?;
Ok(self.inner.get_u16())
}

fn read_u32(&mut self) -> Result<u32, Error> {
self.has_remaining(4)?;
Ok(self.inner.get_u32())
}

fn read_u64(&mut self) -> Result<u64, Error> {
self.has_remaining(8)?;
Ok(self.inner.get_u64())
}

fn read_i32(&mut self) -> Result<i32, Error> {
self.has_remaining(4)?;
Ok(self.inner.get_i32())
}

fn read_i64(&mut self) -> Result<i64, Error> {
self.has_remaining(8)?;
Ok(self.inner.get_i64())
}

fn read_bytes_len_prefix(&mut self) -> Result<Vec<u8>, Error> {
let len = self.read_u64()?;
self.read_fixed_bytes(len as usize)
}

fn read_fixed_bytes(&mut self, len: usize) -> Result<Vec<u8>, Error> {
// not reading more than 100k bytes in a single read
if len > 100_000 {
return Err(Error::TooLargeReadErr(format!(
"read unexpected large chunk of {} bytes",
len
)));
}
self.has_remaining(len)?;

let mut buf = vec![0; len];
self.inner.copy_to_slice(&mut buf[..]);
Ok(buf)
}

fn expect_u8(&mut self, val: u8) -> Result<u8, Error> {
let b = self.read_u8()?;
if b == val {
Ok(b)
} else {
Err(Error::UnexpectedData {
expected: vec![val],
received: vec![b],
})
}
}

fn protocol_version(&self) -> ProtocolVersion {
self.version
}
}

impl Readable for Commitment {
fn read<R: Reader>(reader: &mut R) -> Result<Commitment, Error> {
let a = reader.read_fixed_bytes(PEDERSEN_COMMITMENT_SIZE)?;
Expand Down
1 change: 1 addition & 0 deletions p2p/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ async-std = "1.9"
tokio = {version = "0.2", features = ["full"] }
ed25519-dalek = "1"
serde_json = "1"
bytes = "0.5"

grin_core = { path = "../core", version = "4.4.2" }
grin_store = { path = "../store", version = "4.4.2" }
Expand Down
Loading

0 comments on commit 7dc4125

Please sign in to comment.