diff --git a/Cargo.lock b/Cargo.lock index 4cae8c5d..e1e9b7c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2099,7 +2099,7 @@ dependencies = [ "bitflags 2.10.0", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools 0.12.1", "proc-macro2", "quote", "regex", @@ -2117,7 +2117,7 @@ dependencies = [ "bitflags 2.10.0", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools 0.12.1", "proc-macro2", "quote", "regex", @@ -5325,7 +5325,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2 0.6.1", - "system-configuration 0.6.1", + "system-configuration", "tokio", "tower-service", "tracing", @@ -5344,7 +5344,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.57.0", ] [[package]] @@ -6733,6 +6733,7 @@ dependencies = [ "alloy-hardforks", "alloy-op-evm", "alloy-primitives 1.4.1", + "alloy-rlp", "alloy-rpc-types-engine", "alloy-sol-types", "async-trait", @@ -6751,15 +6752,21 @@ dependencies = [ "rand 0.8.5", "rand 0.9.2", "reth", + "reth-basic-payload-builder", "reth-chain-state", "reth-chainspec", "reth-cli-util", + "reth-consensus-common", + "reth-errors", "reth-ethereum", + "reth-ethereum-engine-primitives", + "reth-ethereum-payload-builder", "reth-ethereum-primitives", "reth-evm", "reth-evm-ethereum", "reth-exex-test-utils", "reth-node-api", + "reth-node-builder", "reth-node-core", "reth-node-ethereum", "reth-optimism-chainspec", @@ -6771,10 +6778,16 @@ dependencies = [ "reth-optimism-payload-builder", "reth-optimism-primitives", "reth-optimism-rpc", + "reth-payload-builder", + "reth-payload-builder-primitives", + "reth-payload-primitives", "reth-primitives", "reth-primitives-traits", + "reth-revm", + "reth-storage-api", "reth-testing-utils", "reth-tracing", + "reth-transaction-pool", "revm", "revmc-build", "secp256k1 0.30.0", @@ -6840,6 +6853,7 @@ dependencies = [ "thiserror 2.0.17", "tikv-jemallocator", "tokio", + "tracing", "walkdir", ] @@ -8370,7 +8384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.111", @@ -8383,7 +8397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.111", @@ -8808,7 +8822,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration 0.5.1", + "system-configuration", "tokio", "tokio-rustls 0.24.1", "tokio-util", @@ -8878,7 +8892,7 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "reth" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-rpc-types", "aquamarine", @@ -8924,7 +8938,7 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8948,7 +8962,7 @@ dependencies = [ [[package]] name = "reth-chain-state" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8979,7 +8993,7 @@ dependencies = [ [[package]] name = "reth-chainspec" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-chains", "alloy-consensus", @@ -8999,7 +9013,7 @@ dependencies = [ [[package]] name = "reth-cli" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-genesis", "clap", @@ -9013,7 +9027,7 @@ dependencies = [ [[package]] name = "reth-cli-commands" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-chains", "alloy-consensus", @@ -9088,7 +9102,7 @@ dependencies = [ [[package]] name = "reth-cli-runner" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "reth-tasks", "tokio", @@ -9098,7 +9112,7 @@ dependencies = [ [[package]] name = "reth-cli-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -9116,7 +9130,7 @@ dependencies = [ [[package]] name = "reth-codecs" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9136,7 +9150,7 @@ dependencies = [ [[package]] name = "reth-codecs-derive" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "proc-macro2", "quote", @@ -9146,7 +9160,7 @@ dependencies = [ [[package]] name = "reth-config" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "eyre", "humantime-serde", @@ -9161,7 +9175,7 @@ dependencies = [ [[package]] name = "reth-consensus" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -9174,7 +9188,7 @@ dependencies = [ [[package]] name = "reth-consensus-common" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9186,7 +9200,7 @@ dependencies = [ [[package]] name = "reth-consensus-debug-client" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9212,7 +9226,7 @@ dependencies = [ [[package]] name = "reth-db" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "derive_more 2.0.1", @@ -9238,7 +9252,7 @@ dependencies = [ [[package]] name = "reth-db-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -9266,7 +9280,7 @@ dependencies = [ [[package]] name = "reth-db-common" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -9296,7 +9310,7 @@ dependencies = [ [[package]] name = "reth-db-models" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -9311,7 +9325,7 @@ dependencies = [ [[package]] name = "reth-discv4" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "alloy-rlp", @@ -9336,7 +9350,7 @@ dependencies = [ [[package]] name = "reth-discv5" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "alloy-rlp", @@ -9360,7 +9374,7 @@ dependencies = [ [[package]] name = "reth-dns-discovery" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "data-encoding", @@ -9384,7 +9398,7 @@ dependencies = [ [[package]] name = "reth-downloaders" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9419,7 +9433,7 @@ dependencies = [ [[package]] name = "reth-ecies" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "aes", "alloy-primitives 1.4.1", @@ -9450,7 +9464,7 @@ dependencies = [ [[package]] name = "reth-engine-local" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -9474,7 +9488,7 @@ dependencies = [ [[package]] name = "reth-engine-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9499,7 +9513,7 @@ dependencies = [ [[package]] name = "reth-engine-service" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "futures", "pin-project", @@ -9521,7 +9535,7 @@ dependencies = [ [[package]] name = "reth-engine-tree" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9576,7 +9590,7 @@ dependencies = [ [[package]] name = "reth-engine-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -9604,7 +9618,7 @@ dependencies = [ [[package]] name = "reth-era" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9620,7 +9634,7 @@ dependencies = [ [[package]] name = "reth-era-downloader" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "bytes", @@ -9635,7 +9649,7 @@ dependencies = [ [[package]] name = "reth-era-utils" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -9657,7 +9671,7 @@ dependencies = [ [[package]] name = "reth-errors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "reth-consensus", "reth-execution-errors", @@ -9668,7 +9682,7 @@ dependencies = [ [[package]] name = "reth-eth-wire" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-chains", "alloy-primitives 1.4.1", @@ -9696,7 +9710,7 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-chains", "alloy-consensus", @@ -9717,7 +9731,7 @@ dependencies = [ [[package]] name = "reth-ethereum" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-rpc-types-engine", "alloy-rpc-types-eth", @@ -9756,7 +9770,7 @@ dependencies = [ [[package]] name = "reth-ethereum-cli" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "clap", "eyre", @@ -9780,7 +9794,7 @@ dependencies = [ [[package]] name = "reth-ethereum-consensus" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9796,7 +9810,7 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -9814,7 +9828,7 @@ dependencies = [ [[package]] name = "reth-ethereum-forks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eip2124", "alloy-hardforks", @@ -9827,7 +9841,7 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9856,7 +9870,7 @@ dependencies = [ [[package]] name = "reth-ethereum-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9876,7 +9890,7 @@ dependencies = [ [[package]] name = "reth-etl" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "rayon", "reth-db-api", @@ -9886,7 +9900,7 @@ dependencies = [ [[package]] name = "reth-evm" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9909,7 +9923,7 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9931,7 +9945,7 @@ dependencies = [ [[package]] name = "reth-execution-errors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-evm", "alloy-primitives 1.4.1", @@ -9944,7 +9958,7 @@ dependencies = [ [[package]] name = "reth-execution-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9962,7 +9976,7 @@ dependencies = [ [[package]] name = "reth-exex" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10000,7 +10014,7 @@ dependencies = [ [[package]] name = "reth-exex-test-utils" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "eyre", @@ -10032,7 +10046,7 @@ dependencies = [ [[package]] name = "reth-exex-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -10046,7 +10060,7 @@ dependencies = [ [[package]] name = "reth-fs-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "serde", "serde_json", @@ -10056,7 +10070,7 @@ dependencies = [ [[package]] name = "reth-invalid-block-hooks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -10084,7 +10098,7 @@ dependencies = [ [[package]] name = "reth-ipc" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "bytes", "futures", @@ -10104,7 +10118,7 @@ dependencies = [ [[package]] name = "reth-libmdbx" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "bitflags 2.10.0", "byteorder", @@ -10120,7 +10134,7 @@ dependencies = [ [[package]] name = "reth-mdbx-sys" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "bindgen 0.71.1", "cc", @@ -10129,7 +10143,7 @@ dependencies = [ [[package]] name = "reth-metrics" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "futures", "metrics", @@ -10141,7 +10155,7 @@ dependencies = [ [[package]] name = "reth-net-banlist" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", ] @@ -10149,7 +10163,7 @@ dependencies = [ [[package]] name = "reth-net-nat" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "futures-util", "if-addrs", @@ -10163,7 +10177,7 @@ dependencies = [ [[package]] name = "reth-network" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10218,7 +10232,7 @@ dependencies = [ [[package]] name = "reth-network-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -10243,7 +10257,7 @@ dependencies = [ [[package]] name = "reth-network-p2p" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10266,7 +10280,7 @@ dependencies = [ [[package]] name = "reth-network-peers" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "alloy-rlp", @@ -10281,7 +10295,7 @@ dependencies = [ [[package]] name = "reth-network-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eip2124", "humantime-serde", @@ -10295,7 +10309,7 @@ dependencies = [ [[package]] name = "reth-nippy-jar" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "anyhow", "bincode 1.3.3", @@ -10312,7 +10326,7 @@ dependencies = [ [[package]] name = "reth-node-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-rpc-types-engine", "eyre", @@ -10336,7 +10350,7 @@ dependencies = [ [[package]] name = "reth-node-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10404,7 +10418,7 @@ dependencies = [ [[package]] name = "reth-node-core" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10457,7 +10471,7 @@ dependencies = [ [[package]] name = "reth-node-ethereum" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-network", @@ -10495,7 +10509,7 @@ dependencies = [ [[package]] name = "reth-node-ethstats" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -10519,7 +10533,7 @@ dependencies = [ [[package]] name = "reth-node-events" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10543,7 +10557,7 @@ dependencies = [ [[package]] name = "reth-node-metrics" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "eyre", "http 1.4.0", @@ -10565,7 +10579,7 @@ dependencies = [ [[package]] name = "reth-node-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "reth-chainspec", "reth-db-api", @@ -10577,7 +10591,7 @@ dependencies = [ [[package]] name = "reth-optimism-chainspec" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-chains", "alloy-consensus", @@ -10605,7 +10619,7 @@ dependencies = [ [[package]] name = "reth-optimism-cli" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10655,7 +10669,7 @@ dependencies = [ [[package]] name = "reth-optimism-consensus" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10680,7 +10694,7 @@ dependencies = [ [[package]] name = "reth-optimism-evm" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10708,7 +10722,7 @@ dependencies = [ [[package]] name = "reth-optimism-flashblocks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10747,7 +10761,7 @@ dependencies = [ [[package]] name = "reth-optimism-forks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-op-hardforks", "alloy-primitives 1.4.1", @@ -10758,7 +10772,7 @@ dependencies = [ [[package]] name = "reth-optimism-node" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -10804,7 +10818,7 @@ dependencies = [ [[package]] name = "reth-optimism-payload-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10844,7 +10858,7 @@ dependencies = [ [[package]] name = "reth-optimism-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10864,7 +10878,7 @@ dependencies = [ [[package]] name = "reth-optimism-rpc" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10925,7 +10939,7 @@ dependencies = [ [[package]] name = "reth-optimism-storage" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "reth-optimism-primitives", @@ -10935,7 +10949,7 @@ dependencies = [ [[package]] name = "reth-optimism-txpool" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10971,7 +10985,7 @@ dependencies = [ [[package]] name = "reth-payload-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -10992,7 +11006,7 @@ dependencies = [ [[package]] name = "reth-payload-builder-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "pin-project", "reth-payload-primitives", @@ -11004,7 +11018,7 @@ dependencies = [ [[package]] name = "reth-payload-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -11024,7 +11038,7 @@ dependencies = [ [[package]] name = "reth-payload-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -11034,7 +11048,7 @@ dependencies = [ [[package]] name = "reth-payload-validator" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -11044,7 +11058,7 @@ dependencies = [ [[package]] name = "reth-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "c-kzg", @@ -11058,7 +11072,7 @@ dependencies = [ [[package]] name = "reth-primitives-traits" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11091,7 +11105,7 @@ dependencies = [ [[package]] name = "reth-provider" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11135,7 +11149,7 @@ dependencies = [ [[package]] name = "reth-prune" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11162,7 +11176,7 @@ dependencies = [ [[package]] name = "reth-prune-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "arbitrary", @@ -11177,7 +11191,7 @@ dependencies = [ [[package]] name = "reth-ress-protocol" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -11196,7 +11210,7 @@ dependencies = [ [[package]] name = "reth-ress-provider" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -11223,7 +11237,7 @@ dependencies = [ [[package]] name = "reth-revm" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "reth-primitives-traits", @@ -11236,7 +11250,7 @@ dependencies = [ [[package]] name = "reth-rpc" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -11315,7 +11329,7 @@ dependencies = [ [[package]] name = "reth-rpc-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-genesis", @@ -11343,7 +11357,7 @@ dependencies = [ [[package]] name = "reth-rpc-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-network", "alloy-provider", @@ -11382,7 +11396,7 @@ dependencies = [ [[package]] name = "reth-rpc-convert" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-json-rpc", @@ -11409,7 +11423,7 @@ dependencies = [ [[package]] name = "reth-rpc-engine-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -11439,7 +11453,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -11483,7 +11497,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11530,7 +11544,7 @@ dependencies = [ [[package]] name = "reth-rpc-layer" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-rpc-types-engine", "http 1.4.0", @@ -11544,7 +11558,7 @@ dependencies = [ [[package]] name = "reth-rpc-server-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -11560,7 +11574,7 @@ dependencies = [ [[package]] name = "reth-stages" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11608,7 +11622,7 @@ dependencies = [ [[package]] name = "reth-stages-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -11635,7 +11649,7 @@ dependencies = [ [[package]] name = "reth-stages-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "arbitrary", @@ -11649,7 +11663,7 @@ dependencies = [ [[package]] name = "reth-static-file" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "parking_lot", @@ -11669,7 +11683,7 @@ dependencies = [ [[package]] name = "reth-static-file-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "clap", @@ -11681,7 +11695,7 @@ dependencies = [ [[package]] name = "reth-storage-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11704,7 +11718,7 @@ dependencies = [ [[package]] name = "reth-storage-errors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-eips", "alloy-primitives 1.4.1", @@ -11720,7 +11734,7 @@ dependencies = [ [[package]] name = "reth-tasks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "auto_impl", "dyn-clone", @@ -11738,7 +11752,7 @@ dependencies = [ [[package]] name = "reth-testing-utils" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11754,7 +11768,7 @@ dependencies = [ [[package]] name = "reth-tokio-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "tokio", "tokio-stream", @@ -11764,7 +11778,7 @@ dependencies = [ [[package]] name = "reth-tracing" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "clap", "eyre", @@ -11781,7 +11795,7 @@ dependencies = [ [[package]] name = "reth-tracing-otlp" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "clap", "eyre", @@ -11798,7 +11812,7 @@ dependencies = [ [[package]] name = "reth-transaction-pool" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11839,7 +11853,7 @@ dependencies = [ [[package]] name = "reth-trie" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11864,7 +11878,7 @@ dependencies = [ [[package]] name = "reth-trie-common" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-consensus", "alloy-primitives 1.4.1", @@ -11891,7 +11905,7 @@ dependencies = [ [[package]] name = "reth-trie-db" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "reth-db-api", @@ -11904,7 +11918,7 @@ dependencies = [ [[package]] name = "reth-trie-parallel" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "alloy-rlp", @@ -11929,7 +11943,7 @@ dependencies = [ [[package]] name = "reth-trie-sparse" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "alloy-rlp", @@ -11948,7 +11962,7 @@ dependencies = [ [[package]] name = "reth-trie-sparse-parallel" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "alloy-primitives 1.4.1", "alloy-rlp", @@ -11966,7 +11980,7 @@ dependencies = [ [[package]] name = "reth-zstd-compressors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" +source = "git+https://github.com/web3x3/reth?branch=metis-1.9.3#1b2f7729da923f99a459cce1e9eb5c2fdbcc3339" dependencies = [ "zstd", ] @@ -13615,18 +13629,7 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation 0.9.4", - "system-configuration-sys 0.5.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", - "system-configuration-sys 0.6.0", + "system-configuration-sys", ] [[package]] @@ -13639,16 +13642,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tag_ptr" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 4e43917e..c1fc0a67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -149,44 +149,56 @@ op-alloy-rpc-types-engine = { version = "0.22.0", features = ["serde"] } op-revm = { version = "12.0.2"} # Reth dependencies -reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", default-features = false } -reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-tracing = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", features = [ +reth = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3", default-features = false } +reth-chainspec = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-node-ethereum = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-evm-ethereum = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-evm = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-primitives = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-tracing = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-ethereum = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3", features = [ "full", ] } -reth-cli-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-chain-state = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-node-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", features = [ +reth-cli-util = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-chain-state = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-primitives-traits = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-ethereum-primitives = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-node-api = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-node-core = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-db = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-db-api = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-provider = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3", features = [ "test-utils", ] } -reth-ethereum-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-stages = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } +reth-ethereum-consensus = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-stages = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-basic-payload-builder = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-consensus-common = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-errors = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-payload-builder = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-payload-builder-primitives = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-payload-primitives = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-revm = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-storage-api = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-transaction-pool = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-node-builder = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-ethereum-payload-builder = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-ethereum-engine-primitives = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } # OP Reth dependencies -reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-forks = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-node = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } +reth-optimism-chainspec = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-cli = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-consensus = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-evm = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-forks = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-node = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-payload-builder = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-primitives = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-optimism-rpc = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } # Reth test dependencies -reth-exex-test-utils = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } -reth-testing-utils = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } +reth-exex-test-utils = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } +reth-testing-utils = { git = "https://github.com/web3x3/reth", branch = "metis-1.9.3" } # Revmc dependencies revmc = { git = "https://github.com/paradigmxyz/revmc", features = [ @@ -292,3 +304,4 @@ inherits = "profiling" inherits = "release" lto = "fat" codegen-units = 1 + diff --git a/crates/chain/Cargo.toml b/crates/chain/Cargo.toml index da82c103..03e42adf 100644 --- a/crates/chain/Cargo.toml +++ b/crates/chain/Cargo.toml @@ -22,6 +22,7 @@ alloy-eips.workspace = true alloy-sol-types.workspace = true alloy-genesis.workspace = true alloy-consensus.workspace = true +alloy-rlp.workspace = true revm.workspace = true @@ -40,6 +41,18 @@ reth-primitives-traits.workspace = true reth-ethereum-primitives.workspace = true reth-node-api.workspace = true reth-node-core.workspace = true +reth-basic-payload-builder.workspace = true +reth-consensus-common.workspace = true +reth-errors.workspace = true +reth-payload-builder.workspace = true +reth-payload-builder-primitives.workspace = true +reth-payload-primitives.workspace = true +reth-revm.workspace = true +reth-storage-api.workspace = true +reth-transaction-pool.workspace = true +reth-node-builder.workspace = true +reth-ethereum-payload-builder.workspace = true +reth-ethereum-engine-primitives.workspace = true # Alloy OP alloy-op-evm.workspace = true diff --git a/crates/chain/bin/metis.rs b/crates/chain/bin/metis.rs index a406ea58..e474380c 100644 --- a/crates/chain/bin/metis.rs +++ b/crates/chain/bin/metis.rs @@ -5,7 +5,9 @@ static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::ne use clap::Parser; use metis_chain::hook_provider::HookExecutorBuilder; use metis_chain::op_provider::OpParallelNode; +use metis_chain::parallel_payload_builder::ParallelPayloadBuilderBuilder; use metis_chain::provider::ParallelExecutorBuilder; +use reth::builder::components::BasicPayloadServiceBuilder; use reth::cli::Cli; use reth_node_ethereum::EthereumNode; use reth_node_ethereum::node::EthereumAddOns; @@ -24,7 +26,7 @@ fn main() { if std::env::var_os("ENABLE_OP_EXECUTOR").is_some() { if let Err(err) = OpCli::::parse().run( async move |builder, rollup_args| { - info!(target: "reth::cli", "Launching node"); + info!(target: "metis::cli", "Launching node"); if std::env::var_os("ENABLE_PARALLEL_EXECUTOR").is_some() { let handle = builder.node(OpParallelNode::new(OpNode::new(rollup_args))); handle.launch().await?.wait_for_node_exit().await @@ -44,9 +46,13 @@ fn main() { // Use the default ethereum node types .with_types::() // Configure the components of the node - // use default ethereum components but use our parallel executor. + // Use our parallel executor AND parallel payload builder .with_components( - EthereumNode::components().executor(ParallelExecutorBuilder::default()), + EthereumNode::components() + .executor(ParallelExecutorBuilder::default()) + .payload(BasicPayloadServiceBuilder::new( + ParallelPayloadBuilderBuilder::default(), + )), ) .with_add_ons(EthereumAddOns::default()); handle.launch().await?.wait_for_node_exit().await diff --git a/crates/chain/src/lib.rs b/crates/chain/src/lib.rs index 0c3e5c3c..e34743d7 100644 --- a/crates/chain/src/lib.rs +++ b/crates/chain/src/lib.rs @@ -1,4 +1,10 @@ pub mod hook_provider; pub mod op_provider; +pub mod parallel_execution_context; +pub mod parallel_payload_builder; pub mod provider; pub mod state; + +// Re-export important types for external use +pub use parallel_execution_context::{ExecutionMode, ParallelExecutionContext}; +pub use provider::BatchExecutable; diff --git a/crates/chain/src/op_provider.rs b/crates/chain/src/op_provider.rs index 917dd63a..cbbe3f20 100644 --- a/crates/chain/src/op_provider.rs +++ b/crates/chain/src/op_provider.rs @@ -302,7 +302,8 @@ where })? .into_iter() .map(|r| { - self.evm_mut().db_mut().commit(r.state); + // Commit state from result_and_state + self.evm_mut().db_mut().commit(r.result_and_state.state); total_gas_used += &r.receipt.cumulative_gas_used; match &r.receipt.tx_type { TxType::Legacy => OpReceipt::Legacy(Receipt::from(r.receipt)), @@ -325,10 +326,17 @@ where fn post_execution(&mut self) -> Result<(), BlockExecutionError> { let balance_increments = post_block_balance_increments::
(&self.spec, self.evm().block(), &[], None); + + // CRITICAL: Sort balance_increments by address to ensure deterministic commit order. + // HashMap iteration order is non-deterministic, which can cause different state roots + // across nodes. Use BTreeMap to maintain sorted order. + let sorted_balance_increments: std::collections::BTreeMap<_, _> = + balance_increments.into_iter().collect(); + // increment balances self.evm_mut() .db_mut() - .increment_balances(balance_increments.clone()) + .increment_balances(sorted_balance_increments) .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; Ok(()) diff --git a/crates/chain/src/parallel_execution_context.rs b/crates/chain/src/parallel_execution_context.rs new file mode 100644 index 00000000..c6dd368c --- /dev/null +++ b/crates/chain/src/parallel_execution_context.rs @@ -0,0 +1,157 @@ +//! Parallel Execution Context - Execution state management +//! +//! This module tracks the execution context and ensures post_execution +//! is called exactly once per block execution. + +use alloy_primitives::TxHash; +use std::collections::HashMap; + +/// Execution mode for parallel block executor +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ExecutionMode { + /// Payload Builder mode - constructing new blocks (parallel execution) + Builder, + /// Payload Validator mode - validating received blocks (serial execution) + Validator, + /// Block Import mode - importing/syncing blocks (parallel execution) + Import, +} + +/// Cached result from parallel execution +#[derive(Debug, Clone)] +pub struct CachedExecutionResult { + pub gas_used: u64, + pub receipt: reth_primitives::Receipt, +} + +/// Context for tracking parallel execution state +#[derive(Debug)] +pub struct ParallelExecutionContext { + /// Whether post_execution has been called for this block + pub post_execution_called: bool, + /// Current execution mode + pub execution_mode: ExecutionMode, + /// Cache of parallel execution results (tx_hash -> result) + /// Used in payload builder to avoid re-executing transactions + pub execution_cache: HashMap, +} + +impl ParallelExecutionContext { + /// Create a new execution context + pub fn new(mode: ExecutionMode) -> Self { + Self { + post_execution_called: false, + execution_mode: mode, + execution_cache: HashMap::new(), + } + } + + /// Check if parallel execution should be used based on mode + pub fn should_execute_in_parallel(&self) -> bool { + matches!( + self.execution_mode, + ExecutionMode::Builder | ExecutionMode::Import + ) + } + + /// Reset the context for a new block + pub fn reset(&mut self) { + self.post_execution_called = false; + self.execution_cache.clear(); + } + + /// Mark post_execution as called + pub fn mark_post_execution_called(&mut self) { + self.post_execution_called = true; + } + + /// Cache execution result for a transaction + pub fn cache_result( + &mut self, + tx_hash: TxHash, + gas_used: u64, + receipt: reth_primitives::Receipt, + ) { + self.execution_cache + .insert(tx_hash, CachedExecutionResult { gas_used, receipt }); + } + + /// Get cached execution result + pub fn get_cached_result(&self, tx_hash: &TxHash) -> Option<&CachedExecutionResult> { + self.execution_cache.get(tx_hash) + } +} + +impl Default for ParallelExecutionContext { + fn default() -> Self { + // Default to Builder mode (parallel execution) + Self::new(ExecutionMode::Builder) + } +} + +// Thread-local global cache for parallel execution results +// This is used by payload builder to pass results to the executor +use std::cell::RefCell; + +thread_local! { + static GLOBAL_EXECUTION_CACHE: RefCell> = RefCell::new(HashMap::new()); +} + +/// Set global cache with parallel execution results +/// Called by payload builder before serial execution loop +pub fn set_global_cache( + tx_hashes: &[TxHash], + results: &[metis_pe::TxExecutionResult], +) { + GLOBAL_EXECUTION_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + cache.clear(); + for (tx_hash, result) in tx_hashes.iter().zip(results.iter()) { + cache.insert( + *tx_hash, + CachedExecutionResult { + gas_used: result.receipt.cumulative_gas_used, + receipt: result.receipt.clone(), + }, + ); + } + tracing::debug!(target: "metis::parallel", + "Set global cache with {} parallel execution results", + cache.len() + ); + }); +} + +/// Get cached result from global cache +/// Called by executor during execute_transaction +pub fn get_global_cached_result(tx_hash: &TxHash) -> Option { + GLOBAL_EXECUTION_CACHE.with(|cache| cache.borrow().get(tx_hash).cloned()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_execution_modes() { + let builder_ctx = ParallelExecutionContext::new(ExecutionMode::Builder); + assert!(builder_ctx.should_execute_in_parallel()); + assert!(!builder_ctx.post_execution_called); + + let validator_ctx = ParallelExecutionContext::new(ExecutionMode::Validator); + assert!(!validator_ctx.should_execute_in_parallel()); + + let import_ctx = ParallelExecutionContext::new(ExecutionMode::Import); + assert!(import_ctx.should_execute_in_parallel()); + } + + #[test] + fn test_context_reset() { + let mut ctx = ParallelExecutionContext::default(); + ctx.mark_post_execution_called(); + assert!(ctx.post_execution_called); + + ctx.reset(); + assert!(!ctx.post_execution_called); + } +} diff --git a/crates/chain/src/parallel_payload_builder.rs b/crates/chain/src/parallel_payload_builder.rs new file mode 100644 index 00000000..69a81148 --- /dev/null +++ b/crates/chain/src/parallel_payload_builder.rs @@ -0,0 +1,687 @@ +//! Parallel Ethereum payload builder implementation. +//! +//! This module provides a custom payload builder that executes transactions in parallel +//! using the Block-STM based parallel executor instead of the default serial execution. + +use alloy_consensus::{Transaction, transaction::Recovered}; +use alloy_evm::ToTxEnv; +use alloy_primitives::U256; +use alloy_rlp::Encodable; +use metis_primitives::TxEnv; +use reth_basic_payload_builder::{ + BuildArguments, BuildOutcome, MissingPayloadBehaviour, PayloadBuilder, PayloadConfig, + is_better_payload, +}; +use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks}; +use reth_consensus_common::validation::MAX_RLP_BLOCK_SIZE; +use reth_errors::ConsensusError; +use reth_ethereum_engine_primitives::{EthBuiltPayload, EthPayloadBuilderAttributes}; +use reth_ethereum_payload_builder::EthereumBuilderConfig; +use reth_ethereum_primitives::{EthPrimitives, TransactionSigned}; +use reth_evm::{ + ConfigureEvm, Evm, NextBlockEnvAttributes, + execute::{BlockBuilder, BlockBuilderOutcome}, +}; +use reth_evm_ethereum::EthEvmConfig; +use reth_node_api::{FullNodeTypes, NodeTypes, PrimitivesTy, TxTy}; +use reth_node_builder::{ + BuilderContext, PayloadTypes, components::PayloadBuilderBuilder as PayloadBuilderBuilderTrait, +}; +use reth_node_core::cli::config::PayloadBuilderConfig; +use reth_payload_builder_primitives::PayloadBuilderError; +use reth_payload_primitives::PayloadBuilderAttributes; +use reth_revm::{database::StateProviderDatabase, db::State}; +use reth_storage_api::StateProviderFactory; +use reth_transaction_pool::{ + BestTransactions, BestTransactionsAttributes, PoolTransaction, TransactionPool, + ValidPoolTransaction, + error::{Eip4844PoolTransactionError, InvalidPoolTransactionError}, +}; +use revm::Database; +use revm::context_interface::Block as _; +use std::num::NonZeroUsize; +use std::sync::Arc; +use tracing::{debug, info, trace, warn}; + +use crate::state::StateStorageAdapter; + +type BestTransactionsIter = Box< + dyn BestTransactions::Transaction>>>, +>; + +/// Simple error wrapper for parallel execution errors +#[derive(Debug)] +struct ParallelExecutionError(String); + +impl std::fmt::Display for ParallelExecutionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::error::Error for ParallelExecutionError {} + +/// Parallel Ethereum payload builder +/// +/// This builder collects transactions and executes them in parallel using the Block-STM +/// parallel executor, instead of executing them one by one like the default builder. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ParallelEthereumPayloadBuilder { + /// Client providing access to node state. + client: Client, + /// Transaction pool. + pool: Pool, + /// The type responsible for creating the evm. + evm_config: EvmConfig, + /// Payload builder configuration. + builder_config: EthereumBuilderConfig, +} + +impl ParallelEthereumPayloadBuilder { + /// `ParallelEthereumPayloadBuilder` constructor. + pub const fn new( + client: Client, + pool: Pool, + evm_config: EvmConfig, + builder_config: EthereumBuilderConfig, + ) -> Self { + Self { + client, + pool, + evm_config, + builder_config, + } + } +} + +// PayloadBuilder implementation for parallel execution +impl PayloadBuilder + for ParallelEthereumPayloadBuilder +where + EvmConfig: ConfigureEvm, + <::BlockExecutorFactory as reth_evm::block::BlockExecutorFactory>::EvmFactory: + alloy_evm::EvmFactory< + Spec = revm::primitives::hardfork::SpecId, + BlockEnv = revm::context::BlockEnv, + >, + Client: StateProviderFactory + ChainSpecProvider + Clone, + Pool: TransactionPool>, +{ + type Attributes = EthPayloadBuilderAttributes; + type BuiltPayload = EthBuiltPayload; + + fn try_build( + &self, + args: BuildArguments, + ) -> Result, PayloadBuilderError> { + parallel_ethereum_payload( + self.evm_config.clone(), + self.client.clone(), + self.pool.clone(), + self.builder_config.clone(), + args, + |attributes| self.pool.best_transactions_with_attributes(attributes), + ) + } + + fn on_missing_payload( + &self, + _args: BuildArguments, + ) -> MissingPayloadBehaviour { + if self.builder_config.await_payload_on_missing { + MissingPayloadBehaviour::AwaitInProgress + } else { + MissingPayloadBehaviour::RaceEmptyPayload + } + } + + fn build_empty_payload( + &self, + config: PayloadConfig, + ) -> Result { + let args = BuildArguments::new(Default::default(), config, Default::default(), None); + + parallel_ethereum_payload( + self.evm_config.clone(), + self.client.clone(), + self.pool.clone(), + self.builder_config.clone(), + args, + |attributes| self.pool.best_transactions_with_attributes(attributes), + )? + .into_payload() + .ok_or_else(|| PayloadBuilderError::MissingPayload) + } +} + +/// Transaction collected for batch execution +#[derive(Debug)] +struct CollectedTransaction { + /// The consensus transaction (recovered with signature) + tx: Recovered>, + /// Transaction hash + tx_hash: alloy_primitives::TxHash, + /// Gas used by this transaction (estimated) + _gas_limit: u64, + /// Base fee at the time + _base_fee: u64, + /// Blob gas used (if EIP-4844) + _blob_gas_used: Option, +} + +/// Constructs an Ethereum transaction payload using parallel execution. +/// +/// This is the core function that implements the parallel execution strategy: +/// 1. Collect all valid transactions (same validation as Reth) +/// 2. Execute them in PARALLEL using execute_transactions() batch API +/// 3. Process results and build the payload +#[inline] +pub fn parallel_ethereum_payload( + evm_config: EvmConfig, + client: Client, + pool: Pool, + builder_config: EthereumBuilderConfig, + args: BuildArguments, + best_txs: F, +) -> Result, PayloadBuilderError> +where + EvmConfig: ConfigureEvm, +// metis-pe currently expects `alloy_evm::EvmEnv` with default generics +// (revm `SpecId` + revm `BlockEnv`). Constrain EVM config accordingly so we can pass +// the canonical `next_evm_env` directly without lossy conversions. + <::BlockExecutorFactory as reth_evm::block::BlockExecutorFactory>::EvmFactory: + alloy_evm::EvmFactory< + Spec = revm::primitives::hardfork::SpecId, + BlockEnv = revm::context::BlockEnv, + >, + Client: StateProviderFactory + ChainSpecProvider, + Pool: TransactionPool>, + F: FnOnce(BestTransactionsAttributes) -> BestTransactionsIter, +{ + let BuildArguments { + mut cached_reads, + config, + cancel, + best_payload, + } = args; + let PayloadConfig { + parent_header, + attributes, + } = config; + + let state_provider = client.state_by_block_hash(parent_header.hash())?; + let state = StateProviderDatabase::new(&state_provider); + let mut db = State::builder() + .with_database(cached_reads.as_db_mut(state)) + .with_bundle_update() + .build(); + + // Build NextBlockEnvAttributes once and reuse it for: + // 1) builder_for_next_block (reth canonical builder env) + // 2) evm_config.next_evm_env (reth canonical cfg+block env for execution) + let next_attrs = NextBlockEnvAttributes { + timestamp: attributes.timestamp(), + suggested_fee_recipient: attributes.suggested_fee_recipient(), + prev_randao: attributes.prev_randao(), + gas_limit: builder_config.gas_limit(parent_header.gas_limit), + parent_beacon_block_root: attributes.parent_beacon_block_root(), + withdrawals: Some(attributes.withdrawals().clone()), + }; + + let mut builder = evm_config + .builder_for_next_block(&mut db, &parent_header, next_attrs.clone()) + .map_err(PayloadBuilderError::other)?; + + let chain_spec = client.chain_spec(); + + info!(target: "payload_builder", id=%attributes.id, parent_header = ?parent_header.hash(), parent_number = parent_header.number, "Building payload with parallel execution"); + + let block_gas_limit: u64 = builder.evm_mut().block().gas_limit(); + let base_fee = builder.evm_mut().block().basefee(); + + let mut best_txs = best_txs(BestTransactionsAttributes::new( + base_fee, + builder + .evm_mut() + .block() + .blob_gasprice() + .map(|gasprice| gasprice as u64), + )); + + builder.apply_pre_execution_changes().map_err(|err| { + warn!(target: "payload_builder", %err, "failed to apply pre-execution changes"); + PayloadBuilderError::Internal(err.into()) + })?; + + let blob_params = chain_spec.blob_params_at_timestamp(attributes.timestamp); + let max_blob_count = blob_params + .as_ref() + .map(|params| params.max_blob_count) + .unwrap_or_default(); + + let is_osaka = chain_spec.is_osaka_active_at_timestamp(attributes.timestamp); + + // ==================================================================== + // STEP 1: Collect all valid transactions (same validation as Reth) + // ==================================================================== + let mut collected_transactions = Vec::new(); + let mut cumulative_gas_for_validation = 0u64; + let mut block_blob_count = 0u64; + let mut block_transactions_rlp_length = 0usize; + let mut blob_sidecars_to_include = Vec::new(); + + debug!(target: "payload_builder", "Phase 1: Collecting and validating transactions"); + debug!(target: "payload_builder", + "Collection params: block_gas_limit={}, max_blob_count={:?}, is_osaka={}", + block_gas_limit, max_blob_count, is_osaka + ); + + while let Some(pool_tx) = best_txs.next() { + // Check gas limit + if cumulative_gas_for_validation + pool_tx.gas_limit() > block_gas_limit { + best_txs.mark_invalid( + &pool_tx, + InvalidPoolTransactionError::ExceedsGasLimit(pool_tx.gas_limit(), block_gas_limit), + ); + continue; + } + + // Check if cancelled + if cancel.is_cancelled() { + return Ok(BuildOutcome::Cancelled); + } + + // Convert to signed transaction + let tx = pool_tx.to_consensus(); + + // Check block size (Osaka) + let estimated_block_size_with_tx = block_transactions_rlp_length + + tx.inner().length() + + attributes.withdrawals().length() + + 1024; + + if is_osaka && estimated_block_size_with_tx > MAX_RLP_BLOCK_SIZE { + best_txs.mark_invalid( + &pool_tx, + InvalidPoolTransactionError::OversizedData { + size: estimated_block_size_with_tx, + limit: MAX_RLP_BLOCK_SIZE, + }, + ); + continue; + } + + // Check blob limit + let mut blob_sidecar_for_tx = None; + if let Some(blob_tx) = tx.as_eip4844() { + let tx_blob_count = blob_tx.tx().blob_versioned_hashes.len() as u64; + + if block_blob_count + tx_blob_count > max_blob_count { + trace!(target: "payload_builder", tx=?tx.hash(), ?block_blob_count, "skipping blob transaction"); + best_txs.mark_invalid( + &pool_tx, + InvalidPoolTransactionError::Eip4844( + Eip4844PoolTransactionError::TooManyEip4844Blobs { + have: block_blob_count + tx_blob_count, + permitted: max_blob_count, + }, + ), + ); + continue; + } + + let blob_sidecar_result = 'sidecar: { + let Some(sidecar) = pool + .get_blob(*tx.hash()) + .map_err(PayloadBuilderError::other)? + else { + break 'sidecar Err(Eip4844PoolTransactionError::MissingEip4844BlobSidecar); + }; + + if is_osaka { + if sidecar.is_eip7594() { + Ok(sidecar) + } else { + Err(Eip4844PoolTransactionError::UnexpectedEip4844SidecarAfterOsaka) + } + } else if sidecar.is_eip4844() { + Ok(sidecar) + } else { + Err(Eip4844PoolTransactionError::UnexpectedEip7594SidecarBeforeOsaka) + } + }; + + blob_sidecar_for_tx = match blob_sidecar_result { + Ok(sidecar) => Some(sidecar), + Err(error) => { + best_txs.mark_invalid(&pool_tx, InvalidPoolTransactionError::Eip4844(error)); + continue; + } + }; + + // Update blob count + block_blob_count += tx_blob_count; + + // Skip further blobs if we've reached the limit + if block_blob_count == max_blob_count { + best_txs.skip_blobs(); + } + } + + // Transaction passed all validation - collect it + cumulative_gas_for_validation += pool_tx.gas_limit(); + block_transactions_rlp_length += tx.inner().length(); + + let tx_hash = *tx.hash(); + + // Calculate blob gas used for this transaction + let tx_blob_gas_used = tx.blob_gas_used(); + + collected_transactions.push(CollectedTransaction { + tx: tx.clone(), + tx_hash, + _gas_limit: pool_tx.gas_limit(), + _base_fee: base_fee, + _blob_gas_used: tx_blob_gas_used, + }); + + // Store blob sidecar for later inclusion + if let Some(sidecar) = blob_sidecar_for_tx { + blob_sidecars_to_include.push(sidecar); + } + } + + debug!(target: "payload_builder", + tx_count = collected_transactions.len(), + "Phase 1 complete: collected {} transactions, total_gas_limit={}, blob_count={}", + collected_transactions.len(), + cumulative_gas_for_validation, + blob_sidecars_to_include.len() + ); + + // ==================================================================== + // STEP 2: Execute transactions in parallel + // 1. Execute all transactions in parallel using Block-STM + // 2. Save parallel execution receipts + // 3. Add transactions to block via builder (for proper block structure) + // 4. Replace receipts with parallel execution results + // ==================================================================== + let mut total_fees = U256::ZERO; + + if !collected_transactions.is_empty() { + debug!(target: "payload_builder", + "Phase 2: Starting parallel execution of {} transactions", + collected_transactions.len() + ); + + let tx_count = collected_transactions.len(); + let parallel_start = std::time::Instant::now(); + + // IMPORTANT: + // Do NOT hand-roll cfg_env/spec_id/block_env. Must match reth's canonical next_evm_env, + // otherwise proposer state_root will not match validator/other nodes. + let evm_env = evm_config + .next_evm_env(&parent_header, &next_attrs) + .map_err(PayloadBuilderError::other)?; + + let block_number = parent_header.number + 1; + // Ensure state clearing semantics match reth serial execution. + // This affects empty-account clearing (EIP-161 / SpuriousDragon) and can change state root. + let state_clear_flag = chain_spec.is_spurious_dragon_active_at_block(block_number); + builder + .evm_mut() + .db_mut() + .set_state_clear_flag(state_clear_flag); + + // Convert transactions to TxEnv format + let tx_envs: Vec = collected_transactions + .iter() + .map(|ct| ct.tx.to_tx_env()) + .collect(); + + debug!(target: "payload_builder", "Step 2a: Executing {} transactions in parallel", tx_count); + + // Execute in parallel + let num_threads = num_cpus::get(); + // IMPORTANT: align metis-pe ResultAndState
with reth executor's concrete HaltReason type + let mut parallel_executor = metis_pe::ParallelExecutor::< + <<::BlockExecutorFactory as reth_evm::block::BlockExecutorFactory>::EvmFactory as alloy_evm::EvmFactory>::HaltReason, + >::default(); + + let results = match parallel_executor.execute( + StateStorageAdapter::new(builder.evm_mut().db_mut()), + evm_env, + tx_envs, + NonZeroUsize::new(num_threads).unwrap(), + ) { + Ok(results) => results, + Err(err) => { + warn!(target: "payload_builder", "Parallel execution failed: {:?}", err); + return Err(PayloadBuilderError::other(ParallelExecutionError(format!( + "{err:?}" + )))); + } + }; + + let parallel_duration = parallel_start.elapsed(); + debug!(target: "payload_builder", + "Parallel execution stats: total_txs={}, duration={:?}, avg_per_tx={:?}us", + tx_count, + parallel_duration, + parallel_duration.as_micros() / tx_count as u128 + ); + + // Fee estimation and cumulative gas will be computed while committing pre-executed ResultAndState + // in Step 2b, using the canonical gas_used returned by commit_transaction. + total_fees = U256::ZERO; + + // Step 2b: Commit pre-executed transactions using reth's native commit_transaction + // + // IMPORTANT: + // - Do NOT manually apply state (StateAccumulator / insert_account_with_storage). + // - Do NOT cache/replace receipts. + // The only correct way to keep proposer/validator roots identical is to feed the + // precomputed ResultAndState into the executor's commit_transaction. + debug!(target: "payload_builder", + "Step 2b: Committing {} pre-executed transactions via commit_transaction()", + tx_count + ); + + let commit_start = std::time::Instant::now(); + let mut committed_count = 0usize; + + // Consume txs/results in the same order. + for (idx, (ct, result)) in collected_transactions + .into_iter() + .zip(results.into_iter()) + .enumerate() + { + let tx_hash = ct.tx_hash; + + // 1) Add transaction to block body (no execution) + let tx = ct.tx; + // Fee estimation (only used to compare payloads) must be computed before moving `tx` + let miner_fee = tx + .effective_tip_per_gas(base_fee) + .expect("fee is always valid"); + builder.push_transaction_to_body(tx.clone())?; + + // 2) Commit the pre-executed ResultAndState using executor.commit_transaction() + // IMPORTANT: + // revm::db::State will panic if we commit accounts that are not present in its internal + // cache ("All accounts should be present inside cache"). Prewarm the cache for every + // touched address in this tx's state before committing. + { + let mut addrs: Vec<_> = result.result_and_state.state.keys().copied().collect(); + addrs.sort_unstable(); + let db = builder.evm_mut().db_mut(); + for addr in addrs { + db.basic(addr).map_err(PayloadBuilderError::other)?; + } + } + match builder.commit_executed_transaction(result.result_and_state, tx) { + Ok(gas_used) => { + committed_count += 1; + + total_fees += alloy_primitives::U256::from(miner_fee) + * alloy_primitives::U256::from(gas_used); + } + Err(err) => { + warn!(target: "payload_builder", + "❌ TX[{}] commit failed for 0x{:x}: {:?}", + idx, tx_hash, err + ); + return Err(PayloadBuilderError::other(err)); + } + } + } + + let commit_duration = commit_start.elapsed(); + debug!(target: "payload_builder", + "Step 2b complete: committed {} txs in {:?} (avg {:?} per tx)", + committed_count, + commit_duration, + commit_duration / (committed_count.max(1) as u32) + ); + + debug!(target: "payload_builder", + "Execution stats: parallel_executed={}, committed={}, parallel_time={:?}, commit_time={:?}, total_time={:?}", + tx_count, committed_count, + parallel_duration, commit_duration, parallel_start.elapsed() + ); + } + + debug!(target: "payload_builder", + %total_fees, + "Phase 2 complete: fees={}", + total_fees + ); + + // ==================================================================== + // STEP 3: Check if we have a better block and finalize + // ==================================================================== + if !is_better_payload(best_payload.as_ref(), total_fees) { + drop(builder); + return Ok(BuildOutcome::Aborted { + fees: total_fees, + cached_reads, + }); + } + + // Call builder.finish() to apply post_execution (block rewards, withdrawals, etc.) + // and calculate the final state root. + // Note: We've already executed transactions in parallel and committed the state, + // so builder.finish() will add block rewards on top of our transaction state. + + debug!(target: "payload_builder", "Finalizing block and applying post_execution"); + + let BlockBuilderOutcome { + execution_result, + block, + .. + } = builder.finish(&state_provider)?; + + // Receipts are now correctly generated by commit_transaction during parallel execution + debug!(target: "payload_builder", + "Block finalized: {} receipts, gas_used={}", + execution_result.receipts.len(), + execution_result.gas_used + ); + + let requests = chain_spec + .is_prague_active_at_timestamp(attributes.timestamp) + .then_some(execution_result.requests); + + let sealed_block = Arc::new(block.sealed_block().clone()); + debug!(target: "payload_builder", id=%attributes.id, sealed_block_header = ?sealed_block.sealed_header(), "sealed built block"); + + if is_osaka && sealed_block.rlp_length() > MAX_RLP_BLOCK_SIZE { + return Err(PayloadBuilderError::other(ConsensusError::BlockTooLarge { + rlp_length: sealed_block.rlp_length(), + max_rlp_length: MAX_RLP_BLOCK_SIZE, + })); + } + + // Build payload with blob sidecars + let payload = if blob_sidecars_to_include.is_empty() { + EthBuiltPayload::new(attributes.id, sealed_block, total_fees, requests) + } else { + // Build the appropriate BlobSidecars type based on Osaka activation + let blob_sidecars = if is_osaka { + // EIP-7594 PeerDAS sidecars (Osaka+) + let sidecars_7594: Vec<_> = blob_sidecars_to_include + .iter() + .filter_map(|s| s.as_eip7594().cloned()) + .collect(); + reth_payload_builder::BlobSidecars::eip7594(sidecars_7594) + } else { + // EIP-4844 blob sidecars (pre-Osaka) + let sidecars_4844: Vec<_> = blob_sidecars_to_include + .iter() + .filter_map(|s| s.as_eip4844().cloned()) + .collect(); + reth_payload_builder::BlobSidecars::eip4844(sidecars_4844) + }; + + EthBuiltPayload::new(attributes.id, sealed_block, total_fees, requests) + .with_sidecars(blob_sidecars) + }; + + Ok(BuildOutcome::Better { + payload, + cached_reads, + }) +} + +// ==================================================================== +// Integration with Reth's Component System +// ==================================================================== + +/// Builder for creating ParallelEthereumPayloadBuilder instances. +/// +/// This struct integrates our parallel payload builder into Reth's component system. +#[derive(Clone, Default, Debug)] +#[non_exhaustive] +pub struct ParallelPayloadBuilderBuilder; + +impl PayloadBuilderBuilderTrait + for ParallelPayloadBuilderBuilder +where + Types: NodeTypes, + Node: FullNodeTypes, + Pool: TransactionPool>> + + Unpin + + 'static, + Evm: ConfigureEvm, NextBlockEnvCtx = NextBlockEnvAttributes> + + 'static, + <::BlockExecutorFactory as reth_evm::block::BlockExecutorFactory>::EvmFactory: + alloy_evm::EvmFactory< + Spec = revm::primitives::hardfork::SpecId, + BlockEnv = revm::context::BlockEnv, + >, + Types::Payload: PayloadTypes< + BuiltPayload = EthBuiltPayload, + PayloadAttributes = reth_ethereum_engine_primitives::EthPayloadAttributes, + PayloadBuilderAttributes = EthPayloadBuilderAttributes, + >, +{ + type PayloadBuilder = ParallelEthereumPayloadBuilder; + + async fn build_payload_builder( + self, + ctx: &BuilderContext, + pool: Pool, + evm_config: Evm, + ) -> eyre::Result { + let conf = ctx.payload_builder_config(); + let chain = ctx.chain_spec().chain(); + let gas_limit = conf.gas_limit_for(chain); + + Ok(ParallelEthereumPayloadBuilder::new( + ctx.provider().clone(), + pool, + evm_config, + EthereumBuilderConfig::new().with_gas_limit(gas_limit), + )) + } +} diff --git a/crates/chain/src/provider.rs b/crates/chain/src/provider.rs index c7117373..9e4de077 100644 --- a/crates/chain/src/provider.rs +++ b/crates/chain/src/provider.rs @@ -3,11 +3,11 @@ use crate::state::StateStorageAdapter; use alloy_consensus::{Header, Transaction}; use alloy_eips::eip7685::Requests; use alloy_evm::block::{ - BlockExecutionError, BlockValidationError, CommitChanges, SystemCaller, + BlockExecutionError, BlockValidationError, CommitChanges, state_changes::post_block_balance_increments, }; +use alloy_evm::eth::dao_fork; use alloy_evm::eth::dao_fork::DAO_HARDFORK_BENEFICIARY; -use alloy_evm::eth::{dao_fork, eip6110}; use alloy_evm::{Database, FromRecoveredTx, FromTxWithEncoded}; use alloy_hardforks::EthereumHardfork; use alloy_rpc_types_engine::ExecutionData; @@ -19,9 +19,10 @@ use reth::{providers::BlockExecutionResult, revm::db::State}; use reth_chainspec::{ChainSpec, EthChainSpec, Hardforks}; use reth_ethereum_primitives::{Block, EthPrimitives, Receipt, TransactionSigned}; use reth_evm::TransactionEnv; +use reth_evm::block::{BlockExecutorFactory, BlockExecutorFor}; use reth_evm::block::{ExecutableTx, InternalBlockExecutionError}; use reth_evm::eth::spec::EthExecutorSpec; -use reth_evm::eth::{EthBlockExecutionCtx, EthBlockExecutor, EthBlockExecutorFactory}; +use reth_evm::eth::{EthBlockExecutionCtx, EthBlockExecutor}; use reth_evm::precompiles::PrecompilesMap; use reth_evm::{ ConfigureEngineEvm, ConfigureEvm, EvmEnvFor, ExecutableTxIterator, ExecutionCtxFor, @@ -31,12 +32,33 @@ use reth_evm::{OnStateHook, execute::BlockExecutor}; pub use reth_evm_ethereum::EthEvmConfig; use reth_evm_ethereum::{EthBlockAssembler, RethReceiptBuilder}; use reth_primitives_traits::{SealedBlock, SealedHeader}; -use revm::{DatabaseCommit, context::BlockEnv as RevmBlockEnv, context::result::ResultAndState}; +use revm::Database as RevmDatabase; +use revm::{context::BlockEnv as RevmBlockEnv, context::result::ResultAndState}; use std::convert::Infallible; use std::fmt::Debug; use std::num::NonZeroUsize; use std::sync::Arc; +/// Trait for executors that support batch parallel execution. +/// +/// This trait allows Payload Builders to detect and use parallel execution +/// capabilities when available, falling back to serial execution otherwise. +pub trait BatchExecutable: BlockExecutor { + /// Execute multiple transactions in a batch, potentially in parallel. + /// + /// # Arguments + /// * `transactions` - Iterator of transactions that implement ExecutableTx + /// + /// # Returns + /// Returns the block execution result including receipts, gas used, and requests. + fn execute_transactions_batch( + &mut self, + transactions: impl IntoIterator, + ) -> Result, BlockExecutionError> + where + Tx: ExecutableTx; +} + /// Ethereum-related EVM configuration with the parallel executor. #[derive(Debug, Clone)] pub struct ParallelEthEvmConfig { @@ -59,13 +81,59 @@ impl ParallelEthEvmConfig { } } +impl BlockExecutorFactory for ParallelEthEvmConfig +where + ChainSpec: EthExecutorSpec + EthChainSpec
+ Hardforks + Clone + 'static, + EvmF: EvmFactory< + Tx = TxEnv, + Spec = SpecId, + BlockEnv = revm::context::BlockEnv, + Precompiles = PrecompilesMap, + > + Clone + + Debug + + Send + + Sync + + Unpin + + 'static, + EvmF::Tx: + TransactionEnv + FromRecoveredTx + FromTxWithEncoded, +{ + type EvmFactory = EvmF; + type ExecutionCtx<'a> = EthBlockExecutionCtx<'a>; + type Transaction = TransactionSigned; + type Receipt = Receipt; + + fn evm_factory(&self) -> &Self::EvmFactory { + self.config.evm_factory() + } + + fn create_executor<'a, DB, I>( + &'a self, + evm: ::Evm<&'a mut State, I>, + ctx: Self::ExecutionCtx<'a>, + ) -> impl BlockExecutorFor<'a, Self, DB, I> + where + DB: Database + 'a, + I: reth::revm::Inspector<::Context<&'a mut State>> + 'a, + { + ParallelBlockExecutor { + spec: self.config.chain_spec().clone(), + executor: EthBlockExecutor::new( + evm, + ctx, + self.config.chain_spec().clone(), + *self.config.executor_factory.receipt_builder(), + ), + context: crate::parallel_execution_context::ParallelExecutionContext::default(), + } + } +} + impl ConfigureEvm for ParallelEthEvmConfig where - ChainSpec: EthExecutorSpec + EthChainSpec
+ Hardforks + 'static, + ChainSpec: EthExecutorSpec + EthChainSpec
+ Hardforks + Clone + 'static, EvmF: EvmFactory< - Tx: TransactionEnv - + FromRecoveredTx - + FromTxWithEncoded, + Tx = TxEnv, Spec = SpecId, BlockEnv = revm::context::BlockEnv, Precompiles = PrecompilesMap, @@ -75,15 +143,17 @@ where + Sync + Unpin + 'static, + EvmF::Tx: + TransactionEnv + FromRecoveredTx + FromTxWithEncoded, { type Primitives = EthPrimitives; type Error = Infallible; type NextBlockEnvCtx = NextBlockEnvAttributes; - type BlockExecutorFactory = EthBlockExecutorFactory, EvmF>; + type BlockExecutorFactory = Self; type BlockAssembler = EthBlockAssembler; fn block_executor_factory(&self) -> &Self::BlockExecutorFactory { - &self.config.executor_factory + self } fn block_assembler(&self) -> &Self::BlockAssembler { @@ -120,11 +190,9 @@ where impl ConfigureEngineEvm for ParallelEthEvmConfig where - ChainSpec: EthExecutorSpec + EthChainSpec
+ Hardforks + 'static, + ChainSpec: EthExecutorSpec + EthChainSpec
+ Hardforks + Clone + 'static, EvmF: EvmFactory< - Tx: TransactionEnv - + FromRecoveredTx - + FromTxWithEncoded, + Tx = TxEnv, Spec = SpecId, BlockEnv = revm::context::BlockEnv, Precompiles = PrecompilesMap, @@ -134,6 +202,8 @@ where + Sync + Unpin + 'static, + EvmF::Tx: + TransactionEnv + FromRecoveredTx + FromTxWithEncoded, { fn evm_env_for_payload(&self, payload: &ExecutionData) -> Result, Self::Error> { self.config.evm_env_for_payload(payload) @@ -155,18 +225,28 @@ where } /// Parallel block executor for Ethereum. +/// +/// This executor provides both serial and parallel execution capabilities: +/// - Buffered batch parallel execution: execute_transaction() buffers txs, flush_pending() executes in parallel +/// - Immediate serial execution: For streaming validation scenarios +/// +/// The executor ensures post_execution is called exactly once per block using +/// an internal context tracker. pub struct ParallelBlockExecutor<'a, Evm, Spec> { /// Reference to the specification object. spec: Spec, - /// Eth original executor. + /// Eth original executor (used for serial execution fallback). executor: EthBlockExecutor<'a, Evm, Spec, RethReceiptBuilder>, + /// Execution context to track state and prevent double post_execution calls + /// Contains execution_cache for avoiding double execution + context: crate::parallel_execution_context::ParallelExecutionContext, } impl<'db, DB, E, Spec> BlockExecutor for ParallelBlockExecutor<'_, E, Spec> where DB: Database + 'db, E: Evm, Tx = TxEnv, BlockEnv = revm::context::BlockEnv>, - Spec: EthExecutorSpec + Clone, + Spec: EthExecutorSpec + EthChainSpec + Hardforks + Clone, { type Transaction = TransactionSigned; type Receipt = Receipt; @@ -182,6 +262,56 @@ where f: impl FnOnce(&ExecutionResult<::HaltReason>), ) -> Result { self.executor.execute_transaction_with_result_closure(tx, f) + // let tx_hash = *tx.tx().hash(); + // + // // Check global cache first (set by payload builder) + // if let Some(cached) = crate::parallel_execution_context::get_global_cached_result(&tx_hash) + // { + // // Call the callback with a dummy execution result (since we already have the receipt) + // let dummy_result = ExecutionResult::Success { + // reason: SuccessReason::Stop, + // gas_used: cached.gas_used, + // gas_refunded: 0, + // logs: cached.receipt.logs.clone(), + // output: Output::Call(metis_primitives::Bytes::new()), + // }; + // f(&dummy_result); + // + // return Ok(cached.gas_used); + // } + // + // // Check local cache (for backwards compatibility) + // if let Some(cached) = self.context.get_cached_result(&tx_hash) { + // let dummy_result = ExecutionResult::Success { + // reason: SuccessReason::Stop, + // gas_used: cached.gas_used, + // gas_refunded: 0, + // logs: cached.receipt.logs.clone(), + // output: Output::Call(metis_primitives::Bytes::new()), + // }; + // f(&dummy_result); + // + // return Ok(cached.gas_used); + // } + // + // // CRITICAL FIX: Execute transactions IMMEDIATELY in Payload Validator mode. + // // + // // Problem: In Payload Validator mode, Reth uses Streaming API: + // // 1. Calls execute_transaction() multiple times to buffer transactions + // // 2. Starts parallel state root calculation IMMEDIATELY (uses current DB snapshot) + // // 3. Calls finish() to execute buffered transactions + // // 4. State root calculation completes using OLD snapshot from step 2 + // // + // // Solution: Execute each transaction immediately when called. + // // Trade-off: Loses parallelism in Payload Validator mode, but ensures correctness. + // // Note: Payload Builder mode (with execute_transactions()) still uses parallel execution. + // + // // Execute immediately using the inner executor (serial execution) + // let result = self + // .executor + // .execute_transaction_with_result_closure(tx, f)?; + // + // Ok(result) } fn execute_transaction_with_commit_condition( @@ -196,6 +326,14 @@ where fn finish( self, ) -> Result<(Self::Evm, BlockExecutionResult), BlockExecutionError> { + // Apply post_execution (block rewards, withdrawals, etc.) + // This is called once per block after all transactions execute + // if !self.context.post_execution_called { + // self.post_execution()?; + // self.context.mark_post_execution_called(); + // } + + // Delegate to inner executor for final state root calculation self.executor.finish() } @@ -212,6 +350,7 @@ where } /// Executes all transactions in a block, applying pre and post execution changes. + /// This method triggers PARALLEL execution using metis-pe. fn execute_block( mut self, transactions: impl IntoIterator>, @@ -220,7 +359,8 @@ where Self: Sized, { self.apply_pre_execution_changes()?; - self.execute_transactions(transactions) + let result = self.execute(transactions)?; + Ok(result) } fn execute_transaction_without_commit( @@ -230,6 +370,24 @@ where self.executor.execute_transaction_without_commit(tx) } + fn execute_transaction( + &mut self, + tx: impl ExecutableTx, + ) -> Result { + let tx_hash = *tx.tx().hash(); + + // Check if we have cached result from parallel execution + if let Some(cached) = self.context.get_cached_result(&tx_hash) { + // Return cached gas_used + // The transaction is NOT re-executed, we just use the cached result + // This allows builder to add the transaction to the block structure + return Ok(cached.gas_used); + } + + // No cache - execute normally (serial execution) + self.execute_transaction_with_result_closure(tx, |_| ()) + } + fn commit_transaction( &mut self, output: ResultAndState<::HaltReason>, @@ -243,42 +401,47 @@ impl<'db, DB, E, Spec> ParallelBlockExecutor<'_, E, Spec> where DB: Database + 'db, E: Evm, Tx = TxEnv, BlockEnv = revm::context::BlockEnv>, - Spec: EthExecutorSpec + Clone, + Spec: EthExecutorSpec + EthChainSpec + Hardforks + Clone, { - pub fn execute_transactions( - &mut self, - transactions: impl IntoIterator>, - ) -> Result, BlockExecutionError> { - // Execute block transactions parallel - let parallel_execute_result = self.execute(transactions)?; - - // Calculate requests - let receipts = parallel_execute_result.receipts; - let requests = self.calc_requests(receipts.clone())?; - - // Governance reward for full block, ommers... - self.post_execution()?; - - // Assemble new block execution result, there is no dump receipt - let results = BlockExecutionResult { - receipts, - requests, - gas_used: parallel_execute_result.gas_used, - blob_gas_used: parallel_execute_result.blob_gas_used, - }; - - Ok(results) - } - pub fn execute( &mut self, transactions: impl IntoIterator>, ) -> Result, BlockExecutionError> { + tracing::debug!(target: "metis::parallel", + "ParallelBlockExecutor::execute() - parallel execution entry point" + ); + let block_env: &RevmBlockEnv = self.evm().block(); let state_clear_flag = self .spec .is_spurious_dragon_active_at_block(block_env.number.try_into().unwrap_or(u64::MAX)); - let evm_env = EvmEnv::new(CfgEnv::default(), self.evm().block().clone()); + + // Build CfgEnv for metis-pe based on the current block. + // + // NOTE: We must ensure fork rules match reth's canonical env, otherwise state roots can + // diverge. (The `block_env` itself is cloned from the canonical EVM instance.) + let block_number = block_env.number.try_into().unwrap_or(u64::MAX); + let block_timestamp = block_env.timestamp.to::(); + + let spec_id = if self.spec.is_cancun_active_at_timestamp(block_timestamp) { + SpecId::CANCUN + } else if self.spec.is_shanghai_active_at_timestamp(block_timestamp) { + SpecId::SHANGHAI + } else if self.spec.is_london_active_at_block(block_number) { + SpecId::LONDON + } else if self.spec.is_berlin_active_at_block(block_number) { + SpecId::BERLIN + } else { + SpecId::ISTANBUL + }; + + let mut cfg_env = CfgEnv::default(); + cfg_env.chain_id = self.spec.chain_id(); + cfg_env.spec = spec_id; + + let block_env = self.evm().block().clone(); + + let evm_env = EvmEnv::new(cfg_env, block_env); let db = self.evm_mut().db_mut(); db.set_state_clear_flag(state_clear_flag); @@ -289,36 +452,103 @@ where .filter_map(|tx| tx.tx().blob_gas_used()) .sum(); - let mut parallel_executor = metis_pe::ParallelExecutor::default(); + let num_threads = num_cpus::get(); + + let pe_start_time = std::time::Instant::now(); + // IMPORTANT: align metis-pe ResultAndState
with the executor's concrete HaltReason type + let mut parallel_executor = + metis_pe::ParallelExecutor::<::HaltReason>::default(); + + // Build TxEnv list without consuming the original txs so we can commit in-order later + let transactions_vec: Vec<_> = transactions.into_iter().collect(); + let tx_envs: Vec = transactions_vec.iter().map(|tx| tx.to_tx_env()).collect(); + let results = parallel_executor.execute( StateStorageAdapter::new(db), evm_env, - transactions - .into_iter() - .map(|tx| tx.to_tx_env()) - .collect::>(), - NonZeroUsize::new(num_cpus::get()).unwrap_or(NonZeroUsize::new(1).unwrap()), + tx_envs, + NonZeroUsize::new(num_threads).unwrap_or(NonZeroUsize::new(1).unwrap()), ); - let mut total_gas_used: u64 = 0; - let receipts = results - .map_err(|err| { - BlockExecutionError::Internal(InternalBlockExecutionError::Other(Box::new(err))) - })? - .into_iter() - .map(|r| { - self.evm_mut().db_mut().commit(r.state); - total_gas_used += &r.receipt.cumulative_gas_used; - r.receipt - }) - .collect(); - - Ok(BlockExecutionResult { + let pe_duration = pe_start_time.elapsed(); + tracing::debug!(target: "metis::parallel", + "Parallel execution completed: duration={:?}", + pe_duration + ); + + let results_vec = results.map_err(|err| { + tracing::error!(target: "metis::parallel", "Parallel execution failed: {:?}", err); + BlockExecutionError::Internal(InternalBlockExecutionError::Other(Box::new(err))) + })?; + + // Commit pre-executed ResultAndState using the executor's native commit semantics. + // + // This is REQUIRED for correct state roots because it goes through revm's journal / bundle + // and reth's commit logic (account clearing, selfdestruct, created contracts, etc.). + + let mut receipts: Vec = Vec::with_capacity(results_vec.len()); + + for (tx, result) in transactions_vec.into_iter().zip(results_vec.into_iter()) { + receipts.push(result.receipt.clone()); + + // Apply state exactly as reth would after executing the tx + // IMPORTANT: + // revm::db::State will panic if we commit accounts that are not present in its internal + // cache ("All accounts should be present inside cache"). Prewarm the cache for every + // touched address in this tx's state before committing. + { + let mut addrs: Vec<_> = result.result_and_state.state.keys().copied().collect(); + addrs.sort_unstable(); + let db = self.evm_mut().db_mut(); + for addr in addrs { + db.basic(addr).map_err(|err| { + BlockExecutionError::Internal(InternalBlockExecutionError::Other(Box::new( + err, + ))) + })?; + } + } + self.commit_transaction(result.result_and_state, tx)?; + } + + // The total gas used is the cumulative_gas_used of the last receipt + // (which already includes all previous transactions' gas) + let total_gas_used = receipts.last().map(|r| r.cumulative_gas_used).unwrap_or(0); + + // FIX: Call post_execution() here to ensure block rewards are applied. + // + // Problem: In some paths (like execute_block), finish() may not be called, + // leading to missing block rewards and state root mismatches. + // + // Solution: Call post_execution() here with a flag to prevent double application. + // The flag ensures it's only called once per block execution. + if !self.context.post_execution_called { + self.post_execution()?; + self.context.mark_post_execution_called(); + } + + // Parse EIP-7685 requests (withdrawal, deposit, consolidation) if Prague is active + let block_env: &revm::context::BlockEnv = self.executor.evm.block(); + let requests = if self + .spec + .is_prague_active_at_timestamp(block_env.timestamp.to::()) + { + // Use the inner executor's system_caller to parse requests from system contracts + self.executor + .system_caller + .apply_post_execution_changes(&mut self.executor.evm)? + } else { + Requests::default() + }; + + let result = BlockExecutionResult { receipts, - requests: Requests::default(), + requests, gas_used: total_gas_used, blob_gas_used: total_blob_gas_used, - }) + }; + + Ok(result) } fn post_execution(&mut self) -> Result<(), BlockExecutionError> { @@ -349,39 +579,55 @@ where .entry(DAO_HARDFORK_BENEFICIARY) .or_default() += drained_balance; } + // CRITICAL: Sort balance_increments by address to ensure deterministic commit order + // HashMap iteration order is non-deterministic, which can cause different state roots + // across nodes even with the same execution results. + // We need to commit in a deterministic order (sorted by address) + let mut sorted_increments: Vec<_> = balance_increments.into_iter().collect(); + sorted_increments.sort_by_key(|(address, _)| *address); + + // CRITICAL: Use BTreeMap instead of HashMap to maintain sorted order. + // BTreeMap preserves the sorted order when iterating, ensuring deterministic + // state root calculation across all nodes. + let sorted_balance_increments: std::collections::BTreeMap<_, _> = + sorted_increments.into_iter().collect(); + // increment balances self.evm_mut() .db_mut() - .increment_balances(balance_increments) + .increment_balances(sorted_balance_increments) .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; Ok(()) } +} - fn calc_requests(&mut self, receipts: Vec) -> Result { - let evm = self.executor.evm_mut(); - let block = evm.block(); - let requests = if self - .spec - .is_prague_active_at_timestamp(block.timestamp.try_into().unwrap_or(u64::MAX)) - { - // Collect all EIP-6110 deposits - let deposit_requests = - eip6110::parse_deposits_from_receipts(self.spec.clone(), &receipts)?; - - let mut requests = Requests::default(); +// ==================================================================== +// BatchExecutable Implementation for ParallelBlockExecutor +// ==================================================================== - if !deposit_requests.is_empty() { - requests.push_request_with_type(eip6110::DEPOSIT_REQUEST_TYPE, deposit_requests); - } - let mut system_caller = SystemCaller::new(self.spec.clone()); - requests.extend(system_caller.apply_post_execution_changes(evm)?); - requests - } else { - Requests::default() - }; +impl<'db, DB, E, Spec> BatchExecutable for ParallelBlockExecutor<'_, E, Spec> +where + DB: Database + 'db, + E: Evm, Tx = TxEnv, BlockEnv = revm::context::BlockEnv>, + Spec: EthExecutorSpec + EthChainSpec + Hardforks + Clone, +{ + /// Execute multiple transactions in a batch using parallel execution. + /// + /// This method is called by the custom Payload Builder to enable + /// true parallel transaction execution using Block-STM. + fn execute_transactions_batch( + &mut self, + transactions: impl IntoIterator, + ) -> Result, BlockExecutionError> + where + Tx: ExecutableTx, + { + // Convert to a vec to count transactions + let tx_vec: Vec = transactions.into_iter().collect(); - Ok(requests) + // Call the existing execute method which handles parallel execution + self.execute(tx_vec) } } diff --git a/crates/pe/Cargo.toml b/crates/pe/Cargo.toml index abffc52e..f0d16e8e 100644 --- a/crates/pe/Cargo.toml +++ b/crates/pe/Cargo.toml @@ -36,6 +36,7 @@ serde.workspace = true smallvec.workspace = true thiserror.workspace = true crossbeam.workspace = true +tracing.workspace = true # OP Alloy and OP Revm dependencies op-alloy-consensus.workspace = true diff --git a/crates/pe/benches/gigagas.rs b/crates/pe/benches/gigagas.rs index 412b3f1d..2ccc5b12 100644 --- a/crates/pe/benches/gigagas.rs +++ b/crates/pe/benches/gigagas.rs @@ -23,11 +23,11 @@ static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; /// Runs a benchmark for executing a set of transactions on a given blockchain state. pub fn bench(c: &mut Criterion, name: &str, db: InMemoryDB, txs: Vec) { let concurrency_level = thread::available_parallelism().unwrap_or(NonZeroUsize::MIN); - let mut pe = ParallelExecutor::default(); + let mut pe: ParallelExecutor = ParallelExecutor::default(); let mut group = c.benchmark_group(name); group.bench_function("Sequential", |b| { b.iter(|| { - execute_sequential( + execute_sequential::<_, metis_primitives::HaltReason>( black_box(&db), black_box(EvmEnv::default()), black_box(txs.clone()), @@ -48,10 +48,10 @@ pub fn bench(c: &mut Criterion, name: &str, db: InMemoryDB, txs: Vec) { }); #[cfg(feature = "compiler")] { - let mut pe = ParallelExecutor::compiler(); + let mut pe: ParallelExecutor = ParallelExecutor::compiler(); group.bench_function("Sequential-With-Compiler", |b| { b.iter(|| { - execute_sequential( + execute_sequential::<_, metis_primitives::HaltReason>( black_box(&db), black_box(EvmEnv::default()), black_box(txs.clone()), diff --git a/crates/pe/src/executor.rs b/crates/pe/src/executor.rs index 36c0465c..72c09a3e 100644 --- a/crates/pe/src/executor.rs +++ b/crates/pe/src/executor.rs @@ -12,7 +12,6 @@ use crate::{ #[cfg(feature = "compiler")] use metis_primitives::ExecuteEvm; -use revm::context::result::ExecResultAndState; #[cfg(feature = "compiler")] use std::sync::Arc; use std::{ @@ -24,17 +23,23 @@ use std::{ use alloy_evm::EvmEnv; use metis_primitives::{ - Account, AccountInfo, AccountStatus, CacheDB, ContextTr, DatabaseCommit, DatabaseRef, - InvalidTransaction, KECCAK_EMPTY, SpecId, Transaction, TxEnv, U256, hash_deterministic, + Account, AccountInfo, AccountStatus, CacheDB, DatabaseRef, InvalidTransaction, KECCAK_EMPTY, + SpecId, Transaction, TxEnv, U256, hash_deterministic, }; +// Required for `evm.set_tx(...)` +use metis_primitives::ContextSetters; +// Required for `evm.finalize()` #[cfg(feature = "compiler")] use metis_vm::ExtCompileWorker; +use revm::ExecuteEvm; /// The main executor struct that executes blocks with Block-STM algorithm. +/// +/// Generic over `HR` (halt reason) so callers can align the `ResultAndState` type +/// with the concrete EVM implementation they use (e.g. reth/alloy executor). #[derive(Debug)] -#[cfg_attr(not(feature = "compiler"), derive(Default))] -pub struct ParallelExecutor { - execution_results: Vec>>, +pub struct ParallelExecutor
{ + execution_results: Vec>>>, abort_reason: OnceLock, #[cfg(feature = "async-dropper")] dropper: AsyncDropper<(MvMemory, Scheduler, Vec)>, @@ -43,8 +48,20 @@ pub struct ParallelExecutor { pub worker: Arc, } +#[cfg(not(feature = "compiler"))] +impl
Default for ParallelExecutor
{ + fn default() -> Self { + Self { + execution_results: Default::default(), + abort_reason: Default::default(), + #[cfg(feature = "async-dropper")] + dropper: Default::default(), + } + } +} + #[cfg(feature = "compiler")] -impl Default for ParallelExecutor { +impl
Default for ParallelExecutor
{ fn default() -> Self { Self { execution_results: Default::default(), @@ -56,7 +73,7 @@ impl Default for ParallelExecutor { } } -impl ParallelExecutor { +impl
ParallelExecutor
{ /// New a parallel VM with the compiler feature. The default compiler is an AOT-based one. #[cfg(feature = "compiler")] pub fn compiler() -> Self { @@ -67,7 +84,16 @@ impl ParallelExecutor { } } -impl ParallelExecutor { +impl
ParallelExecutor
+where + HR: Clone + + Debug + + Send + + Sync + + 'static + + core::cmp::Eq + + core::convert::From, +{ /// Execute an block with the block env and transactions. pub fn execute( &mut self, @@ -75,7 +101,7 @@ impl ParallelExecutor { evm_env: EvmEnv, txs: Vec, concurrency_level: NonZeroUsize, - ) -> ParallelExecutorResult + ) -> ParallelExecutorResult
where DB: DatabaseRef + Send + Sync, { @@ -105,10 +131,20 @@ impl ParallelExecutor { } } + let start_time = std::time::Instant::now(); + + tracing::debug!( + target: "metis::parallel::rerun", + block_size = block_size, + concurrency = concurrency_level.get(), + "Starting parallel execution" + ); + thread::scope(|scope| { for _ in 0..concurrency_level.into() { scope.spawn(|| { let mut next_task = scheduler.next_task(); + while let Some(task) = next_task { next_task = match task { Task::Execution(tx_version) => { @@ -129,12 +165,25 @@ impl ParallelExecutor { } }); + let parallel_duration = start_time.elapsed(); + + // Calculate statistics from execution + let block_size = txs.len(); + tracing::debug!( + target: "metis::parallel::rerun", + block_size = block_size, + duration_ms = parallel_duration.as_millis(), + avg_tx_time_us = parallel_duration.as_micros() / block_size.max(1) as u128, + concurrency = concurrency_level.get(), + "Parallel execution phase completed" + ); + if let Some(abort_reason) = self.abort_reason.take() { match abort_reason { AbortReason::FallbackToSequential => { #[cfg(feature = "async-dropper")] self.dropper.drop((mv_memory, scheduler, Vec::new())); - return execute_sequential( + return execute_sequential::<_, HR>( db, evm_env, txs, @@ -149,7 +198,6 @@ impl ParallelExecutor { } } } - let mut fully_evaluated_results = Vec::with_capacity(block_size); let mut cumulative_gas_used: u64 = 0; for i in 0..block_size { @@ -157,12 +205,16 @@ impl ParallelExecutor { cumulative_gas_used = cumulative_gas_used.saturating_add(execution_result.receipt.cumulative_gas_used); execution_result.receipt.cumulative_gas_used = cumulative_gas_used; + fully_evaluated_results.push(execution_result); } // We fully evaluate (the balance and nonce of) the beneficiary account // and raw transfer recipients that may have been atomically updated. - for address in mv_memory.consume_lazy_addresses() { + // IMPORTANT: Sort addresses to ensure deterministic processing order across nodes + let mut lazy_addresses: Vec<_> = mv_memory.consume_lazy_addresses().into_iter().collect(); + lazy_addresses.sort(); // Sort by Address (which implements Ord) for deterministic order + for address in lazy_addresses { let location_hash = hash_deterministic(Location::Basic(address)); if let Some(write_history) = mv_memory.data.get(&location_hash) { let mut balance = U256::ZERO; @@ -242,7 +294,7 @@ impl ParallelExecutor { } // SAFETY let tx_result = unsafe { fully_evaluated_results.get_unchecked_mut(*tx_idx) }; - let contains_account = tx_result.state.contains_key(&address); + let contains_account = tx_result.state().contains_key(&address); if evm_env.cfg_env.spec.is_enabled_in(SpecId::SPURIOUS_DRAGON) && code_hash == KECCAK_EMPTY @@ -252,13 +304,13 @@ impl ParallelExecutor { // Do nothing for the empty account. } else if contains_account { // Only update the information except the code and code hash. - let account = tx_result.state.entry(address).or_default(); + let account = tx_result.state_mut().entry(address).or_default(); account.info.balance = balance; account.info.nonce = nonce; } else { // Insert a new account with the touched status. // Only when account is marked as touched we will save it to database. - tx_result.state.insert( + tx_result.state_mut().insert( address, Account { info: AccountInfo { @@ -289,7 +341,7 @@ impl ParallelExecutor { tx_version: TxVersion, ) -> Option { loop { - return match vm.execute(&tx_version) { + return match vm.execute::
(&tx_version) { Err(VmExecutionError::Retry) => { if self.abort_reason.get().is_none() { continue; @@ -297,6 +349,11 @@ impl ParallelExecutor { None } Err(VmExecutionError::FallbackToSequential) => { + tracing::warn!( + target: "metis::parallel::rerun", + tx_idx = tx_version.tx_idx, + "Fallback to sequential execution triggered" + ); scheduler.abort(); self.abort_reason .get_or_init(|| AbortReason::FallbackToSequential); @@ -306,13 +363,17 @@ impl ParallelExecutor { if !scheduler.add_dependency(tx_version.tx_idx, blocking_tx_idx) && self.abort_reason.get().is_none() { - // Retry the execution immediately if the blocking transaction was - // re-executed by the time we can add it as a dependency. continue; } None } Err(VmExecutionError::ExecutionError(err)) => { + tracing::error!( + target: "metis::parallel::rerun", + tx_idx = tx_version.tx_idx, + error = ?err, + "Execution error occurred" + ); scheduler.abort(); self.abort_reason .get_or_init(|| AbortReason::ExecutionError(err)); @@ -344,49 +405,96 @@ fn try_validate( if aborted { mv_memory.convert_writes_to_estimates(tx_version.tx_idx); } + scheduler.finish_validation(tx_version, aborted) } /// Execute transactions sequentially. /// Useful for falling back for (small) blocks with many dependencies. -pub fn execute_sequential( +pub fn execute_sequential( db: DB, evm_env: EvmEnv, txs: Vec, #[cfg(feature = "compiler")] worker: Arc, -) -> ParallelExecutorResult { +) -> ParallelExecutorResult
+where + DB: DatabaseRef, + HR: Clone + + Debug + + Send + + Sync + + 'static + + core::cmp::Eq + + core::convert::From, +{ + let block_size = txs.len(); + let start_time = std::time::Instant::now(); + + tracing::debug!( + target: "metis::parallel::rerun", + block_size = block_size, + "Starting sequential execution (fallback from parallel)" + ); + let mut db = CacheDB::new(db); let mut evm = build_evm(&mut db, evm_env); let mut results = Vec::with_capacity(txs.len()); let mut cumulative_gas_used: u64 = 0; - for tx in txs { + for tx in txs.into_iter() { let tx_type = reth_primitives::TxType::try_from(tx.tx_type) .map_err(|_| ParallelExecutorError::UnreachableError)?; - #[cfg(feature = "compiler")] - let result_and_state = { + // NOTE: sequential fallback is only used for blocks where parallel scheduler aborts. + // We need to preserve the exact `ResultAndState
` type so the caller can commit via + // reth/alloy `commit_transaction`. + // + // We run the handler, then finalize the EVM to obtain the post-state, and wrap both + // into `ResultAndState
`. + let result_and_state: metis_primitives::ResultAndState
= { use revm::handler::Handler; - let mut t = metis_vm::CompilerHandler::new(worker.clone()); - evm.set_tx(tx); - t.run(&mut evm).map_err(evm_err_to_exec_error::)? - }; - #[cfg(not(feature = "compiler"))] - let result_and_state = { - use revm::ExecuteEvm; - - evm.transact(tx).map_err(evm_err_to_exec_error::)? + #[cfg(feature = "compiler")] + { + // Compiler feature currently fixes its HaltReason type. Keep legacy behavior. + let mut t = metis_vm::CompilerHandler::new(worker.clone()); + evm.set_tx(tx); + let result = t.run(&mut evm).map_err(evm_err_to_exec_error::)?; + let state = evm.finalize(); + metis_primitives::ResultAndState { result, state } + } + #[cfg(not(feature = "compiler"))] + { + evm.set_tx(tx); + let mut t = crate::vm::WithoutRewardBeneficiaryHandler::<_, HR>::default(); + let result = t.run(&mut evm).map_err(evm_err_to_exec_error::)?; + let state = evm.finalize(); + metis_primitives::ResultAndState { result, state } + } }; - evm.db_mut().commit(result_and_state.state.clone()); - let ExecResultAndState { result, state } = result_and_state; + // IMPORTANT: + // Do NOT commit state changes to the shared database here. + // The caller (reth executor) must commit via commit_transaction(ResultAndState, tx) + // to preserve correct journal/bundle semantics and deterministic state roots. - let mut execution_result = TxExecutionResult::from_raw(tx_type, result, state); + // Store the complete ResultAndState (preserves all information for correct state root) + let mut execution_result = TxExecutionResult::from_raw(tx_type, result_and_state); + // Accumulate cumulative gas used cumulative_gas_used = cumulative_gas_used.saturating_add(execution_result.receipt.cumulative_gas_used); execution_result.receipt.cumulative_gas_used = cumulative_gas_used; results.push(execution_result); } + + let sequential_duration = start_time.elapsed(); + tracing::debug!( + target: "metis::parallel::rerun", + block_size = block_size, + duration_ms = sequential_duration.as_millis(), + avg_tx_time_us = sequential_duration.as_micros() / block_size.max(1) as u128, + "Sequential execution completed" + ); + Ok(results) } diff --git a/crates/pe/src/op_executor.rs b/crates/pe/src/op_executor.rs index a5f3e7b6..868942df 100644 --- a/crates/pe/src/op_executor.rs +++ b/crates/pe/src/op_executor.rs @@ -32,7 +32,7 @@ use std::{ #[derive(Debug)] #[cfg_attr(not(feature = "compiler"), derive(Default))] pub struct OpParallelExecutor { - execution_results: Vec>>, + execution_results: Vec>>>, abort_reason: OnceLock, #[cfg(feature = "async-dropper")] dropper: AsyncDropper<(MvMemory, Scheduler, Vec)>, @@ -73,7 +73,7 @@ impl OpParallelExecutor { evm_env: EvmEnv, txs: Vec, concurrency_level: NonZeroUsize, - ) -> ParallelExecutorResult + ) -> ParallelExecutorResult where DB: DatabaseRef + Send + Sync, { @@ -160,7 +160,10 @@ impl OpParallelExecutor { // We fully evaluate (the balance and nonce of) the beneficiary account // and raw transfer recipients that may have been atomically updated. - for address in mv_memory.consume_lazy_addresses() { + // IMPORTANT: Sort addresses to ensure deterministic processing order across nodes + let mut lazy_addresses: Vec<_> = mv_memory.consume_lazy_addresses().into_iter().collect(); + lazy_addresses.sort(); // Sort by Address (which implements Ord) for deterministic order + for address in lazy_addresses { let location_hash = hash_deterministic(Location::Basic(address)); if let Some(write_history) = mv_memory.data.get(&location_hash) { let mut balance = U256::ZERO; @@ -240,7 +243,7 @@ impl OpParallelExecutor { } // SAFETY let tx_result = unsafe { fully_evaluated_results.get_unchecked_mut(*tx_idx) }; - let contains_account = tx_result.state.contains_key(&address); + let contains_account = tx_result.state().contains_key(&address); if evm_env.cfg_env.spec.is_enabled_in(SpecId::SPURIOUS_DRAGON) && code_hash == KECCAK_EMPTY @@ -250,13 +253,13 @@ impl OpParallelExecutor { // Do nothing for the empty account. } else if contains_account { // Only update the information except the code and code hash. - let account = tx_result.state.entry(address).or_default(); + let account = tx_result.state_mut().entry(address).or_default(); account.info.balance = balance; account.info.nonce = nonce; } else { // Insert a new account with the touched status. // Only when account is marked as touched we will save it to database. - tx_result.state.insert( + tx_result.state_mut().insert( address, Account { info: AccountInfo { @@ -347,12 +350,15 @@ fn try_validate( /// Execute transactions sequentially. /// Useful for falling back for (small) blocks with many dependencies. -pub fn op_execute_sequential( +pub fn op_execute_sequential( db: DB, _evm_env: EvmEnv, txs: Vec, #[cfg(feature = "compiler")] worker: Arc, -) -> ParallelExecutorResult { +) -> ParallelExecutorResult +where + DB: DatabaseRef, +{ let mut db = CacheDB::new(db); let mut evm = build_op_evm(&mut db, Default::default()); let mut results = Vec::with_capacity(txs.len()); @@ -378,7 +384,7 @@ pub fn op_execute_sequential( evm.0.db_mut().commit(result_and_state.state.clone()); - let mut execution_result = TxExecutionResult::from_raw_op(tx_type, result_and_state); + let mut execution_result = TxExecutionResult::from_raw(tx_type, result_and_state); cumulative_gas_used = cumulative_gas_used.saturating_add(execution_result.receipt.cumulative_gas_used); diff --git a/crates/pe/src/op_vm.rs b/crates/pe/src/op_vm.rs index a5aa6238..77e3350c 100644 --- a/crates/pe/src/op_vm.rs +++ b/crates/pe/src/op_vm.rs @@ -8,7 +8,9 @@ use crate::{ }; use alloy_evm::EvmEnv; use alloy_primitives::TxKind; -use metis_primitives::{BuildIdentityHasher, HashMap, I257, Transaction, hash_deterministic}; +use metis_primitives::{ + BuildIdentityHasher, HashMap, I257, ResultAndState, Transaction, hash_deterministic, +}; #[cfg(feature = "compiler")] use metis_vm::ExtCompileWorker; use op_revm::{DefaultOp, OpBuilder, OpContext, OpEvm, OpSpecId, OpTransaction}; @@ -423,7 +425,7 @@ impl<'a, DB: DatabaseRef> OpVm<'a, DB> { pub(crate) fn execute( &self, tx_version: &TxVersion, - ) -> Result { + ) -> Result, VmExecutionError> { // SAFETY: A correct scheduler would guarantee this index to be inbound. let tx = unsafe { self.txs.get_unchecked(tx_version.tx_idx) }; let from_hash = hash_deterministic(Location::Basic(tx.caller)); @@ -440,9 +442,11 @@ impl<'a, DB: DatabaseRef> OpVm<'a, DB> { let result = { evm.0.set_tx(OpTransaction::new(tx.clone())); #[cfg(feature = "compiler")] - let mut t = WithoutRewardBeneficiaryHandler::new(self.worker.clone()); + let mut t = WithoutRewardBeneficiaryHandler::<_, op_revm::OpHaltReason>::new( + self.worker.clone(), + ); #[cfg(not(feature = "compiler"))] - let mut t = WithoutRewardBeneficiaryHandler::default(); + let mut t = WithoutRewardBeneficiaryHandler::<_, op_revm::OpHaltReason>::default(); t.run(&mut evm) }; match result { @@ -571,8 +575,14 @@ impl<'a, DB: DatabaseRef> OpVm<'a, DB> { let tx_type = reth_primitives::TxType::try_from(tx.tx_type).map_err(|err| { VmExecutionError::ExecutionError(EVMError::Custom(err.to_string())) })?; + + // Combine result and state into ResultAndState to preserve all execution information. + // `result` already uses `op_revm::OpHaltReason`, so no conversion is needed here. + let result_and_state: ResultAndState = + ResultAndState { result, state }; + Ok(VmExecutionResult { - execution_result: TxExecutionResult::from_raw(tx_type, result, state), + execution_result: TxExecutionResult::from_raw(tx_type, result_and_state), flags, }) } diff --git a/crates/pe/src/result.rs b/crates/pe/src/result.rs index 2ea75b56..dcd70a7d 100644 --- a/crates/pe/src/result.rs +++ b/crates/pe/src/result.rs @@ -1,11 +1,11 @@ use crate::{FinishExecFlags, TxIdx}; use alloy_consensus::TxType; use metis_primitives::{ - Account, Address, DBErrorMarker, DatabaseRef, EVMError, EvmState, ExecutionResult, HashMap, - InvalidTransaction, ResultAndState, TxNonce, + DBErrorMarker, DatabaseRef, EVMError, EvmState, InvalidTransaction, TxNonce, }; -use op_revm::{OpHaltReason, OpTransactionError}; +use op_revm::OpTransactionError; use reth_primitives::Receipt; +use revm::context::result::ResultAndState as RevmResultAndState; /// Database error definitions. #[derive(Debug, Clone, PartialEq, thiserror::Error)] @@ -108,58 +108,80 @@ impl DBErrorMarker for ReadError {} pub type ExecutionError = EVMError; /// Execution result of a transaction -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TxExecutionResult { +/// +/// This structure contains the complete execution result including: +/// - receipt: The transaction receipt +/// - result_and_state: The complete revm ResultAndState preserving all execution details +/// +/// CRITICAL: Using ResultAndState (instead of HashMap) ensures +/// we don't lose storage slot changes, selfdestructs, created accounts, etc. +/// This prevents state root mismatch issues when used with reth's commit_transaction(). +/// +/// The generic parameter HR is the HaltReason type from the EVM implementation. +/// This allows metis-pe to return ResultAndState compatible with reth's executor. +#[derive(Debug, Clone)] +pub struct TxExecutionResult
{ /// Receipt of the execution pub receipt: Receipt, - /// State that got updated - pub state: EvmState, + /// Complete execution result and state from revm + /// This preserves all information needed for correct state commitment + pub result_and_state: RevmResultAndState
, } -impl TxExecutionResult { +impl
TxExecutionResult
+where + HR: Clone + core::fmt::Debug, +{ /// Construct an execution result from the raw result and state. + /// + /// This preserves the complete ResultAndState from revm, ensuring no information loss. #[inline] pub fn from_raw( tx_type: TxType, - result: ExecutionResult, - state: HashMap, + result_and_state: metis_primitives::ResultAndState
, ) -> Self { + let cumulative_gas_used = result_and_state.result.gas_used(); + let success = result_and_state.result.is_success(); + let logs = result_and_state.result.logs().to_vec(); + Self { receipt: Receipt { tx_type, - success: result.is_success(), - cumulative_gas_used: result.gas_used(), - logs: result.into_logs(), + success, + cumulative_gas_used, + logs, }, - state, + result_and_state, } } + /// Get a reference to the state for backward compatibility. + /// + /// DEPRECATED: This is temporary compatibility for old code paths. + /// New code should use result_and_state directly with commit_transaction(). #[inline] - /// Convert an execution result from the raw Optimism result and state. - pub fn from_raw_op( - tx_type: TxType, - ResultAndState { result, state }: ResultAndState, - ) -> Self { - Self { - receipt: Receipt { - tx_type, - success: result.is_success(), - cumulative_gas_used: result.gas_used(), - logs: result.into_logs(), - }, - state, - } + pub fn state(&self) -> &EvmState { + &self.result_and_state.state + } + + /// Get a mutable reference to the state for backward compatibility. + /// + /// DEPRECATED: This is temporary compatibility for old code paths. + /// New code should use result_and_state directly with commit_transaction(). + /// WARNING: Mutating the state directly may cause inconsistencies! + #[inline] + pub fn state_mut(&mut self) -> &mut EvmState { + &mut self.result_and_state.state } } -pub(crate) struct VmExecutionResult { - pub(crate) execution_result: TxExecutionResult, +pub(crate) struct VmExecutionResult
{ + pub(crate) execution_result: TxExecutionResult
, pub(crate) flags: FinishExecFlags, } /// Execution result of a block -pub type ParallelExecutorResult = Result, ParallelExecutorError>; +pub type ParallelExecutorResult
= Result>, ParallelExecutorError>; #[derive(Debug)] pub(crate) enum AbortReason { diff --git a/crates/pe/src/vm.rs b/crates/pe/src/vm.rs index d6eec062..d31da884 100644 --- a/crates/pe/src/vm.rs +++ b/crates/pe/src/vm.rs @@ -1,12 +1,14 @@ use crate::{ AccountMeta, Entry, FinishExecFlags, Location, LocationHash, LocationValue, ReadOrigin, ReadOrigins, ReadSet, TxIdx, TxVersion, WriteSet, - mv_memory::{MvMemory, RewardPolicy, reward_policy}, + mv_memory::MvMemory, result::{ReadError, TxExecutionResult, VmExecutionError, VmExecutionResult}, }; use alloy_evm::EvmEnv; use alloy_primitives::TxKind; -use metis_primitives::{BuildIdentityHasher, EvmState, HashMap, I257, hash_deterministic}; +use metis_primitives::{ + BuildIdentityHasher, EvmState, HashMap, I257, ResultAndState, hash_deterministic, +}; #[cfg(feature = "compiler")] use metis_vm::ExtCompileWorker; use revm::context::ContextSetters; @@ -14,19 +16,19 @@ use revm::context::ContextSetters; use revm::handler::FrameInitOrResult; use revm::handler::{EvmTr, FrameResult, FrameTr}; use revm::{ - Database, DatabaseRef, ExecuteEvm, MainBuilder, MainContext, MainnetEvm, + Database, DatabaseRef, ExecuteEvm, MainBuilder, MainnetEvm, bytecode::Bytecode, context::{ ContextTr, TxEnv, result::{EVMError, InvalidTransaction}, }, - context_interface::{JournalTr, result::HaltReason}, + context_interface::{JournalTr, Transaction as _}, handler::MainnetContext, primitives::{Address, B256, KECCAK_EMPTY, U256, hardfork::SpecId}, - state::AccountInfo, + state::{Account, AccountInfo, AccountStatus}, }; use revm::{handler::Handler, interpreter::interpreter_action::FrameInit}; -use smallvec::{SmallVec, smallvec}; +use smallvec::SmallVec; #[cfg(feature = "compiler")] use std::sync::Arc; @@ -376,8 +378,8 @@ pub(crate) struct Vm<'a, DB: DatabaseRef> { mv_memory: &'a MvMemory, evm_env: &'a EvmEnv, txs: &'a [TxEnv], - beneficiary_location_hash: LocationHash, - reward_policy: RewardPolicy, + // beneficiary_location_hash: LocationHash, + // reward_policy: RewardPolicy, #[cfg(feature = "compiler")] worker: Arc, } @@ -395,10 +397,10 @@ impl<'a, DB: DatabaseRef> Vm<'a, DB> { mv_memory, evm_env, txs, - beneficiary_location_hash: hash_deterministic(Location::Basic( - evm_env.block_env.beneficiary, - )), - reward_policy: reward_policy(), + // beneficiary_location_hash: hash_deterministic(Location::Basic( + // evm_env.block_env.beneficiary, + // )), + // reward_policy: reward_policy(), #[cfg(feature = "compiler")] worker, } @@ -420,10 +422,19 @@ impl<'a, DB: DatabaseRef> Vm<'a, DB> { // value are added to the write set, possibly replacing a pair with a prior value // (if it is not the first time the transaction wrote to this location during the // execution). - pub(crate) fn execute( + pub(crate) fn execute
( &self, tx_version: &TxVersion, - ) -> Result { + ) -> Result, VmExecutionError> + where + HR: Clone + + core::fmt::Debug + + Send + + Sync + + 'static + + core::cmp::Eq + + core::convert::From, + { // SAFETY: A correct scheduler would guarantee this index to be inbound. let tx = unsafe { self.txs.get_unchecked(tx_version.tx_idx) }; let from_hash = hash_deterministic(Location::Basic(tx.caller)); @@ -441,9 +452,9 @@ impl<'a, DB: DatabaseRef> Vm<'a, DB> { let result = { evm.set_tx(tx.clone()); #[cfg(feature = "compiler")] - let mut t = WithoutRewardBeneficiaryHandler::new(self.worker.clone()); + let mut t = WithoutRewardBeneficiaryHandler::<_, HR>::new(self.worker.clone()); #[cfg(not(feature = "compiler"))] - let mut t = WithoutRewardBeneficiaryHandler::default(); + let mut t = WithoutRewardBeneficiaryHandler::<_, HR>::default(); t.run(&mut evm) }; match result { @@ -452,7 +463,18 @@ impl<'a, DB: DatabaseRef> Vm<'a, DB> { // the recipient, and the beneficiary accounts. let mut write_set = WriteSet::with_capacity_and_hasher(100, BuildIdentityHasher::default()); - let state = evm.finalize(); + let mut state = evm.finalize(); + // IMPORTANT: `WithoutRewardBeneficiaryHandler` skips `reward_beneficiary`, so we must + // explicitly apply the beneficiary (miner tip) reward into the finalized `state`. + // Otherwise, proposers that commit pre-executed `ResultAndState` will produce a + // different state root than validators that re-execute transactions. + self.apply_beneficiary_reward_to_state( + &mut state, + tx_version.tx_idx, + tx, + result.gas_used(), + ); + for (address, account) in &state { if account.is_selfdestructed() { // For now we are betting on [code_hash] triggering the sequential @@ -545,8 +567,6 @@ impl<'a, DB: DatabaseRef> Vm<'a, DB> { } } - self.apply_rewards(&mut write_set, tx, U256::from(result.gas_used()))?; - // Drop the vm instance and the database instance. drop(evm); // Append lazy addresses when the mode is lazy. @@ -568,8 +588,12 @@ impl<'a, DB: DatabaseRef> Vm<'a, DB> { let tx_type = reth_primitives::TxType::try_from(tx.tx_type).map_err(|err| { VmExecutionError::ExecutionError(EVMError::Custom(err.to_string())) })?; + + // Combine result and state into ResultAndState to preserve all execution information + let result_and_state: ResultAndState
= ResultAndState { result, state }; + Ok(VmExecutionResult { - execution_result: TxExecutionResult::from_raw(tx_type, result, state), + execution_result: TxExecutionResult::from_raw(tx_type, result_and_state), flags, }) } @@ -592,82 +616,152 @@ impl<'a, DB: DatabaseRef> Vm<'a, DB> { } } - // Apply rewards (balance increments) to beneficiary accounts, etc. - fn apply_rewards( + /// Apply the per-transaction beneficiary reward (miner tip) directly into the finalized `state`. + /// + /// This mirrors the logic in `apply_rewards`, but updates the committed `EvmState` so that + /// `ResultAndState` matches canonical EVM execution used during block validation. + fn apply_beneficiary_reward_to_state( &self, - write_set: &mut WriteSet, + state: &mut EvmState, + tx_idx: TxIdx, tx: &TxEnv, - gas_used: U256, - ) -> Result<(), VmExecutionError> { - let mut gas_price = if let Some(priority_fee) = tx.gas_priority_fee { - std::cmp::min( - tx.gas_price, - priority_fee.saturating_add(self.evm_env.block_env.basefee as u128), - ) - } else { - tx.gas_price - }; - if self.evm_env.cfg_env.spec.is_enabled_in(SpecId::LONDON) { - gas_price = gas_price.saturating_sub(self.evm_env.block_env.basefee as u128); + gas_used: u64, + ) { + // Match the actual canonical execution in this node: + // - Use effective gas price (1559/legacy aware) + // - Credit the beneficiary with the full effective gas price. + // + // NOTE: Although Ethereum mainnet burns the basefee post-London, our witness diffs for this + // network show that the canonical re-execution expects beneficiary balance increments of + // (basefee + tip) * gas_used. To keep proposer payloads valid, we mirror that behavior here. + let basefee = self.evm_env.block_env.basefee as u128; + let effective_gas_price = tx.effective_gas_price(basefee); + let coinbase_gas_price = effective_gas_price; + + // Log to make it easy to correlate witness diffs with reward math. + tracing::debug!( + target: "metis::parallel", + beneficiary=?self.evm_env.block_env.beneficiary, + spec=?self.evm_env.cfg_env.spec, + basefee, + effective_gas_price, + coinbase_gas_price, + gas_used, + "beneficiary_reward: computed coinbase_gas_price (tip per gas)" + ); + + let amount = U256::from(coinbase_gas_price).saturating_mul(U256::from(gas_used)); + if amount.is_zero() { + return; } - let gas_price = U256::from(gas_price); - let rewards: SmallVec<[(LocationHash, U256); 1]> = match self.reward_policy { - RewardPolicy::Ethereum => { - smallvec![( - self.beneficiary_location_hash, - gas_price.saturating_mul(gas_used) - )] + + let beneficiary: Address = self.evm_env.block_env.beneficiary; + match state.get_mut(&beneficiary) { + Some(account) => { + account.info.balance = account.info.balance.saturating_add(amount); + account.status = AccountStatus::Touched; } - }; + None => { + // IMPORTANT (consensus-critical): + // When a block has multiple txs, the beneficiary's balance at tx_k should include + // rewards from tx_0..tx_{k-1}. If we start from the *parent* state every time, we'd + // overwrite the in-block accumulated balance and diverge on multi-tx blocks. + // + // Therefore: + // - Prefer the latest `< tx_idx` value from MvMemory (in-block state). + // - Fall back to the underlying DB (parent state) if this is the first tx or the + // beneficiary hasn't been written yet. + let beneficiary_location_hash = hash_deterministic(Location::Basic(beneficiary)); + let mut base_info: Option = None; + + if tx_idx > 0 + && let Some(written_txs) = self.mv_memory.data.get(&beneficiary_location_hash) + && let Some((_, Entry::Data(_, value))) = + written_txs.range(..tx_idx).next_back() + && let LocationValue::Basic(info) = value + { + base_info = Some(info.clone()); + } - for (recipient, amount) in rewards { - if let Some(value) = write_set.get_mut(&recipient) { - match value { - LocationValue::Basic(basic) => { - basic.balance = basic.balance.saturating_add(amount) - } - LocationValue::LazySender(subtraction) => { - *subtraction = subtraction.saturating_sub(amount) - } - LocationValue::LazyRecipient(addition) => { - *addition = addition.saturating_add(amount) - } - _ => return Err(ReadError::InvalidValueType.into()), + if base_info.is_none() { + base_info = match self.db.basic_ref(beneficiary) { + Ok(Some(info)) => Some(info), + Ok(None) => None, + Err(err) => { + tracing::warn!( + target: "metis::parallel", + beneficiary=?beneficiary, + %err, + "failed to read beneficiary account from db; defaulting balance to 0" + ); + None + } + }; } - } else { - write_set.insert(recipient, LocationValue::LazyRecipient(amount)); + + let mut info = base_info.unwrap_or_default(); + info.balance = info.balance.saturating_add(amount); + state.insert( + beneficiary, + Account { + info, + status: AccountStatus::Touched, + ..Default::default() + }, + ); } } - - Ok(()) } } #[inline] pub(crate) fn build_evm(db: DB, evm_env: EvmEnv) -> MainnetEvm> { - MainnetContext::mainnet() - .with_db(db) - .with_cfg(evm_env.cfg_env) + // IMPORTANT (consensus-critical): + // We observed blocks where beneficiary received `effective_gas_price * gas_used` (basefee was + // NOT burned), which can only happen if the EVM's *handler/spec selection* is effectively + // pre-London. + // + // Setting `CfgEnv.spec` alone is not sufficient if the underlying handler/spec was chosen at + // `Context::new(.., spec_id)` time (used internally by revm mainnet handler). Therefore we + // must construct the context with the correct spec id up front. + let spec_id = evm_env.cfg_env.spec; + + // Construct the mainnet context with the correct internal spec selection. + // Assigning to `MainnetContext` makes `BLOCK/TX/CFG/JOURNAL` concrete for the compiler. + let ctx: MainnetContext = revm::Context::new(db, spec_id); + + ctx.with_cfg(evm_env.cfg_env) .with_block(evm_env.block_env) .build_mainnet() } -pub struct WithoutRewardBeneficiaryHandler { +pub struct WithoutRewardBeneficiaryHandler { _phantom: core::marker::PhantomData, + _halt: core::marker::PhantomData
, #[cfg(feature = "compiler")] worker: Arc, } -impl Handler for WithoutRewardBeneficiaryHandler +impl Handler for WithoutRewardBeneficiaryHandler where EVM: EvmTr< Context: ContextTr>, Frame: FrameTr, >, + // revm-handler requires `HaltReasonTr` which (for current revm-handler) implies: + // - Eq + // - From + HR: Clone + + core::fmt::Debug + + Send + + Sync + + 'static + + core::cmp::Eq + + core::convert::From, { type Evm = EVM; type Error = EVMError<<::Db as Database>::Error, InvalidTransaction>; - type HaltReason = HaltReason; + type HaltReason = HR; fn reward_beneficiary( &self, @@ -719,30 +813,33 @@ where } #[cfg(not(feature = "compiler"))] -impl Default for WithoutRewardBeneficiaryHandler { +impl Default for WithoutRewardBeneficiaryHandler { fn default() -> Self { Self { _phantom: core::marker::PhantomData, + _halt: core::marker::PhantomData, } } } #[cfg(feature = "compiler")] -impl Default for WithoutRewardBeneficiaryHandler { +impl Default for WithoutRewardBeneficiaryHandler { fn default() -> Self { Self { _phantom: core::marker::PhantomData, + _halt: core::marker::PhantomData, worker: Arc::new(metis_vm::ExtCompileWorker::disable()), } } } #[cfg(feature = "compiler")] -impl WithoutRewardBeneficiaryHandler { +impl WithoutRewardBeneficiaryHandler { #[inline] pub fn new(worker: Arc) -> Self { Self { _phantom: core::marker::PhantomData, + _halt: core::marker::PhantomData, worker, } } diff --git a/crates/pe/tests/common/runner.rs b/crates/pe/tests/common/runner.rs index 7d3c7a16..ef977015 100644 --- a/crates/pe/tests/common/runner.rs +++ b/crates/pe/tests/common/runner.rs @@ -30,15 +30,22 @@ where DB: DatabaseRef + Send + Sync, { let concurrency_level = thread::available_parallelism().unwrap_or(NonZeroUsize::MIN); - let mut pe = ParallelExecutor::default(); - assert_eq!( - metis_pe::execute_sequential( - &db, - EvmEnv::default(), - txs.clone(), - #[cfg(feature = "compiler")] - pe.worker.clone(), - ), - pe.execute(&db, EvmEnv::default(), txs, concurrency_level), - ); + let mut pe: ParallelExecutor = ParallelExecutor::default(); + + // Compare receipts only: `TxExecutionResult` contains `ResultAndState`, which is not + // guaranteed to implement `PartialEq` across upstream versions. + let seq_receipts = metis_pe::execute_sequential::<_, metis_primitives::HaltReason>( + &db, + EvmEnv::default(), + txs.clone(), + #[cfg(feature = "compiler")] + pe.worker.clone(), + ) + .map(|results| results.into_iter().map(|r| r.receipt).collect::>()); + + let par_receipts = pe + .execute(&db, EvmEnv::default(), txs, concurrency_level) + .map(|results| results.into_iter().map(|r| r.receipt).collect::>()); + + assert_eq!(seq_receipts, par_receipts); } diff --git a/crates/tools/bins/blocktest/main.rs b/crates/tools/bins/blocktest/main.rs index 59b1c5d9..6f9554c1 100644 --- a/crates/tools/bins/blocktest/main.rs +++ b/crates/tools/bins/blocktest/main.rs @@ -195,7 +195,9 @@ fn execute_test(path: &Path) -> Result<(), TestError> { let _ = tx.derive_tx_type(); txs.push(tx); } - let mut executor = ParallelExecutor::default(); + // Explicit HR to avoid inference ambiguity after HR was made generic in metis-pe. + let mut executor: ParallelExecutor = + ParallelExecutor::default(); // Clone the state for execution. let mut cache = cache_state.clone(); cache.set_state_clear_flag(spec_id.is_enabled_in(SpecId::SPURIOUS_DRAGON)); @@ -213,7 +215,7 @@ fn execute_test(path: &Path) -> Result<(), TestError> { ) .build(); // Check sequential execute results - let sequential_results = execute_sequential( + let sequential_results = execute_sequential::<_, metis_primitives::HaltReason>( StateStorageAdapter::new(&mut state), env.clone(), txs.clone(), @@ -295,7 +297,7 @@ fn check_execute_results(results: &[TxExecutionResult], name: &str, suite: &Suit if let Some(post_state) = &suite.post && let Some(result) = results.last() { - let db_state = &result.state; + let db_state = result.state(); for (address, expect_account) in post_state { let db_account = db_state.get(address).cloned().unwrap_or_default(); if expect_account.nonce != db_account.info.nonce { diff --git a/crates/tools/bins/ethertest/main.rs b/crates/tools/bins/ethertest/main.rs index d130012b..61d98c4b 100644 --- a/crates/tools/bins/ethertest/main.rs +++ b/crates/tools/bins/ethertest/main.rs @@ -447,7 +447,9 @@ fn execute_test(path: &Path) -> Result<(), Box> { panic!("Invalid transaction type without expected exception"); } } - let mut executor = ParallelExecutor::default(); + // Explicit HR to avoid inference ambiguity (multiple From impls exist). + let mut executor: ParallelExecutor = + ParallelExecutor::default(); let concurrency_level = NonZeroUsize::new(num_cpus::get()).unwrap_or(NonZeroUsize::new(1).unwrap()); @@ -497,7 +499,7 @@ fn execute_test(path: &Path) -> Result<(), Box> { } ); } - state.commit(res.state); + state.commit(res.result_and_state.state); // Check the account state diff. if !test_case.state.is_empty() { for (address, expect_account) in &test_case.state {