diff --git a/bin/reth/src/test_eth_chain/models.rs b/bin/reth/src/test_eth_chain/models.rs index 7ba4ef448..ccc20aaa7 100644 --- a/bin/reth/src/test_eth_chain/models.rs +++ b/bin/reth/src/test_eth_chain/models.rs @@ -80,7 +80,7 @@ impl From
for SealedHeader { base_fee_per_gas: value.base_fee_per_gas.map(|v| v.0.to::()), beneficiary: value.coinbase, difficulty: value.difficulty.0, - extra_data: value.extra_data.0, + extra_data: value.extra_data, gas_limit: value.gas_limit.0.to::(), gas_used: value.gas_used.0.to::(), mix_hash: value.mix_hash, diff --git a/bin/reth/src/util/chainspec.rs b/bin/reth/src/util/chainspec.rs index c0fc92cb6..c5f67f9ad 100644 --- a/bin/reth/src/util/chainspec.rs +++ b/bin/reth/src/util/chainspec.rs @@ -48,7 +48,7 @@ impl From for Header { gas_limit: genesis.gas_limit, difficulty: genesis.difficulty, nonce: genesis.nonce, - extra_data: genesis.extra_data.0, + extra_data: genesis.extra_data, state_root: genesis.state_root, timestamp: genesis.timestamp, mix_hash: genesis.mix_hash, diff --git a/crates/consensus/src/engine/mod.rs b/crates/consensus/src/engine/mod.rs index c3661dbc0..7b0780783 100644 --- a/crates/consensus/src/engine/mod.rs +++ b/crates/consensus/src/engine/mod.rs @@ -143,7 +143,7 @@ impl EthConsensusEngine< timestamp: payload.timestamp.as_u64(), mix_hash: payload.prev_randao, base_fee_per_gas: Some(payload.base_fee_per_gas.to::()), - extra_data: payload.extra_data.0, + extra_data: payload.extra_data, // Defaults ommers_hash: EMPTY_LIST_HASH, difficulty: Default::default(), @@ -372,7 +372,7 @@ mod tests { // Valid extra data let block_with_valid_extra_data = transform_block(block.clone(), |mut b| { - b.header.extra_data = BytesMut::zeroed(32).freeze(); + b.header.extra_data = BytesMut::zeroed(32).freeze().into(); b }); assert_matches!(engine.try_construct_block(block_with_valid_extra_data.into()), Ok(_)); @@ -380,7 +380,7 @@ mod tests { // Invalid extra data let block_with_invalid_extra_data: Bytes = BytesMut::zeroed(33).freeze(); let invalid_extra_data_block = transform_block(block.clone(), |mut b| { - b.header.extra_data = block_with_invalid_extra_data.clone(); + b.header.extra_data = block_with_invalid_extra_data.clone().into(); b }); assert_matches!( diff --git a/crates/net/common/src/bandwidth_meter.rs b/crates/net/common/src/bandwidth_meter.rs index e2fb62d05..6b4fd3668 100644 --- a/crates/net/common/src/bandwidth_meter.rs +++ b/crates/net/common/src/bandwidth_meter.rs @@ -194,15 +194,13 @@ mod tests { let actual_inbound = bandwidth_meter.total_inbound(); assert_eq!( actual_inbound, expected_inbound, - "Expected {} inbound bytes, but got {}", - expected_inbound, actual_inbound, + "Expected {expected_inbound} inbound bytes, but got {actual_inbound}", ); let actual_outbound = bandwidth_meter.total_outbound(); assert_eq!( actual_outbound, expected_outbound, - "Expected {} inbound bytes, but got {}", - expected_outbound, actual_outbound, + "Expected {expected_outbound} inbound bytes, but got {actual_outbound}", ); } diff --git a/crates/net/rpc-types/src/eth/engine.rs b/crates/net/rpc-types/src/eth/engine.rs index e14082231..32c73ddca 100644 --- a/crates/net/rpc-types/src/eth/engine.rs +++ b/crates/net/rpc-types/src/eth/engine.rs @@ -55,7 +55,7 @@ impl From for ExecutionPayload { gas_limit: value.gas_limit.into(), gas_used: value.gas_used.into(), timestamp: value.timestamp.into(), - extra_data: value.extra_data.clone().into(), + extra_data: value.extra_data.clone(), base_fee_per_gas: U256::from(value.base_fee_per_gas.unwrap_or_default()), block_hash: value.hash(), transactions, diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index ca24f52a2..54010dc36 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -45,7 +45,6 @@ serde = "1.0" serde_with = "2.1.0" thiserror = "1" sucds = "0.5.0" -arbitrary = { version = "1.1.7", features = ["derive"], optional = true } hex = "0.4" hex-literal = "0.3" modular-bitfield = "0.11.2" @@ -59,6 +58,10 @@ triehash = "0.8" plain_hasher = "0.2" hash-db = "0.15" +# optional +arbitrary = { version = "1.1.7", features = ["derive"], optional = true } +proptest = { version = "1.0", optional = true } + [dev-dependencies] arbitrary = { version = "1.1.7", features = ["derive"] } serde_json = "1.0" @@ -75,4 +78,4 @@ secp256k1 = "0.24.2" [features] default = [] -arbitrary = ["dep:arbitrary", "revm-interpreter/arbitrary"] \ No newline at end of file +arbitrary = ["dep:arbitrary", "dep:proptest", "revm-interpreter/arbitrary"] \ No newline at end of file diff --git a/crates/primitives/src/header.rs b/crates/primitives/src/header.rs index 4b56c8487..1b840bf01 100644 --- a/crates/primitives/src/header.rs +++ b/crates/primitives/src/header.rs @@ -1,7 +1,7 @@ use crate::{ keccak256, proofs::{EMPTY_LIST_HASH, EMPTY_ROOT}, - BlockHash, BlockNumber, Bloom, H160, H256, U256, + BlockHash, BlockNumber, Bloom, Bytes, H160, H256, U256, }; use bytes::{BufMut, BytesMut}; use ethers_core::types::H64; @@ -66,7 +66,7 @@ pub struct Header { pub base_fee_per_gas: Option, /// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or /// fewer; formally Hx. - pub extra_data: bytes::Bytes, + pub extra_data: Bytes, } impl Default for Header { @@ -355,12 +355,9 @@ impl From for bool { #[cfg(test)] mod tests { - use super::{Decodable, Encodable, Header, H256}; + use super::{Bytes, Decodable, Encodable, Header, H256}; use crate::{Address, U256}; - use ethers_core::{ - types::Bytes, - utils::hex::{self, FromHex}, - }; + use ethers_core::utils::hex::{self, FromHex}; use std::str::FromStr; @@ -374,7 +371,7 @@ mod tests { gas_limit: 0x115c_u64, gas_used: 0x15b3_u64, timestamp: 0x1a0a_u64, - extra_data: Bytes::from_str("7788").unwrap().0, + extra_data: Bytes::from_str("7788").unwrap(), ommers_hash: H256::zero(), state_root: H256::zero(), transactions_root: H256::zero(), @@ -406,7 +403,7 @@ mod tests { gas_limit: 0x016345785d8a0000_u64, gas_used: 0x015534_u64, timestamp: 0x079e, - extra_data: Bytes::from_str("42").unwrap().0, + extra_data: Bytes::from_str("42").unwrap(), mix_hash: H256::from_str("0000000000000000000000000000000000000000000000000000000000000000").unwrap(), nonce: 0, base_fee_per_gas: Some(0x036b_u64), @@ -424,7 +421,7 @@ mod tests { gas_limit: 0x115cu64, gas_used: 0x15b3u64, timestamp: 0x1a0au64, - extra_data: Bytes::from_str("7788").unwrap().0, + extra_data: Bytes::from_str("7788").unwrap(), ommers_hash: H256::zero(), state_root: H256::zero(), transactions_root: H256::zero(), diff --git a/crates/primitives/src/hex_bytes.rs b/crates/primitives/src/hex_bytes.rs index 4efac1664..be6a5323e 100644 --- a/crates/primitives/src/hex_bytes.rs +++ b/crates/primitives/src/hex_bytes.rs @@ -1,6 +1,7 @@ -use reth_codecs::{main_codec, Compact}; +use bytes::Buf; +use reth_codecs::Compact; use reth_rlp::{Decodable, DecodeError, Encodable}; -use serde::{Deserialize, Deserializer, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{ borrow::Borrow, clone::Clone, @@ -11,8 +12,7 @@ use std::{ use thiserror::Error; /// Wrapper type around Bytes to deserialize/serialize "0x" prefixed ethereum hex strings -#[main_codec] -#[derive(Clone, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[derive(Clone, Default, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] pub struct Bytes( #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub bytes::Bytes, @@ -86,6 +86,12 @@ impl<'a> IntoIterator for &'a Bytes { } } +impl From<&[u8]> for Bytes { + fn from(src: &[u8]) -> Self { + Self(bytes::Bytes::copy_from_slice(src)) + } +} + impl From for Bytes { fn from(src: bytes::Bytes) -> Self { Self(src) @@ -195,6 +201,39 @@ where .map_err(|e| serde::de::Error::custom(e.to_string())) } +impl Compact for Bytes { + fn to_compact(self, buf: &mut impl bytes::BufMut) -> usize { + let len = self.len(); + buf.put(self.0); + len + } + fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) { + (buf.copy_to_bytes(len).into(), buf) + } +} + +#[cfg(any(test, feature = "arbitrary"))] +use proptest::strategy::Strategy; +#[cfg(any(test, feature = "arbitrary"))] +impl proptest::prelude::Arbitrary for Bytes { + type Parameters = proptest::arbitrary::ParamsFor; + type Strategy = proptest::prelude::BoxedStrategy; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + proptest::collection::vec(proptest::arbitrary::any_with::(args), 0..1000) + .prop_map(move |vec| bytes::Bytes::from(vec).into()) + .boxed() + } +} + +#[cfg(any(test, feature = "arbitrary"))] +impl<'a> arbitrary::Arbitrary<'a> for Bytes { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + let size = u.int_in_range(0..=1000)?; + Ok(Self(bytes::Bytes::copy_from_slice(u.bytes(size)?))) + } +} + #[cfg(test)] mod tests { use super::*; @@ -318,4 +357,17 @@ mod tests { let wrong_b = bytes::Bytes::from("0123absd"); assert_ne!(wrong_b, b); } + + #[test] + fn arbitrary() { + proptest::proptest!(|(bytes: Bytes)| { + let mut buf = vec![]; + bytes.clone().to_compact(&mut buf); + + let (decoded, remaining_buf) = Bytes::from_compact(&buf, buf.len()); + + assert!(bytes == decoded); + assert!(remaining_buf.is_empty()); + }); + } }