chore: move Bytecode, Requests and Withdrawals to reth-primitives-traits (#8954)

This commit is contained in:
joshieDo
2024-06-19 17:21:00 +02:00
committed by GitHub
parent 590356b341
commit 32500aa9a6
10 changed files with 168 additions and 175 deletions

3
Cargo.lock generated
View File

@ -7717,7 +7717,6 @@ dependencies = [
name = "reth-primitives"
version = "1.0.0-rc.2"
dependencies = [
"alloy-consensus",
"alloy-eips",
"alloy-genesis",
"alloy-primitives",
@ -7726,7 +7725,6 @@ dependencies = [
"alloy-trie",
"arbitrary",
"assert_matches",
"byteorder",
"bytes",
"c-kzg",
"criterion",
@ -7769,6 +7767,7 @@ dependencies = [
"alloy-rlp",
"alloy-rpc-types-eth",
"arbitrary",
"byteorder",
"bytes",
"derive_more",
"modular-bitfield",

View File

@ -14,7 +14,7 @@ workspace = true
[dependencies]
reth-codecs.workspace = true
alloy-consensus.workspace = true
alloy-consensus = { workspace = true, features = ["serde"] }
alloy-eips.workspace = true
alloy-genesis.workspace = true
alloy-primitives.workspace = true
@ -22,11 +22,12 @@ alloy-rlp.workspace = true
alloy-rpc-types-eth = { workspace = true, optional = true }
derive_more.workspace = true
revm-primitives.workspace = true
revm-primitives = { workspace = true, features = ["serde"] }
# misc
thiserror-no-std = { workspace = true, default-features = false }
roaring = "0.10.2"
byteorder = "1"
# required by reth-codecs
modular-bitfield.workspace = true
@ -51,6 +52,7 @@ default = ["std"]
std = ["thiserror-no-std/std"]
test-utils = ["arbitrary"]
arbitrary = [
"alloy-consensus/arbitrary",
"dep:arbitrary",
"dep:proptest",
"dep:proptest-derive"

View File

@ -1,7 +1,12 @@
use alloy_consensus::constants::KECCAK_EMPTY;
use alloy_genesis::GenesisAccount;
use alloy_primitives::{keccak256, B256, U256};
use alloy_primitives::{keccak256, Bytes, B256, U256};
use byteorder::{BigEndian, ReadBytesExt};
use bytes::Buf;
use derive_more::Deref;
use reth_codecs::{main_codec, Compact};
use revm_primitives::{Bytecode as RevmBytecode, JumpTable};
use serde::{Deserialize, Serialize};
/// An Ethereum account.
#[main_codec]
@ -45,3 +50,148 @@ impl Account {
self.bytecode_hash.unwrap_or(KECCAK_EMPTY)
}
}
/// Bytecode for an account.
///
/// A wrapper around [`revm::primitives::Bytecode`][RevmBytecode] with encoding/decoding support.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Deref)]
pub struct Bytecode(pub RevmBytecode);
impl Bytecode {
/// Create new bytecode from raw bytes.
///
/// No analysis will be performed.
pub fn new_raw(bytes: Bytes) -> Self {
Self(RevmBytecode::new_raw(bytes))
}
}
impl Compact for Bytecode {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
let bytecode = &self.0.bytecode()[..];
buf.put_u32(bytecode.len() as u32);
buf.put_slice(bytecode);
let len = match &self.0 {
RevmBytecode::LegacyRaw(_) => {
buf.put_u8(0);
1
}
// `1` has been removed.
RevmBytecode::LegacyAnalyzed(analyzed) => {
buf.put_u8(2);
buf.put_u64(analyzed.original_len() as u64);
let map = analyzed.jump_table().as_slice();
buf.put_slice(map);
1 + 8 + map.len()
}
RevmBytecode::Eof(_) => {
// buf.put_u8(3);
// TODO(EOF)
todo!("EOF")
}
};
len + bytecode.len() + 4
}
// # Panics
//
// A panic will be triggered if a bytecode variant of 1 or greater than 2 is passed from the
// database.
fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
let len = buf.read_u32::<BigEndian>().expect("could not read bytecode length");
let bytes = Bytes::from(buf.copy_to_bytes(len as usize));
let variant = buf.read_u8().expect("could not read bytecode variant");
let decoded = match variant {
0 => Self(RevmBytecode::new_raw(bytes)),
1 => unreachable!("Junk data in database: checked Bytecode variant was removed"),
2 => Self(unsafe {
RevmBytecode::new_analyzed(
bytes,
buf.read_u64::<BigEndian>().unwrap() as usize,
JumpTable::from_slice(buf),
)
}),
// TODO(EOF)
3 => todo!("EOF"),
_ => unreachable!("Junk data in database: unknown Bytecode variant"),
};
(decoded, &[])
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::{hex_literal::hex, B256, U256};
use revm_primitives::LegacyAnalyzedBytecode;
#[test]
fn test_account() {
let mut buf = vec![];
let mut acc = Account::default();
let len = acc.to_compact(&mut buf);
assert_eq!(len, 2);
acc.balance = U256::from(2);
let len = acc.to_compact(&mut buf);
assert_eq!(len, 3);
acc.nonce = 2;
let len = acc.to_compact(&mut buf);
assert_eq!(len, 4);
}
#[test]
fn test_empty_account() {
let mut acc = Account { nonce: 0, balance: U256::ZERO, bytecode_hash: None };
// Nonce 0, balance 0, and bytecode hash set to None is considered empty.
assert!(acc.is_empty());
acc.bytecode_hash = Some(KECCAK_EMPTY);
// Nonce 0, balance 0, and bytecode hash set to KECCAK_EMPTY is considered empty.
assert!(acc.is_empty());
acc.balance = U256::from(2);
// Non-zero balance makes it non-empty.
assert!(!acc.is_empty());
acc.balance = U256::ZERO;
acc.nonce = 10;
// Non-zero nonce makes it non-empty.
assert!(!acc.is_empty());
acc.nonce = 0;
acc.bytecode_hash = Some(B256::from(U256::ZERO));
// Non-empty bytecode hash makes it non-empty.
assert!(!acc.is_empty());
}
#[test]
fn test_bytecode() {
let mut buf = vec![];
let bytecode = Bytecode::new_raw(Bytes::default());
let len = bytecode.to_compact(&mut buf);
assert_eq!(len, 5);
let mut buf = vec![];
let bytecode = Bytecode::new_raw(Bytes::from(&hex!("ffff")));
let len = bytecode.to_compact(&mut buf);
assert_eq!(len, 7);
let mut buf = vec![];
let bytecode = Bytecode(RevmBytecode::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
Bytes::from(&hex!("ffff")),
2,
JumpTable::from_slice(&[0]),
)));
let len = bytecode.clone().to_compact(&mut buf);
assert_eq!(len, 16);
let (decoded, remainder) = Bytecode::from_compact(&buf, len);
assert_eq!(decoded, bytecode);
assert!(remainder.is_empty());
}
}

View File

@ -19,11 +19,17 @@ pub mod constants;
/// Minimal account
pub mod account;
pub use account::Account;
pub use account::{Account, Bytecode};
mod integer_list;
pub use integer_list::IntegerList;
pub mod request;
pub use request::{Request, Requests};
mod withdrawal;
pub use withdrawal::{Withdrawal, Withdrawals};
/// Common header types
pub mod header;
#[cfg(any(test, feature = "arbitrary", feature = "test-utils"))]

View File

@ -1,6 +1,6 @@
//! EIP-7685 requests.
use crate::Request;
pub use alloy_consensus::Request;
use alloy_eips::eip7685::{Decodable7685, Encodable7685};
use alloy_rlp::{Decodable, Encodable};
use derive_more::{Deref, DerefMut, From, IntoIterator};

View File

@ -68,7 +68,7 @@ impl Withdrawals {
#[cfg(test)]
mod tests {
use super::*;
use crate::Address;
use alloy_primitives::Address;
use alloy_rlp::{RlpDecodable, RlpEncodable};
use proptest::proptest;

View File

@ -22,7 +22,6 @@ reth-chainspec.workspace = true
revm-primitives = { workspace = true, features = ["serde"] }
# ethereum
alloy-consensus = { workspace = true, features = ["serde"] }
alloy-primitives = { workspace = true, features = ["rand", "rlp"] }
alloy-rlp = { workspace = true, features = ["arrayvec"] }
alloy-rpc-types = { workspace = true, optional = true }
@ -40,7 +39,6 @@ c-kzg = { workspace = true, features = ["serde"], optional = true }
# misc
bytes.workspace = true
byteorder = "1"
derive_more.workspace = true
modular-bitfield.workspace = true
once_cell.workspace = true
@ -62,7 +60,6 @@ revm-primitives = { workspace = true, features = ["arbitrary"] }
nybbles = { workspace = true, features = ["arbitrary"] }
alloy-trie = { workspace = true, features = ["arbitrary"] }
alloy-eips = { workspace = true, features = ["arbitrary"] }
alloy-consensus = { workspace = true, features = ["arbitrary"] }
assert_matches.workspace = true
arbitrary = { workspace = true, features = ["derive"] }
@ -94,7 +91,6 @@ arbitrary = [
"reth-ethereum-forks/arbitrary",
"nybbles/arbitrary",
"alloy-trie/arbitrary",
"alloy-consensus/arbitrary",
"alloy-eips/arbitrary",
"dep:arbitrary",
"dep:proptest",

View File

@ -1,154 +0,0 @@
use crate::revm_primitives::{Bytecode as RevmBytecode, Bytes};
use byteorder::{BigEndian, ReadBytesExt};
use bytes::Buf;
use derive_more::Deref;
use reth_codecs::Compact;
use revm_primitives::JumpTable;
use serde::{Deserialize, Serialize};
pub use reth_primitives_traits::Account;
/// Bytecode for an account.
///
/// A wrapper around [`revm::primitives::Bytecode`][RevmBytecode] with encoding/decoding support.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Deref)]
pub struct Bytecode(pub RevmBytecode);
impl Bytecode {
/// Create new bytecode from raw bytes.
///
/// No analysis will be performed.
pub fn new_raw(bytes: Bytes) -> Self {
Self(RevmBytecode::new_raw(bytes))
}
}
impl Compact for Bytecode {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
let bytecode = &self.0.bytecode()[..];
buf.put_u32(bytecode.len() as u32);
buf.put_slice(bytecode);
let len = match &self.0 {
RevmBytecode::LegacyRaw(_) => {
buf.put_u8(0);
1
}
// `1` has been removed.
RevmBytecode::LegacyAnalyzed(analyzed) => {
buf.put_u8(2);
buf.put_u64(analyzed.original_len() as u64);
let map = analyzed.jump_table().as_slice();
buf.put_slice(map);
1 + 8 + map.len()
}
RevmBytecode::Eof(_) => {
// buf.put_u8(3);
// TODO(EOF)
todo!("EOF")
}
};
len + bytecode.len() + 4
}
// # Panics
//
// A panic will be triggered if a bytecode variant of 1 or greater than 2 is passed from the
// database.
fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
let len = buf.read_u32::<BigEndian>().expect("could not read bytecode length");
let bytes = Bytes::from(buf.copy_to_bytes(len as usize));
let variant = buf.read_u8().expect("could not read bytecode variant");
let decoded = match variant {
0 => Self(RevmBytecode::new_raw(bytes)),
1 => unreachable!("Junk data in database: checked Bytecode variant was removed"),
2 => Self(unsafe {
RevmBytecode::new_analyzed(
bytes,
buf.read_u64::<BigEndian>().unwrap() as usize,
JumpTable::from_slice(buf),
)
}),
// TODO(EOF)
3 => todo!("EOF"),
_ => unreachable!("Junk data in database: unknown Bytecode variant"),
};
(decoded, &[])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{hex_literal::hex, B256, KECCAK_EMPTY, U256};
use revm_primitives::LegacyAnalyzedBytecode;
#[test]
fn test_account() {
let mut buf = vec![];
let mut acc = Account::default();
let len = acc.to_compact(&mut buf);
assert_eq!(len, 2);
acc.balance = U256::from(2);
let len = acc.to_compact(&mut buf);
assert_eq!(len, 3);
acc.nonce = 2;
let len = acc.to_compact(&mut buf);
assert_eq!(len, 4);
}
#[test]
fn test_empty_account() {
let mut acc = Account { nonce: 0, balance: U256::ZERO, bytecode_hash: None };
// Nonce 0, balance 0, and bytecode hash set to None is considered empty.
assert!(acc.is_empty());
acc.bytecode_hash = Some(KECCAK_EMPTY);
// Nonce 0, balance 0, and bytecode hash set to KECCAK_EMPTY is considered empty.
assert!(acc.is_empty());
acc.balance = U256::from(2);
// Non-zero balance makes it non-empty.
assert!(!acc.is_empty());
acc.balance = U256::ZERO;
acc.nonce = 10;
// Non-zero nonce makes it non-empty.
assert!(!acc.is_empty());
acc.nonce = 0;
acc.bytecode_hash = Some(B256::from(U256::ZERO));
// Non-empty bytecode hash makes it non-empty.
assert!(!acc.is_empty());
}
#[test]
fn test_bytecode() {
let mut buf = vec![];
let bytecode = Bytecode::new_raw(Bytes::default());
let len = bytecode.to_compact(&mut buf);
assert_eq!(len, 5);
let mut buf = vec![];
let bytecode = Bytecode::new_raw(Bytes::from(&hex!("ffff")));
let len = bytecode.to_compact(&mut buf);
assert_eq!(len, 7);
let mut buf = vec![];
let bytecode = Bytecode(RevmBytecode::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
Bytes::from(&hex!("ffff")),
2,
JumpTable::from_slice(&[0]),
)));
let len = bytecode.clone().to_compact(&mut buf);
assert_eq!(len, 16);
let (decoded, remainder) = Bytecode::from_compact(&buf, len);
assert_eq!(decoded, bytecode);
assert!(remainder.is_empty());
}
}

View File

@ -1,5 +1,5 @@
use crate::{
Address, Bytes, GotExpected, Header, Requests, SealedHeader, TransactionSigned,
Address, Bytes, GotExpected, Header, SealedHeader, TransactionSigned,
TransactionSignedEcRecovered, Withdrawals, B256,
};
pub use alloy_eips::eip1898::{
@ -12,6 +12,7 @@ use proptest::prelude::prop_compose;
use reth_codecs::derive_arbitrary;
#[cfg(any(test, feature = "arbitrary"))]
pub use reth_primitives_traits::test_utils::{generate_valid_header, valid_header_strategy};
use reth_primitives_traits::Requests;
use serde::{Deserialize, Serialize};
#[cfg(not(feature = "std"))]

View File

@ -22,7 +22,6 @@
#[cfg(not(feature = "std"))]
extern crate alloc;
mod account;
#[cfg(feature = "alloy-compat")]
mod alloy_compat;
pub mod basefee;
@ -37,14 +36,11 @@ pub mod header;
mod log;
pub mod proofs;
mod receipt;
mod request;
/// Helpers for working with revm
pub mod revm;
pub use reth_static_file_types as static_file;
mod storage;
pub mod transaction;
mod withdrawal;
pub use account::{Account, Bytecode};
#[cfg(any(test, feature = "arbitrary"))]
pub use block::{generate_valid_header, valid_header_strategy};
pub use block::{
@ -64,7 +60,7 @@ pub use log::{logs_bloom, Log};
pub use receipt::{
gas_spent_by_transactions, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Receipts,
};
pub use request::Requests;
pub use reth_primitives_traits::{Account, Bytecode, Request, Requests, Withdrawal, Withdrawals};
pub use static_file::StaticFileSegment;
pub use storage::StorageEntry;
@ -85,11 +81,8 @@ pub use transaction::{
LEGACY_TX_TYPE_ID,
};
pub use withdrawal::{Withdrawal, Withdrawals};
// Re-exports
pub use self::ruint::UintTryTo;
pub use alloy_consensus::Request;
pub use alloy_primitives::{
self, address, b256, bloom, bytes,
bytes::{Buf, BufMut, BytesMut},