mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: reth binary and parsing of eth chain tests (#38)
* Scaffolding for reth test binary. wip for blockchain tests * wip models for chain json tests * reth binary and chain test * fmt,clippy * Update bin/reth/src/lib.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/lib.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/test_eth_chain/mod.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/test_eth_chain/mod.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/test_eth_chain/mod.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/test_eth_chain/models.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/test_eth_chain/models.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/test_eth_chain/mod.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Update bin/reth/src/test_eth_chain/runner.rs Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> * Move JsonU256 to primitives * fmt * Use eyre * nits Co-authored-by: Bjerg <onbjerg@users.noreply.github.com>
This commit is contained in:
130
Cargo.lock
generated
130
Cargo.lock
generated
@ -73,6 +73,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "auto_impl"
|
||||
version = "1.0.1"
|
||||
@ -263,6 +274,43 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "385007cbbed899260395a4107435fead4cad80684461b3cc78238bdcb0bad58f"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db342ce9fda24fb191e2ed4e102055a4d381c1086a06630174cd8da8d5d917ce"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.0"
|
||||
@ -526,6 +574,16 @@ version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
@ -965,6 +1023,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
@ -1457,6 +1521,12 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
|
||||
[[package]]
|
||||
name = "page_size"
|
||||
version = "0.4.2"
|
||||
@ -1716,6 +1786,18 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "reth"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"eyre",
|
||||
"reth-primitives",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-crate-template"
|
||||
@ -1751,8 +1833,8 @@ dependencies = [
|
||||
name = "reth-executor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"eyre",
|
||||
"reth-interfaces",
|
||||
"reth-primitives",
|
||||
"revm",
|
||||
@ -1792,6 +1874,8 @@ dependencies = [
|
||||
"bytes",
|
||||
"ethers-core",
|
||||
"fastrlp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2026,6 +2110,15 @@ version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.20"
|
||||
@ -2263,6 +2356,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.24.1"
|
||||
@ -2335,6 +2434,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.37"
|
||||
@ -2544,6 +2652,17 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
@ -2673,6 +2792,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
||||
13
Cargo.toml
13
Cargo.toml
@ -1,10 +1,6 @@
|
||||
[package]
|
||||
name = "reth"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"bin/reth",
|
||||
"crate-template",
|
||||
"crates/db",
|
||||
"crates/executor",
|
||||
@ -19,9 +15,4 @@ members = [
|
||||
"crates/transaction-pool",
|
||||
"crates/db"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
|
||||
[[bin]]
|
||||
path = "bin/reth.rs"
|
||||
name = "reth"
|
||||
default-members = ["bin/reth"]
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
19
bin/reth/Cargo.toml
Normal file
19
bin/reth/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "reth"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/foundry-rs/reth"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
eyre = "0.6.8"
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
tracing = "0.1"
|
||||
tracing-futures = "0.2"
|
||||
tokio = { version = "1.21", features = ["sync", "macros", "rt-multi-thread"] }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
reth-primitives = { path = "../../crates/primitives" }
|
||||
walkdir = "2.3"
|
||||
36
bin/reth/src/cli.rs
Normal file
36
bin/reth/src/cli.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use clap::{ArgAction, Parser, Subcommand};
|
||||
|
||||
use crate::test_eth_chain;
|
||||
|
||||
/// main function that parses cli and runs command
|
||||
pub async fn run() -> eyre::Result<()> {
|
||||
let opt = Cli::parse();
|
||||
|
||||
match opt.command {
|
||||
Commands::TestEthChain(command) => command.execute().await,
|
||||
}
|
||||
}
|
||||
|
||||
/// Commands to be executed
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
/// Runs Ethereum blockchain tests
|
||||
#[command(name = "test-chain")]
|
||||
TestEthChain(test_eth_chain::Command),
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version="0.1", about="Reth binary", long_about = None)]
|
||||
struct Cli {
|
||||
/// The command to run
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
|
||||
/// Use verbose output
|
||||
#[clap(short, long, action = ArgAction::Count, global = true)]
|
||||
verbose: u8,
|
||||
|
||||
/// Silence all output
|
||||
#[clap(short, long, global = true)]
|
||||
silent: bool,
|
||||
}
|
||||
17
bin/reth/src/lib.rs
Normal file
17
bin/reth/src/lib.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#![warn(missing_docs, unreachable_pub)]
|
||||
#![deny(unused_must_use, rust_2018_idioms)]
|
||||
#![doc(test(
|
||||
no_crate_inject,
|
||||
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
|
||||
))]
|
||||
|
||||
//! Rust Ethereum (reth) binary executable.
|
||||
|
||||
/// CLI definition and entrypoint
|
||||
pub mod cli;
|
||||
|
||||
/// Utility functions.
|
||||
pub mod util;
|
||||
|
||||
/// Command for executing Ethereum blockchain tests
|
||||
pub mod test_eth_chain;
|
||||
9
bin/reth/src/main.rs
Normal file
9
bin/reth/src/main.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use tracing::error;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
if let Err(err) = reth::cli::run().await {
|
||||
error!("Error: {:?}", err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
52
bin/reth/src/test_eth_chain/mod.rs
Normal file
52
bin/reth/src/test_eth_chain/mod.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::util;
|
||||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
/// Models for parsing JSON blockchain tests
|
||||
pub mod models;
|
||||
/// Ethereum blockhain test runner
|
||||
pub mod runner;
|
||||
|
||||
/// Execute Ethereum blockchain tests by specifying path to json files
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Command {
|
||||
/// Path to Ethereum JSON test files
|
||||
path: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
/// Execute the command
|
||||
pub async fn execute(self) -> eyre::Result<()> {
|
||||
// note the use of `into_iter()` to consume `items`
|
||||
let task_group: Vec<_> = self
|
||||
.path
|
||||
.iter()
|
||||
.map(|item| {
|
||||
util::find_all_json_tests(item).into_iter().map(|file| {
|
||||
let tfile = file.clone();
|
||||
let join = tokio::spawn(async move { runner::run_test(tfile.as_path()).await });
|
||||
(join, file)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
// await the tasks for resolve's to complete and give back our test results
|
||||
let mut num_of_failed = 0;
|
||||
let mut num_of_passed = 0;
|
||||
for tasks in task_group {
|
||||
for (join, file) in tasks {
|
||||
match join.await.unwrap() {
|
||||
Ok(_) => {
|
||||
num_of_passed += 1;
|
||||
}
|
||||
Err(error) => {
|
||||
num_of_failed += 1;
|
||||
println!("Test {:?} failed:\n {error}\n", file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("\nPASSED {num_of_passed}/{} tests\n", num_of_passed + num_of_failed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
391
bin/reth/src/test_eth_chain/models.rs
Normal file
391
bin/reth/src/test_eth_chain/models.rs
Normal file
@ -0,0 +1,391 @@
|
||||
use reth_primitives::{Address, Bloom, Bytes, JsonU256, H160, H256, H64};
|
||||
use serde::{self, Deserialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Blockchain test deserializer.
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||
pub struct Test(pub BTreeMap<String, BlockchainTestData>);
|
||||
|
||||
/// Ethereum blockchain test data
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BlockchainTestData {
|
||||
/// Genesis block header.
|
||||
pub genesis_block_header: Header,
|
||||
/// Genesis rlp.
|
||||
#[serde(rename = "genesisRLP")]
|
||||
pub genesis_rlp: Option<Bytes>,
|
||||
/// Blocks.
|
||||
pub blocks: Vec<Block>,
|
||||
/// Post state.
|
||||
pub post_state: Option<State>,
|
||||
/// Pre state.
|
||||
pub pre: State,
|
||||
/// Hash of best block.
|
||||
pub lastblockhash: H256,
|
||||
/// Network.
|
||||
pub network: ForkSpec,
|
||||
#[serde(default)]
|
||||
/// Engine
|
||||
pub self_engine: SealEngine,
|
||||
}
|
||||
|
||||
/// Ethereum blockchain test data Header.
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Header {
|
||||
/// Bloom filter.
|
||||
pub bloom: Bloom,
|
||||
/// Coinbase.
|
||||
pub coinbase: Address,
|
||||
/// Difficulty.
|
||||
pub difficulty: JsonU256,
|
||||
/// Extra data.
|
||||
pub extra_data: Bytes,
|
||||
/// Gas limit.
|
||||
pub gas_limit: JsonU256,
|
||||
/// Gas used.
|
||||
pub gas_used: JsonU256,
|
||||
/// Block Hash.
|
||||
pub hash: H256,
|
||||
/// Mix hash.
|
||||
pub mix_hash: H256,
|
||||
/// Seal nonce.
|
||||
pub nonce: H64,
|
||||
/// Block number.
|
||||
pub number: JsonU256,
|
||||
/// Parent hash.
|
||||
pub parent_hash: H256,
|
||||
/// Receipt trie.
|
||||
pub receipt_trie: H256,
|
||||
/// State root.
|
||||
pub state_root: H256,
|
||||
/// Timestamp.
|
||||
pub timestamp: JsonU256,
|
||||
/// Transactions trie.
|
||||
pub transactions_trie: H256,
|
||||
/// Uncle hash.
|
||||
pub uncle_hash: H256,
|
||||
/// Base fee per gas.
|
||||
pub base_fee_per_gas: Option<JsonU256>,
|
||||
}
|
||||
|
||||
/// Ethereum blockchain test data Block.
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Block {
|
||||
/// Block header.
|
||||
pub block_header: Option<Header>,
|
||||
/// Rlp block bytes
|
||||
pub rlp: Bytes,
|
||||
/// Transactions
|
||||
pub transactions: Option<Vec<Transaction>>,
|
||||
/// Uncle/Omner headers.
|
||||
pub uncle_headers: Option<Vec<Header>>,
|
||||
}
|
||||
|
||||
/// Ethereum blockchain test data State.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct State(pub RootOrState);
|
||||
|
||||
/// Merkle root hash or storage accounts.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum RootOrState {
|
||||
/// If state is too big, only state root is present
|
||||
Root(H256),
|
||||
/// Staet
|
||||
State(BTreeMap<Address, Account>),
|
||||
}
|
||||
|
||||
/// Spec account
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize, Clone)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Account {
|
||||
/// Balance.
|
||||
pub balance: JsonU256,
|
||||
/// Code.
|
||||
pub code: Bytes,
|
||||
/// Nonce.
|
||||
pub nonce: JsonU256,
|
||||
/// Storage.
|
||||
pub storage: BTreeMap<JsonU256, JsonU256>,
|
||||
}
|
||||
|
||||
/// Ethereum blockchain test data State.
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||
pub enum ForkSpec {
|
||||
/// Fork EIP150.
|
||||
EIP150,
|
||||
/// Fork EIP158.
|
||||
EIP158,
|
||||
/// Fork Frontier.
|
||||
Frontier,
|
||||
/// Fork Homestead.
|
||||
Homestead,
|
||||
/// Fork Byzantium.
|
||||
Byzantium,
|
||||
/// Fork Constantinople.
|
||||
Constantinople,
|
||||
/// Fork ConstantinopleFix.
|
||||
ConstantinopleFix,
|
||||
/// Fork Istanbul.
|
||||
Istanbul,
|
||||
/// Fork EIP158ToByzantiumAt5.
|
||||
EIP158ToByzantiumAt5,
|
||||
/// Fork FrontierToHomesteadAt5.
|
||||
FrontierToHomesteadAt5,
|
||||
/// Fork HomesteadToDaoAt5.
|
||||
HomesteadToDaoAt5,
|
||||
/// Fork HomesteadToEIP150At5.
|
||||
HomesteadToEIP150At5,
|
||||
/// Fork ByzantiumToConstantinopleAt5.
|
||||
ByzantiumToConstantinopleAt5,
|
||||
/// Fork ByzantiumToConstantinopleFixAt5.
|
||||
ByzantiumToConstantinopleFixAt5,
|
||||
/// Fork Berlin.
|
||||
Berlin,
|
||||
/// Fork London.
|
||||
London,
|
||||
/// Fork BerlinToLondonAt5.
|
||||
BerlinToLondonAt5,
|
||||
/// Fork Merge,
|
||||
Merge,
|
||||
}
|
||||
|
||||
/// Json Block test possible engine kind.
|
||||
#[derive(Debug, PartialEq, Eq, Default, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum SealEngine {
|
||||
/// No consensus checks.
|
||||
#[default]
|
||||
NoProof,
|
||||
}
|
||||
|
||||
/// Ethereum blockchain test transaction data.
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Transaction {
|
||||
/// Transaction type
|
||||
#[serde(rename = "type")]
|
||||
pub transaction_type: Option<JsonU256>,
|
||||
/// Data.
|
||||
pub data: Bytes,
|
||||
/// Gas limit.
|
||||
pub gas_limit: JsonU256,
|
||||
/// Gas price.
|
||||
pub gas_price: Option<JsonU256>,
|
||||
/// Nonce.
|
||||
pub nonce: JsonU256,
|
||||
/// Signature r part.
|
||||
pub r: JsonU256,
|
||||
/// Signature s part.
|
||||
pub s: JsonU256,
|
||||
/// Parity bit.
|
||||
pub v: JsonU256,
|
||||
/// Transaction value.
|
||||
pub value: JsonU256,
|
||||
/// Chain ID.
|
||||
pub chain_id: Option<JsonU256>,
|
||||
/// Access list.
|
||||
pub access_list: Option<AccessList>,
|
||||
/// Max fee per gas.
|
||||
pub max_fee_per_gas: Option<JsonU256>,
|
||||
/// Max priority fee per gas
|
||||
pub max_priority_fee_per_gas: Option<JsonU256>,
|
||||
/// Transaction hash.
|
||||
pub hash: Option<H256>,
|
||||
}
|
||||
|
||||
/// Access list item
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AccessListItem {
|
||||
/// Account address
|
||||
pub address: H160,
|
||||
/// Storage key.
|
||||
pub storage_keys: Vec<H256>,
|
||||
}
|
||||
|
||||
/// Access list.
|
||||
pub type AccessList = Vec<AccessListItem>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use serde_json;
|
||||
|
||||
#[test]
|
||||
fn blockchain_test_deserialize() {
|
||||
let test = r#"{
|
||||
"evmBytecode_d0g0v0_Berlin" : {
|
||||
"_info" : {
|
||||
"comment" : "",
|
||||
"filling-rpc-server" : "evm version 1.10.18-unstable-53304ff6-20220503",
|
||||
"filling-tool-version" : "retesteth-0.2.2-testinfo+commit.05e0b8ca.Linux.g++",
|
||||
"generatedTestHash" : "0951de8d9e6b2a08e57234f57ef719a17aee9d7e9d7e852e454a641028b791a9",
|
||||
"lllcversion" : "Version: 0.5.14-develop.2021.11.27+commit.401d5358.Linux.g++",
|
||||
"solidity" : "Version: 0.8.5+commit.a4f2e591.Linux.g++",
|
||||
"source" : "src/GeneralStateTestsFiller/stBugs/evmBytecodeFiller.json",
|
||||
"sourceHash" : "6ced7b43100305d1cc5aee48344c0eab6002940358e2c126279ef8444c2dea5a"
|
||||
},
|
||||
"blocks" : [
|
||||
{
|
||||
"blockHeader" : {
|
||||
"bloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase" : "0x1000000000000000000000000000000000000000",
|
||||
"difficulty" : "0x020000",
|
||||
"extraData" : "0x00",
|
||||
"gasLimit" : "0x54a60a4202e088",
|
||||
"gasUsed" : "0x01d4c0",
|
||||
"hash" : "0xb8152a06d2018ed9a1eb1eb6e1fe8c3478d8eae5b04d743bf4a1ec699510cfe5",
|
||||
"mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"nonce" : "0x0000000000000000",
|
||||
"number" : "0x01",
|
||||
"parentHash" : "0xb835c89a42605cfcc542381145b83c826caf10823b81af0f45091040a67e6601",
|
||||
"receiptTrie" : "0x0ef77336cf7bfbd2c500dcefe7b48d0ef7896d38f6373fbeb301ea4dac3746a7",
|
||||
"stateRoot" : "0x27bf1aca92967ecd83e11c52887203bbdcab73a27fe07e814cf749fa50483a53",
|
||||
"timestamp" : "0x03e8",
|
||||
"transactionsTrie" : "0x9008a2d4af552fea9b45675cd2af6d4117303b57da25b28438ccd1f6bad6828d",
|
||||
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
"rlp" : "0xf90264f901fca0b835c89a42605cfcc542381145b83c826caf10823b81af0f45091040a67e6601a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347941000000000000000000000000000000000000000a027bf1aca92967ecd83e11c52887203bbdcab73a27fe07e814cf749fa50483a53a09008a2d4af552fea9b45675cd2af6d4117303b57da25b28438ccd1f6bad6828da00ef77336cf7bfbd2c500dcefe7b48d0ef7896d38f6373fbeb301ea4dac3746a7b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018754a60a4202e0888301d4c08203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f862f860800a8301d4c094b94f5374fce5edbc8e2a8697c15331677e6ebf0b80801ca0f3b41c283c02ed98318dc9cac3f0ddc3de2f2f7853a03299a46f22a7c6726c3aa0396ccb5968a532ea070924408625d3e36d4db21bfbd0cb070ba9e1fe9dba58abc0",
|
||||
"transactions" : [
|
||||
{
|
||||
"data" : "0x",
|
||||
"gasLimit" : "0x01d4c0",
|
||||
"gasPrice" : "0x0a",
|
||||
"nonce" : "0x00",
|
||||
"r" : "0xf3b41c283c02ed98318dc9cac3f0ddc3de2f2f7853a03299a46f22a7c6726c3a",
|
||||
"s" : "0x396ccb5968a532ea070924408625d3e36d4db21bfbd0cb070ba9e1fe9dba58ab",
|
||||
"sender" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"to" : "0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"v" : "0x1c",
|
||||
"value" : "0x00"
|
||||
}
|
||||
],
|
||||
"uncleHeaders" : [
|
||||
]
|
||||
}
|
||||
],
|
||||
"genesisBlockHeader" : {
|
||||
"bloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase" : "0x1000000000000000000000000000000000000000",
|
||||
"difficulty" : "0x020000",
|
||||
"extraData" : "0x00",
|
||||
"gasLimit" : "0x54a60a4202e088",
|
||||
"gasUsed" : "0x00",
|
||||
"hash" : "0xb835c89a42605cfcc542381145b83c826caf10823b81af0f45091040a67e6601",
|
||||
"mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"nonce" : "0x0000000000000000",
|
||||
"number" : "0x00",
|
||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"stateRoot" : "0x642a369a4a9dbf57d83ba05413910a5dd2cff93858c68e9e8293a8fffeae8660",
|
||||
"timestamp" : "0x00",
|
||||
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
},
|
||||
"genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347941000000000000000000000000000000000000000a0642a369a4a9dbf57d83ba05413910a5dd2cff93858c68e9e8293a8fffeae8660a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808754a60a4202e088808000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0",
|
||||
"lastblockhash" : "0xb8152a06d2018ed9a1eb1eb6e1fe8c3478d8eae5b04d743bf4a1ec699510cfe5",
|
||||
"network" : "Berlin",
|
||||
"postState" : {
|
||||
"0x1000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x1bc16d674eda4f80",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x38beec8feeb7d618",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x00",
|
||||
"code" : "0x67ffffffffffffffff600160006000fb",
|
||||
"nonce" : "0x3f",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x38beec8feeca2598",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x00",
|
||||
"code" : "0x67ffffffffffffffff600160006000fb",
|
||||
"nonce" : "0x3f",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"sealEngine" : "NoProof"
|
||||
}
|
||||
}"#;
|
||||
|
||||
let res = serde_json::from_str::<Test>(test);
|
||||
assert!(res.is_ok(), "Failed to deserialize BlockchainTestData with error: {:?}", res);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_deserialize() {
|
||||
let test = r#"{
|
||||
"baseFeePerGas" : "0x0a",
|
||||
"bloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"difficulty" : "0x020000",
|
||||
"extraData" : "0x00",
|
||||
"gasLimit" : "0x10000000000000",
|
||||
"gasUsed" : "0x10000000000000",
|
||||
"hash" : "0x7ebfee2a2c785fef181b8ffd92d4a48a0660ec000f465f309757e3f092d13882",
|
||||
"mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"nonce" : "0x0000000000000000",
|
||||
"number" : "0x01",
|
||||
"parentHash" : "0xa8f2eb2ea9dccbf725801eef5a31ce59bada431e888dfd5501677cc4365dc3be",
|
||||
"receiptTrie" : "0xbdd943f5c62ae0299324244a0f65524337ada9817e18e1764631cc1424f3a293",
|
||||
"stateRoot" : "0xc9c6306ee3e5acbaabe8e2fa28a10c12e27bad1d1aacc271665149f70519f8b0",
|
||||
"timestamp" : "0x03e8",
|
||||
"transactionsTrie" : "0xf5893b055ca05e4f14d1792745586a1376e218180bd56bd96b2b024e1dc78300",
|
||||
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
}"#;
|
||||
let res = serde_json::from_str::<Header>(test);
|
||||
assert!(res.is_ok(), "Failed to deserialize Header with error: {:?}", res);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_deserialize() {
|
||||
let test = r#"[
|
||||
{
|
||||
"accessList" : [
|
||||
],
|
||||
"chainId" : "0x01",
|
||||
"data" : "0x693c61390000000000000000000000000000000000000000000000000000000000000000",
|
||||
"gasLimit" : "0x10000000000000",
|
||||
"maxFeePerGas" : "0x07d0",
|
||||
"maxPriorityFeePerGas" : "0x00",
|
||||
"nonce" : "0x01",
|
||||
"r" : "0x5fecc3972a35c9e341b41b0c269d9a7325e13269fb01c2f64cbce1046b3441c8",
|
||||
"s" : "0x7d4d0eda0e4ebd53c5d0b6fc35c600b317f8fa873b3963ab623ec9cec7d969bd",
|
||||
"sender" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"to" : "0xcccccccccccccccccccccccccccccccccccccccc",
|
||||
"type" : "0x02",
|
||||
"v" : "0x01",
|
||||
"value" : "0x00"
|
||||
}
|
||||
]"#;
|
||||
|
||||
let res = serde_json::from_str::<Vec<Transaction>>(test);
|
||||
assert!(res.is_ok(), "Failed to deserialize transactin with error: {:?}", res);
|
||||
}
|
||||
}
|
||||
13
bin/reth/src/test_eth_chain/runner.rs
Normal file
13
bin/reth/src/test_eth_chain/runner.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use super::models::Test;
|
||||
use std::path::Path;
|
||||
|
||||
/// Run one JSON-encoded Ethereum blockchain test at the specified path.
|
||||
pub async fn run_test(path: &Path) -> eyre::Result<()> {
|
||||
let json_file = std::fs::read(path)?;
|
||||
let suits: Test = serde_json::from_reader(&*json_file)?;
|
||||
|
||||
for suit in suits.0 {
|
||||
println!("TODO:{:?}", suit.0);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
11
bin/reth/src/util/mod.rs
Normal file
11
bin/reth/src/util/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
pub(crate) fn find_all_json_tests(path: &Path) -> Vec<PathBuf> {
|
||||
WalkDir::new(path)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| e.file_name().to_string_lossy().ends_with(".json"))
|
||||
.map(DirEntry::into_path)
|
||||
.collect::<Vec<PathBuf>>()
|
||||
}
|
||||
@ -12,4 +12,4 @@ reth-primitives = { path = "../primitives" }
|
||||
reth-interfaces = { path = "../interfaces" }
|
||||
async-trait = "0.1.57"
|
||||
thiserror = "1.0.37"
|
||||
anyhow = "1.0"
|
||||
eyre = "0.6.8"
|
||||
|
||||
@ -11,3 +11,7 @@ description = "Commonly used types in reth."
|
||||
fastrlp = { version = "0.1.3" }
|
||||
ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false }
|
||||
bytes = "1.2"
|
||||
serde = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0"
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::{Header, HeaderLocked, Receipt, Transaction, TransactionSigned};
|
||||
use crate::{Header, HeaderLocked, Receipt, Transaction, TransactionSigned, H256};
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Ethereum full block.
|
||||
@ -30,6 +30,13 @@ pub struct BlockLocked {
|
||||
pub receipts: Vec<Receipt>,
|
||||
}
|
||||
|
||||
impl BlockLocked {
|
||||
/// Header hash.
|
||||
pub fn hash(&self) -> H256 {
|
||||
self.header.hash()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for BlockLocked {
|
||||
type Target = Header;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
||||
94
crates/primitives/src/jsonu256.rs
Normal file
94
crates/primitives/src/jsonu256.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use crate::U256;
|
||||
use serde::{
|
||||
de::{Error, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
/// Wrapper around primitive U256 type to handle edge cases of json parser
|
||||
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub struct JsonU256(pub U256);
|
||||
|
||||
impl Serialize for JsonU256 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.to_string().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for JsonU256 {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
deserializer.deserialize_any(JsonU256Visitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct JsonU256Visitor;
|
||||
|
||||
impl<'a> Visitor<'a> for JsonU256Visitor {
|
||||
type Value = JsonU256;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(formatter, "a hex encoding or decimal number")
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(JsonU256(U256::from(value)))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let value = match value.len() {
|
||||
0 => U256::from(0),
|
||||
2 if value.starts_with("0x") => U256::zero(),
|
||||
_ if value.starts_with("0x") => U256::from_str(&value[2..]).map_err(|e| {
|
||||
Error::custom(format!("Parsin JsonU256 as hex failed {}: {}", value, e))
|
||||
})?,
|
||||
_ => U256::from_dec_str(value).map_err(|e| {
|
||||
Error::custom(format!("Parsin JsonU256 as decimal failed {}: {:?}", value, e))
|
||||
})?,
|
||||
};
|
||||
|
||||
Ok(JsonU256(value))
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.visit_str(value.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::JsonU256;
|
||||
use crate::U256;
|
||||
use serde_json;
|
||||
|
||||
#[test]
|
||||
fn jsonu256_deserialize() {
|
||||
let deserialized: Vec<JsonU256> =
|
||||
serde_json::from_str(r#"["","0", "0x","10",10,"0x10"]"#).unwrap();
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
vec![
|
||||
JsonU256(U256::from(0)),
|
||||
JsonU256(U256::from(0)),
|
||||
JsonU256(U256::from(0)),
|
||||
JsonU256(U256::from(10)),
|
||||
JsonU256(U256::from(10)),
|
||||
JsonU256(U256::from(16)),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ mod account;
|
||||
mod block;
|
||||
mod chain;
|
||||
mod header;
|
||||
mod jsonu256;
|
||||
mod log;
|
||||
mod receipt;
|
||||
mod transaction;
|
||||
@ -19,6 +20,7 @@ pub use account::Account;
|
||||
pub use block::{Block, BlockLocked};
|
||||
pub use chain::Chain;
|
||||
pub use header::{Header, HeaderLocked};
|
||||
pub use jsonu256::JsonU256;
|
||||
pub use log::Log;
|
||||
pub use receipt::Receipt;
|
||||
pub use transaction::{AccessList, AccessListItem, Transaction, TransactionSigned, TxType};
|
||||
|
||||
Reference in New Issue
Block a user