diff --git a/Cargo.lock b/Cargo.lock index 17db222ed0..6805fd3864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3851,14 +3851,16 @@ dependencies = [ "bytes", "crc", "derive_more", - "ethbloom", "ethers-core", + "fixed-hash", "hash-db", "hex", "hex-literal", + "impl-serde", "modular-bitfield", "parity-scale-codec", "plain_hasher", + "proptest", "rand 0.8.5", "reth-codecs", "reth-rlp", diff --git a/crates/common/rlp/src/decode.rs b/crates/common/rlp/src/decode.rs index afc761c3fe..945f24beac 100644 --- a/crates/common/rlp/src/decode.rs +++ b/crates/common/rlp/src/decode.rs @@ -273,7 +273,6 @@ mod ethereum_types_support { fixed_hash_impl!(H256); fixed_hash_impl!(H512); fixed_hash_impl!(H520); - fixed_hash_impl!(Bloom); macro_rules! fixed_uint_impl { ($t:ty, $n_bytes:tt) => { diff --git a/crates/common/rlp/src/encode.rs b/crates/common/rlp/src/encode.rs index 23532cd62f..947a741977 100644 --- a/crates/common/rlp/src/encode.rs +++ b/crates/common/rlp/src/encode.rs @@ -265,7 +265,6 @@ mod ethereum_types_support { fixed_hash_impl!(H256); fixed_hash_impl!(H512); fixed_hash_impl!(H520); - fixed_hash_impl!(Bloom); macro_rules! fixed_uint_impl { ($t:ty, $n_bytes:tt) => { diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index f5f0b93dc1..ca24f52a29 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -23,7 +23,11 @@ revm-interpreter = { git = "https://github.com/bluealloy/revm", rev = "3a13c9c8a ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } parity-scale-codec = { version = "3.2.1", features = ["derive", "bytes"] } tiny-keccak = { version = "2.0", features = ["keccak"] } -ethbloom = { version = "0.13", features = ["codec"] } + +# Bloom +fixed-hash = { version = "0.8", default-features = false, features = [ + "rustc-hex", +] } # crypto secp256k1 = { version = "0.24.2", default-features = false, features = [ @@ -47,6 +51,7 @@ hex-literal = "0.3" modular-bitfield = "0.11.2" derive_more = "0.99" url = "2.3" +impl-serde = "0.4.0" # proof related triehash = "0.8" @@ -61,8 +66,13 @@ hex-literal = "0.3" test-fuzz = "3.0.4" rand = "0.8" revm-interpreter = { git = "https://github.com/bluealloy/revm", rev = "3a13c9c8a0cda728941f1b26db0beb1025744ea9", features = ["with-serde", "arbitrary"] } +proptest = { version = "1.0" } # necessary so we don't hit a "undeclared 'std'": # https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198 secp256k1 = "0.24.2" + +[features] +default = [] +arbitrary = ["dep:arbitrary", "revm-interpreter/arbitrary"] \ No newline at end of file diff --git a/crates/primitives/src/bloom.rs b/crates/primitives/src/bloom.rs index d26f737ceb..07c2b74024 100644 --- a/crates/primitives/src/bloom.rs +++ b/crates/primitives/src/bloom.rs @@ -1,10 +1,46 @@ //! Bloom related utilities. +use crate::{keccak256, Log}; +use bytes::Buf; +use derive_more::{AsRef, Deref}; +use fixed_hash::construct_fixed_hash; +use impl_serde::impl_fixed_hash_serde; +use reth_codecs::{impl_hash_compact, Compact}; +use reth_rlp::{RlpDecodableWrapper, RlpEncodableWrapper}; -use crate::{keccak256, Bloom, Log}; +#[cfg(test)] +use proptest::{ + arbitrary::{any_with, Arbitrary as PropTestArbitrary, ParamsFor}, + strategy::{BoxedStrategy, Strategy}, +}; + +#[cfg(any(test, feature = "arbitrary"))] +use arbitrary::Arbitrary; /// Length of bloom filter used for Ethereum. pub const BLOOM_BYTE_LENGTH: usize = 256; +construct_fixed_hash! { + /// 2048 bits type. + #[cfg_attr(any(test, feature = "arbitrary"), derive(Arbitrary))] + #[derive(AsRef, Deref, RlpEncodableWrapper, RlpDecodableWrapper)] + pub struct Bloom(BLOOM_BYTE_LENGTH); +} + +impl_hash_compact!(Bloom); +impl_fixed_hash_serde!(Bloom, BLOOM_BYTE_LENGTH); + +#[cfg(test)] +impl PropTestArbitrary for Bloom { + type Parameters = ParamsFor; + type Strategy = BoxedStrategy; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + proptest::collection::vec(any_with::(args), BLOOM_BYTE_LENGTH) + .prop_map(move |vec| Bloom::from_slice(&vec)) + .boxed() + } +} + // See Section 4.3.1 "Transaction Receipt" of the Yellow Paper fn m3_2048(bloom: &mut Bloom, x: &[u8]) { let hash = keccak256(x); @@ -69,4 +105,19 @@ mod tests { )) ); } + #[test] + fn arbitrary() { + proptest::proptest!(|(bloom: Bloom)| { + let mut buf = vec![]; + bloom.to_compact(&mut buf); + + // Add noise + buf.push(1); + + let (decoded, remaining_buf) = Bloom::from_compact(&buf, buf.len()); + + assert!(bloom == decoded); + assert!(remaining_buf.len() == 1); + }); + } } diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index bd91a80f19..229d681745 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -33,9 +33,9 @@ pub mod proofs; pub use account::Account; pub use block::{Block, BlockHashOrNumber, SealedBlock}; +pub use bloom::Bloom; pub use chain::Chain; pub use constants::{EMPTY_OMMER_ROOT, KECCAK_EMPTY, MAINNET_GENESIS}; -pub use ethbloom::Bloom; pub use forkid::{ForkFilter, ForkHash, ForkId, ForkTransition, ValidationError}; pub use hardfork::Hardfork; pub use header::{Header, HeadersDirection, SealedHeader}; diff --git a/crates/storage/codecs/src/lib.rs b/crates/storage/codecs/src/lib.rs index f3ac5b0e42..d54947546b 100644 --- a/crates/storage/codecs/src/lib.rs +++ b/crates/storage/codecs/src/lib.rs @@ -1,6 +1,5 @@ use bytes::{Buf, Bytes}; pub use codecs_derive::*; -use ethers_core::types::Bloom; use revm_interpreter::{B160 as H160, B256 as H256, U256}; /// Trait that implements the `Compact` codec. @@ -222,6 +221,8 @@ impl Compact for Bytes { } } +/// Implements the [`Compact`] trait for fixed size hash types like [`H256`]. +#[macro_export] macro_rules! impl_hash_compact { ($($name:tt),+) => { $( @@ -257,19 +258,6 @@ macro_rules! impl_hash_compact { impl_hash_compact!(H256, H160); -impl Compact for Bloom { - fn to_compact(self, buf: &mut impl bytes::BufMut) -> usize { - buf.put_slice(&self.0); - 256 - } - - fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) { - let result = Bloom::from_slice(&buf[..256]); - buf.advance(256); - (result, buf) - } -} - impl Compact for bool { /// `bool` vars go directly to the `StructFlags` and are not written to the buffer. fn to_compact(self, _: &mut impl bytes::BufMut) -> usize { @@ -303,19 +291,6 @@ mod tests { assert_eq!(bytes::Bytes::from_compact(&buf, list.len()), (list, vec![1].as_slice())); } - #[test] - fn compact_bloom() { - let mut buf = vec![]; - assert_eq!(Bloom::default().to_compact(&mut buf), 256); - assert_eq!(buf, vec![0; 256]); - - // Add some noise data. - buf.push(1); - - // Bloom shouldn't care about the len passed, since it's not actually compacted. - assert_eq!(Bloom::from_compact(&buf, 1000), (Bloom::default(), vec![1u8].as_slice())); - } - #[test] fn compact_address() { let mut buf = vec![]; diff --git a/crates/storage/db/src/tables/models/blocks.rs b/crates/storage/db/src/tables/models/blocks.rs index ae307aaf81..ba152c6c83 100644 --- a/crates/storage/db/src/tables/models/blocks.rs +++ b/crates/storage/db/src/tables/models/blocks.rs @@ -164,8 +164,7 @@ mod test { ommer.ommers.push(Header::default()); ommer.ommers.push(Header::default()); assert!( - ommer.clone() == - StoredBlockOmmers::decompress::>(ommer.compress().into()).unwrap() + ommer.clone() == StoredBlockOmmers::decompress::>(ommer.compress()).unwrap() ); } }