diff --git a/Cargo.lock b/Cargo.lock index 6b5a686a9..8d1e5d5ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7608,6 +7608,7 @@ dependencies = [ "reth-codecs", "reth-ethereum-forks", "reth-network-peers", + "reth-primitives-traits", "reth-static-file-types", "reth-trie-types", "revm", @@ -7625,6 +7626,23 @@ dependencies = [ "zstd", ] +[[package]] +name = "reth-primitives-traits" +version = "0.2.0-beta.9" +dependencies = [ + "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-primitives", + "arbitrary", + "bytes", + "modular-bitfield", + "proptest", + "proptest-derive", + "reth-codecs", + "serde", + "test-fuzz", +] + [[package]] name = "reth-provider" version = "0.2.0-beta.9" diff --git a/Cargo.toml b/Cargo.toml index 26b48055a..b8269979a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ members = [ "crates/payload/primitives/", "crates/payload/validator/", "crates/primitives/", + "crates/primitives-traits/", "crates/prune/prune", "crates/prune/types", "crates/revm/", @@ -302,6 +303,7 @@ reth-payload-builder = { path = "crates/payload/builder" } reth-payload-primitives = { path = "crates/payload/primitives" } reth-payload-validator = { path = "crates/payload/validator" } reth-primitives = { path = "crates/primitives" } +reth-primitives-traits = { path = "crates/primitives-traits" } reth-provider = { path = "crates/storage/provider" } reth-prune = { path = "crates/prune/prune" } reth-prune-types = { path = "crates/prune/types" } diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml new file mode 100644 index 000000000..50c5f3c24 --- /dev/null +++ b/crates/primitives-traits/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "reth-primitives-traits" +version.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +description = "Common types in reth." + +[lints] +workspace = true + +[dependencies] +reth-codecs.workspace = true + +alloy-genesis.workspace = true +alloy-primitives.workspace = true +alloy-consensus.workspace = true + +# required by reth-codecs +modular-bitfield.workspace = true +bytes.workspace = true +serde.workspace = true + +# arbitrary utils +arbitrary = { workspace = true, features = ["derive"], optional = true } +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } + +[dev-dependencies] +arbitrary = { workspace = true, features = ["derive"] } +proptest.workspace = true +proptest-derive.workspace = true +test-fuzz.workspace = true + +[features] +arbitrary = [ + "dep:arbitrary", + "dep:proptest", + "dep:proptest-derive" +] + diff --git a/crates/primitives-traits/src/account.rs b/crates/primitives-traits/src/account.rs new file mode 100644 index 000000000..3c3bb3033 --- /dev/null +++ b/crates/primitives-traits/src/account.rs @@ -0,0 +1,47 @@ +use alloy_consensus::constants::KECCAK_EMPTY; +use alloy_genesis::GenesisAccount; +use alloy_primitives::{keccak256, B256, U256}; +use reth_codecs::{main_codec, Compact}; + +/// An Ethereum account. +#[main_codec] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub struct Account { + /// Account nonce. + pub nonce: u64, + /// Account balance. + pub balance: U256, + /// Hash of the account's bytecode. + pub bytecode_hash: Option, +} + +impl Account { + /// Whether the account has bytecode. + pub const fn has_bytecode(&self) -> bool { + self.bytecode_hash.is_some() + } + + /// After `SpuriousDragon` empty account is defined as account with nonce == 0 && balance == 0 + /// && bytecode = None (or hash is [`KECCAK_EMPTY`]). + pub fn is_empty(&self) -> bool { + self.nonce == 0 && + self.balance.is_zero() && + self.bytecode_hash.map_or(true, |hash| hash == KECCAK_EMPTY) + } + + /// Makes an [Account] from [`GenesisAccount`] type + pub fn from_genesis_account(value: &GenesisAccount) -> Self { + Self { + // nonce must exist, so we default to zero when converting a genesis account + nonce: value.nonce.unwrap_or_default(), + balance: value.balance, + bytecode_hash: value.code.as_ref().map(keccak256), + } + } + + /// Returns an account bytecode's hash. + /// In case of no bytecode, returns [`KECCAK_EMPTY`]. + pub fn get_bytecode_hash(&self) -> B256 { + self.bytecode_hash.unwrap_or(KECCAK_EMPTY) + } +} diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs new file mode 100644 index 000000000..af8918de1 --- /dev/null +++ b/crates/primitives-traits/src/lib.rs @@ -0,0 +1,15 @@ +//! Common abstracted types in reth. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged +#![allow(unknown_lints, non_local_definitions)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +/// Minimal account +pub mod account; +pub use account::Account; diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 20b53eead..0add20276 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] # reth +reth-primitives-traits.workspace = true reth-codecs.workspace = true reth-ethereum-forks.workspace = true reth-network-peers.workspace = true @@ -98,6 +99,7 @@ secp256k1.workspace = true default = ["c-kzg", "zstd-codec", "alloy-compat"] asm-keccak = ["alloy-primitives/asm-keccak"] arbitrary = [ + "reth-primitives-traits/arbitrary", "revm-primitives/arbitrary", "reth-ethereum-forks/arbitrary", "nybbles/arbitrary", diff --git a/crates/primitives/src/account.rs b/crates/primitives/src/account.rs index 4ce9fea8c..fead77789 100644 --- a/crates/primitives/src/account.rs +++ b/crates/primitives/src/account.rs @@ -1,57 +1,12 @@ -use crate::{ - keccak256, - revm_primitives::{Bytecode as RevmBytecode, Bytes}, - GenesisAccount, B256, KECCAK_EMPTY, U256, -}; +use crate::revm_primitives::{Bytecode as RevmBytecode, Bytes}; use byteorder::{BigEndian, ReadBytesExt}; use bytes::Buf; -use reth_codecs::{main_codec, Compact}; +use reth_codecs::Compact; use revm_primitives::JumpTable; use serde::{Deserialize, Serialize}; use std::ops::Deref; -/// An Ethereum account. -#[main_codec] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] -pub struct Account { - /// Account nonce. - pub nonce: u64, - /// Account balance. - pub balance: U256, - /// Hash of the account's bytecode. - pub bytecode_hash: Option, -} - -impl Account { - /// Whether the account has bytecode. - pub const fn has_bytecode(&self) -> bool { - self.bytecode_hash.is_some() - } - - /// After `SpuriousDragon` empty account is defined as account with nonce == 0 && balance == 0 - /// && bytecode = None (or hash is [`KECCAK_EMPTY`]). - pub fn is_empty(&self) -> bool { - self.nonce == 0 && - self.balance.is_zero() && - self.bytecode_hash.map_or(true, |hash| hash == KECCAK_EMPTY) - } - - /// Makes an [Account] from [`GenesisAccount`] type - pub fn from_genesis_account(value: &GenesisAccount) -> Self { - Self { - // nonce must exist, so we default to zero when converting a genesis account - nonce: value.nonce.unwrap_or_default(), - balance: value.balance, - bytecode_hash: value.code.as_ref().map(keccak256), - } - } - - /// Returns an account bytecode's hash. - /// In case of no bytecode, returns [`KECCAK_EMPTY`]. - pub fn get_bytecode_hash(&self) -> B256 { - self.bytecode_hash.unwrap_or(KECCAK_EMPTY) - } -} +pub use reth_primitives_traits::Account; /// Bytecode for an account. /// @@ -135,7 +90,7 @@ impl Compact for Bytecode { #[cfg(test)] mod tests { use super::*; - use crate::hex_literal::hex; + use crate::{hex_literal::hex, B256, KECCAK_EMPTY, U256}; use revm_primitives::LegacyAnalyzedBytecode; #[test]