diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index f8d1d475e300..ff2c20def8f1 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -18,8 +18,7 @@ concurrency: name: bench jobs: iai: - runs-on: - group: Reth + runs-on: ubuntu-latest # Only run benchmarks in merge groups and on main if: github.event_name != 'pull_request' steps: diff --git a/.github/workflows/hive.yml b/.github/workflows/hive.yml index d7f891915592..75d3c382adc5 100644 --- a/.github/workflows/hive.yml +++ b/.github/workflows/hive.yml @@ -19,8 +19,7 @@ jobs: prepare-reth: if: github.repository == 'paradigmxyz/reth' timeout-minutes: 45 - runs-on: - group: Reth + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: mkdir artifacts diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 103a87706bca..7d5b87036605 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -19,8 +19,7 @@ concurrency: jobs: test: name: test / ${{ matrix.network }} - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_BACKTRACE: 1 strategy: diff --git a/.github/workflows/propose.yml b/.github/workflows/propose.yml new file mode 100644 index 000000000000..dfe37a1dfa25 --- /dev/null +++ b/.github/workflows/propose.yml @@ -0,0 +1,78 @@ +name: Propose a block + +on: + push: + branches: + - gwyneth + - gwyneth/** + pull_request: + branches: + - gwyneth + - gwyneth/** + +jobs: + build-and-test: + runs-on: ubuntu-latest + + env: + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Docker + uses: docker/setup-buildx-action@v2 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y curl apt-transport-https software-properties-common + + # Install Docker + if ! command -v docker &> /dev/null + then + curl -fsSL https://get.docker.com -o get-docker.sh + sh get-docker.sh + fi + + # Start Docker service + sudo systemctl start docker + sudo systemctl enable docker + + # Check Docker installation + docker --version + + # Install Kurtosis + if ! command -v kurtosis &> /dev/null + then + curl -fsSL https://kurtosis-public.s3.amazonaws.com/cli/cli-installer.sh | bash + fi + + # Check Kurtosis installation + kurtosis version + + # Install Forge + if ! command -v forge &> /dev/null + then + curl -L https://foundry.paradigm.xyz | bash + source ~/.bashrc + foundryup + fi + + # Check Forge installation + forge --version + + # Run setup_deps.sh which installs Docker, checks Docker daemon, installs Kurtosis, and extracts RPC port + ./scripts/setup_deps.sh + + - name: Run Forge Script + run: | + # Read the RPC port from the temporary file + RPC_PORT=$(cat /tmp/kurtosis_rpc_port) + + # Run the forge foundry script using the PRIVATE_KEY from GitHub Secrets + FORGE_COMMAND="forge script --rpc-url http://127.0.0.1:$RPC_PORT scripts/L2_txn_simulation/ProposeBlock.s.sol -vvvv --broadcast --private-key $PRIVATE_KEY --legacy" + echo "Running forge foundry script..." + eval $FORGE_COMMAND + echo "Forge script execution completed." \ No newline at end of file diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index a6663aea8843..2fb4bc900d0f 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -19,8 +19,7 @@ concurrency: jobs: test: name: test / ${{ matrix.network }} (${{ matrix.partition }}/2) - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_BACKTRACE: 1 strategy: @@ -45,8 +44,7 @@ jobs: state: name: Ethereum state tests - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_LOG: info,sync=error RUST_BACKTRACE: 1 @@ -70,8 +68,7 @@ jobs: doc: name: doc tests (${{ matrix.network }}) - runs-on: - group: Reth + runs-on: ubuntu-latest env: RUST_BACKTRACE: 1 timeout-minutes: 30 diff --git a/.gitignore b/.gitignore index 2d5d851a5055..9ae1d85f0572 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,8 @@ jwttoken/ crates/storage/libmdbx-rs/mdbx-sys/libmdbx/cmake-build-debug # Rust bug report -rustc-ice-* \ No newline at end of file +rustc-ice-* + +packages/protocol/broadcast/** +packages/protocol/logs/** +packages/protocol/scripts/memory_drainer_logger/logs/** \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 10ed2226c383..a7de4af463c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -80,6 +74,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0966165eaf052580bd70eb1b32cb3d6245774c0104d1b2793e9650bf83b52a" +dependencies = [ + "equator", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -97,16 +100,17 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.1.29" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07629a5d0645d29f68d2fb6f4d0cf15c89ec0965be915f303967180929743f" +checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" dependencies = [ + "alloy-primitives 0.8.14", "alloy-rlp", "arbitrary", "num_enum", @@ -117,12 +121,12 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7198a527b4c4762cb88d54bcaeb0428f4298b72552c9c8ec4af614b4a4990c59" +checksum = "629b62e38d471cc15fea534eb7283d2f8a4e8bdb1811bcc5d66dda6cfce6fae1" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", "arbitrary", @@ -132,16 +136,16 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5b68572f5dfa99ede0a491d658c9842626c956b840d0b97d0bbc9637742504" +checksum = "80759b3f57b3b20fa7cd8fef6479930fc95461b58ff8adea6e87e618449c8a1d" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-sol-type-parser", "alloy-sol-types", "const-hex", - "derive_more 0.99.18", + "derive_more 1.0.0", "itoa", "serde", "serde_json", @@ -154,7 +158,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "arbitrary", "rand 0.8.5", @@ -163,11 +167,11 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d319bb544ca6caeab58c39cea8921c55d924d4f68f2c60f24f914673f9a74a" +checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "arbitrary", "k256", @@ -177,13 +181,13 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159eab0e4e15b88571f55673af37314f4b8f17630dc1b393c3d70f2128a1d494" +checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" dependencies = [ "alloy-eip2930", "alloy-eip7702", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", "arbitrary", @@ -196,22 +200,22 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210f4b358d724f85df8adaec753c583defb58169ad3cad3d48c80d1a25a6ff0e" +checksum = "3a7a18afb0b318616b6b2b0e2e7ac5529d32a966c673b48091c9919e284e6aca" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-serde", "serde", ] [[package]] name = "alloy-json-abi" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299d2a937b6c60968df3dad2a988b0f0e03277b344639a4f7a31bd68e6285e59" +checksum = "ac4b22b3e51cac09fd2adfcc73b55f447b4df669f983c13f7894ec82b607c63f" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-sol-type-parser", "serde", "serde_json", @@ -219,29 +223,29 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7733446dd531f8eb877331fea02f6c40bdbb47444a17dc3464bf75319cc073a" +checksum = "d3c717b5298fad078cd3a418335b266eba91b511383ca9bd497f742d5975d5ab" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-sol-types", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] [[package]] name = "alloy-network" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b80851d1697fc4fa2827998e3ee010a3d1fc59c7d25e87070840169fcf465832" +checksum = "fb3705ce7d8602132bcf5ac7a1dd293a42adc2f183abf5907c30ac535ceca049" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "alloy-serde", "alloy-signer", @@ -249,32 +253,34 @@ dependencies = [ "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-network-primitives" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76a2336889f3d0624b18213239d27f4f34eb476eb35bef22f6a8cc24e0c0078" +checksum = "94ad40869867ed2d9cd3842b1e800889e5b49e6b92da346e93862b4a741bedf3" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-eips", + "alloy-primitives 0.8.14", "alloy-serde", "serde", ] [[package]] name = "alloy-node-bindings" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2657dae91ae61ed6cdd4c58b7e09330de934eea4e14d2f54f72f2a6720b23437" +checksum = "5988a227293f949525f0a1b3e1ef728d2ef24afa96bad2b7788c6c9617fa3eec" dependencies = [ "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "k256", + "rand 0.8.5", "serde_json", "tempfile", - "thiserror", + "thiserror 1.0.69", "tracing", "url", ] @@ -303,9 +309,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a767e59c86900dd7c3ce3ecef04f3ace5ac9631ee150beb8b7d22f7fa3bbb2d7" +checksum = "9db948902dfbae96a73c2fbf1f7abec62af034ab883e4c777c3fd29702bd6e2c" dependencies = [ "alloy-rlp", "arbitrary", @@ -313,25 +319,31 @@ dependencies = [ "cfg-if", "const-hex", "derive_arbitrary", - "derive_more 0.99.18", + "derive_more 1.0.0", + "foldhash", "getrandom 0.2.15", + "hashbrown 0.15.2", "hex-literal", + "indexmap 2.7.0", "itoa", "k256", "keccak-asm", + "paste", "proptest", "proptest-derive", "rand 0.8.5", "ruint", + "rustc-hash 2.1.0", "serde", + "sha3", "tiny-keccak", ] [[package]] name = "alloy-provider" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d2a195caa6707f5ce13905794865765afc6d9ea92c3a56e3a973c168d703bc" +checksum = "927f708dd457ed63420400ee5f06945df9632d5d101851952056840426a10dc5" dependencies = [ "alloy-chains", "alloy-consensus", @@ -339,7 +351,7 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-network-primitives", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types-admin", @@ -351,7 +363,7 @@ dependencies = [ "async-stream", "async-trait", "auto_impl", - "dashmap 6.0.1", + "dashmap 6.1.0", "futures", "futures-utils-wasm", "lru", @@ -359,7 +371,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "url", @@ -367,12 +379,12 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c59e13200322138fe4279b4676b0d78c4f55502de127f5a448495d3ddfaa43" +checksum = "2d05f63677e210d758cd5d6d1ce10f20c980c3560ccfbe79ba1997791862a04f" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-transport", "bimap", "futures", @@ -380,15 +392,15 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.5.1", "tracing", ] [[package]] name = "alloy-rlp" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -397,23 +409,23 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "alloy-rpc-client" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed31cdba2b23d71c555505b06674f8e7459496abfd7f4875d268434ef5a99ee6" +checksum = "7d82952dca71173813d4e5733e2c986d8b04aea9e0f3b0a576664c232ad050a5" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-pubsub", "alloy-transport", "alloy-transport-http", @@ -425,109 +437,109 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.5.1", "tracing", "url", ] [[package]] name = "alloy-rpc-types" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d758f65aa648491c6358335c578de45cd7de6fdf2877c3cef61f2c9bebea21" +checksum = "64333d639f2a0cf73491813c629a405744e16343a4bc5640931be707c345ecc5" dependencies = [ "alloy-rpc-types-engine", "alloy-rpc-types-eth", - "alloy-rpc-types-trace", "alloy-serde", "serde", ] [[package]] name = "alloy-rpc-types-admin" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e41c33bbddaec71ca1bd7a4df38f95f408ef4fa3b3c29a7e9cc8d0e43be5fbe" +checksum = "fefd12e99dd6b7de387ed13ad047ce2c90d8950ca62fc48b8a457ebb8f936c61" dependencies = [ "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "serde", "serde_json", ] [[package]] name = "alloy-rpc-types-anvil" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa5ee4ffe3e687a6372dd02e998f4f65e512ffdfe0d2c248db822649814c36cd" +checksum = "d25cb45ad7c0930dd62eecf164d2afe4c3d2dd2c82af85680ad1f118e1e5cb83" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-serde", "serde", ] [[package]] name = "alloy-rpc-types-beacon" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3173bf0239a59d3616f4f4ab1682de25dd30b13fb8f52bf7ee7503729354f3c4" +checksum = "2e7081d2206dca51ce23a06338d78d9b536931cc3f15134fc1c6535eb2b77f18" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rpc-types-engine", "serde", "serde_with", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-rpc-types-engine" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e800d959606fa19b36b31d7c24d68ef75b970c654b7aa581dce23de82db0a5" +checksum = "1464c4dd646e1bdfde86ae65ce5ba168dbb29180b478011fe87117ae46b1629b" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", - "alloy-rpc-types-eth", "alloy-serde", + "derive_more 1.0.0", "jsonrpsee-types", "jsonwebtoken", "rand 0.8.5", "serde", - "thiserror", ] [[package]] name = "alloy-rpc-types-eth" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ba05d6ee4db0d89113294a614137940f79abfc2c40a9a3bee2995660358776" +checksum = "83aa984386deda02482660aa31cb8ca1e63d533f1c31a52d7d181ac5ec68e9b8" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-network-primitives", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", "alloy-sol-types", "arbitrary", + "cfg-if", + "derive_more 1.0.0", + "hashbrown 0.14.5", "itertools 0.13.0", "jsonrpsee-types", "serde", "serde_json", - "thiserror", ] [[package]] name = "alloy-rpc-types-mev" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a0b28949d1077826684b5912fe9ab1c752a863af0419b1ba9abff19006d61b1" +checksum = "922d92389e5022650c4c60ffd2f9b2467c3f853764f0f74ff16a23106f9017d5" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-serde", "serde", "serde_json", @@ -535,25 +547,25 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd2af822ed58f2b6dd7cfccf88bf69f42c9a8cbf4663316227646a8a3e5a591f" +checksum = "98db35cd42c90b484377e6bc44d95377a7a38a5ebee996e67754ac0446d542ab" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "alloy-serde", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-rpc-types-txpool" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a8fbdf39e93a9b213df39541be51671e93e6e8b142c3602ddb4ff6219a1bc85" +checksum = "6bac37082c3b21283b3faf5cc0e08974272aee2f756ce1adeb26db56a5fce0d5" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "alloy-serde", "serde", @@ -561,11 +573,11 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd260ede54f0b53761fdd04133acc10ae70427f66a69aa9590529bbd066cd58" +checksum = "731f75ec5d383107fd745d781619bd9cedf145836c51ecb991623d41278e71fa" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "arbitrary", "serde", "serde_json", @@ -573,88 +585,91 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5193ee6b370b89db154d7dc40c6a8e6ce11213865baaf2b418a9f2006be762" +checksum = "307324cca94354cd654d6713629f0383ec037e1ff9e3e3d547212471209860c0" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "async-trait", "auto_impl", "elliptic-curve", "k256", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-signer-local" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6b19bbb231c7f941af07f363d4c74d356dfcdfcd7dfa85a41a504ae856a6d5" +checksum = "9fabe917ab1778e760b4701628d1cae8e028ee9d52ac6307de4e1e9286ab6b5f" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-signer", "async-trait", "coins-bip32", "coins-bip39", "k256", "rand 0.8.5", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-sol-macro" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "183bcfc0f3291d9c41a3774172ee582fb2ce6eb6569085471d8f225de7bb86fc" +checksum = "3bfd7853b65a2b4f49629ec975fee274faf6dff15ab8894c620943398ef283c0" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c4d842beb7a6686d04125603bc57614d5ed78bf95e4753274db3db4ba95214" +checksum = "82ec42f342d9a9261699f8078e57a7a4fda8aaa73c1a212ed3987080e6a9cd13" dependencies = [ + "alloy-json-abi", "alloy-sol-macro-input", "const-hex", - "heck 0.5.0", - "indexmap 2.4.0", - "proc-macro-error", + "heck", + "indexmap 2.7.0", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1306e8d3c9e6e6ecf7a39ffaf7291e73a5f655a2defd366ee92c2efebcdf7fee" +checksum = "ed2c50e6a62ee2b4f7ab3c6d0366e5770a21cad426e109c2f40335a1b3aff3df" dependencies = [ + "alloy-json-abi", "const-hex", "dunce", - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.76", + "serde_json", + "syn 2.0.90", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4691da83dce9c9b4c775dd701c87759f173bd3021cbf2e60cde00c5fe6d7241" +checksum = "ac17c6e89a50fb4a758012e4b409d9a0ba575228e69b539fe37d7a1bd507ca4a" dependencies = [ "serde", "winnow", @@ -662,12 +677,12 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "577e262966e92112edbd15b1b2c0947cc434d6e8311df96d3329793fe8047da9" +checksum = "c9dc0fffe397aa17628160e16b89f704098bf3c9d74d5d369ebc239575936de5" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-sol-macro", "const-hex", "serde", @@ -675,9 +690,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "454220c714857cf68af87d788d1f0638ad8766268b94f6a49fed96cbc2ab382c" +checksum = "33616b2edf7454302a1d48084db185e52c309f73f6c10be99b0fe39354b3f1e9" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -685,33 +700,33 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.5.1", "tracing", "url", ] [[package]] name = "alloy-transport-http" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377f2353d7fea03a2dba6b9ffbb7d610402c040dd5700d1fae8b9ec2673eed9b" +checksum = "a944f5310c690b62bbb3e7e5ce34527cbd36b2d18532a797af123271ce595a49" dependencies = [ "alloy-json-rpc", "alloy-transport", "reqwest", "serde_json", - "tower", + "tower 0.5.1", "tracing", "url", ] [[package]] name = "alloy-transport-ipc" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8653c47dcc30326fb09a34140e8800fa21987fc52453de6cfcdd5c7b8b6e9886" +checksum = "09fd8491249f74d16ec979b1f5672377b12ebb818e6056478ffa386954dbd350" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -728,9 +743,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d43ba8e9a3a7fef626d5fd93cc87ff2d6d2c81acfb866f068b3dce31dda060" +checksum = "a9704761f6297fe482276bee7f77a93cb42bd541c2bd6c1c560b6f3a9ece672e" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -746,11 +761,11 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.5.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd491aade72a82d51db430379f48a44a1d388ff03711a2023f1faa302c5b675d" +checksum = "0a46c9c4fdccda7982e7928904bd85fe235a0404ee3d7e197fff13d61eac8b4f" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "arbitrary", "derive_arbitrary", @@ -787,9 +802,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -802,43 +817,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "aquamarine" @@ -851,14 +866,14 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] @@ -897,7 +912,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -989,9 +1004,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -1024,9 +1039,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.12" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "brotli", "flate2", @@ -1054,9 +1069,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -1065,24 +1080,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -1093,7 +1108,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -1120,14 +1135,14 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backon" @@ -1135,7 +1150,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d67782c3f868daa71d3533538e98a8e13713231969def7536e8039606fc46bf0" dependencies = [ - "fastrand 2.1.1", + "fastrand 2.2.0", "futures-core", "pin-project", "tokio", @@ -1143,17 +1158,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -1215,9 +1230,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.4" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ "bitflags 2.6.0", "cexpr", @@ -1230,14 +1245,32 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.76", + "syn 2.0.90", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.90", ] [[package]] name = "binout" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60b1af88a588fca5fe424ae7d735bc52814f80ff57614f57043cc4e2024f2ea" +checksum = "581d67184175e0c94926cb5e82df97bb6e0d8261d27a88a6ead80994ee73a4ac" [[package]] name = "bit-set" @@ -1272,9 +1305,9 @@ dependencies = [ [[package]] name = "bitm" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06e8e5bec3490b9f6f3adbb78aa4f53e8396fd9994e8a62a346b44ea7c15f35" +checksum = "e7edec3daafc233e78a219c85a77bcf535ee267b0fae7a1aad96bd1a67add5d3" dependencies = [ "dyn_size_of", ] @@ -1333,23 +1366,23 @@ dependencies = [ [[package]] name = "boa_ast" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49637e7ecb7c541c46c3e885d4c49326ad8076dbfb88bef2cf3165d8ea7df2b" +checksum = "3a69ee3a749ea36d4e56d92941e7b25076b493d4917c3d155b6cf369e23547d9" dependencies = [ "bitflags 2.6.0", "boa_interner", "boa_macros", - "indexmap 2.4.0", + "indexmap 2.7.0", "num-bigint", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", ] [[package]] name = "boa_engine" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "411558b4cbc7d0303012e26721815e612fed78179313888fd5dd8d6c50d70099" +checksum = "06e4559b35b80ceb2e6328481c0eca9a24506663ea33ee1e279be6b5b618b25c" dependencies = [ "arrayvec", "bitflags 2.6.0", @@ -1366,7 +1399,7 @@ dependencies = [ "fast-float", "hashbrown 0.14.5", "icu_normalizer", - "indexmap 2.4.0", + "indexmap 2.7.0", "intrusive-collections", "itertools 0.13.0", "num-bigint", @@ -1378,7 +1411,7 @@ dependencies = [ "portable-atomic", "rand 0.8.5", "regress", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "ryu-js", "serde", "serde_json", @@ -1386,15 +1419,15 @@ dependencies = [ "static_assertions", "tap", "thin-vec", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] name = "boa_gc" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eff345a85a39cf9b8ed863198947d61e6df2b1d774002b57341158b0ce2c525" +checksum = "716406f57d67bc3ac7fd227d5513b42df401dff14a3be22cbd8ee29817225363" dependencies = [ "boa_macros", "boa_profiler", @@ -1405,37 +1438,37 @@ dependencies = [ [[package]] name = "boa_interner" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b779280420804c70da9043d152c84eb96e2f7c9e7d1ec3262decf59f9349df" +checksum = "4e18df2272616e1ba0322a69333d37dbb78797f1aa0595aad9dc41e8ecd06ad9" dependencies = [ "boa_gc", "boa_macros", "hashbrown 0.14.5", - "indexmap 2.4.0", + "indexmap 2.7.0", "once_cell", "phf", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "static_assertions", ] [[package]] name = "boa_macros" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e0097fa69cde4c95f9869654004340fbbe2bcf3ce9189ba2a31a65ac40e0a1" +checksum = "240f4126219a83519bad05c9a40bfc0303921eeb571fc2d7e44c17ffac99d3f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", "synstructure", ] [[package]] name = "boa_parser" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd63fe8faf62561fc8c50f9402687e8cfde720b57d292fb3b4ac17c821878ac1" +checksum = "62b59dc05bf1dc019b11478a92986f590cff43fced4d20e866eefb913493e91c" dependencies = [ "bitflags 2.6.0", "boa_ast", @@ -1447,24 +1480,24 @@ dependencies = [ "num-bigint", "num-traits", "regress", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", ] [[package]] name = "boa_profiler" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9da895f0df9e2a97b36c1f98e0c5d2ab963abc8679d80f2a66f7bcb211ce90" +checksum = "00ee0645509b3b91abd724f25072649d9e8e65653a78ff0b6e592788a58dd838" [[package]] name = "boa_string" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9ca6668df83fcd3c2903f6f296b7180421908c5b478ebe0d1c468be9fd60e1c" +checksum = "ae85205289bab1f2c7c8a30ddf0541cf89ba2ff7dbd144feef50bbfa664288d4" dependencies = [ "fast-float", "paste", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "sptr", "static_assertions", ] @@ -1480,9 +1513,9 @@ dependencies = [ [[package]] name = "brotli" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1511,12 +1544,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.9", "serde", ] @@ -1534,22 +1567,22 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.17.1" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -1560,9 +1593,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -1593,9 +1626,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -1611,7 +1644,7 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1637,9 +1670,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "jobserver", "libc", @@ -1667,6 +1700,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.38" @@ -1732,9 +1771,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive", @@ -1742,9 +1781,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -1754,21 +1793,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "coins-bip32" @@ -1783,7 +1822,7 @@ dependencies = [ "k256", "serde", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1799,7 +1838,7 @@ dependencies = [ "pbkdf2", "rand 0.8.5", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1818,14 +1857,14 @@ dependencies = [ "serde", "sha2 0.10.8", "sha3", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -1839,14 +1878,14 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" +checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9" dependencies = [ - "crossterm", + "crossterm 0.28.1", "strum", "strum_macros", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -1894,9 +1933,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" dependencies = [ "cfg-if", "cpufeatures", @@ -1913,9 +1952,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", "konst", @@ -1923,9 +1962,9 @@ dependencies = [ [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -1957,6 +1996,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1974,18 +2023,18 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ "cfg-if", ] [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -2102,6 +2151,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "crossterm" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +dependencies = [ + "bitflags 2.6.0", + "crossterm_winapi", + "parking_lot 0.12.3", + "rustix", + "winapi", +] + [[package]] name = "crossterm_winapi" version = "0.9.1" @@ -2152,9 +2214,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", @@ -2205,7 +2267,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -2218,7 +2280,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -2242,7 +2304,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -2253,7 +2315,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -2271,9 +2333,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.0.1" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", "crossbeam-utils", @@ -2367,13 +2429,13 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -2385,8 +2447,8 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.76", + "rustc_version 0.4.1", + "syn 2.0.90", ] [[package]] @@ -2407,7 +2469,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", "unicode-xid", ] @@ -2515,7 +2577,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -2544,9 +2606,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "dyn_size_of" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d4f78a40b1ec35bf8cafdaaf607ba2f773c366b0b3bda48937cacd7a8d5134" +checksum = "fdbac012a81cc46ca554aceae23c52f4f55adb343f2f32ca99bb4e5ef868cee2" [[package]] name = "ecdsa" @@ -2602,7 +2664,7 @@ dependencies = [ "reth-stages", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "walkdir", ] @@ -2665,14 +2727,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -2683,7 +2745,27 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", +] + +[[package]] +name = "equator" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35da53b5a021d2484a7cc49b2ac7f2d840f8236a286f84202369bd338d761ea" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -2694,12 +2776,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2721,7 +2803,7 @@ dependencies = [ "reth-node-ethereum", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2788,7 +2870,7 @@ dependencies = [ "reth-rpc-types", "reth-tracing", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -3026,9 +3108,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fastrlp" @@ -3048,7 +3130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182f7dbc2ef73d9ef67351c5fbbea084729c48362d3ce9dd44c28e32e277fe5" dependencies = [ "libc", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3067,6 +3149,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "findshlibs" version = "0.10.2" @@ -3093,12 +3187,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -3107,6 +3201,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -3122,6 +3222,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "funty" version = "2.0.0" @@ -3130,9 +3239,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -3145,9 +3254,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -3155,15 +3264,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -3172,9 +3281,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -3193,26 +3302,26 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -3226,9 +3335,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -3295,9 +3404,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -3320,7 +3429,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -3362,11 +3471,69 @@ dependencies = [ "subtle", ] +[[package]] +name = "gwyneth" +version = "1.0.6" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.14", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "bincode", + "eyre", + "futures", + "futures-util", + "jsonrpsee", + "reth-auto-seal-consensus", + "reth-basic-payload-builder", + "reth-beacon-consensus", + "reth-chainspec", + "reth-consensus", + "reth-db", + "reth-errors", + "reth-ethereum-engine-primitives", + "reth-ethereum-payload-builder", + "reth-evm", + "reth-evm-ethereum", + "reth-execution-types", + "reth-exex", + "reth-network", + "reth-node-api", + "reth-node-builder", + "reth-node-core", + "reth-node-ethereum", + "reth-node-events", + "reth-payload-builder", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc", + "reth-rpc-api", + "reth-rpc-builder", + "reth-rpc-engine-api", + "reth-rpc-layer", + "reth-rpc-types", + "reth-tasks", + "reth-tokio-util", + "reth-tracing", + "reth-transaction-pool", + "reth-trie", + "revm", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", @@ -3374,7 +3541,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.4.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -3420,6 +3587,18 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] + [[package]] name = "hashlink" version = "0.8.4" @@ -3439,12 +3618,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -3530,9 +3703,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -3564,9 +3737,9 @@ dependencies = [ [[package]] name = "http-range-header" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] name = "http-types" @@ -3590,9 +3763,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -3624,9 +3797,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", @@ -3645,9 +3818,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http", @@ -3655,7 +3828,7 @@ dependencies = [ "hyper-util", "log", "rustls", - "rustls-native-certs", + "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", "tokio-rustls", @@ -3665,9 +3838,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -3676,9 +3849,8 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", - "tower", "tower-service", "tracing", ] @@ -3703,7 +3875,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -3717,9 +3889,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3853,7 +4025,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -3874,12 +4046,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -3893,13 +4076,13 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -3940,12 +4123,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ + "arbitrary", "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "serde", ] @@ -3962,7 +4146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88" dependencies = [ "ahash", - "indexmap 2.4.0", + "indexmap 2.7.0", "is-terminal", "itoa", "log", @@ -3973,6 +4157,26 @@ dependencies = [ "str_stack", ] +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "inout" version = "0.1.3" @@ -3994,9 +4198,9 @@ dependencies = [ [[package]] name = "interprocess" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f4e4a06d42fab3e85ab1b419ad32b09eab58b901d40c57935ff92db3287a13" +checksum = "894148491d817cb36b6f778017b8ac46b17408d522dd90f539d677ea938362eb" dependencies = [ "doctest-file", "futures-core", @@ -4009,9 +4213,9 @@ dependencies = [ [[package]] name = "intrusive-collections" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b694dc9f70c3bda874626d2aed13b780f137aab435f4e9814121955cf706122e" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" dependencies = [ "memoffset", ] @@ -4022,7 +4226,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.7", + "socket2 0.5.8", "widestring", "windows-sys 0.48.0", "winreg", @@ -4030,15 +4234,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "iri-string" -version = "0.7.2" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f5f6c2df22c009ac44f6f1499308e7a3ac7ba42cd2378475cc691510e1eef1b" +checksum = "dc0f0a572e8ffe56e2ff4f769f32ffe919282c3916799f8b68688b6030063bea" dependencies = [ "memchr", "serde", @@ -4090,9 +4294,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -4104,7 +4308,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", ] @@ -4125,18 +4329,19 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "jsonrpsee" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" +checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -4152,9 +4357,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" +checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" dependencies = [ "base64 0.22.1", "futures-channel", @@ -4167,7 +4372,7 @@ dependencies = [ "rustls-pki-types", "rustls-platform-verifier", "soketto", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-rustls", "tokio-util", @@ -4177,9 +4382,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" +checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" dependencies = [ "async-trait", "bytes", @@ -4192,10 +4397,10 @@ dependencies = [ "parking_lot 0.12.3", "pin-project", "rand 0.8.5", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -4204,9 +4409,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64 0.22.1", @@ -4220,31 +4425,31 @@ dependencies = [ "rustls-platform-verifier", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" +checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "jsonrpsee-server" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" +checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" dependencies = [ "futures-util", "http", @@ -4259,31 +4464,31 @@ dependencies = [ "serde", "serde_json", "soketto", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] [[package]] name = "jsonrpsee-types" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" +checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" dependencies = [ "http", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "jsonrpsee-wasm-client" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0470d0ae043ffcb0cd323797a631e637fb4b55fe3eaa6002934819458bba62a7" +checksum = "1a01cd500915d24ab28ca17527e23901ef1be6d659a2322451e1045532516c25" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -4292,9 +4497,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" +checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" dependencies = [ "http", "jsonrpsee-client-transport", @@ -4320,9 +4525,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", @@ -4343,9 +4548,9 @@ dependencies = [ [[package]] name = "keccak-asm" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -4366,6 +4571,26 @@ version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -4383,31 +4608,31 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p-identity" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +checksum = "257b5621d159b32282eac446bed6670c39c7dc68a200a992d8f056afa0066f6d" dependencies = [ "asn1_der", "bs58", @@ -4417,18 +4642,18 @@ dependencies = [ "multihash", "quick-protobuf", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", "tracing", "zeroize", ] [[package]] name = "libproc" -version = "0.14.8" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9ea4b75e1a81675429dafe43441df1caea70081e82246a8cccf514884a88bb" +checksum = "e78a09b56be5adbcad5aa1197371688dc6bb249a26da3bca2011ee2fb987ebfb" dependencies = [ - "bindgen", + "bindgen 0.70.1", "errno", "libc", ] @@ -4441,6 +4666,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall 0.5.7", ] [[package]] @@ -4514,9 +4740,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -4536,11 +4762,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] @@ -4590,9 +4816,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -4616,6 +4842,16 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "metrics" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a7deb012b3b2767169ff203fadb4c6b0b82b947512e5eb9e0b78c2e186ad9e3" +dependencies = [ + "ahash", + "portable-atomic", +] + [[package]] name = "metrics-exporter-prometheus" version = "0.15.3" @@ -4623,26 +4859,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" dependencies = [ "base64 0.22.1", - "indexmap 2.4.0", - "metrics", + "indexmap 2.7.0", + "metrics 0.23.0", "metrics-util", "quanta", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "metrics-process" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb524e5438255eaa8aa74214d5a62713b77b2c3c6e3c0bbeee65cfd9a58948ba" +checksum = "4a82c8add4382f29a122fa64fff1891453ed0f6b2867d971e7d60cb8dfa322ff" dependencies = [ + "libc", "libproc", "mach2", - "metrics", + "metrics 0.24.1", "once_cell", - "procfs", + "procfs 0.17.0", "rlimit", - "windows 0.57.0", + "windows 0.58.0", ] [[package]] @@ -4655,8 +4892,8 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "hashbrown 0.14.5", - "indexmap 2.4.0", - "metrics", + "indexmap 2.7.0", + "metrics 0.23.0", "num_cpus", "ordered-float", "quanta", @@ -4679,7 +4916,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -4706,15 +4943,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -4738,11 +4966,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", @@ -4772,7 +4999,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -4804,9 +5031,9 @@ checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", @@ -4834,9 +5061,9 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" dependencies = [ "core2", "unsigned-varint", @@ -4873,21 +5100,30 @@ dependencies = [ ] [[package]] -name = "ntapi" -version = "0.4.1" +name = "notify" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "winapi", + "bitflags 2.6.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio 0.8.11", + "walkdir", + "windows-sys 0.48.0", ] [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "ntapi" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ - "overload", "winapi", ] @@ -5010,7 +5246,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -5038,18 +5274,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" @@ -5059,44 +5295,78 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "op-alloy-consensus" -version = "0.2.2" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0db6e3a9bbbcef7cef19d77aa2cc76d61377376e3bb86f89167e7e3f30ea023" +checksum = "21aad1fbf80d2bcd7406880efc7ba109365f44bbb72896758ddcbfa46bf1592c" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", "derive_more 1.0.0", "serde", + "spin", ] [[package]] -name = "op-alloy-network" -version = "0.2.2" +name = "op-alloy-genesis" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66184e6c92269ba4ef1f80e8566ce11d41b584884ce7476d4b1b5e0e38503ecb" +checksum = "6e1b8a9b70da0e027242ec1762f0f3a386278b6291d00d12ff5a64929dc19f68" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-primitives 0.8.14", + "alloy-sol-types", + "serde", + "serde_repr", +] + +[[package]] +name = "op-alloy-network" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "783ce4ebc0a994eee2188431511b16692b704e1e8fff0c77d8c0354d3c2b1fc8" +dependencies = [ + "alloy-consensus", "alloy-network", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "op-alloy-consensus", "op-alloy-rpc-types", ] +[[package]] +name = "op-alloy-protocol" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf300a82ae2d30e2255bfea87a2259da49f63a25a44db561ae64cc9e3084139f" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.14", + "alloy-rlp", + "alloy-serde", + "hashbrown 0.14.5", + "op-alloy-consensus", + "op-alloy-genesis", + "serde", +] + [[package]] name = "op-alloy-rpc-types" -version = "0.2.2" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c604cd3b9680d0edd0b7127f3550bcff634c2d2efe27b2b4853e72320186a8" +checksum = "e281fbfc2198b7c0c16457d6524f83d192662bc9f3df70f24c3038d4521616df" dependencies = [ - "alloy-network", - "alloy-primitives 0.8.0", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "alloy-serde", + "cfg-if", + "hashbrown 0.14.5", "op-alloy-consensus", "serde", "serde_json", @@ -5104,13 +5374,18 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.2.2" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620e645c36cc66220909bf97e6632e7a154a2309356221cbf33ae78bf5294478" +checksum = "2947272a81ebf988f4804b6f0f6a7c0b2f6f89a908cb410e36f8f3828f81c778" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-eips", + "alloy-primitives 0.8.14", "alloy-rpc-types-engine", "alloy-serde", + "derive_more 1.0.0", + "op-alloy-consensus", + "op-alloy-genesis", + "op-alloy-protocol", "serde", ] @@ -5134,19 +5409,13 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-float" -version = "4.2.2" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a91171844676f8c7990ce64959210cd2eaef32c2612c50f9fae9f8aaa6065a6" +checksum = "c65ee1f9701bf938026630b455d5315f490640234259037edb259798b3bcf85e" dependencies = [ "num-traits", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "p256" version = "0.13.2" @@ -5198,9 +5467,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -5245,7 +5514,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.7", "smallvec", "windows-targets 0.52.6", ] @@ -5284,26 +5553,27 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", - "thiserror", + "thiserror 1.0.69", "ucd-trie", ] [[package]] name = "ph" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b7b74d575d7c11fb653fae69688be5206cafc1ead33c01ce61ac7f36eae45b" +checksum = "b2fbaf8da280599aae4047ea0659a1e79cf61739bce5bdc50ca88dc7e6357060" dependencies = [ + "aligned-vec", "binout", "bitm", "dyn_size_of", "rayon", - "wyhash", + "seedable_hash", ] [[package]] @@ -5313,7 +5583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -5346,7 +5616,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -5360,29 +5630,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -5402,9 +5672,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plain_hasher" @@ -5417,9 +5687,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -5430,15 +5700,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -5463,9 +5733,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -5492,7 +5762,7 @@ dependencies = [ "smallvec", "symbolic-demangle", "tempfile", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -5532,12 +5802,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -5593,11 +5863,33 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -5613,7 +5905,19 @@ dependencies = [ "flate2", "hex", "lazy_static", - "procfs-core", + "procfs-core 0.16.0", + "rustix", +] + +[[package]] +name = "procfs" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" +dependencies = [ + "bitflags 2.6.0", + "hex", + "procfs-core 0.17.0", "rustix", ] @@ -5628,6 +5932,16 @@ dependencies = [ "hex", ] +[[package]] +name = "procfs-core" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" +dependencies = [ + "bitflags 2.6.0", + "hex", +] + [[package]] name = "proptest" version = "1.5.0" @@ -5642,7 +5956,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -5666,7 +5980,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -5710,50 +6024,54 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls", - "socket2 0.5.7", - "thiserror", + "socket2 0.5.8", + "thiserror 2.0.4", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom 0.2.15", "rand 0.8.5", "ring", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.4", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ + "cfg_aliases", "libc", "once_cell", - "socket2 0.5.7", + "socket2 0.5.8", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5803,6 +6121,7 @@ dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", + "serde", ] [[package]] @@ -5870,7 +6189,7 @@ dependencies = [ "bitflags 2.6.0", "cassowary", "compact_str", - "crossterm", + "crossterm 0.27.0", "itertools 0.13.0", "lru", "paste", @@ -5879,14 +6198,14 @@ dependencies = [ "strum_macros", "unicode-segmentation", "unicode-truncate", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "raw-cpuid" -version = "11.1.0" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ "bitflags 2.6.0", ] @@ -5928,9 +6247,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -5943,19 +6262,19 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -5969,13 +6288,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -5986,15 +6305,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "regress" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16fe0a24af5daaae947294213d2fd2646fbf5e1fbacc1d4ba3e84b2393854842" +checksum = "1541daf4e4ed43a0922b7969bdc2170178bcacc5dabf7e39bc508a9fa3953a7a" dependencies = [ "hashbrown 0.14.5", "memchr", @@ -6002,9 +6321,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -6025,13 +6344,13 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-native-certs", + "rustls-native-certs 0.8.1", "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tokio-rustls", "tokio-util", @@ -6067,6 +6386,7 @@ dependencies = [ "eyre", "fdlimit", "futures", + "gwyneth", "itertools 0.13.0", "libc", "metrics-process", @@ -6089,6 +6409,7 @@ dependencies = [ "reth-errors", "reth-ethereum-payload-builder", "reth-evm", + "reth-execution-errors", "reth-execution-types", "reth-exex", "reth-fs-util", @@ -6172,7 +6493,7 @@ dependencies = [ "alloy-rlp", "futures-core", "futures-util", - "metrics", + "metrics 0.23.0", "reth-chainspec", "reth-metrics", "reth-payload-builder", @@ -6195,7 +6516,7 @@ dependencies = [ "assert_matches", "futures", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "reth-blockchain-tree", "reth-blockchain-tree-api", "reth-chainspec", @@ -6230,7 +6551,7 @@ dependencies = [ "reth-tokio-util", "reth-tracing", "schnellru", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -6269,11 +6590,11 @@ dependencies = [ "reth-tracing", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tikv-jemallocator", "tokio", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] @@ -6284,8 +6605,9 @@ dependencies = [ "alloy-genesis", "aquamarine", "assert_matches", + "bincode", "linked_hash_set", - "metrics", + "metrics 0.23.0", "parking_lot 0.12.3", "reth-blockchain-tree-api", "reth-chainspec", @@ -6308,6 +6630,8 @@ dependencies = [ "reth-trie", "reth-trie-db", "reth-trie-parallel", + "serde", + "serde_json", "tokio", "tracing", ] @@ -6320,7 +6644,7 @@ dependencies = [ "reth-execution-errors", "reth-primitives", "reth-storage-errors", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -6331,7 +6655,7 @@ dependencies = [ "alloy-signer-local", "auto_impl", "derive_more 1.0.0", - "metrics", + "metrics 0.23.0", "parking_lot 0.12.3", "pin-project", "rand 0.8.5", @@ -6355,7 +6679,7 @@ dependencies = [ "alloy-chains", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-trie", "auto_impl", @@ -6388,7 +6712,7 @@ dependencies = [ "backon", "clap", "comfy-table", - "crossterm", + "crossterm 0.27.0", "eyre", "fdlimit", "futures", @@ -6450,13 +6774,13 @@ name = "reth-cli-util" version = "1.0.6" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "eyre", "libc", "rand 0.8.5", "reth-fs-util", "secp256k1", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -6466,7 +6790,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-trie", "arbitrary", "bytes", @@ -6487,7 +6811,7 @@ dependencies = [ "proc-macro2", "quote", "similar-asserts", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -6559,7 +6883,7 @@ dependencies = [ "derive_more 1.0.0", "eyre", "iai-callgrind", - "metrics", + "metrics 0.23.0", "page_size", "paste", "pprof", @@ -6577,14 +6901,14 @@ dependencies = [ "reth-storage-errors", "reth-tracing", "reth-trie-common", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "serde_json", "strum", "sysinfo", "tempfile", "test-fuzz", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -6597,7 +6921,7 @@ dependencies = [ "criterion", "derive_more 1.0.0", "iai-callgrind", - "metrics", + "metrics 0.23.0", "modular-bitfield", "parity-scale-codec", "pprof", @@ -6638,7 +6962,7 @@ dependencies = [ "reth-trie-db", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -6661,7 +6985,7 @@ dependencies = [ name = "reth-discv4" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "assert_matches", "discv5", @@ -6677,7 +7001,7 @@ dependencies = [ "schnellru", "secp256k1", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -6687,14 +7011,14 @@ dependencies = [ name = "reth-discv5" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "derive_more 1.0.0", "discv5", "enr", "futures", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "rand 0.8.5", "reth-chainspec", "reth-ethereum-forks", @@ -6702,7 +7026,7 @@ dependencies = [ "reth-network-peers", "reth-tracing", "secp256k1", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -6712,7 +7036,7 @@ name = "reth-dns-discovery" version = "1.0.6" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "data-encoding", "enr", @@ -6728,7 +7052,7 @@ dependencies = [ "secp256k1", "serde", "serde_with", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -6744,7 +7068,7 @@ dependencies = [ "futures", "futures-util", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "pin-project", "rand 0.8.5", "rayon", @@ -6763,7 +7087,7 @@ dependencies = [ "reth-testing-utils", "reth-tracing", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -6810,7 +7134,7 @@ name = "reth-ecies" version = "1.0.6" dependencies = [ "aes", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "block-padding", "byteorder", @@ -6827,7 +7151,7 @@ dependencies = [ "secp256k1", "sha2 0.10.8", "sha3", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -6870,7 +7194,7 @@ dependencies = [ "reth-prune-types", "reth-stages-api", "reth-tasks", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", ] @@ -6882,7 +7206,7 @@ dependencies = [ "alloy-rlp", "assert_matches", "futures", - "metrics", + "metrics 0.23.0", "rand 0.8.5", "reth-beacon-consensus", "reth-blockchain-tree", @@ -6915,7 +7239,7 @@ dependencies = [ "reth-tasks", "reth-tracing", "reth-trie", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -6958,7 +7282,7 @@ dependencies = [ "reth-execution-errors", "reth-fs-util", "reth-storage-errors", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -6987,7 +7311,7 @@ dependencies = [ "serde", "snap", "test-fuzz", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -7011,7 +7335,7 @@ dependencies = [ "reth-codecs-derive", "reth-primitives", "serde", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -7061,7 +7385,7 @@ name = "reth-ethereum-forks" version = "1.0.6" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "arbitrary", "auto_impl", @@ -7070,7 +7394,7 @@ dependencies = [ "once_cell", "proptest", "proptest-derive", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "thiserror-no-std", ] @@ -7098,7 +7422,7 @@ dependencies = [ name = "reth-etl" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "rayon", "reth-db-api", "tempfile", @@ -7136,6 +7460,7 @@ dependencies = [ "reth-primitives", "reth-prune-types", "reth-revm", + "reth-storage-api", "reth-testing-utils", "revm-primitives", "secp256k1", @@ -7158,7 +7483,7 @@ dependencies = [ "reth-revm", "revm", "revm-primitives", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -7167,7 +7492,7 @@ name = "reth-execution-errors" version = "1.0.6" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "derive_more 1.0.0", "nybbles", @@ -7182,7 +7507,7 @@ name = "reth-execution-types" version = "1.0.6" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "reth-chainspec", "reth-execution-errors", "reth-primitives", @@ -7197,7 +7522,7 @@ version = "1.0.6" dependencies = [ "eyre", "futures", - "metrics", + "metrics 0.23.0", "reth-blockchain-tree", "reth-chainspec", "reth-config", @@ -7250,7 +7575,7 @@ dependencies = [ "reth-provider", "reth-tasks", "reth-transaction-pool", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -7258,7 +7583,7 @@ dependencies = [ name = "reth-exex-types" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "reth-provider", "serde", ] @@ -7269,7 +7594,7 @@ version = "1.0.6" dependencies = [ "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -7286,11 +7611,11 @@ dependencies = [ "rand 0.8.5", "reth-tracing", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] @@ -7301,16 +7626,16 @@ dependencies = [ "bitflags 2.6.0", "byteorder", "criterion", - "dashmap 6.0.1", + "dashmap 6.1.0", "derive_more 1.0.0", - "indexmap 2.4.0", + "indexmap 2.7.0", "parking_lot 0.12.3", "pprof", "rand 0.8.5", "rand_xorshift", "reth-mdbx-sys", "tempfile", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -7318,7 +7643,7 @@ dependencies = [ name = "reth-mdbx-sys" version = "1.0.6" dependencies = [ - "bindgen", + "bindgen 0.69.5", "cc", ] @@ -7327,7 +7652,7 @@ name = "reth-metrics" version = "1.0.6" dependencies = [ "futures", - "metrics", + "metrics 0.23.0", "reth-metrics-derive", "tokio", "tokio-util", @@ -7337,12 +7662,12 @@ dependencies = [ name = "reth-metrics-derive" version = "1.0.6" dependencies = [ - "metrics", + "metrics 0.23.0", "proc-macro2", "quote", "regex", "serial_test", - "syn 2.0.76", + "syn 2.0.90", "trybuild", ] @@ -7350,7 +7675,7 @@ dependencies = [ name = "reth-net-banlist" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", ] [[package]] @@ -7361,7 +7686,7 @@ dependencies = [ "reqwest", "reth-tracing", "serde_with", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -7380,7 +7705,7 @@ dependencies = [ "enr", "futures", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "parking_lot 0.12.3", "pin-project", "pprof", @@ -7407,14 +7732,14 @@ dependencies = [ "reth-tokio-util", "reth-tracing", "reth-transaction-pool", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "schnellru", "secp256k1", "serde", "serial_test", "smallvec", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -7426,7 +7751,7 @@ dependencies = [ name = "reth-network-api" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rpc-types-admin", "auto_impl", "derive_more 1.0.0", @@ -7439,7 +7764,7 @@ dependencies = [ "reth-network-types", "reth-tokio-util", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", ] @@ -7466,14 +7791,14 @@ dependencies = [ name = "reth-network-peers" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "enr", "rand 0.8.5", "secp256k1", "serde_json", "serde_with", - "thiserror", + "thiserror 1.0.69", "tokio", "url", ] @@ -7507,7 +7832,7 @@ dependencies = [ "serde", "sucds", "tempfile", - "thiserror", + "thiserror 1.0.69", "tracing", "zstd", ] @@ -7645,7 +7970,7 @@ name = "reth-node-ethereum" version = "1.0.6" dependencies = [ "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "eyre", "futures", "futures-util", @@ -7703,11 +8028,11 @@ dependencies = [ "eyre", "http", "jsonrpsee", - "metrics", + "metrics 0.23.0", "metrics-exporter-prometheus", "metrics-process", "metrics-util", - "procfs", + "procfs 0.16.0", "reqwest", "reth-chainspec", "reth-db", @@ -7718,7 +8043,7 @@ dependencies = [ "socket2 0.4.10", "tikv-jemalloc-ctl", "tokio", - "tower", + "tower 0.4.13", "tracing", "vergen", ] @@ -7728,7 +8053,7 @@ name = "reth-node-optimism" version = "1.0.6" dependencies = [ "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "async-trait", "clap", "eyre", @@ -7767,7 +8092,7 @@ dependencies = [ "reth-transaction-pool", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -7778,7 +8103,7 @@ version = "1.0.6" dependencies = [ "alloy-chains", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "derive_more 1.0.0", "once_cell", "op-alloy-rpc-types", @@ -7792,7 +8117,7 @@ dependencies = [ name = "reth-optimism-cli" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "clap", "eyre", @@ -7860,7 +8185,7 @@ dependencies = [ "reth-trie", "revm", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -7872,7 +8197,7 @@ version = "1.0.6" name = "reth-optimism-rpc" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "jsonrpsee-types", "op-alloy-network", "parking_lot 0.12.3", @@ -7894,7 +8219,7 @@ dependencies = [ "reth-transaction-pool", "revm", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -7904,7 +8229,7 @@ name = "reth-payload-builder" version = "1.0.6" dependencies = [ "futures-util", - "metrics", + "metrics 0.23.0", "pin-project", "reth-errors", "reth-ethereum-engine-primitives", @@ -7912,10 +8237,11 @@ dependencies = [ "reth-payload-primitives", "reth-primitives", "reth-provider", + "reth-revm", "reth-rpc-types", "reth-transaction-pool", "revm", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -7932,7 +8258,7 @@ dependencies = [ "reth-rpc-types", "reth-transaction-pool", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -7953,7 +8279,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-rpc-types", "alloy-serde", @@ -7979,13 +8305,14 @@ dependencies = [ "reth-primitives-traits", "reth-static-file-types", "reth-trie-common", + "revm", "revm-primitives", "secp256k1", "serde", "serde_json", "tempfile", "test-fuzz", - "thiserror", + "thiserror 1.0.69", "zstd", ] @@ -7996,7 +8323,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-rpc-types-eth", "arbitrary", @@ -8022,10 +8349,11 @@ dependencies = [ "alloy-rpc-types-engine", "assert_matches", "auto_impl", - "dashmap 6.0.1", + "dashmap 6.1.0", "eyre", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", + "notify", "once_cell", "parking_lot 0.12.3", "rand 0.8.5", @@ -8062,10 +8390,10 @@ dependencies = [ name = "reth-prune" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "assert_matches", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "rayon", "reth-chainspec", "reth-config", @@ -8081,8 +8409,8 @@ dependencies = [ "reth-testing-utils", "reth-tokio-util", "reth-tracing", - "rustc-hash 2.0.0", - "thiserror", + "rustc-hash 2.1.0", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -8091,7 +8419,7 @@ dependencies = [ name = "reth-prune-types" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "arbitrary", "assert_matches", "bytes", @@ -8103,7 +8431,7 @@ dependencies = [ "serde", "serde_json", "test-fuzz", - "thiserror", + "thiserror 1.0.69", "toml", ] @@ -8130,7 +8458,7 @@ dependencies = [ "alloy-dyn-abi", "alloy-genesis", "alloy-network", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "async-trait", "derive_more 1.0.0", @@ -8173,10 +8501,10 @@ dependencies = [ "secp256k1", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tracing", "tracing-futures", ] @@ -8218,7 +8546,7 @@ dependencies = [ "clap", "http", "jsonrpsee", - "metrics", + "metrics 0.23.0", "pin-project", "reth-beacon-consensus", "reth-chainspec", @@ -8250,9 +8578,9 @@ dependencies = [ "reth-transaction-pool", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.4.13", "tower-http", "tracing", ] @@ -8266,7 +8594,7 @@ dependencies = [ "async-trait", "jsonrpsee-core", "jsonrpsee-types", - "metrics", + "metrics 0.23.0", "reth-beacon-consensus", "reth-chainspec", "reth-engine-primitives", @@ -8285,7 +8613,7 @@ dependencies = [ "reth-testing-utils", "reth-tokio-util", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -8335,7 +8663,7 @@ dependencies = [ "futures", "jsonrpsee-core", "jsonrpsee-types", - "metrics", + "metrics 0.23.0", "rand 0.8.5", "reth-chain-state", "reth-chainspec", @@ -8358,7 +8686,7 @@ dependencies = [ "schnellru", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -8375,7 +8703,7 @@ dependencies = [ "pin-project", "reqwest", "tokio", - "tower", + "tower 0.4.13", "tracing", ] @@ -8383,7 +8711,7 @@ dependencies = [ name = "reth-rpc-server-types" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "jsonrpsee-core", "jsonrpsee-types", "reth-errors", @@ -8398,7 +8726,7 @@ dependencies = [ name = "reth-rpc-types" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rpc-types", "alloy-rpc-types-admin", "alloy-rpc-types-anvil", @@ -8470,7 +8798,7 @@ dependencies = [ "reth-trie-db", "serde_json", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -8479,12 +8807,12 @@ dependencies = [ name = "reth-stages-api" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "aquamarine", "assert_matches", "auto_impl", "futures-util", - "metrics", + "metrics 0.23.0", "reth-consensus", "reth-db-api", "reth-errors", @@ -8498,7 +8826,7 @@ dependencies = [ "reth-static-file-types", "reth-testing-utils", "reth-tokio-util", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -8508,7 +8836,7 @@ dependencies = [ name = "reth-stages-types" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "arbitrary", "bytes", "modular-bitfield", @@ -8525,7 +8853,7 @@ dependencies = [ name = "reth-static-file" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "assert_matches", "parking_lot 0.12.3", "rayon", @@ -8548,7 +8876,7 @@ dependencies = [ name = "reth-static-file-types" version = "1.0.6" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "clap", "derive_more 1.0.0", "serde", @@ -8587,11 +8915,11 @@ dependencies = [ "auto_impl", "dyn-clone", "futures-util", - "metrics", + "metrics 0.23.0", "pin-project", "rayon", "reth-metrics", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "tracing-futures", @@ -8642,7 +8970,7 @@ dependencies = [ "bitflags 2.6.0", "criterion", "futures-util", - "metrics", + "metrics 0.23.0", "parking_lot 0.12.3", "paste", "pprof", @@ -8661,13 +8989,13 @@ dependencies = [ "reth-tasks", "reth-tracing", "revm", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "schnellru", "serde", "serde_json", "smallvec", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -8682,7 +9010,7 @@ dependencies = [ "criterion", "derive_more 1.0.0", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "proptest", "proptest-arbitrary-interop", "rayon", @@ -8710,7 +9038,7 @@ version = "1.0.6" dependencies = [ "alloy-consensus", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-trie", "arbitrary", @@ -8739,7 +9067,7 @@ dependencies = [ "criterion", "derive_more 1.0.0", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "proptest", "proptest-arbitrary-interop", "rayon", @@ -8772,7 +9100,7 @@ dependencies = [ "criterion", "derive_more 1.0.0", "itertools 0.13.0", - "metrics", + "metrics 0.23.0", "proptest", "proptest-arbitrary-interop", "rand 0.8.5", @@ -8786,16 +9114,15 @@ dependencies = [ "reth-tasks", "reth-trie", "reth-trie-db", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "revm" -version = "14.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69eae90188e48c81588fe1987b4bd35cd90d69b3602cb0c3a9ab12b882f18d91" +version = "14.0.1" +source = "git+https://github.com/taikoxyz/revm.git?branch=v43-gwyneth#bd0a19a55e23d32c8de3c1992cf0f54b9c1179e9" dependencies = [ "auto_impl", "cfg-if", @@ -8809,11 +9136,11 @@ dependencies = [ [[package]] name = "revm-inspectors" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48184032103bb23788e42e42c7c85207f5b0b8a248b09ea8f5233077f35ab56e" +source = "git+https://github.com/taikoxyz/revm-inspectors.git?branch=v0.7.4-gwyneth#a8023c1dac7c348da28b996a468642d3968754a7" dependencies = [ - "alloy-primitives 0.8.0", - "alloy-rpc-types", + "alloy-primitives 0.8.14", + "alloy-rpc-types-eth", + "alloy-rpc-types-trace", "alloy-sol-types", "anstyle", "boa_engine", @@ -8821,14 +9148,13 @@ dependencies = [ "colorchoice", "revm", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "revm-interpreter" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7bad33a4f862ed8e2dc8bb5e7935852990da74f6db986732ef4f47f9021b2e4" +version = "10.0.1" +source = "git+https://github.com/taikoxyz/revm.git?branch=v43-gwyneth#bd0a19a55e23d32c8de3c1992cf0f54b9c1179e9" dependencies = [ "revm-primitives", "serde", @@ -8836,9 +9162,8 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "11.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24db0f8fb5bc636e18b4d36bdc4c402ea941be79cfbdb096469887b616959a46" +version = "11.0.1" +source = "git+https://github.com/taikoxyz/revm.git?branch=v43-gwyneth#bd0a19a55e23d32c8de3c1992cf0f54b9c1179e9" dependencies = [ "aurora-engine-modexp", "blst", @@ -8856,12 +9181,11 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "9.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13132ed599b17fa9057fcfc1d37d2954921958f3b96173fc4f4cf52803b32c3" +version = "9.0.1" +source = "git+https://github.com/taikoxyz/revm.git?branch=v43-gwyneth#bd0a19a55e23d32c8de3c1992cf0f54b9c1179e9" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.14", "auto_impl", "bitflags 2.6.0", "bitvec", @@ -8886,9 +9210,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f86ae463694029097b846d8f99fd5536740602ae00022c0c50c5600720b2f71" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" dependencies = [ "bytemuck", ] @@ -8925,9 +9249,9 @@ dependencies = [ [[package]] name = "rlimit" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8" +checksum = "7043b63bd0cd1aaa628e476b80e6d4023a3b50eb32789f2728908107bd0c793a" dependencies = [ "libc", ] @@ -8944,9 +9268,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4b84ba6e838ceb47b41de5194a60244fac43d9fe03b71dbe8c5a201081d6d1" +checksum = "f81dc953b2244ddd5e7860cb0bb2a790494b898ef321d4aff8e260efab60cc88" dependencies = [ "bytemuck", "byteorder", @@ -9012,9 +9336,12 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +dependencies = [ + "rand 0.8.5", +] [[package]] name = "rustc-hex" @@ -9033,18 +9360,18 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -9055,9 +9382,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "log", "once_cell", @@ -9070,32 +9397,46 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04182dffc9091a404e0fc069ea5cd60e5b866c3adf881eff99a32d048242dffa" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", "rustls-pemfile", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.0.1", ] [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-platform-verifier" @@ -9103,16 +9444,16 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" dependencies = [ - "core-foundation", + "core-foundation 0.9.4", "core-foundation-sys", "jni", "log", "once_cell", "rustls", - "rustls-native-certs", + "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "webpki-roots", "winapi", @@ -9126,9 +9467,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.102.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -9137,9 +9478,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rusty-fork" @@ -9176,20 +9517,20 @@ dependencies = [ [[package]] name = "scc" -version = "2.1.16" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb7ac86243095b70a7920639507b71d51a63390d1ba26c4f60a552fbb914a37" +checksum = "66b202022bb57c049555430e11fc22fea12909276a80a4c3d368da36ac1d88ed" dependencies = [ "sdd", ] [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -9211,9 +9552,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sdd" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0495e4577c672de8254beb68d01a9b62d0e8a13c099edecdbedccce3223cd29f" +checksum = "49c1eeaf4b6a87c7479688c6d52b9f1153cedd3c489300564f932b065c6eab95" [[package]] name = "sec1" @@ -9231,9 +9572,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "rand 0.8.5", "secp256k1-sys", @@ -9242,9 +9583,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -9256,23 +9597,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", - "core-foundation", + "core-foundation 0.9.4", "core-foundation-sys", "libc", "num-bigint", "security-framework-sys", ] +[[package]] +name = "security-framework" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", ] +[[package]] +name = "seedable_hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed064ed6aaf88eb6a28ae191f5871a7fcdd2858e1cd6e1ffcc746baef8cd3cfd" +dependencies = [ + "wyhash", +] + [[package]] name = "semver" version = "0.11.0" @@ -9293,9 +9656,9 @@ dependencies = [ [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] @@ -9314,9 +9677,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -9332,22 +9695,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -9362,14 +9725,25 @@ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ "percent-encoding", "serde", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -9388,15 +9762,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.7.0", "serde", "serde_derive", "serde_json", @@ -9406,21 +9780,21 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "serial_test" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" dependencies = [ "futures", "log", @@ -9432,13 +9806,13 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -9488,9 +9862,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d79b758b7cb2085612b11a235055e485605a5103faccdd633f35bd7aee69dd" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ "cc", "cfg-if", @@ -9572,9 +9946,9 @@ dependencies = [ [[package]] name = "similar-asserts" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e041bb827d1bfca18f213411d51b665309f1afb37a04a5d1464530e13779fc0f" +checksum = "cfe85670573cd6f0fa97940f26e7e6601213c3b0555246c24234131f88c5709e" dependencies = [ "console", "similar", @@ -9588,7 +9962,7 @@ checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -9641,9 +10015,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -9651,9 +10025,9 @@ dependencies = [ [[package]] name = "soketto" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" dependencies = [ "base64 0.22.1", "bytes", @@ -9670,6 +10044,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -9694,7 +10071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" dependencies = [ "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -9736,11 +10113,11 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -9774,9 +10151,9 @@ dependencies = [ [[package]] name = "symbolic-common" -version = "12.10.0" +version = "12.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16629323a4ec5268ad23a575110a724ad4544aae623451de600c747bf87b36cf" +checksum = "e5ba5365997a4e375660bed52f5b42766475d5bc8ceb1bb13fea09c469ea0f49" dependencies = [ "debugid", "memmap2", @@ -9786,9 +10163,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.10.0" +version = "12.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c043a45f08f41187414592b3ceb53fb0687da57209cc77401767fb69d5b596" +checksum = "beff338b2788519120f38c59ff4bb15174f52a183e547bac3d6072c2c0aa48aa" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -9808,9 +10185,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.76" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -9819,21 +10196,27 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.0" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284c41c2919303438fcf8dede4036fd1e82d4fc0fbb2b279bd2a1442c909ca92" +checksum = "da0523f59468a2696391f2a772edc089342aacd53c3caa2ac3264e598edf119b" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -9846,7 +10229,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -9869,14 +10252,20 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-triple" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" + [[package]] name = "tempfile" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", - "fastrand 2.1.1", + "fastrand 2.2.0", "once_cell", "rustix", "windows-sys 0.59.0", @@ -9932,7 +10321,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -9956,22 +10345,42 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +dependencies = [ + "thiserror-impl 2.0.4", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -10046,9 +10455,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -10070,9 +10479,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -10124,18 +10533,18 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.2", + "mio 1.0.3", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -10148,7 +10557,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -10164,9 +10573,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -10192,9 +10601,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -10228,11 +10637,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -10260,6 +10669,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-http" version = "0.5.2" @@ -10284,7 +10707,7 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -10305,9 +10728,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -10322,27 +10745,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", - "thiserror", + "thiserror 1.0.69", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -10360,26 +10783,15 @@ dependencies = [ [[package]] name = "tracing-journald" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba316a74e8fc3c3896a850dba2375928a9fa171b085ecddfc7c054d39970f3fd" +checksum = "fc0b4143302cf1022dac868d521e36e8b27691f72c84b3311750d5188ebba657" dependencies = [ "libc", "tracing-core", "tracing-subscriber", ] -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - [[package]] name = "tracing-logfmt" version = "0.3.5" @@ -10394,9 +10806,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -10404,22 +10816,19 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", - "nu-ansi-term", "once_cell", "regex", "serde", "serde_json", "sharded-slab", - "smallvec", "thread_local", "tracing", "tracing-core", - "tracing-log", "tracing-serde", ] @@ -10451,7 +10860,7 @@ dependencies = [ "once_cell", "rand 0.8.5", "smallvec", - "thiserror", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -10473,7 +10882,7 @@ dependencies = [ "rand 0.8.5", "resolv-conf", "smallvec", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "trust-dns-proto", @@ -10487,14 +10896,15 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" +checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" dependencies = [ "glob", "serde", "serde_derive", "serde_json", + "target-triple", "termcolor", "toml", ] @@ -10515,7 +10925,7 @@ dependencies = [ "rustls", "rustls-pki-types", "sha1", - "thiserror", + "thiserror 1.0.69", "utf-8", ] @@ -10527,9 +10937,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -10551,39 +10961,36 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-truncate" @@ -10593,20 +11000,26 @@ checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ "itertools 0.13.0", "unicode-segmentation", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -10620,9 +11033,9 @@ dependencies = [ [[package]] name = "unsigned-varint" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" [[package]] name = "untrusted" @@ -10632,12 +11045,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -10668,9 +11081,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom 0.2.15", ] @@ -10749,9 +11162,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -10760,36 +11173,37 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10797,28 +11211,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -10829,9 +11243,19 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -10839,9 +11263,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -10874,7 +11298,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -10895,11 +11319,11 @@ dependencies = [ [[package]] name = "windows" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core 0.57.0", + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -10914,36 +11338,37 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ "windows-implement", "windows-interface", - "windows-result 0.1.2", + "windows-result", + "windows-strings", "windows-targets 0.52.6", ] [[package]] name = "windows-implement" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "windows-interface" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -10952,20 +11377,11 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-strings", "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.2.0" @@ -10981,7 +11397,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-targets 0.52.6", ] @@ -11135,9 +11551,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -11175,9 +11591,9 @@ dependencies = [ "js-sys", "log", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "send_wrapper 0.6.0", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -11203,9 +11619,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -11215,13 +11631,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", "synstructure", ] @@ -11243,27 +11659,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", "synstructure", ] @@ -11284,7 +11700,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] @@ -11306,7 +11722,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.90", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bfe18acbf57a..8629d387d02d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,7 +142,7 @@ members = [ "examples/stateful-precompile/", "examples/txpool-tracing/", "testing/ef-tests/", - "testing/testing-utils", + "testing/testing-utils", "crates/gwyneth", ] default-members = ["bin/reth"] @@ -253,12 +253,10 @@ opt-level = 3 lto = "thin" [profile.release] -opt-level = 3 +opt-level = 1 lto = "thin" -debug = "line-tables-only" -strip = true -panic = "unwind" -codegen-units = 16 +debug = true +codegen-units = 8 # Use the `--profile profiling` flag to show symbols in release mode. # e.g. `cargo build --profile profiling` @@ -277,6 +275,8 @@ lto = "fat" codegen-units = 1 [workspace.dependencies] +gwyneth = { path = "crates/gwyneth" } + # reth reth = { path = "bin/reth" } reth-auto-seal-consensus = { path = "crates/consensus/auto-seal" } @@ -407,10 +407,10 @@ revm-primitives = { version = "9.0.0", features = [ # eth alloy-chains = "0.1.18" -alloy-dyn-abi = "0.8.0" -alloy-primitives = { version = "0.8.0", default-features = false } +alloy-dyn-abi = "0.8.2" +alloy-primitives = { version = "0.8.2", default-features = false } alloy-rlp = "0.3.4" -alloy-sol-types = "0.8.0" +alloy-sol-types = "0.8.2" alloy-trie = { version = "0.5", default-features = false } alloy-consensus = { version = "0.3.0", default-features = false } @@ -492,6 +492,7 @@ tracing = "0.1.0" tracing-appender = "0.2" url = "2.3" zstd = "0.13" +bincode = "1.3" # metrics metrics = "0.23.0" @@ -562,3 +563,17 @@ serial_test = "3" similar-asserts = "1.5.0" tempfile = "3.8" test-fuzz = "5" + +[patch.crates-io] +revm = { git = "https://github.com/taikoxyz/revm.git", branch = "v43-gwyneth" } +revm-primitives = { git = "https://github.com/taikoxyz/revm.git", branch = "v43-gwyneth" } +revm-interpreter = { git = "https://github.com/taikoxyz/revm.git", branch = "v43-gwyneth" } +revm-precompile = { git = "https://github.com/taikoxyz/revm.git", branch = "v43-gwyneth" } + +#revm = { path = "../../revm-gwyneth/revm/crates/revm" } +#revm-primitives = { path = "../../revm-gwyneth/revm/crates/primitives" } +#revm-interpreter = { path = "../../revm-gwyneth/revm/crates/interpreter" } +#revm-precompile = { path = "../../revm-gwyneth/revm/crates/precompile" } + +revm-inspectors = { git = "https://github.com/taikoxyz/revm-inspectors.git", branch = "v0.7.4-gwyneth" } +#revm-inspectors = { path = "../../revm-inspector-gwyneth/revm-inspectors"} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 85546548dba9..6ce9b69fe31c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ -FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef +# Use the latest Rust image for building reth +FROM lukemathwalker/cargo-chef:0.1.68-rust-1 AS chef WORKDIR /app - LABEL org.opencontainers.image.source=https://github.com/paradigmxyz/reth LABEL org.opencontainers.image.licenses="MIT OR Apache-2.0" # Install system dependencies -RUN apt-get update && apt-get -y upgrade && apt-get install -y libclang-dev pkg-config +RUN apt-get update && apt-get -y upgrade && apt-get install -y libclang-dev pkg-config git -# Builds a cargo-chef plan +# Build a cargo-chef plan FROM chef AS planner COPY . . RUN cargo chef prepare --recipe-path recipe.json @@ -17,36 +17,60 @@ COPY --from=planner /app/recipe.json recipe.json # Build profile, release by default ARG BUILD_PROFILE=release -ENV BUILD_PROFILE=$BUILD_PROFILE +ENV BUILD_PROFILE $BUILD_PROFILE # Extra Cargo flags ARG RUSTFLAGS="" -ENV RUSTFLAGS="$RUSTFLAGS" +ENV RUSTFLAGS "$RUSTFLAGS" # Extra Cargo features ARG FEATURES="" -ENV FEATURES=$FEATURES +ENV FEATURES $FEATURES # Builds dependencies RUN cargo chef cook --profile $BUILD_PROFILE --features "$FEATURES" --recipe-path recipe.json -# Build application +# Build reth application COPY . . RUN cargo build --profile $BUILD_PROFILE --features "$FEATURES" --locked --bin reth -# ARG is not resolved in COPY so we have to hack around it by copying the -# binary to a temporary location +# Clone rbuilder repository to access its config files +RUN git clone -b gwyneth https://github.com/taikoxyz/rbuilder.git /app/rbuilder + +# Copy reth binary to a temporary location RUN cp /app/target/$BUILD_PROFILE/reth /app/reth -# Use Ubuntu as the release image -FROM ubuntu AS runtime +# Use Ubuntu as the final runtime image +FROM ubuntu:22.04 AS runtime WORKDIR /app -# Copy reth over from the build stage +# Install necessary runtime dependencies +RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* + +# Install Rust and Cargo +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# Copy reth binary from the build stage COPY --from=builder /app/reth /usr/local/bin +# Copy rbuilder binary from the published Docker Hub image +COPY --from=gwynethtaiko/rbuilder:devnet /usr/local/bin/rbuilder /usr/local/bin/rbuilder + +# Copy rbuilder repository (configs, etc.) from the build stage +COPY --from=builder /app/rbuilder /app/rbuilder + # Copy licenses COPY LICENSE-* ./ +# Create start script for rbuilder +RUN echo '#!/bin/bash\nrbuilder run /app/rbuilder/config-gwyneth-reth.toml' > /app/start_rbuilder.sh && \ + chmod +x /app/start_rbuilder.sh + +# Expose necessary ports EXPOSE 30303 30303/udp 9001 8545 8546 -ENTRYPOINT ["/usr/local/bin/reth"] + +ENV RUST_BACKTRACE=full + +# Set reth as the entrypoint +ENTRYPOINT ["/usr/local/bin/reth"] \ No newline at end of file diff --git a/README.md b/README.md index 1f1b73c633db..04b28744f33f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,58 @@ +# Gwyneth + +## Install + +```sh +cd packages/protocol +pnpm install +make install +``` + +## Use + +Add custom networks to your wallet: + +``` +chain_id: 167010 +name: Gwyneth-1 +rpc: http://127.0.0.1:32005 +Currency: ETH +Block explorer: http://127.0.0.1:64003 +``` + +``` +chain_id: 167011 +name: Gwyneth-2 +rpc: http://127.0.0.1:32006 +Currency: ETH +Block explorer: http://127.0.0.1:64005 +``` + +``` +chain_id: 160010 +name: Gwyneth L1 +rpc: http://127.0.0.1:32002 +Currency: ETH +Block explorer: http://127.0.0.1:64001 +``` + +Add test accounts that have some ETH to play with: +- 0x8943545177806ED17B9F23F0a21ee5948eCaa776 (private key: bcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31) +- 0xE25583099BA105D9ec0A67f5Ae86D90e50036425 (private key: 39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d) +- 0x614561D2d143621E126e87831AEF287678B442b8 (private key: 53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710) + +Rabby/Brave wallet works, but some issues with nonces so you may have to manually input the correct nonce. + +# How to add extra layer2s ? + +In order to add extra layer 2 networks, you need to increase the the `NUM_L2_CHAINS` in the main function [here](https://github.com/taikoxyz/gwyneth/blob/5f6d3a6ffcf0ea359e4c52bbd94a251aef28b54c/bin/reth/src/main.rs#L15). (Later on it will be a configurational setting - no code !) + +If you want infrastructure support too, namingly: + +1. Exposing the jspn rpc port to the host machine (since everything is running in Docker with Kurtosis), you need to specify as a config param like [here](https://github.com/taikoxyz/gwyneth/blob/5f6d3a6ffcf0ea359e4c52bbd94a251aef28b54c/packages/protocol/scripts/confs/network_params.yaml#L6). (By default, if you dont specify this param, the first Layer2 port - which is 10110 - will be exposed to the host anyways. You only need to add this param if you are exposing more than 1 ports to the outter world.) +2. Blockscout support: [Here](https://github.com/taikoxyz/gwyneth/blob/5f6d3a6ffcf0ea359e4c52bbd94a251aef28b54c/packages/protocol/scripts/confs/network_params.yaml#L16) you can see a pattern, how to shoot up blockscout service too. If you want 3 layer2 explorers, just use the service name `blockscout_l2_3`. + + # reth [![CI status](https://github.com/paradigmxyz/reth/workflows/unit/badge.svg)][gh-ci] diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 49ea27b8f2fc..66648878e786 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -13,6 +13,9 @@ default-run = "reth" workspace = true [dependencies] + +gwyneth.workspace = true + # reth reth-chainspec.workspace = true reth-config.workspace = true @@ -26,6 +29,7 @@ reth-evm.workspace = true reth-revm.workspace = true reth-stages.workspace = true reth-execution-types.workspace = true +reth-execution-errors.workspace = true reth-errors.workspace = true reth-transaction-pool.workspace = true reth-beacon-consensus.workspace = true @@ -148,6 +152,8 @@ optimism = [ # no-op feature flag for switching between the `optimism` and default functionality in CI matrices ethereum = [] +gwyneth = ["reth-payload-primitives/gwyneth"] + [[bin]] name = "reth" path = "src/main.rs" diff --git a/bin/reth/src/commands/debug_cmd/build_block.rs b/bin/reth/src/commands/debug_cmd/build_block.rs index 098ac1e2722d..a7fdbac148da 100644 --- a/bin/reth/src/commands/debug_cmd/build_block.rs +++ b/bin/reth/src/commands/debug_cmd/build_block.rs @@ -19,6 +19,7 @@ use reth_evm::execute::{BlockExecutorProvider, Executor}; use reth_execution_types::ExecutionOutcome; use reth_fs_util as fs; use reth_node_api::PayloadBuilderAttributes; +//use reth_node_api::PayloadBuilderAttributes; use reth_payload_builder::database::CachedReads; use reth_primitives::{ constants::eip4844::LoadKzgSettingsError, revm_primitives::KzgSettings, Address, @@ -30,7 +31,10 @@ use reth_provider::{ ProviderFactory, StageCheckpointReader, StateProviderFactory, }; use reth_prune::PruneModes; -use reth_revm::{database::StateProviderDatabase, primitives::EnvKzgSettings}; +use reth_revm::{ + database::{StateProviderDatabase, SyncStateProviderDatabase}, + primitives::EnvKzgSettings, +}; use reth_rpc_types::engine::{BlobsBundleV1, PayloadAttributes}; use reth_stages::StageId; use reth_transaction_pool::{ @@ -115,6 +119,7 @@ impl Command { /// Execute `debug in-memory-merkle` command pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> { + // Brecht: good end to end block building code let Environment { provider_factory, .. } = self.env.init(AccessRights::RW)?; let consensus: Arc = @@ -270,13 +275,19 @@ impl Command { let block_with_senders = SealedBlockWithSenders::new(block.clone(), senders).unwrap(); - let db = StateProviderDatabase::new(blockchain_db.latest()?); + println!("debug_cmd build"); + + let chain_id = provider_factory.chain_spec().chain.id(); + let db = SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(blockchain_db.latest()?), + ); let executor = block_executor!(provider_factory.chain_spec()).executor(db); let block_execution_output = executor.execute((&block_with_senders.clone().unseal(), U256::MAX).into())?; let execution_outcome = - ExecutionOutcome::from((block_execution_output, block.number)); + ExecutionOutcome::from((block_execution_output, chain_id, block.number)); debug!(target: "reth::cli", ?execution_outcome, "Executed block"); let hashed_post_state = execution_outcome.hash_state_slow(); diff --git a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs index 86857bebe184..0bad36f51f04 100644 --- a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs @@ -20,7 +20,7 @@ use reth_provider::{ HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderFactory, StageCheckpointReader, StateWriter, StaticFileProviderFactory, StorageReader, }; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_stages::StageId; use reth_tasks::TaskExecutor; use reth_trie::StateRoot; @@ -78,6 +78,7 @@ impl Command { /// Execute `debug in-memory-merkle` command pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> { + println!("debug_cmd in mem"); let Environment { provider_factory, config, data_dir } = self.env.init(AccessRights::RW)?; let provider = provider_factory.provider()?; @@ -120,6 +121,7 @@ impl Command { let client = fetch_client.clone(); let chain = provider_factory.chain_spec(); + let chain_id = chain.chain().id(); let block = (move || get_single_body(client.clone(), Arc::clone(&chain), header.clone())) .retry(&backoff) .notify( @@ -127,10 +129,13 @@ impl Command { ) .await?; - let db = StateProviderDatabase::new(LatestStateProviderRef::new( - provider.tx_ref(), - provider_factory.static_file_provider(), - )); + let db = SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(LatestStateProviderRef::new( + provider.tx_ref(), + provider_factory.static_file_provider(), + )), + ); let executor = block_executor!(provider_factory.chain_spec()).executor(db); @@ -147,7 +152,8 @@ impl Command { ) .into(), )?; - let execution_outcome = ExecutionOutcome::from((block_execution_output, block.number)); + let execution_outcome = + ExecutionOutcome::from((block_execution_output, chain_id, block.number)); // Unpacked `BundleState::state_root_slow` function let (in_memory_state_root, in_memory_updates) = StateRoot::overlay_root_with_updates( diff --git a/bin/reth/src/commands/debug_cmd/merkle.rs b/bin/reth/src/commands/debug_cmd/merkle.rs index 08236e30ec4a..3adfac23e783 100644 --- a/bin/reth/src/commands/debug_cmd/merkle.rs +++ b/bin/reth/src/commands/debug_cmd/merkle.rs @@ -20,8 +20,9 @@ use reth_primitives::BlockHashOrNumber; use reth_provider::{ writer::UnifiedStorageWriter, BlockNumReader, BlockWriter, ChainSpecProvider, HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, ProviderFactory, StateWriter, + StaticFileProviderFactory, }; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_stages::{ stages::{AccountHashingStage, MerkleStage, StorageHashingStage}, ExecInput, Stage, StageCheckpoint, @@ -146,12 +147,14 @@ impl Command { provider_rw.insert_block(sealed_block.clone())?; td += sealed_block.difficulty; - let mut executor = executor_provider.batch_executor(StateProviderDatabase::new( - LatestStateProviderRef::new( + let db = SyncStateProviderDatabase::new( + Some(provider_factory.chain_spec().chain().id()), + StateProviderDatabase::new(LatestStateProviderRef::new( provider_rw.tx_ref(), provider_rw.static_file_provider().clone(), - ), - )); + )), + ); + let mut executor = executor_provider.batch_executor(db); executor.execute_and_verify_one((&sealed_block.clone().unseal(), td).into())?; let execution_outcome = executor.finalize(); diff --git a/bin/reth/src/main.rs b/bin/reth/src/main.rs index 3476d81887a5..148849557b4c 100644 --- a/bin/reth/src/main.rs +++ b/bin/reth/src/main.rs @@ -1,73 +1,87 @@ #![allow(missing_docs)] - // We use jemalloc for performance reasons. #[cfg(all(feature = "jemalloc", unix))] #[global_allocator] static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -#[cfg(all(feature = "optimism", not(test)))] -compile_error!("Cannot build the `reth` binary with the `optimism` feature flag enabled. Did you mean to build `op-reth`?"); +use gwyneth::{engine_api::RpcServerArgsExEx, GwynethNode}; +use reth::args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}; +use reth_chainspec::ChainSpecBuilder; +use reth_node_builder::{NodeBuilder, NodeConfig, NodeHandle}; +use reth_node_ethereum::EthereumNode; +use reth_provider::NODES; +use reth_tasks::TaskManager; -/// clap [Args] for Engine related arguments. -use clap::Args; +const BASE_CHAIN_ID: u64 = gwyneth::exex::BASE_CHAIN_ID; // Base chain ID for L2s +const NUM_L2_CHAINS: u64 = 2; // Number of L2 chains to create. Todo: Shall come from config */ -/// Parameters for configuring the engine -#[derive(Debug, Clone, Args, PartialEq, Eq, Default)] -#[command(next_help_heading = "Engine")] -pub struct EngineArgs { - /// Enable the engine2 experimental features on reth binary - #[arg(long = "engine.experimental", default_value = "false")] - pub experimental: bool, -} +fn main() -> eyre::Result<()> { + reth::cli::Cli::parse_args().run(|builder, _| async move { + let tasks = TaskManager::current(); + let exec = tasks.executor(); + let network_config = NetworkArgs { + discovery: DiscoveryArgs { disable_discovery: true, ..DiscoveryArgs::default() }, + ..NetworkArgs::default() + }; -#[cfg(not(feature = "optimism"))] -fn main() { - use clap::Parser; - use reth::cli::Cli; - use reth_node_builder::EngineNodeLauncher; - use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; - use reth_provider::providers::BlockchainProvider2; + let mut gwyneth_nodes = Vec::new(); - reth_cli_util::sigsegv_handler::install(); + for i in 0..NUM_L2_CHAINS { + let chain_id = BASE_CHAIN_ID + i; // Increment by 1 for each L2 - // Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided. - if std::env::var_os("RUST_BACKTRACE").is_none() { - std::env::set_var("RUST_BACKTRACE", "1"); - } + let chain_spec = ChainSpecBuilder::default() + .chain(chain_id.into()) + .genesis( + serde_json::from_str(include_str!( + "../../../crates/ethereum/node/tests/assets/genesis.json" + )) + .unwrap(), + ) + .cancun_activated() + .build(); + + let node_config = NodeConfig::test() + .with_chain(chain_spec.clone()) + .with_network(network_config.clone()) + .with_unused_ports() + .with_rpc( + RpcServerArgs::default() + .with_unused_ports() + .with_static_l2_rpc_ip_and_port(chain_id) + ); - if let Err(err) = Cli::::parse().run(|builder, engine_args| async move { - let enable_engine2 = engine_args.experimental; - match enable_engine2 { - true => { - let handle = builder - .with_types_and_provider::>() - .with_components(EthereumNode::components()) - .with_add_ons::() - .launch_with_fn(|builder| { - let launcher = EngineNodeLauncher::new( - builder.task_executor().clone(), - builder.config().datadir(), - ); - builder.launch_with(launcher) - }) + let chain_id = chain_spec.chain.id(); + + let NodeHandle { node: gwyneth_node, node_exit_future: _ } = + NodeBuilder::new(node_config.clone()) + .gwyneth_node(exec.clone(), chain_id) + .node(GwynethNode::default()) + .launch() .await?; - handle.node_exit_future.await - } - false => { - let handle = builder.launch_node(EthereumNode::default()).await?; - handle.node_exit_future.await - } + + NODES.lock().unwrap().insert(chain_id, gwyneth_node.provider.clone()); + gwyneth_nodes.push(gwyneth_node); } - }) { - eprintln!("Error: {err:?}"); - std::process::exit(1); - } + + let handle = builder + .node(EthereumNode::default()) + .install_exex("Rollup", move |ctx| async { + Ok(gwyneth::exex::Rollup::new(ctx, gwyneth_nodes).await?.start()) + }) + .launch() + .await?; + + + NODES.lock().unwrap().insert(handle.node.chain_spec().chain.id(), handle.node.provider.clone()); + + handle.wait_for_node_exit().await + }) } #[cfg(test)] mod tests { use super::*; - use clap::Parser; + use clap::{Args, Parser}; /// A helper type to parse Args more easily #[derive(Parser)] @@ -75,11 +89,4 @@ mod tests { #[command(flatten)] args: T, } - - #[test] - fn test_parse_engine_args() { - let default_args = EngineArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} +} \ No newline at end of file diff --git a/crates/blockchain-tree/Cargo.toml b/crates/blockchain-tree/Cargo.toml index 988bb54e8580..43c190430b2e 100644 --- a/crates/blockchain-tree/Cargo.toml +++ b/crates/blockchain-tree/Cargo.toml @@ -42,6 +42,9 @@ metrics.workspace = true # misc aquamarine.workspace = true linked_hash_set.workspace = true +serde.workspace = true +serde_json.workspace = true +bincode.workspace = true [dev-dependencies] reth-chainspec.workspace = true diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index faadd6ffdf59..cfbc37b8ca16 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -15,13 +15,13 @@ use reth_evm::execute::BlockExecutorProvider; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ - BlockHash, BlockNumHash, BlockNumber, EthereumHardfork, ForkBlock, GotExpected, Receipt, - SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, B256, U256, + BlockHash, BlockNumHash, BlockNumber, BufMut, EthereumHardfork, ForkBlock, GotExpected, + Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, B256, U256, }; use reth_provider::{ BlockExecutionWriter, BlockNumReader, BlockWriter, CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications, ChainSpecProvider, ChainSplit, - ChainSplitTarget, DisplayBlocksChain, HeaderProvider, ProviderError, StaticFileProviderFactory, + ChainSplitTarget, DisplayBlocksChain, HeaderProvider, ProviderError, StaticFileProviderFactory, NODES, }; use reth_prune_types::PruneModes; use reth_stages_api::{MetricEvent, MetricEventsSender}; @@ -643,13 +643,14 @@ where return None; }; + println!("insert_unwound_chain"); debug!(target: "blockchain_tree", unwound_block= ?block.num_hash(), chain_id = ?chain_id, chain_tip = ?chain.tip().num_hash(), "Prepend unwound block state to blockchain tree chain"); - - chain.prepend_state(cloned_execution_outcome.state().clone()) + let chain_id = self.externals.provider_factory.chain_spec().chain.id(); + chain.prepend_state(cloned_execution_outcome.state(chain_id)) } } } @@ -1023,6 +1024,7 @@ where &mut self, block_hash: BlockHash, ) -> Result { + // Brecht reorg make_canonical let mut durations_recorder = MakeCanonicalDurationsRecorder::default(); let old_block_indices = self.block_indices().clone(); @@ -1216,6 +1218,7 @@ where chain: Chain, recorder: &mut MakeCanonicalDurationsRecorder, ) -> Result<(), CanonicalError> { + // Brecht reorg state trie calculation let (blocks, state, chain_trie_updates) = chain.into_inner(); let hashed_state = state.hash_state_slow(); let prefix_sets = hashed_state.construct_prefix_sets().freeze(); @@ -1278,25 +1281,6 @@ where Ok(()) } - /// Unwind tables and put it inside state - pub fn unwind(&mut self, unwind_to: BlockNumber) -> Result<(), CanonicalError> { - // nothing to be done if unwind_to is higher then the tip - if self.block_indices().canonical_tip().number <= unwind_to { - return Ok(()) - } - // revert `N` blocks from current canonical chain and put them inside BlockchainTree - let old_canon_chain = self.revert_canonical_from_database(unwind_to)?; - - // check if there is block in chain - if let Some(old_canon_chain) = old_canon_chain { - self.state.block_indices.unwind_canonical_chain(unwind_to); - // insert old canonical chain to BlockchainTree. - self.insert_unwound_chain(AppendableChain::new(old_canon_chain)); - } - - Ok(()) - } - /// Reverts the canonical chain down to the given block from the database and returns the /// unwound chain. /// @@ -1972,12 +1956,12 @@ mod tests { // chain 0 has two blocks so receipts and reverts len is 2 let chain0 = tree.state.chains.get(&0.into()).unwrap().execution_outcome(); assert_eq!(chain0.receipts().len(), 2); - assert_eq!(chain0.state().reverts.len(), 2); + assert_eq!(chain0.all_states().reverts.len(), 2); assert_eq!(chain0.first_block(), block1.number); // chain 1 has one block so receipts and reverts len is 1 let chain1 = tree.state.chains.get(&1.into()).unwrap().execution_outcome(); assert_eq!(chain1.receipts().len(), 1); - assert_eq!(chain1.state().reverts.len(), 1); + assert_eq!(chain1.all_states().reverts.len(), 1); assert_eq!(chain1.first_block(), block2.number); } diff --git a/crates/blockchain-tree/src/chain.rs b/crates/blockchain-tree/src/chain.rs index 74510de23893..66d4b754f62c 100644 --- a/crates/blockchain-tree/src/chain.rs +++ b/crates/blockchain-tree/src/chain.rs @@ -15,13 +15,12 @@ use reth_evm::execute::{BlockExecutorProvider, Executor}; use reth_execution_errors::BlockExecutionError; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ - BlockHash, BlockNumber, ForkBlock, GotExpected, SealedBlockWithSenders, SealedHeader, U256, + BlockHash, BlockNumber, ForkBlock, GotExpected, SealedBlockWithSenders, SealedHeader, B256, U256 }; use reth_provider::{ - providers::{BundleStateProvider, ConsistentDbView}, - FullExecutionDataProvider, ProviderError, StateRootProvider, + providers::{BundleStateProvider, ConsistentDbView}, AccountReader, BlockNumReader, ChainSpecProvider, DatabaseProviderFactory, FullExecutionDataProvider, ProviderError, StateProvider, StateRootProvider, NODES }; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_trie::{updates::TrieUpdates, HashedPostState}; use reth_trie_parallel::parallel_root::ParallelStateRoot; use std::{ @@ -29,6 +28,7 @@ use std::{ ops::{Deref, DerefMut}, time::Instant, }; +use reth_execution_types::state_diff_to_block_execution_output; /// A chain in the blockchain tree that has functionality to execute blocks and append them to /// itself. @@ -89,6 +89,7 @@ impl AppendableChain { canonical_fork, }; + println!("Brecht: new_canonical_fork"); let (bundle_state, trie_updates) = Self::validate_and_execute( block.clone(), parent_header, @@ -117,13 +118,15 @@ impl AppendableChain { DB: Database + Clone, E: BlockExecutorProvider, { + println!("AppendableChain::new_chain_fork"); let parent_number = block.number.checked_sub(1).ok_or(BlockchainTreeError::GenesisBlockHasNoParent)?; let parent = self.blocks().get(&parent_number).ok_or( BlockchainTreeError::BlockNumberNotFoundInChain { block_number: parent_number }, )?; - let mut execution_outcome = self.execution_outcome().clone(); + // Filter out the bundle state that belongs to the current chain. + let mut execution_outcome = self.execution_outcome().filter_current_chain(); // Revert state to the state after execution of the parent block execution_outcome.revert_to(parent.number); @@ -135,6 +138,7 @@ impl AppendableChain { canonical_block_hashes, canonical_fork, }; + println!("Brecht: new_chain_fork"); let (block_state, _) = Self::validate_and_execute( block.clone(), parent, @@ -151,7 +155,8 @@ impl AppendableChain { // forked from and not the new chain we are creating. let size = execution_outcome.receipts().len(); execution_outcome.receipts_mut().drain(0..size - 1); - execution_outcome.state_mut().take_n_reverts(size - 1); + // take all states since we have filtered + execution_outcome.all_states_mut().take_n_reverts(size - 1); execution_outcome.set_first_block(block.number); // If all is okay, return new chain back. Present chain is not modified. @@ -167,6 +172,275 @@ impl AppendableChain { /// - [`BlockAttachment`] represents if the block extends the canonical chain, and thus we can /// cache the trie state updates. /// - [`BlockValidationKind`] determines if the state root __should__ be validated. + // fn validate_and_execute( + // block: SealedBlockWithSenders, + // parent_block: &SealedHeader, + // bundle_state_data_provider: EDP, + // externals: &TreeExternals, + // block_attachment: BlockAttachment, + // block_validation_kind: BlockValidationKind, + // ) -> Result<(ExecutionOutcome, Option), BlockExecutionError> + // where + // EDP: FullExecutionDataProvider, + // DB: Database + Clone, + // E: BlockExecutorProvider, + // { + // // some checks are done before blocks comes here. + // externals.consensus.validate_header_against_parent(&block, parent_block)?; + + // // get the state provider. + // let canonical_fork = bundle_state_data_provider.canonical_fork(); + + // // SAFETY: For block execution and parallel state root computation below we open multiple + // // independent database transactions. Upon opening the database transaction the consistent + // // view will check a current tip in the database and throw an error if it doesn't match + // // the one recorded during initialization. + // // It is safe to use consistent view without any special error handling as long as + // // we guarantee that plain state cannot change during processing of new payload. + // // The usage has to be re-evaluated if that was ever to change. + // let consistent_view = + // ConsistentDbView::new_with_latest_tip(externals.provider_factory.clone())?; + // let state_provider = consistent_view + // .provider_ro()? + // // State root calculation can take a while, and we're sure no write transaction + // // will be open in parallel. See https://github.com/paradigmxyz/reth/issues/7509. + // .disable_long_read_transaction_safety() + // .state_provider_by_block_number(canonical_fork.number)?; + + + // // // Brecht + // // let mut super_db = SyncStateProviderDatabase::new( + // // Some(externals.provider_factory.chain_spec().chain.id()), + // // StateProviderDatabase::new(&provider), + // // ); + + // // // Add all external state dependencies + // // let providers = NODES.lock().unwrap(); + // // let mut chain_providers = Vec::new(); + // // for (&chain_id, chain_provider) in providers.iter() { + // // println!("Adding db for chain_id: {}", chain_id); + + // // let state_provider = chain_provider + // // .database_provider_ro() + // // .unwrap(); + // // let last_block_number = state_provider.last_block_number()?; + // // let state_provider = state_provider.state_provider_by_block_number(last_block_number).unwrap(); + + // // let chain_provider = BundleStateProvider::new(state_provider, bundle_state_data_provider); + // // chain_providers.push(chain_provider); + + // // //let boxed: Box = Box::new(state_provider); + // // //let state_provider = StateProviderDatabase::new(boxed); + // // super_db.add_db(chain_id, StateProviderDatabase::new(&chain_providers.last().unwrap())); + // // } + + // // Brecht + // // let mut super_db: SyncStateProviderDatabase> = SyncStateProviderDatabase::new( + // // Some(externals.provider_factory.chain_spec().chain.id()), + // // StateProviderDatabase::new(state_provider), + // // ); + + // // println!("Brecht executed: Adding db for chain_id: {}", externals.provider_factory.chain_spec().chain.id()); + // // // Add all external state dependencies + // // let providers = NODES.lock().unwrap(); + // // //let mut chain_providers = Vec::new(); + // // for (&chain_id, chain_provider) in providers.iter() { + // // if chain_id == externals.provider_factory.chain_spec().chain.id() { + // // continue; + // // } + // // println!("Brecht executed: Adding db for chain_id: {}", chain_id); + + // // let state_provider = chain_provider + // // .database_provider_ro() + // // .unwrap(); + // // //let last_block_number = state_provider.last_block_number()?; + // // let last_block_number = block.number - 1; + // // println!("[{}-{}] Executing against block {} {}", externals.provider_factory.chain_spec().chain.id(), block.number, chain_id, last_block_number); + // // let state_provider = state_provider.state_provider_by_block_number(last_block_number).unwrap(); + + // // //let chain_provider = BundleStateProvider::new(state_provider, bundle_state_data_provider); + // // //chain_providers.push(chain_provider); + + // // //let boxed: Box = Box::new(state_provider); + // // //let state_provider = StateProviderDatabase::new(boxed); + // // super_db.add_db(chain_id, StateProviderDatabase::new(state_provider)); + // // } + + // let block_number = block.number; + // let block_hash = block.hash(); + + // //println!("Block extra data: {:?}", block.extra_data); + // let state_diff = if block.extra_data.len() > 32 { + // //let json_str = String::from_utf8(block.extra_data.to_vec()).unwrap(); + // //let state_diff = serde_json::from_str(&json_str).unwrap_or(None); + // //let state_diff: Option = serde_json::from_str(&json_str).unwrap_or(None); + // Some(bincode::deserialize(&block.extra_data.to_vec()).unwrap()) + // } else { + // None + // }; + + // println!("Applying block update: {:?}", state_diff); + + // let chain_id = externals.provider_factory.chain_spec().chain.id(); + + // let initial_execution_outcome = if let Some(state_diff) = &state_diff { + // println!("[{}] Applying state from diff", chain_id); + + // // let block = block.clone().unseal(); + // // let executor = externals.executor_factory.executor(super_db); + // // let state_execution = executor.execute((&block, U256::MAX).into())?; + + // let mut state_execution_diff = state_diff_to_block_execution_output(chain_id, state_diff); + // state_execution_diff.state = state_diff.bundle.clone(); + // state_execution_diff.receipts = state_diff.receipts.clone(); + + // for (tx, receipt) in block.transactions().zip(state_diff.receipts.iter()) { + // println!("{} [BBB] tx: {}: {:?}", chain_id, tx.hash(), receipt); + // } + + // //println!("ori: {:?}", state_execution); + // //println!("new: {:?}", state_execution_diff); + + // //let execution_outcome_execution = ExecutionOutcome::from((state_execution.clone(), chain_id, block_number)).filter_chain(chain_id); + // let execution_outcome_diff = ExecutionOutcome::from((state_execution_diff, chain_id, block_number)); + + + // //println!("ori: {:?}", execution_outcome_execution.bundle); + // println!("new: {:?}", execution_outcome_diff.bundle); + + // // for (address, account) in execution_outcome_diff.bundle.state.iter_mut() { + // // //let provider = consistent_view.provider_ro().unwrap(); + // // //let account = provider.basic_account(address) + // // //account.original_info = execution_outcome_execution.bundle.state.get(address).unwrap().original_info.clone(); + // // *account = execution_outcome_execution.bundle.state.get(address).unwrap().clone(); + // // } + + + // println!("new: {:?}", execution_outcome_diff.bundle); + + // // execution_outcome_diff.bundle = execution_outcome_execution.bundle.clone(); + + // // println!("ori: {:?}", execution_outcome_execution.bundle); + // // println!("new: {:?}", execution_outcome_diff.bundle); + + // //execution_outcome_diff.bundle.state = execution_outcome_execution.bundle.state.clone(); + // //execution_outcome_diff.bundle.contracts = execution_outcome_execution.bundle.contracts.clone(); + + // // execution_outcome_diff.bundle.state_size = execution_outcome_execution.bundle.state_size; + // // execution_outcome_diff.bundle.reverts_size = execution_outcome_execution.bundle.reverts_size; + // // execution_outcome_diff.bundle.reverts = execution_outcome_execution.bundle.reverts.clone(); + + // println!("new: {:?}", execution_outcome_diff); + + // //let hashed_state_execution = execution_outcome_execution.hash_state_slow(); + // let hashed_state_diff = execution_outcome_diff.hash_state_slow(); + // //assert_eq!(hashed_state_execution, hashed_state_diff, "state diff incorrect"); + + // //println!("ori: {:?}", hashed_state_execution); + // println!("new: {:?}", hashed_state_diff); + + // //execution_outcome_diff.bundle = state_diff.bundle.clone(); + + // execution_outcome_diff + // } else { + // let mut super_db: SyncStateProviderDatabase> = SyncStateProviderDatabase::new( + // Some(externals.provider_factory.chain_spec().chain.id()), + // StateProviderDatabase::new(state_provider), + // ); + // println!("Applying state from transactions"); + // let block = block.clone().unseal(); + // let executor = externals.executor_factory.executor(super_db); + // let state = executor.execute((&block, U256::MAX).into())?; + + // // externals.consensus.validate_block_post_execution( + // // &block, + // // PostExecutionInput::new(&state.receipts, &state.requests), + // // )?; + + // let initial_execution_outcome = ExecutionOutcome::from((state, chain_id, block_number)); + // let initial_execution_outcome = initial_execution_outcome.filter_chain(chain_id); + + // initial_execution_outcome + // }; + + // // SAFETY: For block execution and parallel state root computation below we open multiple + // // independent database transactions. Upon opening the database transaction the consistent + // // view will check a current tip in the database and throw an error if it doesn't match + // // the one recorded during initialization. + // // It is safe to use consistent view without any special error handling as long as + // // we guarantee that plain state cannot change during processing of new payload. + // // The usage has to be re-evaluated if that was ever to change. + // let consistent_view = + // ConsistentDbView::new_with_latest_tip(externals.provider_factory.clone())?; + // let state_provider = consistent_view + // .provider_ro()? + // // State root calculation can take a while, and we're sure no write transaction + // // will be open in parallel. See https://github.com/paradigmxyz/reth/issues/7509. + // .disable_long_read_transaction_safety() + // .state_provider_by_block_number(canonical_fork.number)?; + + // let provider = BundleStateProvider::new(state_provider, bundle_state_data_provider); + + + // // check state root if the block extends the canonical chain __and__ if state root + // // validation was requested. + // if block_validation_kind.is_exhaustive() { + // // calculate and check state root + // let start = Instant::now(); + // let (state_root, trie_updates) = if block_attachment.is_canonical() { + // println!("canonical block"); + // // TODO(Cecilie): refactor the bundle state provider for cross-chain bundles + // //let mut execution_outcome = + // // provider.block_execution_data_provider.execution_outcome().clone(); + // //execution_outcome.chain_id = chain_id; + // //execution_outcome.extend(initial_execution_outcome.clone()); + // //let execution_outcome = initial_execution_outcome.clone(); + + // let mut execution_outcome = + // provider.block_execution_data_provider.execution_outcome().clone(); + // execution_outcome.extend(initial_execution_outcome.clone()); + // let hashed_state = execution_outcome.hash_state_slow(); + // ParallelStateRoot::new(consistent_view, hashed_state) + // .incremental_root_with_updates() + // .map(|(root, updates)| (root, Some(updates))) + // .map_err(ProviderError::from)? + + // // let hashed_state = execution_outcome.hash_state_slow(); + // // ParallelStateRoot::new(consistent_view, hashed_state) + // // .incremental_root_with_updates() + // // .map(|(root, updates)| (root, Some(updates))) + // // .map_err(ProviderError::from)? + // } else { + // let hashed_state = HashedPostState::from_bundle_state( + // &initial_execution_outcome.current_state().state, + // ); + // let state_root = provider.state_root(hashed_state)?; + // //let state_root = super_db.get(&externals.provider_factory.chain_spec().chain.id()).unwrap().state_root(hashed_state)?; + // (state_root, None) + // //println!("Skipping check for chain {}", chain_id); + // //(B256::ZERO, None) + // }; + // if block.state_root != state_root { + // return Err(ConsensusError::BodyStateRootDiff( + // GotExpected { got: state_root, expected: block.state_root }.into(), + // ) + // .into()) + // } + + // tracing::debug!( + // target: "blockchain_tree::chain", + // number = block.number, + // hash = %block_hash, + // elapsed = ?start.elapsed(), + // "Validated state root" + // ); + + // Ok((initial_execution_outcome, trie_updates)) + // } else { + // Ok((initial_execution_outcome, None)) + // } + // } + fn validate_and_execute( block: SealedBlockWithSenders, parent_block: &SealedHeader, @@ -203,19 +477,93 @@ impl AppendableChain { .state_provider_by_block_number(canonical_fork.number)?; let provider = BundleStateProvider::new(state_provider, bundle_state_data_provider); + let chain_id = externals.provider_factory.chain_spec().chain.id(); - let db = StateProviderDatabase::new(&provider); - let executor = externals.executor_factory.executor(db); - let block_hash = block.hash(); - let block = block.unseal(); + let db = SyncStateProviderDatabase::new( + Some(externals.provider_factory.chain_spec().chain.id()), + StateProviderDatabase::new(&provider), + ); - let state = executor.execute((&block, U256::MAX).into())?; - externals.consensus.validate_block_post_execution( - &block, - PostExecutionInput::new(&state.receipts, &state.requests), - )?; + let state_diff = if block.extra_data.len() > 32 { + //let json_str = String::from_utf8(block.extra_data.to_vec()).unwrap(); + //let state_diff = serde_json::from_str(&json_str).unwrap_or(None); + //let state_diff: Option = serde_json::from_str(&json_str).unwrap_or(None); + Some(bincode::deserialize(&block.extra_data.to_vec()).unwrap()) + } else { + None + }; + let initial_execution_outcome = if let Some(state_diff) = &state_diff { + println!("[{}] Applying state from diff", chain_id); + + // let block = block.clone().unseal(); + // let executor = externals.executor_factory.executor(super_db); + // let state_execution = executor.execute((&block, U256::MAX).into())?; + + let state_execution_diff = state_diff_to_block_execution_output(chain_id, state_diff); + //state_execution_diff.state = state_diff.bundle.clone(); + //state_execution_diff.receipts = state_diff.receipts.clone(); + + for (tx, receipt) in block.transactions().zip(state_diff.receipts.iter()) { + println!("{} [Applying] tx: {}: {:?}", chain_id, tx.hash(), receipt); + } + + //println!("ori: {:?}", state_execution); + //println!("new: {:?}", state_execution_diff); - let initial_execution_outcome = ExecutionOutcome::from((state, block.number)); + //let execution_outcome_execution = ExecutionOutcome::from((state_execution.clone(), chain_id, block_number)).filter_chain(chain_id); + let execution_outcome_diff = ExecutionOutcome::from((state_execution_diff, chain_id, block.number)); + + + //println!("ori: {:?}", execution_outcome_execution.bundle); + //println!("new: {:?}", execution_outcome_diff.bundle); + + // for (address, account) in execution_outcome_diff.bundle.state.iter_mut() { + // //let provider = consistent_view.provider_ro().unwrap(); + // //let account = provider.basic_account(address) + // //account.original_info = execution_outcome_execution.bundle.state.get(address).unwrap().original_info.clone(); + // *account = execution_outcome_execution.bundle.state.get(address).unwrap().clone(); + // } + + + //println!("new: {:?}", execution_outcome_diff.bundle); + + // execution_outcome_diff.bundle = execution_outcome_execution.bundle.clone(); + + // println!("ori: {:?}", execution_outcome_execution.bundle); + // println!("new: {:?}", execution_outcome_diff.bundle); + + //execution_outcome_diff.bundle.state = execution_outcome_execution.bundle.state.clone(); + //execution_outcome_diff.bundle.contracts = execution_outcome_execution.bundle.contracts.clone(); + + // execution_outcome_diff.bundle.state_size = execution_outcome_execution.bundle.state_size; + // execution_outcome_diff.bundle.reverts_size = execution_outcome_execution.bundle.reverts_size; + // execution_outcome_diff.bundle.reverts = execution_outcome_execution.bundle.reverts.clone(); + + // println!("new: {:?}", execution_outcome_diff); + + //let hashed_state_execution = execution_outcome_execution.hash_state_slow(); + //let hashed_state_diff = execution_outcome_diff.hash_state_slow(); + //assert_eq!(hashed_state_execution, hashed_state_diff, "state diff incorrect"); + + //println!("ori: {:?}", hashed_state_execution); + //println!("new: {:?}", hashed_state_diff); + + //execution_outcome_diff.bundle = state_diff.bundle.clone(); + + execution_outcome_diff + } else { + let executor = externals.executor_factory.executor(db); + let block = block.clone().unseal(); + + let state = executor.execute((&block, U256::MAX).into())?; + externals.consensus.validate_block_post_execution( + &block, + PostExecutionInput::new(&state.receipts, &state.requests), + )?; + + let chain_id = externals.provider_factory.chain_spec().chain.id(); + ExecutionOutcome::from((state, chain_id, block.number)) + }; // check state root if the block extends the canonical chain __and__ if state root // validation was requested. @@ -225,6 +573,7 @@ impl AppendableChain { let (state_root, trie_updates) = if block_attachment.is_canonical() { let mut execution_outcome = provider.block_execution_data_provider.execution_outcome().clone(); + execution_outcome.chain_id = chain_id; execution_outcome.extend(initial_execution_outcome.clone()); let hashed_state = execution_outcome.hash_state_slow(); ParallelStateRoot::new(consistent_view, hashed_state) @@ -232,11 +581,13 @@ impl AppendableChain { .map(|(root, updates)| (root, Some(updates))) .map_err(ProviderError::from)? } else { - let hashed_state = - HashedPostState::from_bundle_state(&initial_execution_outcome.state().state); + let hashed_state = HashedPostState::from_bundle_state( + &initial_execution_outcome.state(chain_id).state, + ); let state_root = provider.state_root(hashed_state)?; (state_root, None) }; + assert_eq!(block.state_root, state_root, "state root mismatch"); if block.state_root != state_root { return Err(ConsensusError::BodyStateRootDiff( GotExpected { got: state_root, expected: block.state_root }.into(), @@ -247,7 +598,7 @@ impl AppendableChain { tracing::debug!( target: "blockchain_tree::chain", number = block.number, - hash = %block_hash, + hash = %block.hash(), elapsed = ?start.elapsed(), "Validated state root" ); @@ -294,6 +645,7 @@ impl AppendableChain { canonical_fork, }; + println!("Brecht: append_block"); let (block_state, _) = Self::validate_and_execute( block.clone(), parent_block, diff --git a/crates/chain-state/src/test_utils.rs b/crates/chain-state/src/test_utils.rs index d101b309a92a..7171f9e669b2 100644 --- a/crates/chain-state/src/test_utils.rs +++ b/crates/chain-state/src/test_utils.rs @@ -8,13 +8,16 @@ use rand::{thread_rng, Rng}; use reth_chainspec::{ChainSpec, EthereumHardfork}; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ - constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH}, + constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH, ETHEREUM_CHAIN_ID}, proofs::{calculate_receipt_root, calculate_transaction_root, calculate_withdrawals_root}, Address, BlockNumber, Header, Receipt, Receipts, Requests, SealedBlock, SealedBlockWithSenders, Signature, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, B256, U256, }; use reth_trie::{root::state_root_unhashed, updates::TrieUpdates, HashedPostState}; -use revm::{db::BundleState, primitives::AccountInfo}; +use revm::{ + db::BundleState, + primitives::{AccountInfo, ChainAddress}, +}; use std::{ collections::HashMap, ops::Range, @@ -207,6 +210,7 @@ impl TestBlockBuilder { Arc::new(block_with_senders.block.clone()), Arc::new(block_with_senders.senders), Arc::new(ExecutionOutcome::new( + ETHEREUM_CHAIN_ID, BundleState::default(), receipts, block_number, @@ -271,7 +275,7 @@ impl TestBlockBuilder { for tx in &block.body { self.signer_execute_account_info.balance -= Self::single_tx_cost(); bundle_state_builder = bundle_state_builder.state_present_account_info( - self.signer, + ChainAddress(self.chain_spec.chain.id(), self.signer), AccountInfo { nonce: tx.nonce(), balance: self.signer_execute_account_info.balance, @@ -281,6 +285,7 @@ impl TestBlockBuilder { } let execution_outcome = ExecutionOutcome::new( + self.chain_spec.chain.id(), bundle_state_builder.build(), vec![vec![None]].into(), block.number, diff --git a/crates/cli/commands/src/common.rs b/crates/cli/commands/src/common.rs index 55e4b79f2a38..5bb0df9ac64a 100644 --- a/crates/cli/commands/src/common.rs +++ b/crates/cli/commands/src/common.rs @@ -55,6 +55,7 @@ impl EnvironmentArgs { /// Initializes environment according to [`AccessRights`] and returns an instance of /// [`Environment`]. pub fn init(&self, access: AccessRights) -> eyre::Result { + println!("EnvironmentArgs::init"); let data_dir = self.datadir.clone().resolve_datadir(self.chain.chain); let db_path = data_dir.db(); let sf_path = data_dir.static_files(); @@ -85,7 +86,7 @@ impl EnvironmentArgs { ), AccessRights::RO => ( Arc::new(open_db_read_only(&db_path, self.db.database_args())?), - StaticFileProvider::read_only(sf_path)?, + StaticFileProvider::read_only(sf_path, false)?, ), }; diff --git a/crates/cli/commands/src/db/stats.rs b/crates/cli/commands/src/db/stats.rs index 37f7d617ba47..868cdb232a78 100644 --- a/crates/cli/commands/src/db/stats.rs +++ b/crates/cli/commands/src/db/stats.rs @@ -168,7 +168,7 @@ impl Command { } let static_files = iter_static_files(data_dir.static_files())?; - let static_file_provider = StaticFileProvider::read_only(data_dir.static_files())?; + let static_file_provider = StaticFileProvider::read_only(data_dir.static_files(), false)?; let mut total_data_size = 0; let mut total_index_size = 0; diff --git a/crates/cli/commands/src/node.rs b/crates/cli/commands/src/node.rs index 7a8c47d1f696..2cf1689fdd8f 100644 --- a/crates/cli/commands/src/node.rs +++ b/crates/cli/commands/src/node.rs @@ -135,7 +135,7 @@ impl NodeCommand { L: FnOnce(WithLaunchContext>>, Ext) -> Fut, Fut: Future>, { - tracing::info!(target: "reth::cli", version = ?version::SHORT_VERSION, "Starting reth"); + tracing::info!(target: "reth::cli", version = ?version::SHORT_VERSION, "Brecht Starting reth"); let Self { datadir, diff --git a/crates/cli/commands/src/stage/dump/mod.rs b/crates/cli/commands/src/stage/dump/mod.rs index 7366ff9981e0..8308bd7fe865 100644 --- a/crates/cli/commands/src/stage/dump/mod.rs +++ b/crates/cli/commands/src/stage/dump/mod.rs @@ -116,6 +116,7 @@ pub(crate) fn setup( output_db: &PathBuf, db_tool: &DbTool, ) -> eyre::Result<(DatabaseEnv, u64)> { + println!("chain setup"); assert!(from < to, "FROM block should be bigger than TO block."); info!(target: "reth::cli", ?output_db, "Creating separate db"); diff --git a/crates/consensus/auto-seal/Cargo.toml b/crates/consensus/auto-seal/Cargo.toml index 9c4c26c91fda..9a3680d03af1 100644 --- a/crates/consensus/auto-seal/Cargo.toml +++ b/crates/consensus/auto-seal/Cargo.toml @@ -39,3 +39,7 @@ tracing.workspace = true [features] optimism = ["reth-provider/optimism"] +gwyneth = [ + "reth-beacon-consensus/gwyneth", + "reth-engine-primitives/gwyneth", +] diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index 8bf9616a0790..0f50f1ea15a3 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -29,7 +29,7 @@ use reth_primitives::{ TransactionSigned, Withdrawals, B256, U256, }; use reth_provider::{BlockReaderIdExt, StateProviderFactory, StateRootProvider}; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_transaction_pool::TransactionPool; use reth_trie::HashedPostState; use std::{ @@ -340,6 +340,8 @@ impl StorageInner { Executor: BlockExecutorProvider, Provider: StateProviderFactory, { + println!("build_and_execute"); + let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs(); // if shanghai is active, include empty withdrawals @@ -370,16 +372,23 @@ impl StorageInner { trace!(target: "consensus::auto", transactions=?&block.body, "executing transactions"); - let mut db = StateProviderDatabase::new( - provider.latest().map_err(InternalBlockExecutionError::LatestBlock)?, + let chain_id = chain_spec.chain().id(); + let mut db = SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new( + provider.latest().map_err(InternalBlockExecutionError::LatestBlock)?, + ), ); // execute the block let block_execution_output = executor.executor(&mut db).execute((&block, U256::ZERO).into())?; let gas_used = block_execution_output.gas_used; - let execution_outcome = ExecutionOutcome::from((block_execution_output, block.number)); - let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state); + let execution_outcome = + ExecutionOutcome::from((block_execution_output, chain_id, block.number)) + .filter_current_chain(); + let hashed_state = + HashedPostState::from_bundle_state(&execution_outcome.current_state().state); // todo(onbjerg): we should not pass requests around as this is building a block, which // means we need to extract the requests from the execution output and compute the requests @@ -391,7 +400,7 @@ impl StorageInner { trace!(target: "consensus::auto", ?execution_outcome, ?header, ?body, "executed block, calculating state root and completing header"); // now we need to update certain header fields with the results of the execution - header.state_root = db.state_root(hashed_state)?; + header.state_root = db.get_db(chain_spec.chain.id()).unwrap().state_root(hashed_state)?; header.gas_used = gas_used; let receipts = execution_outcome.receipts_by_block(header.number); diff --git a/crates/consensus/beacon/Cargo.toml b/crates/consensus/beacon/Cargo.toml index 483f4b702a34..aeb2d03a0ca8 100644 --- a/crates/consensus/beacon/Cargo.toml +++ b/crates/consensus/beacon/Cargo.toml @@ -77,3 +77,8 @@ optimism = [ "reth-provider/optimism", "reth-blockchain-tree/optimism", ] +gwyneth = [ + "reth-payload-primitives/gwyneth", + "reth-engine-primitives/gwyneth", + "reth-payload-builder/gwyneth", + ] diff --git a/crates/consensus/beacon/src/engine/handle.rs b/crates/consensus/beacon/src/engine/handle.rs index aee554f8241a..d29925ad4f1b 100644 --- a/crates/consensus/beacon/src/engine/handle.rs +++ b/crates/consensus/beacon/src/engine/handle.rs @@ -49,8 +49,11 @@ where cancun_fields: Option, ) -> Result { let (tx, rx) = oneshot::channel(); + println!("new_payload start"); let _ = self.to_engine.send(BeaconEngineMessage::NewPayload { payload, cancun_fields, tx }); - rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)? + let res = rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)?; + println!("new_payload end"); + res } /// Sends a forkchoice update message to the beacon consensus engine and waits for a response. diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index 50944891d6e9..fc4939acc345 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -457,17 +457,18 @@ where header: &SealedHeader, attrs: &mut Option, ) -> bool { + println!("Brecht: on_head_already_canonical: {:?}", self.blockchain.chain_spec().chain.id()); // On Optimism, the proposers are allowed to reorg their own chain at will. - #[cfg(feature = "optimism")] - if self.blockchain.chain_spec().is_optimism() { + //#[cfg(feature = "optimism")] + //if self.blockchain.chain_spec().is_optimism() { debug!( target: "consensus::engine", fcu_head_num=?header.number, current_head_num=?head.number, "[Optimism] Allowing beacon reorg to old head" ); - return true - } + return true; + //} // 2. Client software MAY skip an update of the forkchoice state and MUST NOT begin a // payload build process if `forkchoiceState.headBlockHash` references a `VALID` ancestor @@ -1082,6 +1083,7 @@ where payload: ExecutionPayload, cancun_fields: Option, ) -> Result, BeaconOnNewPayloadError> { + println!("BeaconConsensusEngine:on_new_payload"); self.metrics.new_payload_messages.increment(1); // Ensures that the given payload does not violate any consensus rules that concern the @@ -1598,9 +1600,12 @@ where &mut self, action: BlockchainTreeAction, ) -> RethResult { + println!("on_blockchain_tree_action"); match action { BlockchainTreeAction::MakeForkchoiceHeadCanonical { state, attrs, tx } => { let start = Instant::now(); + // Brecht: reorg + println!("on_blockchain_tree_action MakeForkchoiceHeadCanonical"); let result = self.blockchain.make_canonical(state.head_block_hash); let elapsed = self.record_make_canonical_latency(start, &result); match self @@ -1857,6 +1862,7 @@ where if let Poll::Ready(Some(msg)) = this.engine_message_stream.poll_next_unpin(cx) { match msg { BeaconEngineMessage::ForkchoiceUpdated { state, payload_attrs, tx } => { + println!("Brecht: BeaconEngineMessage::ForkchoiceUpdated"); this.on_forkchoice_updated(state, payload_attrs, tx); } BeaconEngineMessage::NewPayload { payload, cancun_fields, tx } => { @@ -2213,6 +2219,7 @@ mod tests { assert_matches!(engine_rx.try_recv(), Err(TryRecvError::Empty)); } + // Brecht fork choice update #[tokio::test] async fn valid_forkchoice() { let mut rng = generators::rng(); diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index f3654c42ee2c..b4354c9c29be 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -182,12 +182,14 @@ pub fn validate_4844_header_standalone(header: &Header) -> Result<(), ConsensusE /// This must be 32 bytes or fewer; formally Hx. #[inline] pub fn validate_header_extradata(header: &Header) -> Result<(), ConsensusError> { - let extradata_len = header.extra_data.len(); - if extradata_len > MAXIMUM_EXTRA_DATA_SIZE { - Err(ConsensusError::ExtraDataExceedsMax { len: extradata_len }) - } else { - Ok(()) - } + // TODO(Brecht) + // let extradata_len = header.extra_data.len(); + // if extradata_len > MAXIMUM_EXTRA_DATA_SIZE { + // Err(ConsensusError::ExtraDataExceedsMax { len: extradata_len }) + // } else { + // Ok(()) + // } + Ok(()) } /// Validates against the parent hash and number. diff --git a/crates/e2e-test-utils/src/lib.rs b/crates/e2e-test-utils/src/lib.rs index 25fb77f01e73..74b885837a36 100644 --- a/crates/e2e-test-utils/src/lib.rs +++ b/crates/e2e-test-utils/src/lib.rs @@ -17,7 +17,7 @@ use reth_node_builder::{ components::NodeComponentsBuilder, rpc::EthApiBuilderProvider, FullNodeTypesAdapter, Node, NodeAdapter, NodeAddOns, NodeComponents, NodeTypes, RethFullAdapter, }; -use reth_provider::providers::BlockchainProvider; +use reth_provider::{providers::BlockchainProvider, StateProviderFactory}; use tracing::{span, Level}; use wallet::Wallet; @@ -93,6 +93,8 @@ where .launch() .await?; + //node.state_by_block_id(block_id) + let mut node = NodeTestContext::new(node).await?; // Connect each node in a chain. diff --git a/crates/e2e-test-utils/src/node.rs b/crates/e2e-test-utils/src/node.rs index 0040801fa3fa..2e42abc0ff24 100644 --- a/crates/e2e-test-utils/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -162,6 +162,7 @@ where ) .await?; + // trigger forkchoice update via engine api to commit the block to the blockchain self.engine_api.update_forkchoice(block_hash, block_hash).await?; diff --git a/crates/e2e-test-utils/src/transaction.rs b/crates/e2e-test-utils/src/transaction.rs index 041ba40d6eb2..85561836366e 100644 --- a/crates/e2e-test-utils/src/transaction.rs +++ b/crates/e2e-test-utils/src/transaction.rs @@ -2,7 +2,9 @@ use alloy_consensus::{ BlobTransactionSidecar, EnvKzgSettings, SidecarBuilder, SimpleCoder, TxEip4844Variant, TxEnvelope, }; -use alloy_network::{eip2718::Encodable2718, Ethereum, EthereumWallet, TransactionBuilder}; +use alloy_network::{ + eip2718::Encodable2718, Ethereum, EthereumWallet, TransactionBuilder, TransactionBuilder4844, +}; use alloy_rpc_types::{TransactionInput, TransactionRequest}; use alloy_signer_local::PrivateKeySigner; use eyre::Ok; @@ -36,8 +38,8 @@ impl TransactionTestContext { builder.ingest(b"dummy blob"); let sidecar: BlobTransactionSidecar = builder.build()?; - >::set_blob_sidecar(&mut tx, sidecar); - >::set_max_fee_per_blob_gas( + ::set_blob_sidecar(&mut tx, sidecar); + >::set_max_fee_per_gas( &mut tx, 15e9 as u128, ); diff --git a/crates/engine/primitives/Cargo.toml b/crates/engine/primitives/Cargo.toml index b44a4a8aa4e7..accf174cc156 100644 --- a/crates/engine/primitives/Cargo.toml +++ b/crates/engine/primitives/Cargo.toml @@ -16,4 +16,7 @@ reth-chainspec.workspace = true reth-payload-primitives.workspace = true # misc -serde.workspace = true \ No newline at end of file +serde.workspace = true + +[features] +gwyneth = ["reth-payload-primitives/gwyneth"] \ No newline at end of file diff --git a/crates/engine/tree/Cargo.toml b/crates/engine/tree/Cargo.toml index c978acc107de..c30afda0f7d6 100644 --- a/crates/engine/tree/Cargo.toml +++ b/crates/engine/tree/Cargo.toml @@ -86,3 +86,9 @@ test-utils = [ "reth-static-file", "reth-tracing", ] +gwyneth = [ + "reth-payload-primitives/gwyneth", + "reth-beacon-consensus/gwyneth", + "reth-engine-primitives/gwyneth", + "reth-payload-builder/gwyneth", +] \ No newline at end of file diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index 96af7f027256..19dcbad48d1d 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -30,7 +30,7 @@ use reth_provider::{ BlockReader, ExecutionOutcome, ProviderError, StateProviderBox, StateProviderFactory, StateRootProvider, }; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_rpc_types::{ engine::{ CancunPayloadFields, ForkchoiceState, PayloadStatus, PayloadStatusEnum, @@ -1750,7 +1750,12 @@ where return Err(e.into()) } - let executor = self.executor_provider.executor(StateProviderDatabase::new(&state_provider)); + let chain_id = self.payload_validator.chain_spec().chain.id(); + let db = SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(&state_provider), + ); + let executor = self.executor_provider.executor(db); let block_number = block.number; let block_hash = block.hash(); diff --git a/crates/engine/util/Cargo.toml b/crates/engine/util/Cargo.toml index 383b7290e6af..631c7c356858 100644 --- a/crates/engine/util/Cargo.toml +++ b/crates/engine/util/Cargo.toml @@ -49,3 +49,7 @@ optimism = [ "reth-beacon-consensus/optimism", "reth-ethereum-forks/optimism" ] +gwyneth = [ + "reth-engine-primitives/gwyneth", + "reth-beacon-consensus/gwyneth", +] diff --git a/crates/engine/util/src/reorg.rs b/crates/engine/util/src/reorg.rs index b952050aa068..ba66c61aef53 100644 --- a/crates/engine/util/src/reorg.rs +++ b/crates/engine/util/src/reorg.rs @@ -13,7 +13,7 @@ use reth_primitives::{ }; use reth_provider::{BlockReader, ExecutionOutcome, ProviderError, StateProviderFactory}; use reth_revm::{ - database::StateProviderDatabase, + database::{StateProviderDatabase, SyncStateProviderDatabase}, db::{states::bundle_state::BundleRetention, State}, state_change::post_block_withdrawals_balance_increments, DatabaseCommit, @@ -24,9 +24,9 @@ use reth_rpc_types::{ }; use reth_rpc_types_compat::engine::payload::block_to_payload; use reth_trie::HashedPostState; -use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg}; +use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, ChainAddress, EVMError, EnvWithHandlerCfg}; use std::{ - collections::VecDeque, + collections::{HashMap, VecDeque}, future::Future, pin::Pin, task::{ready, Context, Poll}, @@ -272,7 +272,10 @@ where // Configure state let state_provider = provider.state_by_block_hash(reorg_target.parent_hash)?; let mut state = State::builder() - .with_database_ref(StateProviderDatabase::new(&state_provider)) + .with_database_ref(SyncStateProviderDatabase::new( + Some(chain_spec.chain().id()), + StateProviderDatabase::new(&state_provider), + )) .with_bundle_update() .build(); @@ -363,12 +366,13 @@ where state.merge_transitions(BundleRetention::PlainState); let outcome = ExecutionOutcome::new( + chain_spec.chain().id(), state.take_bundle(), Receipts::from(vec![receipts]), reorg_target.number, Default::default(), ); - let hashed_state = HashedPostState::from_bundle_state(&outcome.state().state); + let hashed_state = HashedPostState::from_bundle_state(&outcome.current_state().state); let (blob_gas_used, excess_blob_gas) = if chain_spec.is_cancun_active_at_timestamp(reorg_target.timestamp) { diff --git a/crates/ethereum/engine-primitives/Cargo.toml b/crates/ethereum/engine-primitives/Cargo.toml index 8a1f25808937..3fe0ef9e7ff1 100644 --- a/crates/ethereum/engine-primitives/Cargo.toml +++ b/crates/ethereum/engine-primitives/Cargo.toml @@ -28,3 +28,9 @@ sha2.workspace = true [dev-dependencies] serde_json.workspace = true + +[features] +gwyneth = [ + "reth-payload-primitives/gwyneth", + "reth-engine-primitives/gwyneth", +] \ No newline at end of file diff --git a/crates/ethereum/engine-primitives/src/lib.rs b/crates/ethereum/engine-primitives/src/lib.rs index fe4a050fa41b..47cc0537bb33 100644 --- a/crates/ethereum/engine-primitives/src/lib.rs +++ b/crates/ethereum/engine-primitives/src/lib.rs @@ -33,6 +33,8 @@ impl PayloadTypes for EthEngineTypes { type BuiltPayload = EthBuiltPayload; type PayloadAttributes = EthPayloadAttributes; type PayloadBuilderAttributes = EthPayloadBuilderAttributes; + #[cfg(feature = "gwyneth")] + type SyncProvider = (); } impl EngineTypes for EthEngineTypes { diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index 45514d4d4415..f74fb3222ef2 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -16,7 +16,9 @@ use reth_rpc_types_compat::engine::payload::{ block_to_payload_v1, block_to_payload_v3, block_to_payload_v4, convert_block_to_payload_field_v2, }; -use revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}; +use revm_primitives::{ + BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, ChainAddress, SpecId, +}; use std::convert::Infallible; /// Contains the built payload. @@ -280,7 +282,7 @@ impl PayloadBuilderAttributes for EthPayloadBuilderAttributes { let block_env = BlockEnv { number: U256::from(parent.number + 1), - coinbase: self.suggested_fee_recipient(), + coinbase: ChainAddress(cfg.chain_id, self.suggested_fee_recipient()), timestamp: U256::from(self.timestamp()), difficulty: U256::ZERO, prevrandao: Some(self.prev_randao()), diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index 25f2d9c6af78..05ac94518da1 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -20,6 +20,7 @@ reth-revm.workspace = true reth-ethereum-consensus.workspace = true reth-prune-types.workspace = true reth-execution-types.workspace = true +reth-storage-api.workspace = true # Ethereum revm-primitives.workspace = true diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 8c15dee96006..ee1dccb84713 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -24,12 +24,14 @@ use reth_primitives::{ }; use reth_prune_types::PruneModes; use reth_revm::{ - batch::BlockBatchRecord, db::states::bundle_state::BundleRetention, - state_change::post_block_balance_increments, Evm, State, + batch::BlockBatchRecord, + db::{states::bundle_state::BundleRetention, State}, + state_change::post_block_balance_increments, + Evm, }; use revm_primitives::{ - db::{Database, DatabaseCommit}, - BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, ResultAndState, + db::{DatabaseCommit, SyncDatabase}, + BlockEnv, CfgEnvWithHandlerCfg, ChainAddress, EVMError, EnvWithHandlerCfg, ResultAndState, }; #[cfg(not(feature = "std"))] @@ -69,7 +71,7 @@ where { fn eth_executor(&self, db: DB) -> EthBlockExecutor where - DB: Database>, + DB: SyncDatabase>, { EthBlockExecutor::new( self.chain_spec.clone(), @@ -83,22 +85,22 @@ impl BlockExecutorProvider for EthExecutorProvider where EvmConfig: ConfigureEvm, { - type Executor + Display>> = + type Executor + Display>> = EthBlockExecutor; - type BatchExecutor + Display>> = + type BatchExecutor + Display>> = EthBatchExecutor; fn executor(&self, db: DB) -> Self::Executor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { self.eth_executor(db) } fn batch_executor(&self, db: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { let executor = self.eth_executor(db); EthBatchExecutor { executor, batch_record: BlockBatchRecord::default() } @@ -142,9 +144,10 @@ where mut evm: Evm<'_, Ext, &mut State>, ) -> Result where - DB: Database, + DB: SyncDatabase, DB::Error: Into + Display, { + print!("EthEvmExecutor::execute_state_transitions"); // apply pre execution changes apply_beacon_root_contract_call( &self.evm_config, @@ -167,6 +170,7 @@ where let mut cumulative_gas_used = 0; let mut receipts = Vec::with_capacity(block.body.len()); for (sender, transaction) in block.transactions_with_sender() { + //println!("Executing transaction from {:?}: {:?}", sender, transaction.chain_id()); // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior, // must be no greater than the block’s gasLimit. let block_available_gas = block.header.gas_limit - cumulative_gas_used; @@ -272,7 +276,7 @@ impl EthBlockExecutor { impl EthBlockExecutor where EvmConfig: ConfigureEvm, - DB: Database + Display>, + DB: SyncDatabase + Display>, { /// Configures a new evm configuration and block environment for the given block. /// @@ -304,6 +308,8 @@ where block: &BlockWithSenders, total_difficulty: U256, ) -> Result { + println!("EthBlockExecutor::execute_without_verification"); + // 1. prepare state on new block self.on_new_block(&block.header); @@ -336,19 +342,23 @@ where ) -> Result<(), BlockExecutionError> { let mut balance_increments = post_block_balance_increments(self.chain_spec(), block, total_difficulty); + let id = self.chain_spec().chain().id(); // Irregular state change at Ethereum DAO hardfork if self.chain_spec().fork(EthereumHardfork::Dao).transitions_at_block(block.number) { // drain balances from hardcoded addresses. let drained_balance: u128 = self .state - .drain_balances(DAO_HARDKFORK_ACCOUNTS) + .drain_balances( + DAO_HARDKFORK_ACCOUNTS.iter().map_while(|a| Some(ChainAddress(id, *a))), + ) .map_err(|_| BlockValidationError::IncrementBalanceFailed)? .into_iter() .sum(); // return balance to DAO beneficiary. - *balance_increments.entry(DAO_HARDFORK_BENEFICIARY).or_default() += drained_balance; + *balance_increments.entry(ChainAddress(id, DAO_HARDFORK_BENEFICIARY)).or_default() += + drained_balance; } // increment balances self.state @@ -362,7 +372,7 @@ where impl Executor for EthBlockExecutor where EvmConfig: ConfigureEvm, - DB: Database + Display>, + DB: SyncDatabase + Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = BlockExecutionOutput; @@ -409,7 +419,7 @@ impl EthBatchExecutor { impl BatchExecutor for EthBatchExecutor where EvmConfig: ConfigureEvm, - DB: Database + Display>, + DB: SyncDatabase + Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = ExecutionOutcome; @@ -442,6 +452,7 @@ where fn finalize(mut self) -> Self::Output { ExecutionOutcome::new( + self.executor.executor.chain_spec.chain().id(), self.executor.state.take_bundle(), self.batch_record.take_receipts(), self.batch_record.first_block().unwrap_or_default(), @@ -470,14 +481,18 @@ mod tests { eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS}, eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE}, }; + use reth_chainspec::{ChainSpecBuilder, ForkCondition}; use reth_primitives::{ constants::{EMPTY_ROOT_HASH, ETH_TO_WEI}, keccak256, public_key_to_address, Account, Block, Transaction, TxKind, TxLegacy, B256, }; use reth_revm::{ - database::StateProviderDatabase, test_utils::StateProviderTest, TransitionState, + database::{StateProviderDatabase, SyncStateProviderDatabase}, + test_utils::StateProviderTest, + TransitionState, }; + use reth_storage_api::StateProvider; use reth_testing_utils::generators::{self, sign_tx_with_key_pair}; use revm_primitives::{b256, fixed_bytes, Bytes, BLOCKHASH_SERVE_WINDOW}; use secp256k1::{Keypair, Secp256k1}; @@ -525,6 +540,10 @@ mod tests { EthExecutorProvider { chain_spec, evm_config: Default::default() } } + fn get_sync_db(chain_id: u64, db: DB) -> SyncStateProviderDatabase { + SyncStateProviderDatabase::new(Some(chain_id), StateProviderDatabase::new(db)) + } + #[test] fn eip_4788_non_genesis_call() { let mut header = @@ -538,12 +557,12 @@ mod tests { .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); - + let chain_id = chain_spec.chain().id(); let provider = executor_provider(chain_spec); // attempt to execute a block without parent beacon block root, expect err let err = provider - .executor(StateProviderDatabase::new(&db)) + .executor(get_sync_db(chain_id, &db)) .execute( ( &BlockWithSenders { @@ -572,7 +591,7 @@ mod tests { // fix header, set a gas limit header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); - let mut executor = provider.executor(StateProviderDatabase::new(&db)); + let mut executor = provider.executor(get_sync_db(chain_id, &db)); // Now execute a block with the fixed header, ensure that it does not fail executor @@ -602,14 +621,19 @@ mod tests { timestamp_index % history_buffer_length + history_buffer_length; // get timestamp storage and compare - let timestamp_storage = - executor.state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap(); + let timestamp_storage = executor + .state + .storage(ChainAddress(chain_id, BEACON_ROOTS_ADDRESS), U256::from(timestamp_index)) + .unwrap(); assert_eq!(timestamp_storage, U256::from(header.timestamp)); // get parent beacon block root storage and compare let parent_beacon_block_root_storage = executor .state - .storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)) + .storage( + ChainAddress(chain_id, BEACON_ROOTS_ADDRESS), + U256::from(parent_beacon_block_root_index), + ) .expect("storage value should exist"); assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); } @@ -635,12 +659,12 @@ mod tests { .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); - + let chain_id = chain_spec.chain().id(); let provider = executor_provider(chain_spec); // attempt to execute an empty block with parent beacon block root, this should not fail provider - .batch_executor(StateProviderDatabase::new(&db)) + .batch_executor(get_sync_db(chain_id, &db)) .execute_and_verify_one( ( &BlockWithSenders { @@ -678,7 +702,7 @@ mod tests { .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); - + let chain_id = chain_spec.chain().id(); let provider = executor_provider(chain_spec); // construct the header for block one @@ -690,7 +714,7 @@ mod tests { ..Header::default() }; - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); // attempt to execute an empty block with parent beacon block root, this should not fail executor @@ -715,7 +739,12 @@ mod tests { ); // ensure that the nonce of the system address account has not changed - let nonce = executor.state_mut().basic(SYSTEM_ADDRESS).unwrap().unwrap().nonce; + let nonce = executor + .state_mut() + .basic(ChainAddress(chain_id, SYSTEM_ADDRESS)) + .unwrap() + .unwrap() + .nonce; assert_eq!(nonce, 0); } @@ -730,10 +759,10 @@ mod tests { .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)) .build(), ); - + let chain_id = chain_spec.chain().id(); let mut header = chain_spec.genesis_header(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); // attempt to execute the genesis block with non-zero parent beacon block root, expect err header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); @@ -816,11 +845,11 @@ mod tests { .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); - + let chain_id = chain_spec.chain().id(); let provider = executor_provider(chain_spec); // execute header - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); // Now execute a block with the fixed header, ensure that it does not fail executor @@ -855,14 +884,17 @@ mod tests { // get timestamp storage and compare let timestamp_storage = executor .state_mut() - .storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)) + .storage(ChainAddress(chain_id, BEACON_ROOTS_ADDRESS), U256::from(timestamp_index)) .unwrap(); assert_eq!(timestamp_storage, U256::from(header.timestamp)); // get parent beacon block root storage and compare let parent_beacon_block_root_storage = executor .state_mut() - .storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)) + .storage( + ChainAddress(chain_id, BEACON_ROOTS_ADDRESS), + U256::from(parent_beacon_block_root_index), + ) .unwrap(); assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); } @@ -900,9 +932,9 @@ mod tests { .with_fork(EthereumHardfork::Prague, ForkCondition::Never) .build(), ); - + let chain_id = chain_spec.chain().id(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); // construct the header for block one let header = Header { timestamp: 1, number: 1, ..Header::default() }; @@ -934,10 +966,10 @@ mod tests { // // we load the account first, because revm expects it to be // loaded - executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap(); + executor.state_mut().basic(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS)).unwrap(); assert!(executor .state_mut() - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::ZERO) .unwrap() .is_zero()); } @@ -952,10 +984,11 @@ mod tests { .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); + let chain_id = chain_spec.chain().id(); let header = chain_spec.genesis_header(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); // attempt to execute genesis block, this should not fail executor @@ -984,10 +1017,10 @@ mod tests { // // we load the account first, because revm expects it to be // loaded - executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap(); + executor.state_mut().basic(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS)).unwrap(); assert!(executor .state_mut() - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::ZERO) .unwrap() .is_zero()); } @@ -1003,6 +1036,7 @@ mod tests { .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) .build(), ); + let chain_id = chain_spec.chain().id(); let header = Header { parent_hash: B256::random(), @@ -1012,7 +1046,7 @@ mod tests { ..Header::default() }; let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); // attempt to execute the fork activation block, this should not fail executor @@ -1037,11 +1071,18 @@ mod tests { ); // the hash for the ancestor of the fork activation block should be present - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .state_mut() + .basic(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS)) + .unwrap() + .is_some()); assert_ne!( executor .state_mut() - .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block - 1)) + .storage( + ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), + U256::from(fork_activation_block - 1) + ) .unwrap(), U256::ZERO ); @@ -1049,7 +1090,10 @@ mod tests { // the hash of the block itself should not be in storage assert!(executor .state_mut() - .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block)) + .storage( + ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), + U256::from(fork_activation_block) + ) .unwrap() .is_zero()); } @@ -1065,9 +1109,10 @@ mod tests { .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) .build(), ); + let chain_id = chain_spec.chain().id(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); let header = Header { parent_hash: B256::random(), @@ -1100,12 +1145,16 @@ mod tests { ); // the hash for the ancestor of the fork activation block should be present - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .state_mut() + .basic(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS)) + .unwrap() + .is_some()); assert_ne!( executor .state_mut() .storage( - HISTORY_STORAGE_ADDRESS, + ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::from(fork_activation_block % BLOCKHASH_SERVE_WINDOW as u64 - 1) ) .unwrap(), @@ -1123,13 +1172,14 @@ mod tests { .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); + let chain_id = chain_spec.chain().id(); let mut header = chain_spec.genesis_header(); header.requests_root = Some(EMPTY_ROOT_HASH); let header_hash = header.hash_slow(); let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + let mut executor = provider.batch_executor(get_sync_db(chain_id, &db)); // attempt to execute the genesis block, this should not fail executor @@ -1157,10 +1207,10 @@ mod tests { // // we load the account first, because revm expects it to be // loaded - executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap(); + executor.state_mut().basic(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS)).unwrap(); assert!(executor .state_mut() - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::ZERO) .unwrap() .is_zero()); @@ -1196,14 +1246,21 @@ mod tests { ); // the block hash of genesis should now be in storage, but not block 1 - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .state_mut() + .basic(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS)) + .unwrap() + .is_some()); assert_ne!( - executor.state_mut().storage(HISTORY_STORAGE_ADDRESS, U256::ZERO).unwrap(), + executor + .state_mut() + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::ZERO) + .unwrap(), U256::ZERO ); assert!(executor .state_mut() - .storage(HISTORY_STORAGE_ADDRESS, U256::from(1)) + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::from(1)) .unwrap() .is_zero()); @@ -1238,18 +1295,28 @@ mod tests { ); // the block hash of genesis and block 1 should now be in storage, but not block 2 - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .state_mut() + .basic(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS)) + .unwrap() + .is_some()); assert_ne!( - executor.state_mut().storage(HISTORY_STORAGE_ADDRESS, U256::ZERO).unwrap(), + executor + .state_mut() + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::ZERO) + .unwrap(), U256::ZERO ); assert_ne!( - executor.state_mut().storage(HISTORY_STORAGE_ADDRESS, U256::from(1)).unwrap(), + executor + .state_mut() + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::from(1)) + .unwrap(), U256::ZERO ); assert!(executor .state_mut() - .storage(HISTORY_STORAGE_ADDRESS, U256::from(2)) + .storage(ChainAddress(chain_id, HISTORY_STORAGE_ADDRESS), U256::from(2)) .unwrap() .is_zero()); } @@ -1262,6 +1329,7 @@ mod tests { .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); + let chain_id = chain_spec.chain().id(); let mut db = create_state_provider_with_withdrawal_requests_contract(); @@ -1304,7 +1372,7 @@ mod tests { let provider = executor_provider(chain_spec); - let executor = provider.executor(StateProviderDatabase::new(&db)); + let executor = provider.executor(get_sync_db(chain_id, &db)); let BlockExecutionOutput { receipts, requests, .. } = executor .execute( @@ -1343,6 +1411,7 @@ mod tests { .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); + let chain_id = chain_spec.chain().id(); // Create a state provider with the withdrawal requests contract pre-deployed let mut db = create_state_provider_with_withdrawal_requests_contract(); @@ -1392,7 +1461,7 @@ mod tests { ); // Create an executor from the state provider - let executor = executor_provider(chain_spec).executor(StateProviderDatabase::new(&db)); + let executor = executor_provider(chain_spec).executor(get_sync_db(chain_id, &db)); // Execute the block and capture the result let exec_result = executor.execute( diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index bead8ae3923c..a21a8cf51a5c 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -15,7 +15,9 @@ extern crate alloc; use reth_chainspec::{ChainSpec, Head}; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; use reth_primitives::{transaction::FillTxEnv, Address, Header, TransactionSigned, U256}; -use revm_primitives::{AnalysisKind, Bytes, CfgEnvWithHandlerCfg, Env, TxEnv, TxKind}; +use revm_primitives::{ + AnalysisKind, Bytes, CfgEnvWithHandlerCfg, ChainAddress, Env, TransactTo, TxEnv, +}; #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -55,6 +57,7 @@ impl ConfigureEvmEnv for EthEvmConfig { }, ); + // TODO(Brecht): parent_chain_id cfg_env.chain_id = chain_spec.chain().id(); cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; @@ -72,10 +75,14 @@ impl ConfigureEvmEnv for EthEvmConfig { contract: Address, data: Bytes, ) { + //print!("fill_tx_env_system_contract_call: 1"); #[allow(clippy::needless_update)] // side-effect of optimism fields + let chain_id = env.cfg.chain_id; + + //print!("Dani Chain id:{:?}", chain_id); let tx = TxEnv { - caller, - transact_to: TxKind::Call(contract), + caller: ChainAddress(chain_id, caller), + transact_to: TransactTo::Call(ChainAddress(chain_id, contract)), // Explicitly set nonce to None so revm does not do any nonce checks nonce: None, gas_limit: 30_000_000, @@ -85,7 +92,7 @@ impl ConfigureEvmEnv for EthEvmConfig { // call, and that the call will not count against the block's gas limit gas_price: U256::ZERO, // The chain ID check is not relevant here and is disabled if set to None - chain_id: None, + chain_ids: None, // Setting the gas priority fee to None ensures the effective gas price is derived from // the `gas_price` field, which we need to be zero gas_priority_fee: None, diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index e7a5e702956e..0136186fa85e 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -51,3 +51,8 @@ serde_json.workspace = true [features] default = [] test-utils = ["reth-node-builder/test-utils"] +gwyneth = [ + "reth-basic-payload-builder/gwyneth", + "reth-beacon-consensus/gwyneth", + "reth-payload-builder/gwyneth", +] diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index ce1498a15f33..85889f366a44 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -226,6 +226,7 @@ where ctx: &BuilderContext, pool: Pool, ) -> eyre::Result> { + println!("EthereumPayloadBuilder.spawn_payload_service"); let payload_builder = reth_ethereum_payload_builder::EthereumPayloadBuilder::new(self.evm_config); let conf = ctx.payload_builder_config(); diff --git a/crates/ethereum/node/tests/assets/genesis.json b/crates/ethereum/node/tests/assets/genesis.json index 671bf85e423f..d3ba31031b66 100644 --- a/crates/ethereum/node/tests/assets/genesis.json +++ b/crates/ethereum/node/tests/assets/genesis.json @@ -1 +1,10 @@ -{"config":{"chainId":1,"homesteadBlock":0,"daoForkSupport":true,"eip150Block":0,"eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0,"berlinBlock":0,"londonBlock":0,"arrowGlacierBlock":0,"grayGlacierBlock":0,"shanghaiTime":0,"cancunTime":0,"terminalTotalDifficulty":"0x0","terminalTotalDifficultyPassed":true},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x1c9c380","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"balance":"0xd3c21bcecceda1000000"},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"balance":"0xd3c21bcecceda1000000"},"0x1cbd3b2770909d4e10f157cabc84c7264073c9ec":{"balance":"0xd3c21bcecceda1000000"},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"balance":"0xd3c21bcecceda1000000"},"0x2546bcd3c84621e976d8185a91a922ae77ecec30":{"balance":"0xd3c21bcecceda1000000"},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"balance":"0xd3c21bcecceda1000000"},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"balance":"0xd3c21bcecceda1000000"},"0x71be63f3384f5fb98995898a86b02fb2426c5788":{"balance":"0xd3c21bcecceda1000000"},"0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199":{"balance":"0xd3c21bcecceda1000000"},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"balance":"0xd3c21bcecceda1000000"},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"balance":"0xd3c21bcecceda1000000"},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"balance":"0xd3c21bcecceda1000000"},"0x9c41de96b2088cdc640c6182dfcf5491dc574a57":{"balance":"0xd3c21bcecceda1000000"},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"balance":"0xd3c21bcecceda1000000"},"0xbcd4042de499d14e55001ccbb24a551f3b954096":{"balance":"0xd3c21bcecceda1000000"},"0xbda5747bfd65f08deb54cb465eb87d40e51b197e":{"balance":"0xd3c21bcecceda1000000"},"0xcd3b766ccdd6ae721141f452c550ca635964ce71":{"balance":"0xd3c21bcecceda1000000"},"0xdd2fd4581271e230360230f9337d5c0430bf44c0":{"balance":"0xd3c21bcecceda1000000"},"0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097":{"balance":"0xd3c21bcecceda1000000"},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"balance":"0xd3c21bcecceda1000000"},"0xfabb0ac9d68b0b445fb7357272ff202c5651694a":{"balance":"0xd3c21bcecceda1000000"}},"number":"0x0"} \ No newline at end of file +{"config":{"chainId":1,"homesteadBlock":0,"daoForkSupport":true,"eip150Block":0,"eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0,"berlinBlock":0,"londonBlock":0,"arrowGlacierBlock":0,"grayGlacierBlock":0,"shanghaiTime":0,"cancunTime":0,"terminalTotalDifficulty":"0x0","terminalTotalDifficultyPassed":true},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x1c9c380","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"balance":"0xd3c21bcecceda1000000"},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"balance":"0xd3c21bcecceda1000000"},"0x1cbd3b2770909d4e10f157cabc84c7264073c9ec":{"balance":"0xd3c21bcecceda1000000"},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"balance":"0xd3c21bcecceda1000000"},"0x2546bcd3c84621e976d8185a91a922ae77ecec30":{"balance":"0xd3c21bcecceda1000000"},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"balance":"0xd3c21bcecceda1000000"},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"balance":"0xd3c21bcecceda1000000"},"0x71be63f3384f5fb98995898a86b02fb2426c5788":{"balance":"0xd3c21bcecceda1000000"},"0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199":{"balance":"0xd3c21bcecceda1000000"},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"balance":"0xd3c21bcecceda1000000"},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"balance":"0xd3c21bcecceda1000000"},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"balance":"0xd3c21bcecceda1000000"},"0x9c41de96b2088cdc640c6182dfcf5491dc574a57":{"balance":"0xd3c21bcecceda1000000"},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"balance":"0xd3c21bcecceda1000000"},"0xbcd4042de499d14e55001ccbb24a551f3b954096":{"balance":"0xd3c21bcecceda1000000"},"0xbda5747bfd65f08deb54cb465eb87d40e51b197e":{"balance":"0xd3c21bcecceda1000000"},"0xcd3b766ccdd6ae721141f452c550ca635964ce71":{"balance":"0xd3c21bcecceda1000000"},"0xdd2fd4581271e230360230f9337d5c0430bf44c0":{"balance":"0xd3c21bcecceda1000000"},"0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097":{"balance":"0xd3c21bcecceda1000000"},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"balance":"0xd3c21bcecceda1000000"},"0xfabb0ac9d68b0b445fb7357272ff202c5651694a":{"balance":"0xd3c21bcecceda1000000"}, + +"0x8943545177806ED17B9F23F0a21ee5948eCaa776":{"balance":"0xd3c21bcecceda1000000"}, +"0xE25583099BA105D9ec0A67f5Ae86D90e50036425":{"balance":"0xd3c21bcecceda1000000"}, +"0x614561D2d143621E126e87831AEF287678B442b8":{"balance":"0xd3c21bcecceda1000000"}, +"0xf93Ee4Cf8c6c40b329b0c0626F28333c132CF241":{"balance":"0xd3c21bcecceda1000000"} + +}, + +"number":"0x0"} \ No newline at end of file diff --git a/crates/ethereum/payload/Cargo.toml b/crates/ethereum/payload/Cargo.toml index 4037ca588ab1..fb5baacffbe1 100644 --- a/crates/ethereum/payload/Cargo.toml +++ b/crates/ethereum/payload/Cargo.toml @@ -30,3 +30,6 @@ revm.workspace = true # misc tracing.workspace = true + +[features] +gwyneth = ["reth-payload-builder/gwyneth"] \ No newline at end of file diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 2e9a2fdaeda9..0c69dd56d669 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -13,7 +13,7 @@ use reth_basic_payload_builder::{ commit_withdrawals, is_better_payload, BuildArguments, BuildOutcome, PayloadBuilder, PayloadConfig, WithdrawalsOutcome, }; -use reth_errors::RethError; +use reth_errors::{DatabaseError, ProviderError, RethError}; use reth_evm::{ system_calls::{ post_block_consolidation_requests_contract_call, @@ -25,7 +25,8 @@ use reth_evm::{ use reth_evm_ethereum::{eip6110::parse_deposits_from_receipts, EthEvmConfig}; use reth_execution_types::ExecutionOutcome; use reth_payload_builder::{ - error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, + database::to_sync_cached_reads, error::PayloadBuilderError, EthBuiltPayload, + EthPayloadBuilderAttributes, }; use reth_primitives::{ constants::{ @@ -37,13 +38,13 @@ use reth_primitives::{ U256, }; use reth_provider::StateProviderFactory; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; use reth_trie::HashedPostState; use revm::{ - db::states::bundle_state::BundleRetention, + db::{states::bundle_state::BundleRetention, State}, primitives::{EVMError, EnvWithHandlerCfg, InvalidTransaction, ResultAndState}, - DatabaseCommit, State, + DatabaseCommit, }; use tracing::{debug, trace, warn}; @@ -101,6 +102,8 @@ where debug!(target: "payload_builder", parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building empty payload"); + println!("brecht: empty payload builder for {}", chain_spec.chain.id()); + let state = client.state_by_block_hash(parent_block.hash()).map_err(|err| { warn!(target: "payload_builder", parent_hash=%parent_block.hash(), @@ -110,7 +113,12 @@ where err })?; let mut db = State::builder() - .with_database(StateProviderDatabase::new(state)) + .with_database( + (SyncStateProviderDatabase::new( + Some(chain_spec.chain.id()), + StateProviderDatabase::new(state), + )), + ) .with_bundle_update() .build(); @@ -173,6 +181,8 @@ where let bundle_state = db.take_bundle(); let state_root = db .database + .get_db(chain_spec.chain.id()) + .ok_or(ProviderError::Database(DatabaseError::GetSyncDatabase(chain_spec.chain.id())))? .state_root(HashedPostState::from_bundle_state(&bundle_state.state)) .map_err(|err| { warn!(target: "payload_builder", @@ -230,7 +240,7 @@ where let header = Header { parent_hash: parent_block.hash(), ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: initialized_block_env.coinbase, + beneficiary: initialized_block_env.coinbase.1, state_root, transactions_root: EMPTY_TRANSACTIONS, withdrawals_root, @@ -254,6 +264,8 @@ where let block = Block { header, body: vec![], ommers: vec![], withdrawals, requests }; let sealed_block = block.seal_slow(); + println!("empty payload done [{:?}]: {:?}", sealed_block.hash(), sealed_block.state_root); + Ok(EthBuiltPayload::new(attributes.payload_id(), sealed_block, U256::ZERO)) } } @@ -273,12 +285,9 @@ where Client: StateProviderFactory, Pool: TransactionPool, { - let BuildArguments { client, pool, mut cached_reads, config, cancel, best_payload } = args; + // Brecht: ethereum payload builder - let state_provider = client.state_by_block_hash(config.parent_block.hash())?; - let state = StateProviderDatabase::new(state_provider); - let mut db = - State::builder().with_database_ref(cached_reads.as_db(state)).with_bundle_update().build(); + let BuildArguments { client, pool, mut cached_reads, config, cancel, best_payload } = args; let extra_data = config.extra_data(); let PayloadConfig { initialized_block_env, @@ -289,6 +298,17 @@ where .. } = config; + let state_provider = client.state_by_block_hash(parent_block.hash())?; + let state = SyncStateProviderDatabase::new( + Some(chain_spec.chain.id()), + StateProviderDatabase::new(state_provider), + ); + let mut sync_cached_reads = to_sync_cached_reads(cached_reads, chain_spec.chain.id()); + let mut db = State::builder() + .with_database_ref(sync_cached_reads.as_db(state)) + .with_bundle_update() + .build(); + debug!(target: "payload_builder", id=%attributes.id, parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); let mut cumulative_gas_used = 0; let mut sum_blob_gas_used = 0; @@ -338,10 +358,10 @@ where warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to update blockhashes for empty payload"); PayloadBuilderError::Internal(err.into()) })?; - let mut receipts = Vec::new(); while let Some(pool_tx) = best_txs.next() { // ensure we still have capacity for this transaction + println!("Brecht: pool tx! {:?}", pool_tx.hash()); if cumulative_gas_used + pool_tx.gas_limit() > block_gas_limit { // we can't fit this transaction into the block, so we need to mark it as invalid // which also removes all dependent transaction from the iterator before we can @@ -352,7 +372,7 @@ where // check if the job was cancelled, if so we can exit early if cancel.is_cancelled() { - return Ok(BuildOutcome::Cancelled) + return Ok(BuildOutcome::Cancelled); } // convert tx to a signed transaction @@ -369,7 +389,7 @@ where // for regular transactions above. trace!(target: "payload_builder", tx=?tx.hash, ?sum_blob_gas_used, ?tx_blob_gas, "skipping blob transaction because it would exceed the max data gas per block"); best_txs.mark_invalid(&pool_tx); - continue + continue; } } @@ -397,11 +417,11 @@ where best_txs.mark_invalid(&pool_tx); } - continue + continue; } err => { // this is an error that we should treat as fatal for this attempt - return Err(PayloadBuilderError::EvmExecutionError(err)) + return Err(PayloadBuilderError::EvmExecutionError(err)); } } } @@ -450,7 +470,10 @@ where // check if we have a better block if !is_better_payload(best_payload.as_ref(), total_fees) { // can skip building the block - return Ok(BuildOutcome::Aborted { fees: total_fees, cached_reads }) + return Ok(BuildOutcome::Aborted { + fees: total_fees, + cached_reads: sync_cached_reads.into(), + }); } // calculate the requests and the requests root @@ -489,6 +512,7 @@ where db.merge_transitions(BundleRetention::PlainState); let execution_outcome = ExecutionOutcome::new( + chain_spec.chain.id(), db.take_bundle(), vec![receipts].into(), block_number, @@ -503,7 +527,11 @@ where let state_provider = db.database.0.inner.borrow_mut(); state_provider .db - .state_root(HashedPostState::from_bundle_state(&execution_outcome.state().state))? + .get_db(chain_spec.chain.id()) + .ok_or(ProviderError::Database(DatabaseError::GetSyncDatabase(chain_spec.chain.id())))? + .state_root(HashedPostState::from_bundle_state( + &execution_outcome.current_state().state, + ))? }; // create the block header @@ -537,7 +565,7 @@ where let header = Header { parent_hash: parent_block.hash(), ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: initialized_block_env.coinbase, + beneficiary: initialized_block_env.coinbase.1, state_root, transactions_root, receipts_root, @@ -564,10 +592,12 @@ where let sealed_block = block.seal_slow(); debug!(target: "payload_builder", ?sealed_block, "sealed built block"); + //println!("default payload done [{:?}]: {:?}", sealed_block.hash(), sealed_block.state_root); + let mut payload = EthBuiltPayload::new(attributes.id, sealed_block, total_fees); // extend the payload with the blob sidecars from the executed txs payload.extend_sidecars(blob_sidecars); - Ok(BuildOutcome::Better { payload, cached_reads }) + Ok(BuildOutcome::Better { payload, cached_reads: sync_cached_reads.into() }) } diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index 1c24f09084d9..bca3c567c029 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -512,8 +512,8 @@ pub enum ChainSplit { #[cfg(test)] mod tests { use super::*; - use reth_primitives::{Receipt, Receipts, TxType, B256}; - use revm::primitives::{AccountInfo, HashMap}; + use reth_primitives::{constants::ETHEREUM_CHAIN_ID, Receipt, Receipts, TxType, B256}; + use revm::primitives::{AccountInfo, ChainAddress, HashMap}; #[test] fn chain_append() { @@ -549,15 +549,13 @@ mod tests { #[test] fn test_number_split() { + let addr1 = ChainAddress(ETHEREUM_CHAIN_ID, Address::new([2; 20])); + let addr2 = ChainAddress(ETHEREUM_CHAIN_ID, Address::new([3; 20])); let execution_outcome1 = ExecutionOutcome::new( + None, BundleState::new( - vec![( - Address::new([2; 20]), - None, - Some(AccountInfo::default()), - HashMap::default(), - )], - vec![vec![(Address::new([2; 20]), None, vec![])]], + vec![(addr1, None, Some(AccountInfo::default()), HashMap::default())], + vec![vec![(addr1, None, vec![])]], vec![], ), vec![vec![]].into(), @@ -566,14 +564,10 @@ mod tests { ); let execution_outcome2 = ExecutionOutcome::new( + None, BundleState::new( - vec![( - Address::new([3; 20]), - None, - Some(AccountInfo::default()), - HashMap::default(), - )], - vec![vec![(Address::new([3; 20]), None, vec![])]], + vec![(addr2, None, Some(AccountInfo::default()), HashMap::default())], + vec![vec![(addr2, None, vec![])]], vec![], ), vec![vec![]].into(), @@ -692,6 +686,7 @@ mod tests { // Create an ExecutionOutcome object with the created bundle, receipts, an empty requests // vector, and first_block set to 10 let execution_outcome = ExecutionOutcome { + chain_id: ETHEREUM_CHAIN_ID, bundle: Default::default(), receipts, requests: vec![], @@ -711,6 +706,7 @@ mod tests { // Create an ExecutionOutcome object with a single receipt vector containing receipt1 let execution_outcome1 = ExecutionOutcome { + chain_id: ETHEREUM_CHAIN_ID, bundle: Default::default(), receipts: Receipts { receipt_vec: vec![vec![Some(receipt1)]] }, requests: vec![], diff --git a/crates/evm/execution-types/src/execution_outcome.rs b/crates/evm/execution-types/src/execution_outcome.rs index 46f4b816a74f..d9da0c368884 100644 --- a/crates/evm/execution-types/src/execution_outcome.rs +++ b/crates/evm/execution-types/src/execution_outcome.rs @@ -1,12 +1,12 @@ use crate::BlockExecutionOutput; use reth_primitives::{ - logs_bloom, Account, Address, BlockNumber, Bloom, Bytecode, Log, Receipt, Receipts, Requests, - StorageEntry, B256, U256, + constants::ETHEREUM_CHAIN_ID, logs_bloom, Account, Address, BlockNumber, Bloom, Bytecode, Log, + Receipt, Receipts, Requests, StorageEntry, B256, U256, }; use reth_trie::HashedPostState; use revm::{ db::{states::BundleState, BundleAccount}, - primitives::AccountInfo, + primitives::{AccountInfo, ChainAddress}, }; use std::collections::HashMap; @@ -35,8 +35,11 @@ impl ChangedAccount { #[derive(Default, Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ExecutionOutcome { + /// Chain id of this execution outcome. + pub chain_id: u64, /// Bundle state with reverts. pub bundle: BundleState, + // FIX(Cecilia): Add (chain_id, Reciepts) /// The collection of receipts. /// Outer vector stores receipts for each block sequentially. /// The inner vector stores receipts ordered by transaction number. @@ -45,6 +48,7 @@ pub struct ExecutionOutcome { pub receipts: Receipts, /// First block of bundle state. pub first_block: BlockNumber, + // FIX(Cecilia): Add (chain_id, Request) /// The collection of EIP-7685 requests. /// Outer vector stores requests for each block sequentially. /// The inner vector stores requests ordered by transaction number. @@ -69,13 +73,14 @@ impl ExecutionOutcome { /// /// This constructor initializes a new `ExecutionOutcome` instance with the provided /// bundle state, receipts, first block number, and EIP-7685 requests. - pub const fn new( + pub fn new( + chain_id: u64, bundle: BundleState, receipts: Receipts, first_block: BlockNumber, requests: Vec, ) -> Self { - Self { bundle, receipts, first_block, requests } + Self { chain_id, bundle, receipts, first_block, requests } } /// Creates a new `ExecutionOutcome` from initialization parameters. @@ -83,6 +88,7 @@ impl ExecutionOutcome { /// This constructor initializes a new `ExecutionOutcome` instance using detailed /// initialization parameters. pub fn new_init( + chain_id: u64, state_init: BundleStateInit, revert_init: RevertsInit, contracts_init: Vec<(B256, Bytecode)>, @@ -98,7 +104,7 @@ impl ExecutionOutcome { let bundle = BundleState::new( state_init.into_iter().map(|(address, (original, present, storage))| { ( - address, + ChainAddress(chain_id, address), original.map(Into::into), present.map(Into::into), storage.into_iter().map(|(k, s)| (k.into(), s)).collect(), @@ -108,28 +114,67 @@ impl ExecutionOutcome { // does not needs to be sorted, it is done when taking reverts. reverts.into_iter().map(|(address, (original, storage))| { ( - address, + ChainAddress(chain_id, address), original.map(|i| i.map(Into::into)), storage.into_iter().map(|entry| (entry.key.into(), entry.value)), ) }) }), - contracts_init.into_iter().map(|(code_hash, bytecode)| (code_hash, bytecode.0)), + contracts_init + .into_iter() + .map(|(code_hash, bytecode)| ((chain_id, code_hash), bytecode.0)), ); - Self { bundle, receipts, first_block, requests } + Self { chain_id, bundle, receipts, first_block, requests } + } + + /// Reture the `ExecutionOutcome` for a speicific chain. + pub fn filter_chain(&self, chain_id: u64) -> Self { + Self { + chain_id, + bundle: self.bundle.filter_for_chain(chain_id), + // FIX(Cecilia): with (chain_id, Reciepts) & (chain_id, Requests) + // we can filter out the right ones + receipts: self.receipts.clone(), + first_block: self.first_block, + requests: self.requests.clone(), + } + } + + /// Filter the `ExecutionOutcome` for the current chain + /// if `chain_id` is not set, default to Ethereum. + pub fn filter_current_chain(&self) -> Self { + Self { + chain_id: self.chain_id, + bundle: self.current_state(), + // FIX(Cecilia): with (chain_id, Reciepts) & (chain_id, Requests) + // we can filter out the right ones + receipts: self.receipts.clone(), + first_block: self.first_block, + requests: self.requests.clone(), + } } /// Return revm bundle state. - pub const fn state(&self) -> &BundleState { + pub const fn all_states(&self) -> &BundleState { &self.bundle } /// Returns mutable revm bundle state. - pub fn state_mut(&mut self) -> &mut BundleState { + pub fn all_states_mut(&mut self) -> &mut BundleState { &mut self.bundle } + /// Reture states for a speicific chain. + pub fn state(&self, chain_id: u64) -> BundleState { + self.bundle.filter_for_chain(chain_id) + } + + /// Reture states for a speicific chain. + pub fn current_state(&self) -> BundleState { + self.bundle.filter_for_chain(self.chain_id) + } + /// Set first block. pub fn set_first_block(&mut self, first_block: BlockNumber) { self.first_block = first_block; @@ -137,35 +182,40 @@ impl ExecutionOutcome { /// Return iterator over all accounts pub fn accounts_iter(&self) -> impl Iterator)> { - self.bundle.state().iter().map(|(a, acc)| (*a, acc.info.as_ref())) + self.bundle.state().iter().map(|(a, acc)| (a.1, acc.info.as_ref())) } /// Return iterator over all [`BundleAccount`]s in the bundle pub fn bundle_accounts_iter(&self) -> impl Iterator { - self.bundle.state().iter().map(|(a, acc)| (*a, acc)) + self.bundle.state().iter().map(|(a, acc)| (a.1, acc)) } /// Get account if account is known. + /// Only support the account of current chain, or default to Ethereum. pub fn account(&self, address: &Address) -> Option> { - self.bundle.account(address).map(|a| a.info.clone().map(Into::into)) + self.bundle + .account(&ChainAddress(self.chain_id, *address)) + .map(|a| a.info.clone().map(Into::into)) } /// Get storage if value is known. /// /// This means that depending on status we can potentially return `U256::ZERO`. pub fn storage(&self, address: &Address, storage_key: U256) -> Option { - self.bundle.account(address).and_then(|a| a.storage_slot(storage_key)) + self.bundle + .account(&ChainAddress(self.chain_id, *address)) + .and_then(|a| a.storage_slot(storage_key)) } /// Return bytecode if known. pub fn bytecode(&self, code_hash: &B256) -> Option { - self.bundle.bytecode(code_hash).map(Bytecode) + self.bundle.bytecode(self.chain_id, code_hash).map(Bytecode) } /// Returns [`HashedPostState`] for this execution outcome. /// See [`HashedPostState::from_bundle_state`] for more info. pub fn hash_state_slow(&self) -> HashedPostState { - HashedPostState::from_bundle_state(&self.bundle.state) + HashedPostState::from_bundle_state(self.current_state().state()) } /// Transform block number to the index of block. @@ -356,9 +406,22 @@ impl ExecutionOutcome { } } +impl From<(BlockExecutionOutput, u64, BlockNumber)> for ExecutionOutcome { + fn from(value: (BlockExecutionOutput, u64, BlockNumber)) -> Self { + Self { + chain_id: value.1, + bundle: value.0.state, + receipts: Receipts::from(value.0.receipts), + first_block: value.2, + requests: vec![Requests::from(value.0.requests)], + } + } +} + impl From<(BlockExecutionOutput, BlockNumber)> for ExecutionOutcome { fn from(value: (BlockExecutionOutput, BlockNumber)) -> Self { Self { + chain_id: ETHEREUM_CHAIN_ID, bundle: value.0.state, receipts: Receipts::from(value.0.receipts), first_block: value.1, @@ -375,12 +438,19 @@ mod tests { use reth_primitives::{Address, Receipts, Request, Requests, TxType, B256}; use std::collections::HashMap; + const CHAIN_ID: u64 = 1u64; + #[test] fn test_initialisation() { // Create a new BundleState object with initial data let bundle = BundleState::new( - vec![(Address::new([2; 20]), None, Some(AccountInfo::default()), HashMap::default())], - vec![vec![(Address::new([2; 20]), None, vec![])]], + vec![( + ChainAddress(CHAIN_ID, Address::new([2; 20])), + None, + Some(AccountInfo::default()), + HashMap::default(), + )], + vec![vec![(ChainAddress(CHAIN_ID, Address::new([2; 20])), None, vec![])]], vec![], ); @@ -428,6 +498,7 @@ mod tests { // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block let exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: bundle.clone(), receipts: receipts.clone(), requests: requests.clone(), @@ -436,7 +507,13 @@ mod tests { // Assert that creating a new ExecutionOutcome using the constructor matches exec_res assert_eq!( - ExecutionOutcome::new(bundle, receipts.clone(), first_block, requests.clone()), + ExecutionOutcome::new( + CHAIN_ID, + bundle, + receipts.clone(), + first_block, + requests.clone() + ), exec_res ); @@ -457,6 +534,7 @@ mod tests { // exec_res assert_eq!( ExecutionOutcome::new_init( + CHAIN_ID, state_init, revert_init, vec![], @@ -490,6 +568,7 @@ mod tests { // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block let exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), receipts, requests: vec![], @@ -528,6 +607,7 @@ mod tests { // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block let exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), receipts, requests: vec![], @@ -563,6 +643,7 @@ mod tests { // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block let exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), // Default value for bundle receipts, // Include the created receipts requests: vec![], // Empty vector for requests @@ -613,6 +694,7 @@ mod tests { // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block let exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), // Default value for bundle receipts, // Include the created receipts requests: vec![], // Empty vector for requests @@ -627,6 +709,7 @@ mod tests { // Create a ExecutionOutcome object with an empty Receipts object let exec_res_empty_receipts = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), // Default value for bundle receipts: receipts_empty, // Include the empty receipts requests: vec![], // Empty vector for requests @@ -676,8 +759,13 @@ mod tests { // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block - let mut exec_res = - ExecutionOutcome { bundle: Default::default(), receipts, requests, first_block }; + let mut exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, + bundle: Default::default(), + receipts, + requests, + first_block, + }; // Assert that the revert_to method returns true when reverting to the initial block number. assert!(exec_res.revert_to(123)); @@ -730,8 +818,13 @@ mod tests { let first_block = 123; // Create an ExecutionOutcome object. - let mut exec_res = - ExecutionOutcome { bundle: Default::default(), receipts, requests, first_block }; + let mut exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, + bundle: Default::default(), + receipts, + requests, + first_block, + }; // Extend the ExecutionOutcome object by itself. exec_res.extend(exec_res.clone()); @@ -740,6 +833,7 @@ mod tests { assert_eq!( exec_res, ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), receipts: Receipts { receipt_vec: vec![vec![Some(receipt.clone())], vec![Some(receipt)]] @@ -791,14 +885,20 @@ mod tests { // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block - let exec_res = - ExecutionOutcome { bundle: Default::default(), receipts, requests, first_block }; + let exec_res = ExecutionOutcome { + chain_id: CHAIN_ID, + bundle: Default::default(), + receipts, + requests, + first_block, + }; // Split the ExecutionOutcome at block number 124 let result = exec_res.clone().split_at(124); // Define the expected lower ExecutionOutcome after splitting let lower_execution_outcome = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), receipts: Receipts { receipt_vec: vec![vec![Some(receipt.clone())]] }, requests: vec![Requests(vec![request])], @@ -807,6 +907,7 @@ mod tests { // Define the expected higher ExecutionOutcome after splitting let higher_execution_outcome = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: Default::default(), receipts: Receipts { receipt_vec: vec![vec![Some(receipt.clone())], vec![Some(receipt)]], @@ -839,7 +940,7 @@ mod tests { // Set up the bundle state with these accounts let mut bundle_state = BundleState::default(); bundle_state.state.insert( - address1, + ChainAddress(CHAIN_ID, address1), BundleAccount { info: Some(account_info1), storage: Default::default(), @@ -848,7 +949,7 @@ mod tests { }, ); bundle_state.state.insert( - address2, + ChainAddress(CHAIN_ID, address2), BundleAccount { info: Some(account_info2), storage: Default::default(), @@ -859,7 +960,7 @@ mod tests { // Unchanged account bundle_state.state.insert( - address3, + ChainAddress(CHAIN_ID, address3), BundleAccount { info: None, storage: Default::default(), @@ -869,6 +970,7 @@ mod tests { ); let execution_outcome = ExecutionOutcome { + chain_id: CHAIN_ID, bundle: bundle_state, receipts: Receipts::default(), first_block: 0, diff --git a/crates/evm/execution-types/src/lib.rs b/crates/evm/execution-types/src/lib.rs index 86abd98de1d9..dff73320a641 100644 --- a/crates/evm/execution-types/src/lib.rs +++ b/crates/evm/execution-types/src/lib.rs @@ -19,3 +19,6 @@ pub use execute::*; mod execution_outcome; pub use execution_outcome::*; + +mod state_diff; +pub use state_diff::*; diff --git a/crates/evm/execution-types/src/state_diff.rs b/crates/evm/execution-types/src/state_diff.rs new file mode 100644 index 000000000000..b737d32acb8a --- /dev/null +++ b/crates/evm/execution-types/src/state_diff.rs @@ -0,0 +1,112 @@ +use std::collections::HashMap; + +use reth_primitives::{ + constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, eip4844::calculate_excess_blob_gas, proofs::{self, calculate_requests_root}, Block, BlockNumber, ChainId, EthereumHardforks, Header, Receipt, Receipts, Requests, StateDiff, StateDiffAccount, StateDiffStorageSlot, TransactionSigned, B256, EMPTY_OMMER_ROOT_HASH, U256 +}; +//use reth_provider::{StateProvider, StateProviderFactory}; +//use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; +//use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; +use revm::{ + db::{states::{bundle_state::BundleRetention, reverts::Reverts}, AccountRevert, BundleAccount, BundleState, State}, + primitives::{AccountInfo, Bytecode, EVMError, EnvWithHandlerCfg, ResultAndState}, + DatabaseCommit, SyncDatabase, +}; + +use revm::primitives::ChainAddress; +use revm::db::AccountStatus; +use revm::db::states::StorageSlot; + +use crate::{BlockExecutionOutput, ExecutionOutcome}; + + +pub fn execution_outcome_to_state_diff(execution_outcome: &ExecutionOutcome, state_root: B256, gas_used: u64) -> StateDiff { + assert_eq!(execution_outcome.receipts().len(), 1); + let receipts = execution_outcome.receipts()[0].iter().map(|r| r.clone().unwrap()).collect(); + to_state_diff(&execution_outcome.bundle, &receipts, state_root, gas_used) +} + +pub fn block_execution_output_to_state_diff(block_execution_output: &BlockExecutionOutput, state_root: B256) -> StateDiff { + to_state_diff(&block_execution_output.state, &block_execution_output.receipts, state_root, block_execution_output.gas_used) +} + +pub fn to_state_diff(bundle_state: &BundleState, receipts: &Vec, state_root: B256, gas_used: u64) -> StateDiff { + let mut state_diff = StateDiff { + accounts: Vec::new(), + receipts: receipts.clone(), + gas_used, + state_root, + transactions_root: B256::ZERO, + bundle: bundle_state.clone(), + }; + for (address, bundle_account) in bundle_state.state.iter() { + let storage = bundle_account.storage.iter().map(|(&key, value)| StateDiffStorageSlot { + key, value: value.present_value + }).collect(); + + let account_info = bundle_account.account_info().unwrap_or_default(); + let state_diff_account = StateDiffAccount { + address: address.1, + storage, + balance: account_info.balance, + nonce: account_info.nonce, + code_hash: account_info.code_hash, + code: account_info.code.unwrap_or_default().bytes(), + }; + state_diff.accounts.push(state_diff_account); + } + state_diff +} + +pub fn state_diff_to_block_execution_output(chain_id: u64, state_diff: &StateDiff) -> BlockExecutionOutput { + let mut block_execution_output = BlockExecutionOutput:: { + state: state_diff.bundle.clone(), + receipts: state_diff.receipts.clone(), + requests: Vec::new(), + gas_used: state_diff.gas_used, + }; + + //block_execution_output.state.reverts = merge_reverts(&block_execution_output.state.reverts); + // for account in state_diff.accounts.iter() { + // let mut new_account = BundleAccount { + // info: Some(AccountInfo { + // balance: account.balance, + // nonce: account.nonce, + // code_hash: account.code_hash, + // code: Some(Bytecode::new_raw_checked(account.code.clone()).unwrap()), + // }), + // original_info: None, + // storage: HashMap::new(), + // status: AccountStatus::Changed, + // }; + // for storage_slot in account.storage.iter() { + // new_account.storage.insert(storage_slot.key, StorageSlot { + // previous_or_original_value: storage_slot.value, + // present_value: storage_slot.value, + // }); + // } + + // block_execution_output.state.state.insert(ChainAddress(chain_id, account.address), new_account); + // } + block_execution_output +} + +pub fn merge_reverts(reverts: &Reverts) -> Reverts { + let mut merged_reverts = HashMap::::new(); + for reverts in reverts.iter() { + for revert in reverts.iter() { + if merged_reverts.contains_key(&revert.0) { + let merged_revert = merged_reverts.get_mut(&revert.0).unwrap(); + for storage in revert.1.storage.iter() { + if !merged_revert.storage.contains_key(storage.0) { + merged_revert.storage.insert(*storage.0, storage.1.clone()); + } + } + } else { + merged_reverts.insert(revert.0, revert.1.clone()); + } + } + } + //println!("original reverts: {:?}", reverts); + //println!("new reverts: {:?}", merged_reverts); + Reverts::new(vec![merged_reverts.into_iter().collect()]) +} diff --git a/crates/evm/src/builder.rs b/crates/evm/src/builder.rs index e238ba8ccaff..43258c4595a6 100644 --- a/crates/evm/src/builder.rs +++ b/crates/evm/src/builder.rs @@ -3,7 +3,7 @@ #[cfg(not(feature = "std"))] use alloc::boxed::Box; -use revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector}; +use revm::{inspector_handle_register, Evm, EvmBuilder, GetInspector, SyncDatabase}; use revm_primitives::EnvWithHandlerCfg; /// Builder for creating an EVM with a database and environment. @@ -13,7 +13,7 @@ use revm_primitives::EnvWithHandlerCfg; /// This is useful for creating an EVM with a custom database and environment without having to /// necessarily rely on Revm inspector. #[derive(Debug)] -pub struct RethEvmBuilder { +pub struct RethEvmBuilder { /// The database to use for the EVM. db: DB, /// The environment to use for the EVM. @@ -24,7 +24,7 @@ pub struct RethEvmBuilder { impl RethEvmBuilder where - DB: Database, + DB: SyncDatabase, { /// Create a new EVM builder with the given database. pub const fn new(db: DB, external_context: EXT) -> Self { @@ -76,7 +76,7 @@ where /// Trait for configuring an EVM builder. pub trait ConfigureEvmBuilder { /// The type of EVM builder that this trait can configure. - type Builder<'a, DB: Database>: EvmFactory; + type Builder<'a, DB: SyncDatabase>: EvmFactory; } /// Trait for configuring the EVM for executing full blocks. @@ -92,7 +92,10 @@ pub trait EvmFactory { /// This does not automatically configure the EVM with [`crate::ConfigureEvmEnv`] methods. It is /// up to the caller to call an appropriate method to fill the transaction and block /// environment before executing any transactions using the provided EVM. - fn evm(self, db: DB) -> Evm<'static, Self::DefaultExternalContext<'static>, DB> + fn evm( + self, + db: DB, + ) -> Evm<'static, Self::DefaultExternalContext<'static>, DB> where Self: Sized, { @@ -103,7 +106,7 @@ pub trait EvmFactory { /// including the spec id. /// /// This will preserve any handler modifications - fn evm_with_env<'a, DB: Database + 'a>( + fn evm_with_env<'a, DB: SyncDatabase + 'a>( &self, db: DB, env: EnvWithHandlerCfg, @@ -124,7 +127,7 @@ pub trait EvmFactory { inspector: I, ) -> Evm<'_, I, DB> where - DB: Database, + DB: SyncDatabase, I: GetInspector, { RethEvmBuilder::new(db, self.default_external_context()) @@ -139,14 +142,14 @@ pub trait EvmFactory { /// and block environment before executing any transactions using the provided EVM. fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> where - DB: Database, + DB: SyncDatabase, I: GetInspector, { RethEvmBuilder::new(db, self.default_external_context()).build_with_inspector(inspector) } } -impl EvmFactory for RethEvmBuilder { +impl EvmFactory for RethEvmBuilder { type DefaultExternalContext<'a> = EXT; fn default_external_context<'a>(&self) -> Self::DefaultExternalContext<'a> { diff --git a/crates/evm/src/either.rs b/crates/evm/src/either.rs index 84e1733e4812..cf37864186da 100644 --- a/crates/evm/src/either.rs +++ b/crates/evm/src/either.rs @@ -8,7 +8,7 @@ use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionO use reth_primitives::{BlockNumber, BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; use reth_storage_errors::provider::ProviderError; -use revm_primitives::db::Database; +use revm_primitives::db::SyncDatabase; // re-export Either pub use futures_util::future::Either; @@ -18,15 +18,15 @@ where A: BlockExecutorProvider, B: BlockExecutorProvider, { - type Executor + Display>> = + type Executor + Display>> = Either, B::Executor>; - type BatchExecutor + Display>> = + type BatchExecutor + Display>> = Either, B::BatchExecutor>; fn executor(&self, db: DB) -> Self::Executor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { match self { Self::Left(a) => Either::Left(a.executor(db)), @@ -36,7 +36,7 @@ where fn batch_executor(&self, db: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { match self { Self::Left(a) => Either::Left(a.batch_executor(db)), @@ -59,7 +59,7 @@ where Output = BlockExecutionOutput, Error = BlockExecutionError, >, - DB: Database + Display>, + DB: SyncDatabase + Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = BlockExecutionOutput; @@ -87,7 +87,7 @@ where Output = ExecutionOutcome, Error = BlockExecutionError, >, - DB: Database + Display>, + DB: SyncDatabase + Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = ExecutionOutcome; diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index 2109d557f8ec..db1d8e5e3742 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -9,7 +9,7 @@ use core::fmt::Display; use reth_primitives::{BlockNumber, BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; -use revm_primitives::db::Database; +use revm_primitives::db::SyncDatabase; /// A general purpose executor trait that executes an input (e.g. block) and produces an output /// (e.g. state changes and receipts). @@ -107,7 +107,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// /// It is not expected to validate the state trie root, this must be done by the caller using /// the returned state. - type Executor + Display>>: for<'a> Executor< + type Executor + Display>>: for<'a> Executor< DB, Input<'a> = BlockExecutionInput<'a, BlockWithSenders>, Output = BlockExecutionOutput, @@ -115,7 +115,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { >; /// An executor that can execute a batch of blocks given a database. - type BatchExecutor + Display>>: for<'a> BatchExecutor< + type BatchExecutor + Display>>: for<'a> BatchExecutor< DB, Input<'a> = BlockExecutionInput<'a, BlockWithSenders>, Output = ExecutionOutcome, @@ -127,7 +127,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// This is used to execute a single block and get the changed state. fn executor(&self, db: DB) -> Self::Executor where - DB: Database + Display>; + DB: SyncDatabase + Display>; /// Creates a new batch executor with the given database and pruning modes. /// @@ -135,7 +135,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// during historical sync which involves executing multiple blocks in sequence. fn batch_executor(&self, db: DB) -> Self::BatchExecutor where - DB: Database + Display>; + DB: SyncDatabase + Display>; } #[cfg(test)] @@ -150,19 +150,20 @@ mod tests { struct TestExecutorProvider; impl BlockExecutorProvider for TestExecutorProvider { - type Executor + Display>> = TestExecutor; - type BatchExecutor + Display>> = TestExecutor; + type Executor + Display>> = TestExecutor; + type BatchExecutor + Display>> = + TestExecutor; fn executor(&self, _db: DB) -> Self::Executor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { TestExecutor(PhantomData) } fn batch_executor(&self, _db: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { TestExecutor(PhantomData) } diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 7b52a8accfc7..34c5a35a512a 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -17,9 +17,9 @@ use core::ops::Deref; use crate::builder::RethEvmBuilder; use reth_chainspec::ChainSpec; use reth_primitives::{Address, Header, TransactionSigned, TransactionSignedEcRecovered, U256}; -use revm::{Database, Evm, GetInspector}; +use revm::{Evm, GetInspector, SyncDatabase}; use revm_primitives::{ - BlockEnv, Bytes, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, SpecId, TxEnv, + BlockEnv, Bytes, CfgEnvWithHandlerCfg, ChainAddress, Env, EnvWithHandlerCfg, SpecId, TxEnv, }; pub mod builder; @@ -29,6 +29,9 @@ pub mod noop; pub mod provider; pub mod system_calls; + +use reth_primitives::constants::{BASE_CHAIN_ID, NUM_L2_CHAINS, L1_CHAIN_ID}; + #[cfg(any(test, feature = "test-utils"))] /// test helpers for mocking executor pub mod test_utils; @@ -44,7 +47,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv { /// This does not automatically configure the EVM with [`ConfigureEvmEnv`] methods. It is up to /// the caller to call an appropriate method to fill the transaction and block environment /// before executing any transactions using the provided EVM. - fn evm(&self, db: DB) -> Evm<'_, Self::DefaultExternalContext<'_>, DB> { + fn evm(&self, db: DB) -> Evm<'_, Self::DefaultExternalContext<'_>, DB> { RethEvmBuilder::new(db, self.default_external_context()).build() } @@ -52,7 +55,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv { /// including the spec id. /// /// This will preserve any handler modifications - fn evm_with_env( + fn evm_with_env( &self, db: DB, env: EnvWithHandlerCfg, @@ -60,6 +63,10 @@ pub trait ConfigureEvm: ConfigureEvmEnv { let mut evm = self.evm(db); evm.modify_spec_id(env.spec_id()); evm.context.evm.env = env.env; + evm.tx_mut().chain_ids = Some(std::iter::once(L1_CHAIN_ID) + .chain((0..NUM_L2_CHAINS).map(|i| BASE_CHAIN_ID + i)) + .collect()); + evm } @@ -76,7 +83,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv { inspector: I, ) -> Evm<'_, I, DB> where - DB: Database, + DB: SyncDatabase, I: GetInspector, { let mut evm = self.evm_with_inspector(db, inspector); @@ -92,7 +99,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv { /// environment before executing any transactions using the provided EVM. fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> where - DB: Database, + DB: SyncDatabase, I: GetInspector, { RethEvmBuilder::new(db, self.default_external_context()).build_with_inspector(inspector) @@ -137,9 +144,15 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { ); /// Fill [`BlockEnv`] field according to the chain spec and given header - fn fill_block_env(&self, block_env: &mut BlockEnv, header: &Header, after_merge: bool) { + fn fill_block_env( + &self, + chain_id: u64, + block_env: &mut BlockEnv, + header: &Header, + after_merge: bool, + ) { block_env.number = U256::from(header.number); - block_env.coinbase = header.beneficiary; + block_env.coinbase = ChainAddress(chain_id, header.beneficiary); block_env.timestamp = U256::from(header.timestamp); if after_merge { block_env.prevrandao = Some(header.mix_hash); @@ -169,6 +182,6 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { ) { self.fill_cfg_env(cfg, chain_spec, header, total_difficulty); let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE; - self.fill_block_env(block_env, header, after_merge); + self.fill_block_env(chain_spec.chain().id(), block_env, header, after_merge); } } diff --git a/crates/evm/src/noop.rs b/crates/evm/src/noop.rs index ff8e893b2b6b..2f1e78b6875b 100644 --- a/crates/evm/src/noop.rs +++ b/crates/evm/src/noop.rs @@ -7,7 +7,7 @@ use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionO use reth_primitives::{BlockNumber, BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; use reth_storage_errors::provider::ProviderError; -use revm_primitives::db::Database; +use revm_primitives::db::SyncDatabase; use crate::execute::{BatchExecutor, BlockExecutorProvider, Executor}; @@ -19,20 +19,20 @@ const UNAVAILABLE_FOR_NOOP: &str = "execution unavailable for noop"; pub struct NoopBlockExecutorProvider; impl BlockExecutorProvider for NoopBlockExecutorProvider { - type Executor + Display>> = Self; + type Executor + Display>> = Self; - type BatchExecutor + Display>> = Self; + type BatchExecutor + Display>> = Self; fn executor(&self, _: DB) -> Self::Executor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { Self } fn batch_executor(&self, _: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { Self } diff --git a/crates/evm/src/system_calls.rs b/crates/evm/src/system_calls.rs index 530ed3cfafa1..2926e8fdb458 100644 --- a/crates/evm/src/system_calls.rs +++ b/crates/evm/src/system_calls.rs @@ -18,10 +18,10 @@ use alloy_eips::{ use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; use reth_primitives::{Buf, Request}; -use revm::{interpreter::Host, Database, DatabaseCommit, Evm}; +use revm::{interpreter::Host, DatabaseCommit, Evm, SyncDatabase}; use revm_primitives::{ - Address, BlockEnv, Bytes, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, FixedBytes, - ResultAndState, B256, + Address, BlockEnv, Bytes, CfgEnvWithHandlerCfg, ChainAddress, EnvWithHandlerCfg, + ExecutionResult, FixedBytes, ResultAndState, B256, }; /// Apply the [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) pre block contract call. @@ -40,7 +40,7 @@ pub fn pre_block_blockhashes_contract_call( parent_block_hash: B256, ) -> Result<(), BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: Display, EvmConfig: ConfigureEvm, { @@ -81,7 +81,7 @@ pub fn apply_blockhashes_contract_call( evm: &mut Evm<'_, EXT, DB>, ) -> Result<(), BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: core::fmt::Display, EvmConfig: ConfigureEvm, { @@ -114,7 +114,7 @@ where } }; - state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS); + state.remove(&ChainAddress(chain_spec.chain().id(), alloy_eips::eip4788::SYSTEM_ADDRESS)); state.remove(&evm.block().coinbase); evm.context.evm.db.commit(state); @@ -141,7 +141,7 @@ pub fn pre_block_beacon_root_contract_call( parent_beacon_block_root: Option, ) -> Result<(), BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: Display, EvmConfig: ConfigureEvm, { @@ -183,7 +183,7 @@ pub fn apply_beacon_root_contract_call( evm: &mut Evm<'_, EXT, DB>, ) -> Result<(), BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: core::fmt::Display, EvmConfig: ConfigureEvm, { @@ -217,6 +217,7 @@ where parent_beacon_block_root.0.into(), ); + let mut state = match evm.transact() { Ok(res) => res.state, Err(e) => { @@ -229,7 +230,7 @@ where } }; - state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS); + state.remove(&ChainAddress(chain_spec.chain().id(), alloy_eips::eip4788::SYSTEM_ADDRESS)); state.remove(&evm.block().coinbase); evm.context.evm.db.commit(state); @@ -254,7 +255,7 @@ pub fn post_block_withdrawal_requests_contract_call( initialized_block_env: &BlockEnv, ) -> Result, BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: Display, EvmConfig: ConfigureEvm, { @@ -282,7 +283,7 @@ pub fn apply_withdrawal_requests_contract_call( evm: &mut Evm<'_, EXT, DB>, ) -> Result, BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: core::fmt::Display, EvmConfig: ConfigureEvm, { @@ -316,7 +317,7 @@ where }; // cleanup the state - state.remove(&alloy_eips::eip7002::SYSTEM_ADDRESS); + state.remove(&ChainAddress(evm.cfg().chain_id, alloy_eips::eip7002::SYSTEM_ADDRESS)); state.remove(&evm.block().coinbase); evm.context.evm.db.commit(state); @@ -384,7 +385,7 @@ pub fn post_block_consolidation_requests_contract_call( initialized_block_env: &BlockEnv, ) -> Result, BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: Display, EvmConfig: ConfigureEvm, { @@ -412,7 +413,7 @@ pub fn apply_consolidation_requests_contract_call( evm: &mut Evm<'_, EXT, DB>, ) -> Result, BlockExecutionError> where - DB: Database + DatabaseCommit, + DB: SyncDatabase + DatabaseCommit, DB::Error: core::fmt::Display, EvmConfig: ConfigureEvm, { @@ -447,7 +448,7 @@ where }; // cleanup the state - state.remove(&alloy_eips::eip7002::SYSTEM_ADDRESS); + state.remove(&ChainAddress(evm.cfg().chain_id, alloy_eips::eip7002::SYSTEM_ADDRESS)); state.remove(&evm.block().coinbase); evm.context.evm.db.commit(state); diff --git a/crates/evm/src/test_utils.rs b/crates/evm/src/test_utils.rs index c3aa34a56a45..e89f73fd949b 100644 --- a/crates/evm/src/test_utils.rs +++ b/crates/evm/src/test_utils.rs @@ -9,7 +9,7 @@ use reth_execution_types::ExecutionOutcome; use reth_primitives::{BlockNumber, BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; use reth_storage_errors::provider::ProviderError; -use revm_primitives::db::Database; +use revm_primitives::db::SyncDatabase; use std::{fmt::Display, sync::Arc}; /// A [`BlockExecutorProvider`] that returns mocked execution results. @@ -26,20 +26,20 @@ impl MockExecutorProvider { } impl BlockExecutorProvider for MockExecutorProvider { - type Executor + Display>> = Self; + type Executor + Display>> = Self; - type BatchExecutor + Display>> = Self; + type BatchExecutor + Display>> = Self; fn executor(&self, _: DB) -> Self::Executor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { self.clone() } fn batch_executor(&self, _: DB) -> Self::BatchExecutor where - DB: Database + Display>, + DB: SyncDatabase + Display>, { self.clone() } @@ -51,7 +51,7 @@ impl Executor for MockExecutorProvider { type Error = BlockExecutionError; fn execute(self, _: Self::Input<'_>) -> Result { - let ExecutionOutcome { bundle, receipts, requests, first_block: _ } = + let ExecutionOutcome { chain_id, bundle, receipts, requests, first_block: _ } = self.exec_results.lock().pop().unwrap(); Ok(BlockExecutionOutput { state: bundle, diff --git a/crates/exex/exex/Cargo.toml b/crates/exex/exex/Cargo.toml index 1ad906e6f010..b91fd9c2ee9a 100644 --- a/crates/exex/exex/Cargo.toml +++ b/crates/exex/exex/Cargo.toml @@ -54,3 +54,4 @@ secp256k1.workspace = true [features] default = [] serde = ["reth-provider/serde", "reth-exex-types/serde"] +gwyneth = ["reth-payload-builder/gwyneth"] \ No newline at end of file diff --git a/crates/exex/exex/src/backfill/job.rs b/crates/exex/exex/src/backfill/job.rs index 385b04976d1f..e1b32fe76a38 100644 --- a/crates/exex/exex/src/backfill/job.rs +++ b/crates/exex/exex/src/backfill/job.rs @@ -13,7 +13,7 @@ use reth_provider::{ BlockReader, Chain, HeaderProvider, ProviderError, StateProviderFactory, TransactionVariant, }; use reth_prune_types::PruneModes; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_stages_api::ExecutionStageThresholds; use reth_tracing::tracing::{debug, trace}; @@ -63,9 +63,13 @@ where } fn execute_range(&mut self) -> Result { - let mut executor = self.executor.batch_executor(StateProviderDatabase::new( - self.provider.history_by_block_number(self.range.start().saturating_sub(1))?, - )); + let db = SyncStateProviderDatabase::new( + None, + StateProviderDatabase::new( + self.provider.history_by_block_number(self.range.start().saturating_sub(1))?, + ), + ); + let mut executor = self.executor.batch_executor(db); executor.set_prune_modes(self.prune_modes.clone()); let mut fetch_block_duration = Duration::default(); @@ -187,6 +191,9 @@ where &self, block_number: u64, ) -> Result<(BlockWithSenders, BlockExecutionOutput), BlockExecutionError> { + + + let td = self .provider .header_td_by_number(block_number)? @@ -199,8 +206,11 @@ where .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; // Configure the executor to use the previous block's state. - let executor = self.executor.executor(StateProviderDatabase::new( - self.provider.history_by_block_number(block_number.saturating_sub(1))?, + let executor = self.executor.executor(SyncStateProviderDatabase::new( + None, + StateProviderDatabase::new( + self.provider.history_by_block_number(block_number.saturating_sub(1))?, + ), )); trace!(target: "exex::backfill", number = block_number, txs = block_with_senders.block.body.len(), "Executing block"); @@ -227,7 +237,7 @@ mod tests { use std::sync::Arc; use crate::{ - backfill::test_utils::{blocks_and_execution_outputs, chain_spec, to_execution_outcome}, + backfill::test_utils::{blocks_and_execution_outputs, chain_spec}, BackfillJobFactory, }; use reth_blockchain_tree::noop::NoopBlockchainTree; @@ -236,6 +246,7 @@ mod tests { use reth_primitives::public_key_to_address; use reth_provider::{ providers::BlockchainProvider, test_utils::create_test_provider_factory_with_chain_spec, + ExecutionOutcome, }; use reth_testing_utils::generators; use secp256k1::Keypair; @@ -249,6 +260,7 @@ mod tests { let address = public_key_to_address(key_pair.public_key()); let chain_spec = chain_spec(address); + let chain_id = chain_spec.chain.id(); let executor = EthExecutorProvider::ethereum(chain_spec.clone()); let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone()); @@ -261,8 +273,8 @@ mod tests { let blocks_and_execution_outputs = blocks_and_execution_outputs(provider_factory, chain_spec, key_pair)?; let (block, block_execution_output) = blocks_and_execution_outputs.first().unwrap(); - let execution_outcome = to_execution_outcome(block.number, block_execution_output); - + let execution_outcome = + ExecutionOutcome::from((block_execution_output.clone(), chain_id, block.number)); // Backfill the first block let factory = BackfillJobFactory::new(executor, blockchain_db); let job = factory.backfill(1..=1); diff --git a/crates/exex/exex/src/backfill/stream.rs b/crates/exex/exex/src/backfill/stream.rs index 5b72dad38b00..523bb11f7ee0 100644 --- a/crates/exex/exex/src/backfill/stream.rs +++ b/crates/exex/exex/src/backfill/stream.rs @@ -260,7 +260,7 @@ mod tests { ); let mut backfill_stream = factory.backfill(1..=2).into_stream(); let mut chain = backfill_stream.next().await.unwrap().unwrap(); - chain.execution_outcome_mut().state_mut().reverts.sort(); + chain.execution_outcome_mut().all_states_mut().reverts.sort(); assert!(chain.blocks_iter().eq(&blocks)); assert_eq!(chain.execution_outcome(), &execution_outcome); diff --git a/crates/exex/exex/src/backfill/test_utils.rs b/crates/exex/exex/src/backfill/test_utils.rs index 14377e520a52..9ab2b19cbc71 100644 --- a/crates/exex/exex/src/backfill/test_utils.rs +++ b/crates/exex/exex/src/backfill/test_utils.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use eyre::OptionExt; +use reth_blockchain_tree::chain; use reth_chainspec::{ChainSpec, ChainSpecBuilder, EthereumHardfork, MAINNET}; use reth_evm::execute::{ BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor, @@ -11,22 +12,10 @@ use reth_primitives::{ Receipt, Requests, SealedBlockWithSenders, Transaction, TxEip2930, TxKind, U256, }; use reth_provider::{BlockWriter as _, ExecutionOutcome, LatestStateProviderRef, ProviderFactory}; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_testing_utils::generators::sign_tx_with_key_pair; use secp256k1::Keypair; -pub(crate) fn to_execution_outcome( - block_number: u64, - block_execution_output: &BlockExecutionOutput, -) -> ExecutionOutcome { - ExecutionOutcome { - bundle: block_execution_output.state.clone(), - receipts: block_execution_output.receipts.clone().into(), - first_block: block_number, - requests: vec![Requests(block_execution_output.requests.clone())], - } -} - pub(crate) fn chain_spec(address: Address) -> Arc { // Create a chain spec with a genesis state that contains the // provided sender @@ -46,6 +35,7 @@ pub(crate) fn chain_spec(address: Address) -> Arc { ) } +// Brecht execute_block_and_commit_to_database pub(crate) fn execute_block_and_commit_to_database( provider_factory: &ProviderFactory, chain_spec: Arc, @@ -55,18 +45,22 @@ where DB: reth_db_api::database::Database, { let provider = provider_factory.provider()?; + let db = SyncStateProviderDatabase::new( + Some(chain_spec.chain.id()), + StateProviderDatabase::new(LatestStateProviderRef::new( + provider.tx_ref(), + provider.static_file_provider().clone(), + )), + ); // Execute the block to produce a block execution output let mut block_execution_output = EthExecutorProvider::ethereum(chain_spec) - .executor(StateProviderDatabase::new(LatestStateProviderRef::new( - provider.tx_ref(), - provider.static_file_provider().clone(), - ))) + .executor(db) .execute(BlockExecutionInput { block, total_difficulty: U256::ZERO })?; block_execution_output.state.reverts.sort(); // Convert the block execution output to an execution outcome for committing to the database - let execution_outcome = to_execution_outcome(block.number, &block_execution_output); + let execution_outcome = ExecutionOutcome::from((block_execution_output.clone(), block.number)); // Commit the block's execution outcome to the database let provider_rw = provider_factory.provider_rw()?; @@ -182,16 +176,20 @@ where let provider = provider_factory.provider()?; - let executor = - EthExecutorProvider::ethereum(chain_spec).batch_executor(StateProviderDatabase::new( - LatestStateProviderRef::new(provider.tx_ref(), provider.static_file_provider().clone()), - )); + let db = SyncStateProviderDatabase::new( + Some(chain_spec.chain.id()), + StateProviderDatabase::new(LatestStateProviderRef::new( + provider.tx_ref(), + provider.static_file_provider().clone(), + )), + ); + let executor = EthExecutorProvider::ethereum(chain_spec).batch_executor(db); let mut execution_outcome = executor.execute_and_verify_batch(vec![ (&block1, U256::ZERO).into(), (&block2, U256::ZERO).into(), ])?; - execution_outcome.state_mut().reverts.sort(); + execution_outcome.filter_current_chain().all_states_mut().reverts.sort(); let block1 = block1.seal_slow(); let block2 = block2.seal_slow(); diff --git a/crates/gwyneth/Cargo.toml b/crates/gwyneth/Cargo.toml new file mode 100644 index 000000000000..87475d523480 --- /dev/null +++ b/crates/gwyneth/Cargo.toml @@ -0,0 +1,75 @@ +[package] +name = "gwyneth" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true +required-features = ["gwyneth"] + +[lints] +workspace = true + + +[dependencies] +# reth +reth-payload-builder = { workspace = true, features = ["gwyneth"]} +reth-ethereum-engine-primitives = { workspace = true, features = ["gwyneth"]} +reth-basic-payload-builder = { workspace = true, features = ["gwyneth"]} +reth-ethereum-payload-builder ={ workspace = true, features = ["gwyneth"]} +reth-node-builder = { workspace = true, features = ["gwyneth"]} +reth-tracing.workspace = true +reth-provider.workspace = true +reth-transaction-pool.workspace = true +reth-network.workspace = true +reth-evm-ethereum.workspace = true +reth-evm.workspace = true +reth-consensus.workspace = true +reth-auto-seal-consensus.workspace = true +reth-beacon-consensus.workspace = true +reth-rpc.workspace = true +reth-rpc-types.workspace = true +reth-rpc-engine-api.workspace = true +reth-node-api.workspace = true +reth-tasks.workspace = true +reth-tokio-util.workspace = true +reth-node-events.workspace = true +reth-node-core.workspace = true +reth-exex.workspace = true +reth-chainspec.workspace = true +reth-execution-types.workspace = true +reth-primitives.workspace = true +reth-revm.workspace = true +reth-errors.workspace = true +reth-rpc-api.workspace = true +reth-rpc-layer.workspace = true +reth-db.workspace = true +reth-trie.workspace = true +reth-rpc-builder.workspace = true + +# ethereum +reth-node-ethereum.workspace = true + +# misc +futures-util.workspace = true +eyre.workspace = true +serde.workspace = true +serde_json.workspace = true +tokio = { workspace = true , features = ["sync"]} +tokio-stream.workspace = true +futures.workspace = true +thiserror.workspace = true +tracing.workspace = true +jsonrpsee.workspace = true +revm.workspace = true +bincode.workspace = true + +# alloy +alloy-primitives.workspace = true +alloy-sol-types = { workspace = true, features = ["json"] } +alloy-consensus.workspace = true +alloy-rlp.workspace = true +alloy-serde.workspace = true +alloy-eips.workspace = true \ No newline at end of file diff --git a/crates/gwyneth/Gwyneth.json b/crates/gwyneth/Gwyneth.json new file mode 100644 index 000000000000..36252d586b45 --- /dev/null +++ b/crates/gwyneth/Gwyneth.json @@ -0,0 +1 @@ +{"abi":[{"type":"receive","stateMutability":"payable"},{"type":"function","name":"init","inputs":[{"name":"_owner","type":"address","internalType":"address"},{"name":"_genesisUltraHash","type":"bytes32","internalType":"bytes32"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"propose","inputs":[{"name":"_block","type":"tuple","internalType":"struct GwynethData.UltraBlock","components":[{"name":"ultraHash","type":"bytes32","internalType":"bytes32"},{"name":"parentUltraHash","type":"bytes32","internalType":"bytes32"},{"name":"parentL1BlockHash","type":"bytes32","internalType":"bytes32"},{"name":"blobHashes","type":"bytes32[]","internalType":"bytes32[]"},{"name":"da","type":"bytes","internalType":"bytes"},{"name":"blocks","type":"tuple[]","internalType":"struct GwynethData.Block[]","components":[{"name":"l1Block","type":"tuple","internalType":"struct GwynethData.L1Block","components":[{"name":"transactions","type":"tuple[]","internalType":"struct GwynethData.Transaction[]","components":[{"name":"addr","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"},{"name":"value","type":"uint256","internalType":"uint256"},{"name":"gas","type":"uint64","internalType":"uint64"},{"name":"reverts","type":"bool","internalType":"bool"}]}]},{"name":"extraData","type":"bytes32","internalType":"bytes32"},{"name":"coinbase","type":"address","internalType":"address"},{"name":"daByteOffset","type":"uint24","internalType":"uint24"},{"name":"daByteSize","type":"uint24","internalType":"uint24"}]}]},{"name":"proof","type":"tuple","internalType":"struct GwynethData.Proof","components":[{"name":"proof","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"ultraHash","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"event","name":"BlockProposed","inputs":[{"name":"block","type":"tuple","indexed":false,"internalType":"struct GwynethData.UltraBlock","components":[{"name":"ultraHash","type":"bytes32","internalType":"bytes32"},{"name":"parentUltraHash","type":"bytes32","internalType":"bytes32"},{"name":"parentL1BlockHash","type":"bytes32","internalType":"bytes32"},{"name":"blobHashes","type":"bytes32[]","internalType":"bytes32[]"},{"name":"da","type":"bytes","internalType":"bytes"},{"name":"blocks","type":"tuple[]","internalType":"struct GwynethData.Block[]","components":[{"name":"l1Block","type":"tuple","internalType":"struct GwynethData.L1Block","components":[{"name":"transactions","type":"tuple[]","internalType":"struct GwynethData.Transaction[]","components":[{"name":"addr","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"},{"name":"value","type":"uint256","internalType":"uint256"},{"name":"gas","type":"uint64","internalType":"uint64"},{"name":"reverts","type":"bool","internalType":"bool"}]}]},{"name":"extraData","type":"bytes32","internalType":"bytes32"},{"name":"coinbase","type":"address","internalType":"address"},{"name":"daByteOffset","type":"uint24","internalType":"uint24"},{"name":"daByteSize","type":"uint24","internalType":"uint24"}]}]}],"anonymous":false},{"type":"event","name":"Executed","inputs":[{"name":"to","type":"address","indexed":false,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"data","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"success","type":"bool","indexed":false,"internalType":"bool"},{"name":"result","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false}],"bytecode":{"object":"0x60808060405234601557610892908161001a8239f35b5f80fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c80632c84a756146100595780632cc0b25414610054578063481ae5fd1461004f57638da5cb5b0361000e576101d7565b6100da565b610097565b34610075575f3660031901126100755760015460805260206080f35b5f80fd5b6001600160a01b0381160361007557565b359061009582610079565b565b34610075576040366003190112610075576004356100b481610079565b5f80546001600160a01b0319166001600160a01b03909216919091179055602435600155005b60403660031901126100755760043567ffffffffffffffff811161007557806004019060c060031982360301126100755760243567ffffffffffffffff8111610075576020906003199036030112610075575f1943014381116101c35761014790406044830135146101fe565b60a4015f5b6101568284610255565b9050811015610184578061017e6101796001936101738688610255565b9061028b565b610716565b0161014c565b7fc4f2c756af8a5b027f0424f7b381f73123ed66091049b15b9a68f34142bf5f456101be846101b281610838565b60405191829182610522565b0390a1005b634e487b7160e01b5f52601160045260245ffd5b34610075575f366003190112610075575f546040516001600160a01b039091168152602090f35b1561020557565b60405162461bcd60e51b815260206004820152602260248201527f696e636c7564656420696e20616e20756e6578706563746564204c3120626c6f604482015261636b60f01b6064820152608490fd5b903590601e1981360301821215610075570180359067ffffffffffffffff821161007557602001918160051b3603831361007557565b91908110156102ad5760051b81013590609e1981360301821215610075570190565b634e487b7160e01b5f52603260045260245ffd5b9035601e198236030181121561007557016020813591019167ffffffffffffffff8211610075578160051b3603831361007557565b9035601e198236030181121561007557016020813591019167ffffffffffffffff821161007557813603831361007557565b908060209392818452848401375f828201840152601f01601f1916010190565b67ffffffffffffffff81160361007557565b8015150361007557565b9035609e1982360301811215610075570190565b359062ffffff8216820361007557565b90602083828152019260208260051b82010193835f925b8484106103af5750505050505090565b909192939495601f198282030184526103c88784610364565b908135601e19833603018112156100755782019160a082526103ee60c0830193806102c1565b8094602060a08601525260e0830160e08560051b85010194825f5b828110610488575050505050600192610478602093608061046e818796878101358886015261044d61043d6040830161008a565b6001600160a01b03166040870152565b61046861045c60608301610378565b62ffffff166060870152565b01610378565b62ffffff16910152565b980194019401929493919061039f565b909192939660208060019260df198a82030188526104a68b87610364565b9081356104b281610079565b858060a01b031681526080806104dd6104cd868601866102f6565b60a08887015260a0860191610328565b936040810135604085015267ffffffffffffffff60608201356104ff81610348565b16606085015201356105108161035a565b15159101529901950193929101610409565b906020825280356020830152602081013560408301526040810135606083015261054f60608201826102c1565b60c0608085015260e0840181905292906001600160fb1b038411610075576105ad6105b8916105ca9560051b8091610100860137830161010061059560808701876102f6565b919092601f1982888303010160a08801520191610328565b9260a08101906102c1565b9160c0601f1982860301910152610388565b90565b903590601e1981360301821215610075570190565b356105ca81610079565b356105ca81610348565b903590601e1981360301821215610075570180359067ffffffffffffffff82116100755760200191813603831361007557565b908092918237015f815290565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761066c57604052565b610636565b3d156106ab573d9067ffffffffffffffff821161066c57604051916106a0601f8201601f19166020018461064a565b82523d5f602084013e565b606090565b9192602096939487956106dc9360018060a01b031685528685015260a0604085015260a0840191610328565b931515606082015260808185039101528051918291828552018484015e5f828201840152601f01601f1916010190565b356105ca8161035a565b5f5b61072b61072583806105cd565b80610255565b9050811015610834576107458161017361072585806105cd565b610760610754610754836105e2565b6001600160a01b031690565b9061080e61080a60806040840135937fec1e55ae257f05e243b15bcaab1eb0dfb16dfd00fe13e626673fe6d4f08371765f806107ae6107a1606086016105ec565b67ffffffffffffffff1690565b6020850199896107be8c886105f6565b92906107cf60405180958193610629565b0393f1956107db610671565b9761080189896107f46107ed886105e2565b94886105f6565b90604051968796876106b0565b0390a10161070c565b1590565b908161082b575b506108235750600101610718565b602081519101fd5b9050155f610815565b5050565b61084e6100959160405191829160208301610522565b0390601f198201815261064a56fea2646970667358221220dbb0c1dbde9201ef339c39c54ea40bdf6cdfe06d32ca2f14aee62353a9680a4464736f6c634300081c0033","sourceMap":"132:2092:1:-:0;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c80632c84a756146100595780632cc0b25414610054578063481ae5fd1461004f57638da5cb5b0361000e576101d7565b6100da565b610097565b34610075575f3660031901126100755760015460805260206080f35b5f80fd5b6001600160a01b0381160361007557565b359061009582610079565b565b34610075576040366003190112610075576004356100b481610079565b5f80546001600160a01b0319166001600160a01b03909216919091179055602435600155005b60403660031901126100755760043567ffffffffffffffff811161007557806004019060c060031982360301126100755760243567ffffffffffffffff8111610075576020906003199036030112610075575f1943014381116101c35761014790406044830135146101fe565b60a4015f5b6101568284610255565b9050811015610184578061017e6101796001936101738688610255565b9061028b565b610716565b0161014c565b7fc4f2c756af8a5b027f0424f7b381f73123ed66091049b15b9a68f34142bf5f456101be846101b281610838565b60405191829182610522565b0390a1005b634e487b7160e01b5f52601160045260245ffd5b34610075575f366003190112610075575f546040516001600160a01b039091168152602090f35b1561020557565b60405162461bcd60e51b815260206004820152602260248201527f696e636c7564656420696e20616e20756e6578706563746564204c3120626c6f604482015261636b60f01b6064820152608490fd5b903590601e1981360301821215610075570180359067ffffffffffffffff821161007557602001918160051b3603831361007557565b91908110156102ad5760051b81013590609e1981360301821215610075570190565b634e487b7160e01b5f52603260045260245ffd5b9035601e198236030181121561007557016020813591019167ffffffffffffffff8211610075578160051b3603831361007557565b9035601e198236030181121561007557016020813591019167ffffffffffffffff821161007557813603831361007557565b908060209392818452848401375f828201840152601f01601f1916010190565b67ffffffffffffffff81160361007557565b8015150361007557565b9035609e1982360301811215610075570190565b359062ffffff8216820361007557565b90602083828152019260208260051b82010193835f925b8484106103af5750505050505090565b909192939495601f198282030184526103c88784610364565b908135601e19833603018112156100755782019160a082526103ee60c0830193806102c1565b8094602060a08601525260e0830160e08560051b85010194825f5b828110610488575050505050600192610478602093608061046e818796878101358886015261044d61043d6040830161008a565b6001600160a01b03166040870152565b61046861045c60608301610378565b62ffffff166060870152565b01610378565b62ffffff16910152565b980194019401929493919061039f565b909192939660208060019260df198a82030188526104a68b87610364565b9081356104b281610079565b858060a01b031681526080806104dd6104cd868601866102f6565b60a08887015260a0860191610328565b936040810135604085015267ffffffffffffffff60608201356104ff81610348565b16606085015201356105108161035a565b15159101529901950193929101610409565b906020825280356020830152602081013560408301526040810135606083015261054f60608201826102c1565b60c0608085015260e0840181905292906001600160fb1b038411610075576105ad6105b8916105ca9560051b8091610100860137830161010061059560808701876102f6565b919092601f1982888303010160a08801520191610328565b9260a08101906102c1565b9160c0601f1982860301910152610388565b90565b903590601e1981360301821215610075570190565b356105ca81610079565b356105ca81610348565b903590601e1981360301821215610075570180359067ffffffffffffffff82116100755760200191813603831361007557565b908092918237015f815290565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761066c57604052565b610636565b3d156106ab573d9067ffffffffffffffff821161066c57604051916106a0601f8201601f19166020018461064a565b82523d5f602084013e565b606090565b9192602096939487956106dc9360018060a01b031685528685015260a0604085015260a0840191610328565b931515606082015260808185039101528051918291828552018484015e5f828201840152601f01601f1916010190565b356105ca8161035a565b5f5b61072b61072583806105cd565b80610255565b9050811015610834576107458161017361072585806105cd565b610760610754610754836105e2565b6001600160a01b031690565b9061080e61080a60806040840135937fec1e55ae257f05e243b15bcaab1eb0dfb16dfd00fe13e626673fe6d4f08371765f806107ae6107a1606086016105ec565b67ffffffffffffffff1690565b6020850199896107be8c886105f6565b92906107cf60405180958193610629565b0393f1956107db610671565b9761080189896107f46107ed886105e2565b94886105f6565b90604051968796876106b0565b0390a10161070c565b1590565b908161082b575b506108235750600101610718565b602081519101fd5b9050155f610815565b5050565b61084e6100959160405191829160208301610522565b0390601f198201815261064a56fea2646970667358221220dbb0c1dbde9201ef339c39c54ea40bdf6cdfe06d32ca2f14aee62353a9680a4464736f6c634300081c0033","sourceMap":"132:2092:1:-:0;;;;;;;;;-1:-1:-1;132:2092:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;-1:-1:-1;;132:2092:1;;;;267:24;132:2092;;;;;;;;;;;-1:-1:-1;;;;;132:2092:1;;;;;:::o;:::-;;;;;;:::i;:::-;:::o;:::-;;;;;;-1:-1:-1;;132:2092:1;;;;;;;;;:::i;:::-;-1:-1:-1;132:2092:1;;-1:-1:-1;;;;;;132:2092:1;-1:-1:-1;;;;;132:2092:1;;;;;;;;;;;;;;;;;-1:-1:-1;;132:2092:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1073:12;132:2092;1073:12;132:2092;;;;1027:102;1063:27;;1035:24;;;132:2092;1035:55;1027:102;:::i;:::-;1161:13;;-1:-1:-1;1183:3:1;1161:13;;;;:::i;:::-;1157:24;;;;;;;1211:13;:16;;132:2092;1211:13;;;;;:::i;:::-;:16;;:::i;:::-;;:::i;:::-;132:2092;1145:10;;1157:24;1285:32;;1157:24;1211:16;;;:::i;:::-;132:2092;;1285:32;;;;;:::i;:::-;;;;132:2092;;;;;-1:-1:-1;132:2092:1;;;;;-1:-1:-1;132:2092:1;;;;;;;-1:-1:-1;;132:2092:1;;;;;;;;-1:-1:-1;;;;;132:2092:1;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;132:2092:1;;;;;;;;;;;;;;;;;-1:-1:-1;;;132:2092:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;132:2092:1;;;;;;;;-1:-1:-1;;132:2092:1;;;;:::o;:::-;;;;;;;:::o;:::-;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;132:2092:1;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;132:2092:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;132:2092:1;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;;;;;132:2092:1;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;132:2092:1;;;;;:::i;:::-;;;;-1:-1:-1;132:2092:1;;;;:::o;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;132:2092:1;;;;:::o;:::-;;;;;:::i;1330:634::-;1461:1;1504:3;1468:27;:14;;;;:::i;:::-;:27;;:::i;:::-;1464:38;;;;;;;1562:30;:14;:27;:14;;;;:::i;:30::-;1645:22;:17;1653:8;;;:::i;:::-;-1:-1:-1;;;;;132:2092:1;;;1645:22;1675:9;1803:12;1804:11;;1675:9;;;132:2092;1691:7;1728:56;1461:1;1691:7;1645:54;1691:7;;;;;:::i;:::-;132:2092;;;;1645:54;1700:8;;;;;;;;;:::i;:::-;132:2092;;;1675:9;132:2092;;;;;;:::i;:::-;1645:64;;;;;;:::i;:::-;1737:8;1728:56;1737:8;;1758;1737;;;:::i;:::-;1758;;;:::i;:::-;132:2092;1675:9;132:2092;1728:56;;;;;:::i;:::-;;;;1804:11;;:::i;:::-;1803:12;;132:2092;1803:12;:24;;;;1504:3;1799:149;;;1504:3;132:2092;;1452:10;;1799:149;1700:8;1847:87;;;;;1803:24;1819:8;;;1803:24;;;1464:38;;;1330:634::o;1970:178::-;2120:18;;1970:178;132:2092;;2120:18;;;;;;;:::i;:::-;;132:2092;;;2120:18;;;;;:::i","linkReferences":{}},"methodIdentifiers":{"init(address,bytes32)":"2cc0b254","owner()":"8da5cb5b","propose((bytes32,bytes32,bytes32,bytes32[],bytes,(((address,bytes,uint256,uint64,bool)[]),bytes32,address,uint24,uint24)[]),(bytes))":"481ae5fd","ultraHash()":"2c84a756"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"ultraHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"parentUltraHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"parentL1BlockHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"blobHashes\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"da\",\"type\":\"bytes\"},{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"gas\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"reverts\",\"type\":\"bool\"}],\"internalType\":\"struct GwynethData.Transaction[]\",\"name\":\"transactions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GwynethData.L1Block\",\"name\":\"l1Block\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"extraData\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"daByteOffset\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"daByteSize\",\"type\":\"uint24\"}],\"internalType\":\"struct GwynethData.Block[]\",\"name\":\"blocks\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"struct GwynethData.UltraBlock\",\"name\":\"block\",\"type\":\"tuple\"}],\"name\":\"BlockProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"result\",\"type\":\"bytes\"}],\"name\":\"Executed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"_genesisUltraHash\",\"type\":\"bytes32\"}],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"ultraHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"parentUltraHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"parentL1BlockHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"blobHashes\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"da\",\"type\":\"bytes\"},{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"gas\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"reverts\",\"type\":\"bool\"}],\"internalType\":\"struct GwynethData.Transaction[]\",\"name\":\"transactions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GwynethData.L1Block\",\"name\":\"l1Block\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"extraData\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"daByteOffset\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"daByteSize\",\"type\":\"uint24\"}],\"internalType\":\"struct GwynethData.Block[]\",\"name\":\"blocks\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GwynethData.UltraBlock\",\"name\":\"_block\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"internalType\":\"struct GwynethData.Proof\",\"name\":\"proof\",\"type\":\"tuple\"}],\"name\":\"propose\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ultraHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"events\":{\"BlockProposed((bytes32,bytes32,bytes32,bytes32[],bytes,(((address,bytes,uint256,uint64,bool)[]),bytes32,address,uint24,uint24)[]))\":{\"details\":\"Emitted when a block is proposed.\",\"params\":{\"block\":\"The block metadata containing information about the proposed block.\"}}},\"kind\":\"dev\",\"methods\":{\"init(address,bytes32)\":{\"params\":{\"_genesisUltraHash\":\"The hash of the genesis ultra block.\"}}},\"title\":\"Gwyneth\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"init(address,bytes32)\":{\"notice\":\"Initializes the rollup.\"},\"propose((bytes32,bytes32,bytes32,bytes32[],bytes,(((address,bytes,uint256,uint64,bool)[]),bytes32,address,uint24,uint24)[]),(bytes))\":{\"notice\":\"Proposes a Gwyneth block\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/L1/Gwyneth.sol\":\"Gwyneth\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/\",\":@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/\",\":ds-test/=node_modules/ds-test/src/\",\":forge-std/=node_modules/forge-std/src/\",\":p256-verifier/=node_modules/p256-verifier/\",\":solady/=node_modules/solady/\",\":solmate/=node_modules/solmate/src/\"],\"viaIR\":true},\"sources\":{\"contracts/L1/Gwyneth.sol\":{\"keccak256\":\"0xabaf9c45aa52222f6738d8511fd18f112126e2cd4ed2cc2367b6ffa3a8758ddd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5b7ee1986c29a1ee88d0a4c4d26fa9286a42a44c8622794ad0ad59913e450e08\",\"dweb:/ipfs/QmenQ1EsG4cCKBHZaGVXpDqNqKP2ZXmFEfJstsdQhrrTdU\"]},\"contracts/L1/GwynethData.sol\":{\"keccak256\":\"0x97984ae4f0a61f69204ad234b11f69a6d684929e87e83455dd9aab7e9762f16d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4d2a68be4a86a813993d4608d2719f55b6c824237502fa6765d9bceb4238ced0\",\"dweb:/ipfs/QmfUcFAQHxyHkFaQpM86zQ24Pndef88zhdsAEruaMV8AZw\"]},\"contracts/L1/IGwyneth.sol\":{\"keccak256\":\"0x2c444de0c6a366ac473e3405705e4242c59f35ad0e7b702ec786048f13dd5b4e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2d152c7c4c06a742f1a6fd61d488a6da80d300160c29e860dd46b7557870380\",\"dweb:/ipfs/QmQSu4byXSBtTBZBCyVqKjsT6Ean213ZTQ3zcSKsxZftR3\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.28+commit.7893614a"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"struct GwynethData.UltraBlock","name":"block","type":"tuple","components":[{"internalType":"bytes32","name":"ultraHash","type":"bytes32"},{"internalType":"bytes32","name":"parentUltraHash","type":"bytes32"},{"internalType":"bytes32","name":"parentL1BlockHash","type":"bytes32"},{"internalType":"bytes32[]","name":"blobHashes","type":"bytes32[]"},{"internalType":"bytes","name":"da","type":"bytes"},{"internalType":"struct GwynethData.Block[]","name":"blocks","type":"tuple[]","components":[{"internalType":"struct GwynethData.L1Block","name":"l1Block","type":"tuple","components":[{"internalType":"struct GwynethData.Transaction[]","name":"transactions","type":"tuple[]","components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint64","name":"gas","type":"uint64"},{"internalType":"bool","name":"reverts","type":"bool"}]}]},{"internalType":"bytes32","name":"extraData","type":"bytes32"},{"internalType":"address","name":"coinbase","type":"address"},{"internalType":"uint24","name":"daByteOffset","type":"uint24"},{"internalType":"uint24","name":"daByteSize","type":"uint24"}]}],"indexed":false}],"type":"event","name":"BlockProposed","anonymous":false},{"inputs":[{"internalType":"address","name":"to","type":"address","indexed":false},{"internalType":"uint256","name":"value","type":"uint256","indexed":false},{"internalType":"bytes","name":"data","type":"bytes","indexed":false},{"internalType":"bool","name":"success","type":"bool","indexed":false},{"internalType":"bytes","name":"result","type":"bytes","indexed":false}],"type":"event","name":"Executed","anonymous":false},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"bytes32","name":"_genesisUltraHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"function","name":"init"},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"struct GwynethData.UltraBlock","name":"_block","type":"tuple","components":[{"internalType":"bytes32","name":"ultraHash","type":"bytes32"},{"internalType":"bytes32","name":"parentUltraHash","type":"bytes32"},{"internalType":"bytes32","name":"parentL1BlockHash","type":"bytes32"},{"internalType":"bytes32[]","name":"blobHashes","type":"bytes32[]"},{"internalType":"bytes","name":"da","type":"bytes"},{"internalType":"struct GwynethData.Block[]","name":"blocks","type":"tuple[]","components":[{"internalType":"struct GwynethData.L1Block","name":"l1Block","type":"tuple","components":[{"internalType":"struct GwynethData.Transaction[]","name":"transactions","type":"tuple[]","components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint64","name":"gas","type":"uint64"},{"internalType":"bool","name":"reverts","type":"bool"}]}]},{"internalType":"bytes32","name":"extraData","type":"bytes32"},{"internalType":"address","name":"coinbase","type":"address"},{"internalType":"uint24","name":"daByteOffset","type":"uint24"},{"internalType":"uint24","name":"daByteSize","type":"uint24"}]}]},{"internalType":"struct GwynethData.Proof","name":"proof","type":"tuple","components":[{"internalType":"bytes","name":"proof","type":"bytes"}]}],"stateMutability":"payable","type":"function","name":"propose"},{"inputs":[],"stateMutability":"view","type":"function","name":"ultraHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"payable","type":"receive"}],"devdoc":{"kind":"dev","methods":{"init(address,bytes32)":{"params":{"_genesisUltraHash":"The hash of the genesis ultra block."}}},"version":1},"userdoc":{"kind":"user","methods":{"init(address,bytes32)":{"notice":"Initializes the rollup."},"propose((bytes32,bytes32,bytes32,bytes32[],bytes,(((address,bytes,uint256,uint64,bool)[]),bytes32,address,uint24,uint24)[]),(bytes))":{"notice":"Proposes a Gwyneth block"}},"version":1}},"settings":{"remappings":["@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/","@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/","ds-test/=node_modules/ds-test/src/","forge-std/=node_modules/forge-std/src/","p256-verifier/=node_modules/p256-verifier/","solady/=node_modules/solady/","solmate/=node_modules/solmate/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"contracts/L1/Gwyneth.sol":"Gwyneth"},"evmVersion":"cancun","libraries":{},"viaIR":true},"sources":{"contracts/L1/Gwyneth.sol":{"keccak256":"0xabaf9c45aa52222f6738d8511fd18f112126e2cd4ed2cc2367b6ffa3a8758ddd","urls":["bzz-raw://5b7ee1986c29a1ee88d0a4c4d26fa9286a42a44c8622794ad0ad59913e450e08","dweb:/ipfs/QmenQ1EsG4cCKBHZaGVXpDqNqKP2ZXmFEfJstsdQhrrTdU"],"license":"MIT"},"contracts/L1/GwynethData.sol":{"keccak256":"0x97984ae4f0a61f69204ad234b11f69a6d684929e87e83455dd9aab7e9762f16d","urls":["bzz-raw://4d2a68be4a86a813993d4608d2719f55b6c824237502fa6765d9bceb4238ced0","dweb:/ipfs/QmfUcFAQHxyHkFaQpM86zQ24Pndef88zhdsAEruaMV8AZw"],"license":"MIT"},"contracts/L1/IGwyneth.sol":{"keccak256":"0x2c444de0c6a366ac473e3405705e4242c59f35ad0e7b702ec786048f13dd5b4e","urls":["bzz-raw://b2d152c7c4c06a742f1a6fd61d488a6da80d300160c29e860dd46b7557870380","dweb:/ipfs/QmQSu4byXSBtTBZBCyVqKjsT6Ean213ZTQ3zcSKsxZftR3"],"license":"MIT"}},"version":1},"id":1} \ No newline at end of file diff --git a/crates/gwyneth/src/builder.rs b/crates/gwyneth/src/builder.rs new file mode 100644 index 000000000000..e52a72158b46 --- /dev/null +++ b/crates/gwyneth/src/builder.rs @@ -0,0 +1,397 @@ +//! A basic Ethereum payload builder implementation. + +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![allow(clippy::useless_let_if_seq)] + +use std::collections::HashMap; + +use reth_basic_payload_builder::{ + commit_withdrawals, is_better_payload, BuildArguments, BuildOutcome, PayloadConfig, + WithdrawalsOutcome, +}; +use reth_errors::RethError; +use reth_evm::{ + execute::BlockExecutionOutput, + system_calls::{ + post_block_withdrawal_requests_contract_call, pre_block_beacon_root_contract_call, + pre_block_blockhashes_contract_call, + }, + ConfigureEvm, +}; +use reth_evm_ethereum::eip6110::parse_deposits_from_receipts; +use reth_execution_types::ExecutionOutcome; +use reth_payload_builder::{ + database::{to_sync_cached_reads, CachedReads, SyncCachedReads}, + error::PayloadBuilderError, + EthBuiltPayload, +}; +use reth_primitives::{ + constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, eip4844::calculate_excess_blob_gas, hex, proofs::{self, calculate_requests_root}, Block, BlockNumber, ChainId, EthereumHardforks, Header, Receipt, Receipts, Requests, StateDiff, StateDiffAccount, StateDiffStorageSlot, TransactionSigned, Withdrawals, B256, EMPTY_OMMER_ROOT_HASH, U256 +}; +use reth_provider::{state_diff_to_block_execution_output, StateProvider, StateProviderFactory}; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; +use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; +use reth_trie::HashedPostState; +use revm::{ + db::{states::bundle_state::BundleRetention, BundleAccount, BundleState, State}, + primitives::{EVMError, EnvWithHandlerCfg, ResultAndState}, + DatabaseCommit, SyncDatabase, +}; +use tracing::{debug, trace, warn}; + +use reth_revm::primitives::ChainAddress; +use reth_revm::db::AccountStatus; +use reth_revm::db::states::StorageSlot; + +use reth_execution_types::execution_outcome_to_state_diff; + +use reth_primitives::alloy_primitives::Bytes; + +use crate::GwynethPayloadBuilderAttributes; + +/// Constructs an Ethereum transaction payload using the best transactions from the pool. +/// +/// Given build arguments including an Ethereum client, transaction pool, +/// and configuration, this function creates a transaction payload. Returns +/// a result indicating success with the payload or an error in case of failure. +#[inline] +pub fn default_gwyneth_payload_builder( + evm_config: EvmConfig, + args: BuildArguments< + Pool, + Client, + GwynethPayloadBuilderAttributes, + EthBuiltPayload, + >, +) -> Result, PayloadBuilderError> +where + EvmConfig: ConfigureEvm, + Client: StateProviderFactory, + Pool: TransactionPool, + SyncProvider: StateProvider, +{ + let BuildArguments { client, pool, mut cached_reads, config, cancel, best_payload } = args; + let PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + attributes, + chain_spec, + extra_data, + .. + } = config; + + println!("[{}] Build", chain_spec.chain().id()); + + let state_provider = client.state_by_block_hash(parent_block.hash())?; + let state = StateProviderDatabase::new(state_provider); + let mut sync_state = SyncStateProviderDatabase::new(Some(chain_spec.chain().id()), state); + + // Add all external state dependencies + for (&chain_id, provider) in attributes.providers.iter() { + //println!("Adding db for chain_id: {}", chain_id); + let boxed: Box = Box::new(provider); + let state_provider = StateProviderDatabase::new(boxed); + sync_state.add_db(chain_id, state_provider); + } + + let mut sync_cached_reads = to_sync_cached_reads(cached_reads, chain_spec.chain.id()); + let mut sync_db = State::builder() + .with_database_ref(sync_cached_reads.as_db(sync_state)) + .with_bundle_update() + .build(); + + debug!(target: "payload_builder", id=%attributes.inner.id, parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); + let mut cumulative_gas_used = 0; + let mut sum_blob_gas_used = 0; + let block_gas_limit: u64 = + initialized_block_env.gas_limit.try_into().unwrap_or(chain_spec.max_gas_limit); + let base_fee = initialized_block_env.basefee.to::(); + + //let mut executed_txs: Vec = Vec::new(); + + // let mut best_txs = pool.best_transactions_with_attributes(BestTransactionsAttributes::new( + // base_fee, + // initialized_block_env.get_blob_gasprice().map(|gasprice| gasprice as u64), + // )); + + let mut total_fees = U256::ZERO; + + let block_number = initialized_block_env.number.to::(); + + // apply eip-4788 pre block contract call + // pre_block_beacon_root_contract_call( + // &mut sync_db, + // &evm_config, + // &chain_spec, + // &initialized_cfg, + // &initialized_block_env, + // attributes.inner.parent_beacon_block_root, + // ) + // .map_err(|err| { + // warn!(target: "payload_builder", + // parent_hash=%parent_block.hash(), + // %err, + // "failed to apply beacon root contract call for empty payload" + // ); + // PayloadBuilderError::Internal(err.into()) + // })?; + + // // apply eip-2935 blockhashes update + // pre_block_blockhashes_contract_call( + // &mut sync_db, + // &evm_config, + // &chain_spec, + // &initialized_cfg, + // &initialized_block_env, + // parent_block.hash(), + // ) + // .map_err(|err| { + // warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to update blockhashes for empty payload"); + // PayloadBuilderError::Internal(err.into()) + // })?; + + // let mut receipts = Vec::new(); + // for tx in &attributes.transactions { + // // // ensure we still have capacity for this transaction + // // if cumulative_gas_used + tx.gas_limit() > block_gas_limit { + // // // we can't fit this transaction into the block, so we need to mark it as invalid + // // // which also removes all dependent transaction from the iterator before we can + // // // continue + // // best_txs.mark_invalid(&tx); + // // continue + // // } + + // // Check if the job was cancelled, if so we can exit early. + // if cancel.is_cancelled() { + // return Ok(BuildOutcome::Cancelled) + // } + + // let tx = tx.clone().1.try_into_ecrecovered().unwrap(); + + // // // There's only limited amount of blob space available per block, so we need to check if + // // // the EIP-4844 can still fit in the block + // // if let Some(blob_tx) = tx.transaction.as_eip4844() { + // // let tx_blob_gas = blob_tx.blob_gas(); + // // if sum_blob_gas_used + tx_blob_gas > MAX_DATA_GAS_PER_BLOCK { + // // // we can't fit this _blob_ transaction into the block, so we mark it as + // // // invalid, which removes its dependent transactions from + // // // the iterator. This is similar to the gas limit condition + // // // for regular transactions above. + // // trace!(target: "payload_builder", tx=?tx.hash, ?sum_blob_gas_used, ?tx_blob_gas, + // // "skipping blob transaction because it would exceed the max data gas per block"); + // // best_txs.mark_invalid(&tx); + // // continue + // // } + // // } + + // let env = EnvWithHandlerCfg::new_with_cfg_env( + // initialized_cfg.clone(), + // initialized_block_env.clone(), + // evm_config.tx_env(&tx), + // ); + + // // Configure the environment for the block. + // let mut evm = evm_config.evm_with_env(&mut sync_db, env); + + // let ResultAndState { result, state } = match evm.transact() { + // Ok(res) => res, + // Err(err) => { + // match err { + // EVMError::Transaction(err) => { + // println!("build tx error: {:?}", err); + // trace!(target: "payload_builder", %err, ?tx, "Error in sequencer transaction, skipping."); + // continue + // } + // err => { + // println!("build tx error fatal: {:?}", err); + // // this is an error that we should treat as fatal for this attempt + // //return Err(PayloadBuilderError::EvmExecutionError(err)) + // continue + // } + // } + // } + // }; + // // drop evm so db is released. + // drop(evm); + // // commit changes + // sync_db.commit(state); + + // // add to the total blob gas used if the transaction successfully executed + // if let Some(blob_tx) = tx.transaction.as_eip4844() { + // let tx_blob_gas = blob_tx.blob_gas(); + // sum_blob_gas_used += tx_blob_gas; + + // // if we've reached the max data gas per block, we can skip blob txs entirely + // if sum_blob_gas_used == MAX_DATA_GAS_PER_BLOCK { + // best_txs.skip_blobs(); + // } + // } + + // let gas_used = result.gas_used(); + + // // add gas used by the transaction to cumulative gas used, before creating the receipt + // cumulative_gas_used += gas_used; + + // // Push transaction changeset and calculate header bloom filter for receipt. + // #[allow(clippy::needless_update)] // side-effect of optimism fields + // receipts.push(Some(Receipt { + // tx_type: tx.tx_type(), + // success: result.is_success(), + // cumulative_gas_used, + // logs: result.into_logs().into_iter().map(Into::into).collect(), + // ..Default::default() + // })); + + // // update add to total fees + // let miner_fee = tx + // .effective_tip_per_gas(Some(base_fee)) + // .expect("fee is always valid; execution succeeded"); + // total_fees += U256::from(miner_fee) * U256::from(gas_used); + + // // append transaction to the list of executed transactions + // executed_txs.push(tx.into_signed()); + // } + + //println!("{} - Build: {:?}", chain_spec.chain().id(), executed_txs); + + total_fees = U256::from(1u64); + + // check if we have a better block + if !is_better_payload(best_payload.as_ref(), total_fees) { + // can skip building the block + return Ok(BuildOutcome::Aborted { + fees: total_fees, + cached_reads: sync_cached_reads.into(), + }) + } + + // merge all transitions into bundle state, this would apply the withdrawal balance changes + // and 4788 contract call + //sync_db.merge_transitions(BundleRetention::PlainState); + + // let execution_outcome = ExecutionOutcome::new( + // Some(chain_spec.chain().id()), + // sync_db.take_bundle(), + // vec![receipts].into(), + // block_number, + // vec![Requests::default()], + // ) + // .filter_current_chain(); + + let execution_outcome = ExecutionOutcome::new( + chain_spec.chain().id(), + attributes.chain_da.state_diff.clone().unwrap().bundle.clone(), + vec![attributes.chain_da.state_diff.clone().unwrap().receipts.iter().map(|r| Some(r.clone())).collect::>()].into(), + block_number, + vec![Requests::default()], + ) + .filter_current_chain(); + + let receipts_root = + execution_outcome.receipts_root_slow(block_number).expect("Number is in range"); + let logs_bloom = execution_outcome.block_logs_bloom(block_number).expect("Number is in range"); + + // calculate the state root + let state_root = { + let state_provider = sync_db.database.0.inner.borrow_mut(); + state_provider.db.get_db(chain_spec.chain().id()).unwrap().state_root( + HashedPostState::from_bundle_state(&execution_outcome.current_state().state), + )? + }; + + //let state_diff = execution_outcome_to_state_diff(&execution_outcome, state_root, cumulative_gas_used); + + let state_diff = attributes.chain_da.state_diff.clone().unwrap(); + + assert!(state_diff.bundle.reverts.len() <= 1, "reverts need to be per block"); + + // let execution_output_state_diff = state_diff_to_block_execution_output(chain_spec.chain().id(), &attributes.chain_da.state_diff.unwrap()); + // let state_root_2 = { + // let state_provider = sync_db.database.0.inner.borrow_mut(); + // state_provider.db.get_db(chain_spec.chain().id()).unwrap().state_root( + // HashedPostState::from_bundle_state(&execution_outcome.current_state().state), + // )? + // }; + + // let state_root_2 = ParallelStateRoot::new(consistent_view, hashed_state) + // .incremental_root_with_updates() + // .map(|(root, updates)| (root, Some(updates))) + // .map_err(ProviderError::from)?; + + let executed_txs = attributes.transactions.iter().cloned().map(|tx| tx.1.try_into_ecrecovered().unwrap().into_signed()).collect::>(); + + // create the block header + //let transactions_root = proofs::calculate_transaction_root(&executed_txs); + + // Put the state diff into the extra bytes of the block + //let extra_data = Bytes::from(serde_json::to_string(&state_diff).unwrap().into_bytes()); + //let extra_data = Bytes::from(bincode::serialize(&state_diff).unwrap()); + + let header = Header { + parent_hash: parent_block.hash(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: initialized_block_env.coinbase.1, + state_root: state_diff.state_root, + transactions_root: state_diff.transactions_root, + receipts_root, + withdrawals_root: Some(B256::from(hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"))), + logs_bloom, + timestamp: attributes.inner.timestamp, + mix_hash: attributes.inner.prev_randao, + nonce: BEACON_NONCE, + base_fee_per_gas: Some(base_fee), + number: parent_block.number + 1, + gas_limit: block_gas_limit, + difficulty: U256::ZERO, + //gas_used: cumulative_gas_used, + gas_used: state_diff.gas_used, + extra_data: attributes.chain_da.extra_data.clone(), + parent_beacon_block_root: attributes.inner.parent_beacon_block_root, + blob_gas_used: Some(0), + excess_blob_gas: Some(0), + requests_root: None, + }; + + //println!("header: {:?}", header); + + //println!("[{}-{}] receipts: {:?}", chain_spec.chain().id(), header.number, state_diff.receipts); + + //println!("extra_data: {}", attributes.chain_da.extra_data); + + if state_diff.state_root != state_root { + println!("State root mismatch! {} {}", state_diff.state_root, state_root); + } + + //println!("reverts: {:?}", state_diff.bundle.reverts); + + // seal the block + let block = Block { header, body: executed_txs, ommers: vec![], withdrawals: Some(Withdrawals::default()), requests: Some(Requests::default()) }; + + let sealed_block = block.seal_slow(); + //sealed_block.state_diff = Some(execution_outcome_to_state_diff(&execution_outcome)); + + //println!("block hash: {:?}", sealed_block.hash()); + + //println!("[{}] execution outcome: {:?}", chain_spec.chain.id(), execution_outcome); + + //assert_eq!(state_diff, attributes.chain_da.state_diff.unwrap()); + + debug!(target: "payload_builder", ?sealed_block, "sealed built block"); + + let payload = EthBuiltPayload::new(attributes.inner.id, sealed_block, total_fees); + + Ok(BuildOutcome::Better { payload, cached_reads: /*sync_cached_reads.into())*/ CachedReads::default() }) +} + +pub fn build_execution_outcome( + sync_db: &mut State, + receipts: Receipts, + first_block: BlockNumber, + requests: Vec, +) -> HashMap { + let bundle_states = sync_db.take_bundle(); + + todo!() +} diff --git a/crates/gwyneth/src/engine_api.rs b/crates/gwyneth/src/engine_api.rs new file mode 100644 index 000000000000..e37266cbedde --- /dev/null +++ b/crates/gwyneth/src/engine_api.rs @@ -0,0 +1,159 @@ +use jsonrpsee::{ + core::client::ClientT, + http_client::{transport::HttpBackend, HttpClient}, +}; +use reth_ethereum_engine_primitives::ExecutionPayloadEnvelopeV3; +use reth_node_api::{EngineTypes}; +use reth_node_core::args::RpcServerArgs; +use reth_payload_builder::PayloadId; +use reth_primitives::B256; +use reth_provider::CanonStateNotificationStream; +use reth_rpc_api::EngineApiClient; +use reth_rpc_layer::AuthClientService; +use reth_rpc_types::{ + engine::{ForkchoiceState, ForkchoiceUpdated, PayloadStatusEnum}, BlockNumberOrTag, ExecutionPayloadV3 +}; +use tracing::error; +use std::{marker::PhantomData, net::Ipv4Addr}; +use reth_rpc_builder::constants; + +use crate::exex::BASE_CHAIN_ID; + +/// Helper for engine api operations +pub struct EngineApiContext { + pub canonical_stream: CanonStateNotificationStream, + pub engine_api_client: HttpClient>, + pub _marker: PhantomData, +} + +impl EngineApiContext { + /// Retrieves a v3 payload from the engine api + pub async fn get_payload_v3( + &self, + payload_id: PayloadId, + ) -> eyre::Result { + Ok(EngineApiClient::::get_payload_v3(&self.engine_api_client, payload_id).await?) + } + + /// Retrieves a v3 payload from the engine api as serde value + pub async fn get_payload_v3_value( + &self, + payload_id: PayloadId, + ) -> eyre::Result { + Ok(self.engine_api_client.request("engine_getPayloadV3", (payload_id,)).await?) + } + + /// Submits a payload to the engine api + pub async fn submit_payload( + &self, + payload: E::BuiltPayload, + parent_beacon_block_root: B256, + expected_status: PayloadStatusEnum, + versioned_hashes: Vec, + ) -> eyre::Result + where + E::ExecutionPayloadV3: From + PayloadEnvelopeExt, + { + // setup payload for submission + let envelope_v3: ::ExecutionPayloadV3 = payload.into(); + + // submit payload to engine api + let submission = EngineApiClient::::new_payload_v3( + &self.engine_api_client, + envelope_v3.execution_payload(), + versioned_hashes, + parent_beacon_block_root, + ) + .await?; + + assert_eq!(submission.status, expected_status); + + Ok(submission.latest_valid_hash.unwrap_or_default()) + } + + /// Sends forkchoice update to the engine api + pub async fn update_forkchoice(&self, finalized_head: B256, new_head: B256) -> eyre::Result<()> { + let fork_choice_state = ForkchoiceState { + head_block_hash: new_head, + safe_block_hash: finalized_head, + finalized_block_hash: finalized_head, + }; + self.fork_choice_updated_v3_wait(fork_choice_state).await + } + + async fn fork_choice_updated_v3_wait( + &self, + fork_choice_state: ForkchoiceState, + ) -> eyre::Result<()> { + println!("fork choice: {:?}", fork_choice_state); + let mut status = + EngineApiClient::::fork_choice_updated_v3( + &self.engine_api_client, + fork_choice_state, + None, + ) + .await?; + + while !status.is_valid() { + if status.is_invalid() { + println!("Invalid forkchoiceUpdatedV3: {status:?}"); + } + status = + EngineApiClient::::fork_choice_updated_v3( + &self.engine_api_client, + fork_choice_state, + None, + ) + .await?; + } + Ok(()) + } + + /// Sends forkchoice update to the engine api with a zero finalized hash + pub async fn update_optimistic_forkchoice(&self, hash: B256) -> eyre::Result<()> { + EngineApiClient::::fork_choice_updated_v3( + &self.engine_api_client, + ForkchoiceState { + head_block_hash: hash, + safe_block_hash: B256::ZERO, + finalized_block_hash: B256::ZERO, + }, + None, + ) + .await?; + + Ok(()) + } +} + +/// The execution payload envelope type. +pub trait PayloadEnvelopeExt: Send + Sync + std::fmt::Debug { + /// Returns the execution payload V3 from the payload + fn execution_payload(&self) -> ExecutionPayloadV3; +} + +impl PayloadEnvelopeExt for ExecutionPayloadEnvelopeV3 { + fn execution_payload(&self) -> ExecutionPayloadV3 { + self.execution_payload.clone() + } +} +pub trait RpcServerArgsExEx { + fn with_static_l2_rpc_ip_and_port(self, chain_id: u64) -> Self; +} + +impl RpcServerArgsExEx for RpcServerArgs { + fn with_static_l2_rpc_ip_and_port(mut self, chain_id: u64) -> Self { + self.http = true; + self.http_addr = Ipv4Addr::new(0, 0, 0, 0).into(); + + // Calculate HTTP and WS ports based on chain_id + let port_offset = (chain_id - BASE_CHAIN_ID) as u16; + self.http_port = 10110 + (port_offset * 100); + self.ws_port = 10111 + (port_offset * 100); + + // Set IPC path + self.ipcpath = format!("{}-{}", constants::DEFAULT_IPC_ENDPOINT, chain_id); + + self + } +} diff --git a/crates/gwyneth/src/exex.rs b/crates/gwyneth/src/exex.rs new file mode 100644 index 000000000000..fe81b21a369a --- /dev/null +++ b/crates/gwyneth/src/exex.rs @@ -0,0 +1,484 @@ +use std::{collections::{HashMap, VecDeque}, marker::PhantomData, sync::Arc}; +use alloy_consensus::{Blob, SidecarCoder, SimpleCoder, Transaction}; +use alloy_rlp::Decodable; +use alloy_sol_types::{sol, SolEventInterface}; +use alloy_eips::eip4844::kzg_to_versioned_hash; +use alloy_primitives::{address, b256}; +use reth_network::NetworkInfo; +use reth_rpc_api::eth::helpers::EthApiSpec; +use crate::{ + engine_api::EngineApiContext, GwynethEngineTypes, GwynethNode, GwynethPayloadAttributes, + GwynethPayloadBuilderAttributes, +}; +use reth_consensus::Consensus; +use reth_db::{test_utils::TempDatabase, DatabaseEnv}; +use reth_ethereum_engine_primitives::EthPayloadAttributes; +use reth_evm_ethereum::EthEvmConfig; +use reth_execution_types::Chain; +use reth_exex::{ExExContext, ExExEvent}; +use reth_node_api::{FullNodeTypesAdapter, PayloadBuilderAttributes}; +use reth_node_builder::{components::Components, FullNode, Node, NodeAdapter}; +use reth_node_ethereum::{node::EthereumAddOns, EthExecutorProvider}; +use reth_payload_builder::EthBuiltPayload; +use reth_primitives::{ + Address, Bytes, ChainDA, GwynethDA, SealedBlock, SealedBlockWithSenders, StateDiff, TransactionSigned, B256, U256 +}; +use reth_provider::{ + providers::BlockchainProvider, BlockNumReader, CanonStateSubscriptions, DatabaseProviderFactory, +}; +use reth_rpc_types::{engine::PayloadStatusEnum, BlockNumberOrTag}; +use reth_transaction_pool::{ + blobstore::DiskFileBlobStore, CoinbaseTipOrdering, EthPooledTransaction, + EthTransactionValidator, Pool, TransactionValidationTaskExecutor, TransactionPool, +}; +use RollupContract::{BlockProposed, RollupContractEvents}; +use reth_provider::BlockReaderIdExt; +use reth_provider::{GWYNETH_SYNCED_L1_BLOCK_IDX, GWYNETH_SYNCED_L2_BLOCK_IDX}; + +const ROLLUP_CONTRACT_ADDRESS: Address = address!("9fCF7D13d10dEdF17d0f24C62f0cf4ED462f65b7"); +pub const BASE_CHAIN_ID: u64 = 167010; +const FINALIZATION_PERIOD: u64 = 64; +const GENESIS_HASH: B256 = b256!("930c04603408ca90f730fb9ad792af0d42bd01db97633df8f9f58330cf103b0c"); + +pub type GwynethFullNode = FullNode< + NodeAdapter< + FullNodeTypesAdapter< + GwynethNode, + Arc, + BlockchainProvider>, + >, + Components< + FullNodeTypesAdapter< + GwynethNode, + Arc, + BlockchainProvider>, + >, + Pool< + TransactionValidationTaskExecutor< + EthTransactionValidator< + BlockchainProvider>, + EthPooledTransaction, + >, + >, + CoinbaseTipOrdering, + DiskFileBlobStore, + >, + EthEvmConfig, + EthExecutorProvider, + Arc, + >, + >, + EthereumAddOns, +>; + +sol!(RollupContract, "Gwyneth.json"); + +pub struct Rollup { + ctx: ExExContext, + nodes: Vec, + engine_apis: Vec>, + l1_to_l2: HashMap>, + l1_finalized_block: u64, +} + +impl Rollup { + pub async fn new(ctx: ExExContext, nodes: Vec) -> eyre::Result { + let mut engine_apis = Vec::new(); + let mut l2_block_info = HashMap::new(); + for node in &nodes { + let engine_api = EngineApiContext { + engine_api_client: node.auth_server_handle().http_client(), + canonical_stream: node.provider.canonical_state_stream(), + _marker: PhantomData::, + }; + engine_apis.push(engine_api); + + let chain_id = node.chain_spec().chain().id(); + + let mut l2_block_indices = GWYNETH_SYNCED_L2_BLOCK_IDX.lock().unwrap(); + l2_block_indices.insert(chain_id, 0); + + l2_block_info.insert(chain_id, (0u64, GENESIS_HASH)); + } + + let l1_finalized_block = ctx.head.number; + let mut l1_to_l2 = HashMap::new(); + l1_to_l2.insert(l1_finalized_block, l2_block_info); + + Ok(Self { + ctx, + nodes, + engine_apis, + l1_to_l2, + l1_finalized_block, + }) + } + + pub async fn start(mut self) -> eyre::Result<()> { + while let Some(notification) = self.ctx.notifications.recv().await { + if let Some(reverted_chain) = notification.reverted_chain() { + // Find the oldest L1 block number (and subtract 1) in the given chain to get the newest latest L1 block + let target_l1_block = reverted_chain.blocks().keys().min().copied() + .ok_or_else(|| eyre::eyre!("Chain is empty"))? + .saturating_sub(1); + + println!("REORG!!! Reverting to {}", target_l1_block); + + // for i in 0..self.nodes.len() { + // self.revert(i, target_l1_block).await?; + // } + + // Update the sync data + unsafe { + GWYNETH_SYNCED_L1_BLOCK_IDX = target_l1_block; + println!("Updated L1 sync data: {}", GWYNETH_SYNCED_L1_BLOCK_IDX); + } + } + + if let Some(committed_chain) = notification.committed_chain() { + println!("EXEX called for block {}", committed_chain.tip().number); + + // Copy the previous l1 -> L2 mapping to the current block, which may get overwritten below with new blocks + for block in committed_chain.blocks_iter() { + self.l1_to_l2.insert(block.number, self.l1_to_l2.get(&(block.number - 1)).unwrap().clone()); + } + //self.l1_finalized_block = committed_chain.tip().number.saturating_sub(FINALIZATION_PERIOD); + // prune list + //self.l1_to_l2.retain(|&l1_block, _| l1_block >= self.l1_finalized_block); + + // Sync nodes + for i in 0..self.nodes.len() { + self.commit(&committed_chain, i).await?; + } + + // Update the sync data + unsafe { + GWYNETH_SYNCED_L1_BLOCK_IDX = committed_chain.tip().number; + println!("Updated L1 sync data: {}", GWYNETH_SYNCED_L1_BLOCK_IDX); + } + + self.ctx.events.send(ExExEvent::FinishedHeight(committed_chain.tip().number))?; + + // if committed_chain.tip().number == 20 { + // println!("REVERT"); + // for i in 0..self.nodes.len() { + // self.revert(i, 10).await?; + // } + // } + } + } + + Ok(()) + } + + // TODO(Brecht): handle block by block instead of chain (easier to manage reorg stuff) + pub async fn commit(&mut self, chain: &Chain, node_idx: usize) -> eyre::Result<()> { + let events = decode_chain_into_rollup_events(chain); + // println!("num events: {:?}", events.len()); + + // Add all other L2 dbs for now as well until dependencies are broken + // let mut last_block_number = HashMap::new(); + // for node in self.nodes.iter() { + // let chain_id = node.config.chain.chain().id(); + // let state_provider = node + // .provider + // .database_provider_ro() + // .unwrap(); + // last_block_number.insert(chain_id, state_provider.last_block_number()?); + // } + + for (block, tx, event) in events { + if let RollupContractEvents::BlockProposed(BlockProposed { + block: ultra_block, + }) = event + { + // Decode blobs and concatenate them to get the raw transactions + // let data = get_blob_data(self.ctx.pool(), tx, ultra_block.blobHashes)?; + // assert_eq!(data, ultra_block.da, "blob data does not match calldata"); + + let (da, tx_list) = bincode::deserialize::<(GwynethDA, Vec)>(&ultra_block.da) + .unwrap_or_else(|err| { + panic!("DA can't be decoded: {}", err); + }); + + let transactions: Vec = decode_transactions(&tx_list); + println!("transactions: {:?}", transactions.len()); + + //println!("da: {:?}", da); + + let all_transactions: Vec = decode_transactions(&tx_list); + let node_chain_id = self.get_chain_id(node_idx); + + let chain_da = da.chain_das.get(&node_chain_id); + if chain_da.is_none() { + println!("No block for {}", node_chain_id); + continue; + } else { + println!("New block for {}!", node_chain_id); + } + let default_chain_da = ChainDA { + block_hash: B256::default(), + extra_data: Bytes::new(), + state_diff: None, + transactions: None, + }; + let chain_da = chain_da.unwrap_or(&default_chain_da); + //println!("chain_da: {:?}", chain_da); + + // let filtered_transactions: Vec = all_transactions + // .into_iter() + // .filter(|tx| tx.chain_id() == Some(node_chain_id)) + // .collect(); + + // if filtered_transactions.len() == 0 { + // println!("no transactions for chain: {}", node_chain_id); + // continue; + // } + + let filtered_transactions: Vec = all_transactions; + + let attrs = GwynethPayloadAttributes { + inner: EthPayloadAttributes { + timestamp: block.timestamp, + prev_randao: block.mix_hash, + suggested_fee_recipient: ultra_block.blocks[0].coinbase, + withdrawals: Some(vec![]), + parent_beacon_block_root: block.parent_beacon_block_root, + }, + transactions: Some(filtered_transactions.clone()), + chain_da: chain_da.clone(), + gas_limit: None, + }; + + let l1_state_provider = self + .ctx + .provider() + .database_provider_ro() + .unwrap() + .state_provider_by_block_number(block.number) + .unwrap(); + + let l1_block_number = block.number; + + let mut builder_attrs = + GwynethPayloadBuilderAttributes::try_new(B256::ZERO, attrs).unwrap(); + builder_attrs.providers.insert(self.ctx.config.chain.chain().id(), Arc::new(l1_state_provider)); + + // Add all other L2 dbs for now as well until dependencies are broken + // for node in self.nodes.iter() { + // let chain_id = node.config.chain.chain().id(); + // println!("other chain_id: {}", chain_id); + // if chain_id != node_chain_id { + // println!("Adding chain_id: {}", chain_id); + // let state_provider = node + // .provider + // .database_provider_ro() + // .unwrap(); + // //let last_block_number = state_provider.last_block_number()?; + // //let last_block_number = *last_block_number.get(&chain_id).unwrap(); + // //println!("last block number: {} -> {}", chain_id, last_block_number); + // let last_block_number = self.num_l2_blocks / self.nodes.len() as u64; + // println!("exex executing against {}", last_block_number); + // let state_provider = state_provider.state_provider_by_block_number(last_block_number).unwrap(); + + // builder_attrs.providers.insert(chain_id, Arc::new(state_provider)); + // } + // } + + let payload_id = builder_attrs.inner.payload_id(); + let parrent_beacon_block_root = + builder_attrs.inner.parent_beacon_block_root.unwrap(); + + //println!("payload_id: {} {}", node_idx, payload_id); + + // trigger new payload building draining the pool + self.nodes[node_idx].payload_builder.new_payload(builder_attrs).await.unwrap(); + + // wait for the payload builder to have finished building + let mut payload = + EthBuiltPayload::new(payload_id, SealedBlock::default(), U256::ZERO); + loop { + let result = self.nodes[node_idx].payload_builder.best_payload(payload_id).await; + + if let Some(result) = result { + if let Ok(new_payload) = result { + payload = new_payload; + if payload.block().body.is_empty() { + tokio::time::sleep(std::time::Duration::from_millis(2000)).await; + continue; + } + } else { + println!("Gwyneth: No payload?"); + continue; + } + } else { + println!("Gwyneth: No block for {}?", node_chain_id); + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + continue; + } + break; + } + + //tokio::time::sleep(std::time::Duration::from_millis(10000)).await; + + // trigger resolve payload via engine api + self.engine_apis[node_idx].get_payload_v3_value(payload_id).await?; + + //self.payloads.push(payload.clone()); + + // submit payload to engine api + let block_hash = self.engine_apis[node_idx] + .submit_payload( + payload.clone(), + parrent_beacon_block_root, + PayloadStatusEnum::Valid, + vec![], + ) + .await?; + + if chain_da.block_hash != B256::ZERO { + if block_hash != chain_da.block_hash { + println!("da data for block: {:?}", chain_da); + println!("reth block: {:?}", payload.block()); + } + assert_eq!(block_hash, chain_da.block_hash, "unexpected block hash for chain {} block {}", node_chain_id, payload.block().number); + } + + // Determine the finalized block hash for this L2 + let finalized_hash = self.l1_to_l2.get(&self.l1_finalized_block).unwrap().get(&node_chain_id).unwrap().1; + + // println!("finalized hash: {}", finalized_hash); + // println!("Block number: {}", payload.block().number); + + // trigger forkchoice update via engine api to commit the block to the blockchain + self.engine_apis[node_idx].update_forkchoice(finalized_hash, block_hash).await?; + + // loop { + // // wait for the block to commit + // if let Some(latest_block) = + // self.nodes[node_idx].provider.block_by_number_or_tag(BlockNumberOrTag::Latest)? + // { + // if latest_block.number == payload.block().number { + // // make sure the block hash we submitted via FCU engine api is the new latest + // // block using an RPC call + // assert_eq!(latest_block.hash_slow(), block_hash); + // break + // } + // } + // println!("waiting on L2 block for {}: {}", node_chain_id, payload.block().number); + // tokio::time::sleep(std::time::Duration::from_millis(2)).await; + // } + + println!("[L1 block {}] Done with block {}: {} ({}, finalized: {})", block.number, node_chain_id, payload.block().number, block_hash, finalized_hash); + if payload.block().number == 1 { + assert_eq!(payload.block().parent_hash, GENESIS_HASH, "genesis hash is incorrect"); + } + + // For rbuilder syncing + let mut l2_block_indices = GWYNETH_SYNCED_L2_BLOCK_IDX.lock().unwrap(); + l2_block_indices.insert(node_chain_id, payload.block().number); + + // To support reorgs + self.l1_to_l2.get_mut(&l1_block_number).unwrap().insert(node_chain_id, (payload.block().number, block_hash)); + } + } + + Ok(()) + } + + pub async fn revert(&mut self, node_idx: usize, target_l1_block: u64) -> eyre::Result<()> { + let chain_id = self.get_chain_id(node_idx); + + // Get the finalized block and the last L2 block still included in the canonical L1 chain + let finalized_block_hash = self.l1_to_l2.get(&self.l1_finalized_block).unwrap().get(&chain_id).unwrap().1; + let newest_block = self.l1_to_l2.get(&target_l1_block).unwrap().get(&chain_id).unwrap(); + + // Update forkchoice to revert back + self.engine_apis[node_idx].update_forkchoice(finalized_block_hash, newest_block.1).await?; + + // Update the sync info + let mut l2_block_indices = GWYNETH_SYNCED_L2_BLOCK_IDX.lock().unwrap(); + l2_block_indices.insert(chain_id, newest_block.0); + + Ok(()) + } + + fn get_chain_id(&self, node_idx: usize) -> u64 { + //BASE_CHAIN_ID + (node_idx as u64) + self.nodes[node_idx].chain_spec().chain().id() + } +} + +/// Decode chain of blocks into a flattened list of receipt logs, filter only transactions to the +/// Rollup contract [`ROLLUP_CONTRACT_ADDRESS`] and extract [`RollupContractEvents`]. +fn decode_chain_into_rollup_events( + chain: &Chain, +) -> Vec<(&SealedBlockWithSenders, &TransactionSigned, RollupContractEvents)> { + chain + // Get all blocks and receipts + .blocks_and_receipts() + // Get all receipts + .flat_map(|(block, receipts)| { + block + .body + .iter() + .zip(receipts.iter().flatten()) + .map(move |(tx, receipt)| (block, tx, receipt)) + }) + // Get all logs from rollup contract + .flat_map(|(block, tx, receipt)| { + receipt + .logs + .iter() + .filter(|log| { + log.address == ROLLUP_CONTRACT_ADDRESS + }) + .map(move |log| (block, tx, log)) + }) + // Decode and filter rollup events + .filter_map(|(block, tx, log)| { + RollupContractEvents::decode_raw_log(log.topics(), &log.data.data, true) + .ok() + .map(|event| (block, tx, event)) + }) + .collect() +} + +fn decode_transactions(tx_list: &[u8]) -> Vec { + #[allow(clippy::useless_asref)] + Vec::::decode(&mut tx_list.as_ref()).unwrap_or_else(|e| { + // If decoding fails we need to make an empty block + println!("decode_transactions not successful: {e:?}, use empty tx_list"); + vec![] + }) +} + +fn get_blob_data(pool: &Pool, tx: &TransactionSigned, blob_hashes: Vec) -> eyre::Result> { + let blobs: Vec<_> = if let Some(sidecar) = pool.get_blob(tx.hash())? { + // Try to get blobs from the transaction pool + sidecar.blobs.clone().into_iter().zip(sidecar.commitments.clone()).collect() + } else { + eyre::bail!("blobs not found for: {:?}", tx.hash()) + }; + + // Filter blobs that are present in the block data + let blobs = blobs + .into_iter() + // Convert blob KZG commitments to versioned hashes + .map(|(blob, commitment)| (blob, kzg_to_versioned_hash(commitment.as_slice()))) + // Filter only blobs that are present in the block data + .filter(|(_, hash)| blob_hashes.contains(hash)) + .map(|(blob, _)| Blob::from(*blob)) + .collect::>(); + if blobs.len() != blob_hashes.len() { + eyre::bail!("some blobs not found") + } + + // Decode blobs and concatenate them to get the raw transactions + let data = SimpleCoder::default() + .decode_all(&blobs) + .ok_or(eyre::eyre!("failed to decode blobs"))? + .concat(); + + Ok(data) +} diff --git a/crates/gwyneth/src/lib.rs b/crates/gwyneth/src/lib.rs new file mode 100644 index 000000000000..3b427695f7da --- /dev/null +++ b/crates/gwyneth/src/lib.rs @@ -0,0 +1,369 @@ +//! Ethereum Node types config. +use std::{collections::HashMap, fmt::Debug, sync::Arc}; + +use builder::default_gwyneth_payload_builder; +use reth_evm_ethereum::EthEvmConfig; +use reth_primitives::{ChainDA, ChainId, StateDiff}; +use reth_tasks::TaskManager; +use thiserror::Error; + +use reth_basic_payload_builder::{ + BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig, BuildArguments, BuildOutcome, + PayloadBuilder, PayloadConfig, +}; +use reth_chainspec::{Chain, ChainSpec}; +use reth_ethereum_engine_primitives::{ + EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes, ExecutionPayloadEnvelopeV2, + ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, +}; +use reth_node_api::{ + payload::{EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes}, + validate_version_specific_fields, EngineTypes, PayloadAttributes, PayloadBuilderAttributes, +}; +use reth_node_builder::{ + components::{ComponentsBuilder, PayloadServiceBuilder}, + node::{FullNodeTypes, NodeTypes}, + BuilderContext, Node, NodeBuilder, NodeConfig, PayloadBuilderConfig, PayloadTypes, +}; +use reth_node_core::{ + args::RpcServerArgs, + primitives::{ + revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, + transaction::WithEncoded, + Address, Genesis, Header, TransactionSigned, Withdrawals, B256, + }, +}; +use reth_node_ethereum::node::{ + EthereumAddOns, EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder, + EthereumPoolBuilder, +}; +use reth_payload_builder::{ + error::PayloadBuilderError, PayloadBuilderHandle, PayloadBuilderService, PayloadId, +}; +use reth_provider::{CanonStateSubscriptions, StateProviderBox, StateProviderFactory}; +use reth_rpc_types::{ExecutionPayloadV1, Withdrawal}; +use reth_tracing::{RethTracer, Tracer}; +use reth_transaction_pool::TransactionPool; +use serde::{Deserialize, Serialize}; + +pub mod builder; +pub mod engine_api; +pub mod exex; + +/// Gwyneth error type used in payload attributes validation +#[derive(Debug, Error)] +pub enum GwynetError { + #[error("Gwyneth field is not zero")] + RlpError(alloy_rlp::Error), +} + +/// Gwyneth Payload Attributes +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GwynethPayloadAttributes { + /// The payload attributes + #[serde(flatten)] + pub inner: EthPayloadAttributes, + /// Transactions is a field for rollups: the transactions list is forced into the block + #[serde(skip_serializing_if = "Option::is_none")] + pub transactions: Option>, + /// Transactions is a field for rollups: the transactions list is forced into the block + pub chain_da: ChainDA, + /// If set, this sets the exact gas limit the block produced with. + #[serde(skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")] + pub gas_limit: Option, +} + +impl PayloadAttributes for GwynethPayloadAttributes { + fn timestamp(&self) -> u64 { + self.inner.timestamp + } + + fn withdrawals(&self) -> Option<&Vec> { + self.inner.withdrawals.as_ref() + } + + fn parent_beacon_block_root(&self) -> Option { + self.inner.parent_beacon_block_root + } + + fn ensure_well_formed_attributes( + &self, + chain_spec: &ChainSpec, + version: EngineApiMessageVersion, + ) -> Result<(), EngineObjectValidationError> { + validate_version_specific_fields(chain_spec, version, self.into())?; + + if self.gas_limit.is_none() { + return Err(EngineObjectValidationError::InvalidParams( + "MissingGasLimitInPayloadAttributes".to_string().into(), + )); + } + + Ok(()) + } +} + +/// Gwyneth Payload Builder Attributes +#[derive(Clone, Debug)] +pub struct GwynethPayloadBuilderAttributes { + /// Inner ethereum payload builder attributes + pub inner: EthPayloadBuilderAttributes, + /// Decoded transactions and the original EIP-2718 encoded bytes as received in the payload + /// attributes. + pub transactions: Vec>, + /// chain DA + pub chain_da: ChainDA, + /// The gas limit for the generated payload + pub gas_limit: Option, + + pub providers: HashMap, +} + +impl PayloadBuilderAttributes + for GwynethPayloadBuilderAttributes +{ + type RpcPayloadAttributes = GwynethPayloadAttributes; + type Error = alloy_rlp::Error; + + fn try_new( + parent: B256, + attributes: GwynethPayloadAttributes, + ) -> Result { + let transactions = attributes + .transactions + .unwrap_or_default() + .into_iter() + .map(|tx| WithEncoded::new(tx.envelope_encoded(), tx)) + .collect(); + + Ok(Self { + inner: EthPayloadBuilderAttributes::new(parent, attributes.inner), + transactions, + chain_da: attributes.chain_da, + gas_limit: attributes.gas_limit, + providers: HashMap::default(), + }) + } + + fn payload_id(&self) -> PayloadId { + self.inner.id + } + + fn parent(&self) -> B256 { + self.inner.parent + } + + fn timestamp(&self) -> u64 { + self.inner.timestamp + } + + fn parent_beacon_block_root(&self) -> Option { + self.inner.parent_beacon_block_root + } + + fn suggested_fee_recipient(&self) -> Address { + self.inner.suggested_fee_recipient + } + + fn prev_randao(&self) -> B256 { + self.inner.prev_randao + } + + fn withdrawals(&self) -> &Withdrawals { + &self.inner.withdrawals + } + + fn cfg_and_block_env( + &self, + chain_spec: &ChainSpec, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv) { + self.inner.cfg_and_block_env(chain_spec, parent) + } +} + +/// Gwyneth engine types - uses a Gwyneth payload attributes RPC type, but uses the default +/// payload builder attributes type. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[non_exhaustive] +pub struct GwynethEngineTypes; + +impl PayloadTypes for GwynethEngineTypes { + type BuiltPayload = EthBuiltPayload; + type PayloadAttributes = GwynethPayloadAttributes; + type PayloadBuilderAttributes = GwynethPayloadBuilderAttributes; + type SyncProvider = Arc; +} + +impl EngineTypes for GwynethEngineTypes { + type ExecutionPayloadV1 = ExecutionPayloadV1; + type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; + type ExecutionPayloadV3 = ExecutionPayloadEnvelopeV3; + type ExecutionPayloadV4 = ExecutionPayloadEnvelopeV4; + + fn validate_version_specific_fields( + chain_spec: &ChainSpec, + version: EngineApiMessageVersion, + payload_or_attrs: PayloadOrAttributes<'_, GwynethPayloadAttributes>, + ) -> Result<(), EngineObjectValidationError> { + validate_version_specific_fields(chain_spec, version, payload_or_attrs) + } +} + +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +pub struct GwynethNode; + +/// Configure the node types +impl NodeTypes for GwynethNode { + type Primitives = (); + // use the Gwyneth engine types + type Engine = GwynethEngineTypes; + // use ethereum chain spec + type ChainSpec = ChainSpec; +} + +/// Implement the Node trait for the Gwyneth node +/// +/// This provides a preset configuration for the node +impl Node for GwynethNode +where + N: FullNodeTypes, +{ + type ComponentsBuilder = ComponentsBuilder< + N, + EthereumPoolBuilder, + GwynethPayloadBuilder, + EthereumNetworkBuilder, + EthereumExecutorBuilder, + EthereumConsensusBuilder, + >; + type AddOns = EthereumAddOns; + + fn components_builder(&self) -> Self::ComponentsBuilder { + ComponentsBuilder::default() + .node_types::() + .pool(EthereumPoolBuilder::default()) + .payload(GwynethPayloadBuilder::default()) + .network(EthereumNetworkBuilder::default()) + .executor(EthereumExecutorBuilder::default()) + .consensus(EthereumConsensusBuilder::default()) + } +} + +/// The type responsible for building Gwyneth payloads +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct GwynethPayloadBuilder; + +impl PayloadBuilder for GwynethPayloadBuilder +where + Client: StateProviderFactory, + Pool: TransactionPool, +{ + type Attributes = GwynethPayloadBuilderAttributes>; + type BuiltPayload = EthBuiltPayload; + + fn try_build( + &self, + args: BuildArguments, + ) -> Result, PayloadBuilderError> { + default_gwyneth_payload_builder(EthEvmConfig::default(), args) + } + + fn build_empty_payload( + &self, + client: &Client, + config: PayloadConfig, + ) -> Result { + let PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + extra_data, + attributes, + chain_spec, + } = config; + let eth_payload_config = PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + extra_data, + attributes: attributes.inner, + chain_spec, + }; + >::build_empty_payload(&reth_ethereum_payload_builder::EthereumPayloadBuilder::default(),client, eth_payload_config) + } + + fn on_missing_payload( + &self, + _args: BuildArguments, + ) -> reth_basic_payload_builder::MissingPayloadBehaviour { + reth_basic_payload_builder::MissingPayloadBehaviour::RaceEmptyPayload + } +} + +impl PayloadServiceBuilder for GwynethPayloadBuilder +where + Node: FullNodeTypes, + Pool: TransactionPool + Unpin + 'static, +{ + async fn spawn_payload_service( + self, + ctx: &BuilderContext, + pool: Pool, + ) -> eyre::Result> { + let payload_builder = Self::default(); + let conf = ctx.payload_builder_config(); + + let payload_job_config = BasicPayloadJobGeneratorConfig::default() + .interval(conf.interval()) + .deadline(conf.deadline()) + .max_payload_tasks(conf.max_payload_tasks()) + .extradata(conf.extradata_bytes()); + + let payload_generator = BasicPayloadJobGenerator::with_builder( + ctx.provider().clone(), + pool, + ctx.task_executor().clone(), + payload_job_config, + ctx.chain_spec(), + payload_builder, + ); + let (payload_service, payload_builder) = + PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream()); + + ctx.task_executor().spawn_critical("payload builder service", Box::pin(payload_service)); + + Ok(payload_builder) + } +} + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let _guard = RethTracer::new().init()?; + + let tasks = TaskManager::current(); + + // create gwyneth genesis with canyon at block 2 + let spec = ChainSpec::builder() + .chain(Chain::mainnet()) + .genesis(Genesis::default()) + .london_activated() + .paris_activated() + .shanghai_activated() + .build(); + + // create node config + let node_config = + NodeConfig::test().with_rpc(RpcServerArgs::default().with_http()).with_chain(spec); + + let handle = NodeBuilder::new(node_config) + .testing_node(tasks.executor()) + .launch_node(GwynethNode::default()) + .await + .unwrap(); + + handle.node_exit_future.await +} diff --git a/crates/net/network/src/network.rs b/crates/net/network/src/network.rs index 8e734caaf8c3..6c6a611a9400 100644 --- a/crates/net/network/src/network.rs +++ b/crates/net/network/src/network.rs @@ -45,6 +45,8 @@ pub struct NetworkHandle { inner: Arc, } +unsafe impl Send for NetworkHandle {} + // === impl NetworkHandle === impl NetworkHandle { diff --git a/crates/node/api/Cargo.toml b/crates/node/api/Cargo.toml index e9f297fc44d1..6c4309340b62 100644 --- a/crates/node/api/Cargo.toml +++ b/crates/node/api/Cargo.toml @@ -23,3 +23,10 @@ reth-payload-primitives.workspace = true reth-tasks.workspace = true reth-rpc-eth-api.workspace = true reth-network-api.workspace = true + +[features] +gwyneth = [ + "reth-payload-primitives/gwyneth", + "reth-engine-primitives/gwyneth", + "reth-payload-builder/gwyneth" +] \ No newline at end of file diff --git a/crates/node/builder/Cargo.toml b/crates/node/builder/Cargo.toml index e5290233b8eb..fdb3d529e9ea 100644 --- a/crates/node/builder/Cargo.toml +++ b/crates/node/builder/Cargo.toml @@ -21,7 +21,7 @@ reth-db-common.workspace = true reth-exex.workspace = true reth-evm.workspace = true reth-provider.workspace = true -reth-db = { workspace = true, features = ["mdbx"], optional = true } +reth-db = { workspace = true, features = ["mdbx", "test-utils"] } reth-db-api.workspace = true reth-rpc-engine-api.workspace = true reth-rpc.workspace = true @@ -90,3 +90,7 @@ tempfile.workspace = true [features] default = [] test-utils = ["reth-db/test-utils"] +gwyneth = [ + "reth-beacon-consensus/gwyneth", + "reth-payload-builder/gwyneth" +] diff --git a/crates/node/builder/src/builder/mod.rs b/crates/node/builder/src/builder/mod.rs index 156ee05ae03b..ee6d60bf44e2 100644 --- a/crates/node/builder/src/builder/mod.rs +++ b/crates/node/builder/src/builder/mod.rs @@ -5,10 +5,11 @@ pub mod add_ons; mod states; +use reth_db::mdbx::DatabaseArguments; use reth_rpc_types::WithOtherFields; pub use states::*; -use std::sync::Arc; +use std::{fs, path::PathBuf, sync::Arc}; use futures::Future; use reth_chainspec::ChainSpec; @@ -176,8 +177,41 @@ impl NodeBuilder { WithLaunchContext { builder: self, task_executor } } + /// Creates a Gwyneth node + pub fn gwyneth_node( + mut self, + task_executor: TaskExecutor, + chain_id: u64, + ) -> WithLaunchContext>> + { + let folder_name = format!("/data/reth/gwyneth-{}/", chain_id); + let path = reth_node_core::dirs::MaybePlatformPath::::from( + PathBuf::from(folder_name.clone()), + ); + + println!("path: {:?}", folder_name); + + fs::create_dir_all(folder_name).expect("gwyneth db dir creation failed"); + + self.config = self.config.with_datadir_args(reth_node_core::args::DatadirArgs { + datadir: path.clone(), + ..Default::default() + }); + + let data_dir = + path.unwrap_or_chain_default(self.config.chain.chain, self.config.datadir.clone()); + + println!("data_dir: {:?}", data_dir); + + let db = Arc::new(reth_db::init_db(data_dir.db(), DatabaseArguments::default()).unwrap()); + + WithLaunchContext { builder: self.with_database(db), task_executor } + } + + + /// Creates an _ephemeral_ preconfigured node for testing purposes. - #[cfg(feature = "test-utils")] + //#[cfg(feature = "test-utils")] pub fn testing_node( mut self, task_executor: TaskExecutor, diff --git a/crates/node/builder/src/launch/common.rs b/crates/node/builder/src/launch/common.rs index 51423f10fcf8..b048cb55a423 100644 --- a/crates/node/builder/src/launch/common.rs +++ b/crates/node/builder/src/launch/common.rs @@ -176,7 +176,7 @@ impl LaunchContext { if let Err(err) = ThreadPoolBuilder::new() .num_threads(num_threads) .thread_name(|i| format!("reth-rayon-{i}")) - .build_global() + .build() { error!(%err, "Failed to build global thread pool") } diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index c579de92eb2b..03b756823ceb 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -119,6 +119,7 @@ where { type Node = NodeHandle, AO>; + // Brecht async fn launch_node( self, target: NodeBuilderWithComponents, diff --git a/crates/node/events/Cargo.toml b/crates/node/events/Cargo.toml index a4970677ac3a..f353c9454054 100644 --- a/crates/node/events/Cargo.toml +++ b/crates/node/events/Cargo.toml @@ -35,3 +35,6 @@ tracing.workspace = true #misc pin-project.workspace = true humantime.workspace = true + +[features] +gwyneth = ["reth-beacon-consensus/gwyneth"] \ No newline at end of file diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index f55616df269f..62b818212bda 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -16,7 +16,7 @@ use reth_primitives::{ transaction::FillTxEnv, Address, Head, Header, TransactionSigned, U256, }; -use reth_revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector}; +use reth_revm::{inspector_handle_register, Evm, EvmBuilder, GetInspector, SyncDatabase}; mod config; pub use config::{revm_spec, revm_spec_by_timestamp_after_bedrock}; diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index db9ffc29eb0f..34644c6e12df 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -239,6 +239,7 @@ where Client: StateProviderFactory, Pool: TransactionPool, { + // Brecht: optimism payload builder let BuildArguments { client, pool, mut cached_reads, config, cancel, best_payload } = args; let state_provider = client.state_by_block_hash(config.parent_block.hash())?; diff --git a/crates/payload/basic/Cargo.toml b/crates/payload/basic/Cargo.toml index de9be0e35b98..9a98642f6a4b 100644 --- a/crates/payload/basic/Cargo.toml +++ b/crates/payload/basic/Cargo.toml @@ -37,3 +37,6 @@ metrics.workspace = true # misc tracing.workspace = true + +[features] +gwyneth = ["reth-payload-primitives/gwyneth"] diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 5df63fe4b71e..6d4cf68fafe7 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -28,8 +28,9 @@ use reth_revm::state_change::post_block_withdrawals_balance_increments; use reth_tasks::TaskSpawner; use reth_transaction_pool::TransactionPool; use revm::{ - primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Database, State, + db::State, + primitives::{BlockEnv, CfgEnvWithHandlerCfg, ChainAddress}, + SyncDatabase, }; use std::{ fmt, @@ -885,12 +886,12 @@ impl WithdrawalsOutcome { } } -/// Executes the withdrawals and commits them to the _runtime_ Database and `BundleState`. +/// Executes the withdrawals and commits them to the _runtime_ SyncDatabase and `BundleState`. /// /// Returns the withdrawals root. /// /// Returns `None` values pre shanghai -pub fn commit_withdrawals>( +pub fn commit_withdrawals>( db: &mut State, chain_spec: &ChainSpec, timestamp: u64, diff --git a/crates/payload/builder/Cargo.toml b/crates/payload/builder/Cargo.toml index d551b4838f97..18234fa0b349 100644 --- a/crates/payload/builder/Cargo.toml +++ b/crates/payload/builder/Cargo.toml @@ -20,6 +20,7 @@ reth-errors.workspace = true reth-provider.workspace = true reth-payload-primitives.workspace = true reth-ethereum-engine-primitives.workspace = true +reth-revm.workspace = true # async tokio = { workspace = true, features = ["sync"] } @@ -39,4 +40,5 @@ tracing.workspace = true revm.workspace = true [features] -test-utils = [] \ No newline at end of file +test-utils = [] +gwyneth = ["reth-payload-primitives/gwyneth"] \ No newline at end of file diff --git a/crates/payload/builder/src/database.rs b/crates/payload/builder/src/database.rs index 03ca5084392d..6c6bd6410998 100644 --- a/crates/payload/builder/src/database.rs +++ b/crates/payload/builder/src/database.rs @@ -2,11 +2,12 @@ use reth_primitives::{ revm_primitives::{ - db::{Database, DatabaseRef}, + db::{DatabaseRef, SyncDatabase}, AccountInfo, Address, Bytecode, B256, }, U256, }; +use reth_revm::revm::{primitives::ChainAddress, Database, SyncDatabaseRef}; use std::{ cell::RefCell, collections::{hash_map::Entry, HashMap}, @@ -153,6 +154,139 @@ impl<'a, DB: DatabaseRef> DatabaseRef for CachedReadsDBRef<'a, DB> { } } +impl From for CachedReads { + fn from(sync: SyncCachedReads) -> Self { + let accounts = sync.accounts.into_iter().map(|(k, v)| (k.1, v)).collect(); + let contracts = sync.contracts.into_iter().map(|(((a, b), v))| (b, v)).collect(); + let block_hashes = sync.block_hashes.into_iter().map(|(((a, b), v))| (b, v)).collect(); + CachedReads { accounts, contracts, block_hashes } + } +} + +pub fn to_sync_cached_reads(cache_reads: CachedReads, chain_id: u64) -> SyncCachedReads { + let accouts = + cache_reads.accounts.into_iter().map(|(k, v)| (ChainAddress(chain_id, k), v)).collect(); + let contracts = cache_reads.contracts.into_iter().map(|(k, v)| ((chain_id, k), v)).collect(); + let block_hashes = + cache_reads.block_hashes.into_iter().map(|(k, v)| ((chain_id, k), v)).collect(); + SyncCachedReads { accounts: accouts, contracts, block_hashes } +} + +#[derive(Debug, Clone, Default)] +pub struct SyncCachedReads { + accounts: HashMap, + contracts: HashMap<(u64, B256), Bytecode>, + block_hashes: HashMap<(u64, u64), B256>, +} + +impl SyncCachedReads { + pub fn as_db(&mut self, db: DB) -> SyncCachedReadsDBRef<'_, DB> { + SyncCachedReadsDBRef { inner: RefCell::new(self.as_db_mut(db)) } + } + + fn as_db_mut(&mut self, db: DB) -> SyncCachedReadsDbMut<'_, DB> { + SyncCachedReadsDbMut { cached: self, db } + } + + pub fn insert_account( + &mut self, + address: ChainAddress, + info: AccountInfo, + storage: HashMap, + ) { + self.accounts.insert(address, CachedAccount { info: Some(info), storage }); + } +} + +#[derive(Debug)] +pub struct SyncCachedReadsDbMut<'a, DB> { + /// The cache of reads. + pub cached: &'a mut SyncCachedReads, + /// The underlying database. + pub db: DB, +} + +impl<'a, DB: SyncDatabaseRef> SyncDatabase for SyncCachedReadsDbMut<'a, DB> { + type Error = ::Error; + + fn basic(&mut self, address: ChainAddress) -> Result, Self::Error> { + let basic = match self.cached.accounts.entry(address) { + Entry::Occupied(entry) => entry.get().info.clone(), + Entry::Vacant(entry) => { + entry.insert(CachedAccount::new(self.db.basic_ref(address)?)).info.clone() + } + }; + Ok(basic) + } + + fn code_by_hash(&mut self, chain_id: u64, code_hash: B256) -> Result { + let code = match self.cached.contracts.entry((chain_id, code_hash)) { + Entry::Occupied(entry) => entry.get().clone(), + Entry::Vacant(entry) => { + entry.insert(self.db.code_by_hash_ref(chain_id, code_hash)?).clone() + } + }; + Ok(code) + } + + fn storage(&mut self, address: ChainAddress, index: U256) -> Result { + match self.cached.accounts.entry(address) { + Entry::Occupied(mut acc_entry) => match acc_entry.get_mut().storage.entry(index) { + Entry::Occupied(entry) => Ok(*entry.get()), + Entry::Vacant(entry) => Ok(*entry.insert(self.db.storage_ref(address, index)?)), + }, + Entry::Vacant(acc_entry) => { + // acc needs to be loaded for us to access slots. + let info = self.db.basic_ref(address)?; + let (account, value) = if info.is_some() { + let value = self.db.storage_ref(address, index)?; + let mut account = CachedAccount::new(info); + account.storage.insert(index, value); + (account, value) + } else { + (CachedAccount::new(info), U256::ZERO) + }; + acc_entry.insert(account); + Ok(value) + } + } + } + + fn block_hash(&mut self, chain_id: u64, number: u64) -> Result { + let code = match self.cached.block_hashes.entry((chain_id, number)) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => *entry.insert(self.db.block_hash_ref(chain_id, number)?), + }; + Ok(code) + } +} + +#[derive(Debug)] +pub struct SyncCachedReadsDBRef<'a, DB> { + /// The inner cache reads db mut. + pub inner: RefCell>, +} + +impl<'a, DB: SyncDatabaseRef> SyncDatabaseRef for SyncCachedReadsDBRef<'a, DB> { + type Error = ::Error; + + fn basic_ref(&self, address: ChainAddress) -> Result, Self::Error> { + self.inner.borrow_mut().basic(address) + } + + fn code_by_hash_ref(&self, chain_id: u64, code_hash: B256) -> Result { + self.inner.borrow_mut().code_by_hash(chain_id, code_hash) + } + + fn storage_ref(&self, address: ChainAddress, index: U256) -> Result { + self.inner.borrow_mut().storage(address, index) + } + + fn block_hash_ref(&self, chain_id: u64, number: u64) -> Result { + self.inner.borrow_mut().block_hash(chain_id, number) + } +} + #[derive(Debug, Clone)] struct CachedAccount { info: Option, diff --git a/crates/payload/primitives/Cargo.toml b/crates/payload/primitives/Cargo.toml index 85a72a3fcdfb..f7a1b97f9a7e 100644 --- a/crates/payload/primitives/Cargo.toml +++ b/crates/payload/primitives/Cargo.toml @@ -25,4 +25,7 @@ tokio = { workspace = true, features = ["sync"] } # misc thiserror.workspace = true -serde.workspace = true \ No newline at end of file +serde.workspace = true + +[features] +gwyneth = [] \ No newline at end of file diff --git a/crates/payload/primitives/src/lib.rs b/crates/payload/primitives/src/lib.rs index 99601301710c..736ed50c5862 100644 --- a/crates/payload/primitives/src/lib.rs +++ b/crates/payload/primitives/src/lib.rs @@ -33,6 +33,10 @@ pub trait PayloadTypes: Send + Sync + Unpin + core::fmt::Debug + Clone { type PayloadBuilderAttributes: PayloadBuilderAttributes + Clone + Unpin; + + #[cfg(feature = "gwyneth")] + /// Access L1 read-only state provider, in particular Arc> + type SyncProvider; } /// Validates the timestamp depending on the version called: @@ -88,7 +92,7 @@ pub fn validate_payload_timestamp( // // 2. Client software **MUST** return `-38005: Unsupported fork` error if the `timestamp` of // the payload does not fall within the time frame of the Cancun fork. - return Err(EngineObjectValidationError::UnsupportedFork) + return Err(EngineObjectValidationError::UnsupportedFork); } let is_prague = chain_spec.is_prague_active_at_timestamp(timestamp); diff --git a/crates/payload/validator/src/lib.rs b/crates/payload/validator/src/lib.rs index 6e21111e62f4..6f9024475d23 100644 --- a/crates/payload/validator/src/lib.rs +++ b/crates/payload/validator/src/lib.rs @@ -113,14 +113,17 @@ impl ExecutionPayloadValidator { payload: ExecutionPayload, cancun_fields: MaybeCancunPayloadFields, ) -> Result { + println!("ensure_well_formed_payload"); let expected_hash = payload.block_hash(); // First parse the block let sealed_block = - try_into_block(payload, cancun_fields.parent_beacon_block_root())?.seal_slow(); + try_into_block(payload.clone(), cancun_fields.parent_beacon_block_root())?.seal_slow(); // Ensure the hash included in the payload matches the block hash if expected_hash != sealed_block.hash() { + println!("payload: {:?}", payload); + println!("sealed_block: {:?}", sealed_block); return Err(PayloadError::BlockHash { execution: sealed_block.hash(), consensus: expected_hash, diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index 34e286a3e1dd..22957def87ee 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -36,6 +36,13 @@ pub const BEACON_NONCE: u64 = 0u64; /// See . pub const ETHEREUM_BLOCK_GAS_LIMIT: u64 = 30_000_000; +pub const ETHEREUM_CHAIN_ID: u64 = 1; +pub const BASE_CHAIN_ID: u64 = 167010; // or whatever value you want to use +pub const L1_CHAIN_ID: u64 = 160010; + +/// Number of L2 chains to create +pub const NUM_L2_CHAINS: u64 = 2; // or whatever number you need + /// The minimum tx fee below which the txpool will reject the transaction. /// /// Configured to `7` WEI which is the lowest possible value of base fee under mainnet EIP-1559 diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 2da37359c023..19f80a28cdfb 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -31,6 +31,10 @@ alloy-genesis.workspace = true alloy-eips = { workspace = true, features = ["serde"] } alloy-consensus.workspace = true +# revm +revm = { workspace = true, features = ["serde"] } +#revm.workspace = true + # optimism op-alloy-rpc-types = { workspace = true, optional = true } @@ -118,4 +122,3 @@ harness = false name = "validate_blob_tx" required-features = ["arbitrary", "c-kzg"] harness = false - diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index 166a43b82f5e..98c38d7b9a17 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -1,6 +1,5 @@ use crate::{ - Address, Bytes, GotExpected, Header, SealedHeader, TransactionSigned, - TransactionSignedEcRecovered, Withdrawals, B256, + Address, Bytes, GotExpected, Header, Receipt, SealedHeader, TransactionSigned, TransactionSignedEcRecovered, Withdrawals, B256, U256 }; pub use alloy_eips::eip1898::{ BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, ForkBlock, RpcBlockHash, @@ -12,7 +11,10 @@ use proptest::prelude::prop_compose; #[cfg(any(test, feature = "arbitrary"))] pub use reth_primitives_traits::test_utils::{generate_valid_header, valid_header_strategy}; use reth_primitives_traits::Requests; +use revm_primitives::AccountInfo; use serde::{Deserialize, Serialize}; +use revm::db::states::BundleState; +use std::collections::HashMap; #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -268,8 +270,6 @@ impl BlockWithSenders { /// Sealed Ethereum full block. /// /// Withdrawals can be optionally included at the end of the RLP encoded message. -#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] -#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp, 32))] #[derive( Debug, Clone, @@ -299,6 +299,114 @@ pub struct SealedBlock { pub requests: Option, } +/// GwynethDA +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Default, + Serialize, + Deserialize, +)] +pub struct GwynethDA { + /// The DA per chain + pub chain_das: HashMap, + /// The transactions of the block for all chains + pub transactions: Option, + /// Extra data + pub extra_data: Bytes, +} +/// ChainDA +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Default, + Serialize, + Deserialize, +)] +pub struct ChainDA { + /// Block hash (for debugging purposes really) + pub block_hash: B256, + /// Extra data + pub extra_data: Bytes, + /// State diff + pub state_diff: Option, + /// Transactions + pub transactions: Option, +} + +/// StateDiff +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Default, + Serialize, + Deserialize, +)] +pub struct StateDiff { + /// Account state. + pub accounts: Vec, + /// Receipts + pub receipts: Vec, + /// State root + pub state_root: B256, + /// Transactions root + pub transactions_root: B256, + /// Gas used + pub gas_used: u64, + /// full bundle state + pub bundle: BundleState, +} + +/// StateDiffAccount +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Default, + Serialize, + Deserialize, +)] +pub struct StateDiffAccount { + /// The address of the account + pub address: Address, + /// Account balance. + pub balance: U256, + /// Account nonce. + pub nonce: u64, + /// code hash, + pub code_hash: B256, + /// code + pub code: Bytes, + /// If Account was destroyed we ignore original value and compare present state with U256::ZERO. + pub storage: Vec, + // Account status. + //pub status: AccountStatus, +} + +/// StateDiffStorage +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Default, + Serialize, + Deserialize, +)] +pub struct StateDiffStorageSlot { + /// Storage slot key + pub key: U256, + /// Storage slot value + pub value: U256, +} + impl SealedBlock { /// Create a new sealed block instance using the sealed header and block body. #[inline] diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 0c4f25057fc3..d080f91b635d 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -40,7 +40,7 @@ pub mod transaction; pub use block::{generate_valid_header, valid_header_strategy}; pub use block::{ Block, BlockBody, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, BlockWithSenders, - ForkBlock, RpcBlockHash, SealedBlock, SealedBlockWithSenders, + ForkBlock, RpcBlockHash, SealedBlock, SealedBlockWithSenders, GwynethDA, ChainDA, StateDiff, StateDiffAccount, StateDiffStorageSlot, }; #[cfg(feature = "reth-codec")] pub use compression::*; diff --git a/crates/primitives/src/transaction/compat.rs b/crates/primitives/src/transaction/compat.rs index 7f47aa7e6655..6d12513be037 100644 --- a/crates/primitives/src/transaction/compat.rs +++ b/crates/primitives/src/transaction/compat.rs @@ -1,9 +1,14 @@ -use crate::{Address, Transaction, TransactionSigned, TxKind, U256}; -use revm_primitives::{AuthorizationList, TxEnv}; +use crate::{Address, Transaction, TransactionSigned, U256}; +use revm_primitives::{AuthorizationList, ChainAddress, TransactTo, TxEnv, TxKind}; #[cfg(all(not(feature = "std"), feature = "optimism"))] use alloc::vec::Vec; +// Hard code for now. +const BASE_CHAIN_ID: u64 = 167010; // Low level crate, should not depend on gwyneth but we need this info, just hard-code now! +const NUM_L2_CHAINS: u64 = 2; +const L1_CHAIN_ID: u64 = 160010; + /// Implements behaviour to fill a [`TxEnv`] from another transaction. pub trait FillTxEnv { /// Fills [`TxEnv`] with an [`Address`] and transaction. @@ -19,16 +24,26 @@ impl FillTxEnv for TransactionSigned { envelope }; - tx_env.caller = sender; + let chain_ids = Some(std::iter::once(L1_CHAIN_ID) + .chain((0..NUM_L2_CHAINS) + .map(|i| BASE_CHAIN_ID + i)) + .collect::>()); + + let chain_id = self + .transaction + .chain_id() + .unwrap_or_else(|| chain_ids.as_ref().map(|ids| ids[0]).unwrap_or(BASE_CHAIN_ID)); + + tx_env.caller = ChainAddress(chain_id, sender); match self.as_ref() { Transaction::Legacy(tx) => { tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.gas_price); tx_env.gas_priority_fee = None; - tx_env.transact_to = tx.to; + tx_env.transact_to = convert_tx_kind(chain_id, tx.to); tx_env.value = tx.value; tx_env.data = tx.input.clone(); - tx_env.chain_id = tx.chain_id; + tx_env.chain_ids = chain_ids; tx_env.nonce = Some(tx.nonce); tx_env.access_list.clear(); tx_env.blob_hashes.clear(); @@ -39,10 +54,10 @@ impl FillTxEnv for TransactionSigned { tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.gas_price); tx_env.gas_priority_fee = None; - tx_env.transact_to = tx.to; + tx_env.transact_to = convert_tx_kind(chain_id, tx.to); tx_env.value = tx.value; tx_env.data = tx.input.clone(); - tx_env.chain_id = Some(tx.chain_id); + tx_env.chain_ids = chain_ids; tx_env.nonce = Some(tx.nonce); tx_env.access_list.clone_from(&tx.access_list.0); tx_env.blob_hashes.clear(); @@ -53,10 +68,10 @@ impl FillTxEnv for TransactionSigned { tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.max_fee_per_gas); tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); - tx_env.transact_to = tx.to; + tx_env.transact_to = convert_tx_kind(chain_id, tx.to); tx_env.value = tx.value; tx_env.data = tx.input.clone(); - tx_env.chain_id = Some(tx.chain_id); + tx_env.chain_ids = chain_ids; tx_env.nonce = Some(tx.nonce); tx_env.access_list.clone_from(&tx.access_list.0); tx_env.blob_hashes.clear(); @@ -67,10 +82,10 @@ impl FillTxEnv for TransactionSigned { tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.max_fee_per_gas); tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); - tx_env.transact_to = TxKind::Call(tx.to); + tx_env.transact_to = TransactTo::Call(ChainAddress(chain_id, tx.to)); tx_env.value = tx.value; tx_env.data = tx.input.clone(); - tx_env.chain_id = Some(tx.chain_id); + tx_env.chain_ids = chain_ids; tx_env.nonce = Some(tx.nonce); tx_env.access_list.clone_from(&tx.access_list.0); tx_env.blob_hashes.clone_from(&tx.blob_versioned_hashes); @@ -81,10 +96,10 @@ impl FillTxEnv for TransactionSigned { tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.max_fee_per_gas); tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); - tx_env.transact_to = tx.to; + tx_env.transact_to = convert_tx_kind(chain_id, tx.to); tx_env.value = tx.value; tx_env.data = tx.input.clone(); - tx_env.chain_id = Some(tx.chain_id); + tx_env.chain_ids = chain_ids; tx_env.nonce = Some(tx.nonce); tx_env.access_list.clone_from(&tx.access_list.0); tx_env.blob_hashes.clear(); @@ -98,7 +113,7 @@ impl FillTxEnv for TransactionSigned { tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::ZERO; tx_env.gas_priority_fee = None; - tx_env.transact_to = tx.to; + tx_env.transact_to = convert_tx_kind(chain_id, tx.to); tx_env.value = tx.value; tx_env.data = tx.input.clone(); tx_env.chain_id = None; @@ -126,3 +141,10 @@ impl FillTxEnv for TransactionSigned { } } } + +const fn convert_tx_kind(chain_id: u64, tx: TxKind) -> TransactTo { + match tx { + TxKind::Create => TransactTo::Create, + TxKind::Call(address) => TransactTo::Call(ChainAddress(chain_id, address)), + } +} diff --git a/crates/revm/src/database.rs b/crates/revm/src/database.rs index 5edd76bea4da..ef9ee03d5293 100644 --- a/crates/revm/src/database.rs +++ b/crates/revm/src/database.rs @@ -1,12 +1,185 @@ use crate::primitives::alloy_primitives::{BlockNumber, StorageKey, StorageValue}; use core::ops::{Deref, DerefMut}; -use reth_primitives::{Account, Address, B256, U256}; +use reth_primitives::{constants::ETHEREUM_CHAIN_ID, Account, Address, B256, U256}; +use reth_storage_api::StateProvider; use reth_storage_errors::provider::{ProviderError, ProviderResult}; use revm::{ - db::DatabaseRef, - primitives::{AccountInfo, Bytecode}, - Database, + db::{CacheDB, DatabaseRef}, + primitives::{AccountInfo, Bytecode, ChainAddress}, + Database, SyncDatabase, SyncDatabaseRef, }; +use std::collections::HashMap; + +#[derive(Debug, Clone)] +pub struct SyncStateProviderDatabase(pub HashMap>); + +impl SyncStateProviderDatabase { + /// Create new State with generic `StateProvider`. + pub fn new(chain_id: Option, db: StateProviderDatabase) -> Self { + // assert!(chain_id.is_some()); + let mut map = HashMap::new(); + map.insert(chain_id.unwrap_or(ETHEREUM_CHAIN_ID), db); + Self(map) + } + + /// Consume State and return inner `StateProvider`. + pub fn into_inner(self) -> HashMap> { + self.0 + } + + pub fn add_db(&mut self, chain_id: u64, db: StateProviderDatabase) { + self.0.insert(chain_id, db); + } + + pub fn get_db(&self, chain_id: u64) -> Option<&StateProviderDatabase> { + self.0.get(&chain_id) + } + + pub fn get_db_mut(&mut self, chain_id: u64) -> Option<&mut StateProviderDatabase> { + self.0.get_mut(&chain_id) + } + + pub fn get_default_db(&self) -> Option<&StateProviderDatabase> { + self.0.get(ÐEREUM_CHAIN_ID) + } + + pub fn get_default_db_mut(&mut self) -> Option<&mut StateProviderDatabase> { + self.0.get_mut(ÐEREUM_CHAIN_ID) + } +} + +impl Deref for SyncStateProviderDatabase { + type Target = HashMap>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for SyncStateProviderDatabase { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub trait SyncEvmStateProvider: Send + Sync { + /// Get basic account information. + /// + /// Returns `None` if the account doesn't exist. + fn basic_account(&self, address: ChainAddress) -> ProviderResult>; + + /// Get the hash of the block with the given number. Returns `None` if no block with this number + /// exists. + fn block_hash(&self, chain_id: u64, number: BlockNumber) -> ProviderResult>; + + /// Get account code by its hash + fn bytecode_by_hash( + &self, + chain_id: u64, + code_hash: B256, + ) -> ProviderResult>; + + /// Get storage of given account. + fn storage( + &self, + account: ChainAddress, + storage_key: StorageKey, + ) -> ProviderResult>; +} + +impl SyncEvmStateProvider for SyncStateProviderDatabase { + fn basic_account(&self, address: ChainAddress) -> ProviderResult> { + if let Some(db) = self.get(&address.0) { + db.0.basic_account(address.1) + } else { + if address.0 != 1 { + println!("Unknown db: {}. Known dbs: {:?}", address.0, self.keys()); + } + Err(ProviderError::UnsupportedProvider) + } + } + + fn block_hash(&self, chain_id: u64, number: BlockNumber) -> ProviderResult> { + if let Some(db) = self.get(&chain_id) { + db.0.block_hash(number) + } else { + if chain_id != 1 { + println!("Unknown db: {}. Known dbs: {:?}", chain_id, self.keys()); + } + Err(ProviderError::UnsupportedProvider) + } + } + + fn bytecode_by_hash( + &self, + chain_id: u64, + code_hash: B256, + ) -> ProviderResult> { + if let Some(db) = self.get(&chain_id) { + db.0.bytecode_by_hash(code_hash) + } else { + if chain_id != 1 { + println!("Unknown db: {}. Known dbs: {:?}", chain_id, self.keys()); + } + Err(ProviderError::UnsupportedProvider) + } + } + + fn storage( + &self, + account: ChainAddress, + storage_key: StorageKey, + ) -> ProviderResult> { + if let Some(db) = self.get(&account.0) { + db.0.storage(account.1, storage_key) + } else { + if account.0 != 1 { + println!("Unknown db: {}. Known dbs: {:?}", account.0, self.keys()); + } + Err(ProviderError::UnsupportedProvider) + } + } +} + +impl SyncDatabase for SyncStateProviderDatabase { + type Error = ProviderError; + + fn basic(&mut self, address: ChainAddress) -> Result, Self::Error> { + SyncDatabaseRef::basic_ref(self, address) + } + + fn code_by_hash(&mut self, chain_id: u64, code_hash: B256) -> Result { + SyncDatabaseRef::code_by_hash_ref(self, chain_id, code_hash) + } + + fn storage(&mut self, address: ChainAddress, index: U256) -> Result { + SyncDatabaseRef::storage_ref(self, address, index) + } + + fn block_hash(&mut self, chain_id: u64, number: u64) -> Result { + SyncDatabaseRef::block_hash_ref(self, chain_id, number) + } +} + +impl SyncDatabaseRef for SyncStateProviderDatabase { + type Error = ::Error; + + fn basic_ref(&self, address: ChainAddress) -> Result, Self::Error> { + Ok(self.basic_account(address)?.map(Into::into)) + } + + fn code_by_hash_ref(&self, chain_id: u64, code_hash: B256) -> Result { + Ok(self.bytecode_by_hash(chain_id, code_hash)?.unwrap_or_default().0) + } + + fn storage_ref(&self, address: ChainAddress, index: U256) -> Result { + Ok(self.storage(address, B256::new(index.to_be_bytes()))?.unwrap_or_default()) + } + + fn block_hash_ref(&self, chain_id: u64, number: u64) -> Result { + Ok(self.block_hash(chain_id, number)?.unwrap_or_default()) + } +} /// A helper trait responsible for providing that necessary state for the EVM execution. /// @@ -68,7 +241,8 @@ pub struct StateProviderDatabase(pub DB); impl StateProviderDatabase { /// Create new State with generic `StateProvider`. - pub const fn new(db: DB) -> Self { + pub fn new(db: DB) -> Self { + //println!("Brecht: StateProviderDatabase::new"); Self(db) } @@ -100,6 +274,7 @@ impl Database for StateProviderDatabase { /// Returns `Ok` with `Some(AccountInfo)` if the account exists, /// `None` if it doesn't, or an error if encountered. fn basic(&mut self, address: Address) -> Result, Self::Error> { + //println!("Brecht: read account"); DatabaseRef::basic_ref(self, address) } @@ -159,3 +334,19 @@ impl DatabaseRef for StateProviderDatabase { Ok(self.0.block_hash(number)?.unwrap_or_default()) } } + +pub struct CachedDBSyncStateProvider(pub CacheDB>); + +impl CachedDBSyncStateProvider { + pub fn new(db: SyncStateProviderDatabase) -> Self { + Self(CacheDB::new(db)) + } + + pub fn get_db(&self, chain_id: u64) -> &S { + &self.0.db.get_db(chain_id).unwrap().0 + } + + pub fn get_db_mut(&mut self, chain_id: u64) -> &mut S { + self.0.db.get_db_mut(chain_id).unwrap() + } +} diff --git a/crates/revm/src/state_change.rs b/crates/revm/src/state_change.rs index 5dddb9b8665e..734a1ea083d3 100644 --- a/crates/revm/src/state_change.rs +++ b/crates/revm/src/state_change.rs @@ -1,7 +1,8 @@ use crate::precompile::HashMap; use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus_common::calc; -use reth_primitives::{Address, Block, Withdrawal, Withdrawals, U256}; +use reth_primitives::{Block, Withdrawal, Withdrawals, U256}; +use revm::primitives::ChainAddress; /// Collect all balance changes at the end of the block. /// @@ -12,21 +13,21 @@ pub fn post_block_balance_increments( chain_spec: &ChainSpec, block: &Block, total_difficulty: U256, -) -> HashMap { +) -> HashMap { let mut balance_increments = HashMap::new(); - + let china_id = chain_spec.chain.id(); // Add block rewards if they are enabled. if let Some(base_block_reward) = calc::base_block_reward(chain_spec, block.number, block.difficulty, total_difficulty) { // Ommer rewards for ommer in &block.ommers { - *balance_increments.entry(ommer.beneficiary).or_default() += + *balance_increments.entry(ChainAddress(china_id, ommer.beneficiary)).or_default() += calc::ommer_reward(base_block_reward, block.number, ommer.number); } // Full block reward - *balance_increments.entry(block.beneficiary).or_default() += + *balance_increments.entry(ChainAddress(china_id, block.beneficiary)).or_default() += calc::block_reward(base_block_reward, block.ommers.len()); } @@ -50,7 +51,7 @@ pub fn post_block_withdrawals_balance_increments( chain_spec: &ChainSpec, block_timestamp: u64, withdrawals: &[Withdrawal], -) -> HashMap { +) -> HashMap { let mut balance_increments = HashMap::with_capacity(withdrawals.len()); insert_post_block_withdrawals_balance_increments( chain_spec, @@ -70,15 +71,16 @@ pub fn insert_post_block_withdrawals_balance_increments( chain_spec: &ChainSpec, block_timestamp: u64, withdrawals: Option<&[Withdrawal]>, - balance_increments: &mut HashMap, + balance_increments: &mut HashMap, ) { // Process withdrawals if chain_spec.is_shanghai_active_at_timestamp(block_timestamp) { if let Some(withdrawals) = withdrawals { for withdrawal in withdrawals { if withdrawal.amount > 0 { - *balance_increments.entry(withdrawal.address).or_default() += - withdrawal.amount_wei().to::(); + *balance_increments + .entry(ChainAddress(chain_spec.chain.id(), withdrawal.address)) + .or_default() += withdrawal.amount_wei().to::(); } } } @@ -89,7 +91,10 @@ pub fn insert_post_block_withdrawals_balance_increments( mod tests { use super::*; use reth_ethereum_forks::{ChainHardforks, EthereumHardfork, ForkCondition}; - use reth_primitives::constants::GWEI_TO_WEI; + use reth_primitives::{ + constants::GWEI_TO_WEI, + Address, + }; /// Tests that the function correctly inserts balance increments when the Shanghai hardfork is /// active and there are withdrawals. @@ -139,11 +144,15 @@ mod tests { assert_eq!(balance_increments.len(), 2); // Verify that the balance increments map contains the correct values for each address assert_eq!( - *balance_increments.get(&Address::from([1; 20])).unwrap(), + *balance_increments + .get(&ChainAddress(chain_spec.chain().id(), Address::from([1; 20]))) + .unwrap(), (1000 * GWEI_TO_WEI).into() ); assert_eq!( - *balance_increments.get(&Address::from([2; 20])).unwrap(), + *balance_increments + .get(&ChainAddress(chain_spec.chain().id(), Address::from([2; 20]))) + .unwrap(), (500 * GWEI_TO_WEI).into() ); } diff --git a/crates/rpc/rpc-api/Cargo.toml b/crates/rpc/rpc-api/Cargo.toml index 3bfb2e9a7662..e91d6bb8ddbc 100644 --- a/crates/rpc/rpc-api/Cargo.toml +++ b/crates/rpc/rpc-api/Cargo.toml @@ -34,3 +34,4 @@ client = [ "jsonrpsee/async-client", "reth-rpc-eth-api/client" ] +gwyneth = ["reth-engine-primitives/gwyneth"] \ No newline at end of file diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index f4b8e4f64b61..cdbb8eeabf1a 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -68,3 +68,6 @@ reth-node-api.workspace = true tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } serde_json.workspace = true clap = { workspace = true, features = ["derive"] } + +[features] +gwyneth = ["reth-engine-primitives/gwyneth"] \ No newline at end of file diff --git a/crates/rpc/rpc-engine-api/Cargo.toml b/crates/rpc/rpc-engine-api/Cargo.toml index d067515f6c2a..ad4250a7f4c8 100644 --- a/crates/rpc/rpc-engine-api/Cargo.toml +++ b/crates/rpc/rpc-engine-api/Cargo.toml @@ -54,3 +54,9 @@ assert_matches.workspace = true [features] optimism = ["reth-primitives/optimism"] +gwyneth = [ + "reth-payload-builder/gwyneth", + "reth-beacon-consensus/gwyneth", + "reth-engine-primitives/gwyneth", + "reth-payload-primitives/gwyneth", +] \ No newline at end of file diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index 409dc0076791..34dbc68bb306 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -18,6 +18,7 @@ use reth_rpc_types::{ }; use reth_transaction_pool::{PoolTransaction, TransactionPool}; use tracing::trace; +use reth_provider::{GWYNETH_SYNCED_L1_BLOCK_IDX, GWYNETH_SYNCED_L2_BLOCK_IDX}; use crate::{ helpers::{ @@ -358,6 +359,14 @@ pub trait EthApi { keys: Vec, block_number: Option, ) -> RpcResult; + + /// Returns the L1 block for which all L2 blocks have been processed + #[method(name = "getSyncedL1BlockIdx")] + async fn get_synced_l1_block_idx(&self) -> RpcResult; + + /// Returns the L2 block to which this L2 is synced (but perhaps not yet fully processed) + #[method(name = "getSyncedL2BlockIdx")] + async fn get_synced_l2_block_idx(&self) -> RpcResult; } #[async_trait::async_trait] @@ -836,4 +845,21 @@ where trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); Ok(EthState::get_proof(self, address, keys, block_number)?.await?) } + + /// Handler for: `eth_getSyncedL1BlockIdx` + async fn get_synced_l1_block_idx(&self) -> RpcResult { + let l1_block_idx = unsafe { + GWYNETH_SYNCED_L1_BLOCK_IDX + }; + Ok(U64::from(l1_block_idx)) + } + + /// Handler for: `eth_getSyncedL2BlockIdx` + async fn get_synced_l2_block_idx(&self) -> RpcResult { + let chain_id = EthApiSpec::chain_id(self).into_limbs()[0]; + let l2_block_idx = unsafe { + *GWYNETH_SYNCED_L2_BLOCK_IDX.lock().unwrap().get(&chain_id).unwrap_or(&0) + }; + Ok(U64::from(l2_block_idx)) + } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index 0d309e6e0863..d922a80e0983 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -1,10 +1,14 @@ //! Loads a pending block from database. Helper trait for `eth_` transaction, call and trace RPC //! methods. +use core::sync; +use std::collections::HashMap; + use crate::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError}; -use futures::Future; +use futures::{io::Chain, Future}; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; use reth_primitives::{ + constants::ETHEREUM_CHAIN_ID, revm_primitives::{ BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HaltReason, ResultAndState, TransactTo, TxEnv, @@ -12,8 +16,14 @@ use reth_primitives::{ transaction::AccessListResult, Bytes, TransactionSignedEcRecovered, TxKind, B256, U256, }; -use reth_provider::{ChainSpecProvider, StateProvider}; -use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef}; + +use reth_primitives::constants::{BASE_CHAIN_ID, NUM_L2_CHAINS, L1_CHAIN_ID}; +use reth_provider::{BlockNumReader, ChainSpecProvider, DatabaseProviderFactory, StateProvider, NODES}; +use reth_revm::{ + database::{CachedDBSyncStateProvider, StateProviderDatabase, SyncStateProviderDatabase}, + db::CacheDB, + DatabaseRef, +}; use reth_rpc_eth_types::{ cache::db::{StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper}, error::ensure_success, @@ -31,8 +41,9 @@ use reth_rpc_types::{ state::{EvmOverrides, StateOverride}, BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo, TransactionRequest, }; -use revm::{Database, DatabaseCommit}; +use revm::{DatabaseCommit, SyncDatabase, SyncDatabaseRef}; use revm_inspectors::access_list::AccessListInspector; +use revm_primitives::ChainAddress; use tracing::trace; use super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace}; @@ -129,7 +140,10 @@ pub trait EthCall: Call + LoadPendingBlock { let this = self.clone(); self.spawn_with_state_at_block(at.into(), move |state| { let mut results = Vec::with_capacity(transactions.len()); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state), + )); if replay_block_txs { // only need to replay the transactions in the block if not all transactions are @@ -225,6 +239,7 @@ pub trait EthCall: Call + LoadPendingBlock { Self: Trace, { let state = self.state_at_block_id(at)?; + let chain_id = cfg.chain_id; let mut env = self.build_call_evm_env(cfg, block, request.clone())?; @@ -237,7 +252,10 @@ pub trait EthCall: Call + LoadPendingBlock { // env.cfg.disable_base_fee = true; - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(state), + )); if request.gas.is_none() && env.tx.gas_price > U256::ZERO { // no gas limit was provided in the request, so we need to cap the request's gas limit @@ -248,8 +266,11 @@ pub trait EthCall: Call + LoadPendingBlock { let to = if let Some(TxKind::Call(to)) = request.to { to } else { - let nonce = - db.basic_ref(from).map_err(Self::Error::from_eth_err)?.unwrap_or_default().nonce; + let nonce = db + .basic_ref(ChainAddress(chain_id, from)) + .map_err(Self::Error::from_eth_err)? + .unwrap_or_default() + .nonce; from.create(nonce) }; @@ -325,10 +346,11 @@ pub trait Call: LoadState + SpawnBlocking { env: EnvWithHandlerCfg, ) -> Result<(ResultAndState, EnvWithHandlerCfg), Self::Error> where - DB: Database, + DB: SyncDatabase, EthApiError: From, { let mut evm = self.evm_config().evm_with_env(db, env); + evm.context.evm.env.cfg.xchain = true; let res = evm.transact().map_err(Self::Error::from_evm_err)?; let (_, env) = evm.into_db_and_env_with_handler_cfg(); Ok((res, env)) @@ -388,8 +410,10 @@ pub trait Call: LoadState + SpawnBlocking { let this = self.clone(); self.spawn_tracing(move |_| { let state = this.state_at_block_id(at)?; - let mut db = - CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state))); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(StateProviderTraitObjWrapper(&state)), + )); let env = this.prepare_call_env( cfg, @@ -443,7 +467,10 @@ pub trait Call: LoadState + SpawnBlocking { let this = self.clone(); self.spawn_with_state_at_block(parent_block.into(), move |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state), + )); // replay all transactions prior to the targeted transaction this.replay_transactions_until( @@ -484,7 +511,7 @@ pub trait Call: LoadState + SpawnBlocking { target_tx_hash: B256, ) -> Result where - DB: DatabaseRef, + DB: SyncDatabaseRef, EthApiError: From, { let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()); @@ -564,6 +591,7 @@ pub trait Call: LoadState + SpawnBlocking { let tx_request_gas_limit = request.gas; let tx_request_gas_price = request.gas_price; let block_env_gas_limit = block.gas_limit; + let chain_id = cfg.chain_id; // Determine the highest possible gas limit, considering both the request's specified limit // and the block's limit. @@ -572,18 +600,47 @@ pub trait Call: LoadState + SpawnBlocking { .unwrap_or(block_env_gas_limit); // Configure the evm env + cfg.xchain = true; let mut env = self.build_call_evm_env(cfg, block, request)?; - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + // Brecht + //let boxed: Box = Box::new(StateProviderDatabase::new(state)); + //let mut super_db = SyncStateProviderDatabase::new( + // Some(chain_id), + // boxed, + //); + + let mut super_db = SyncStateProviderDatabase { 0: HashMap::default() }; + + let providers = NODES.lock().unwrap(); + for (&chain_id, chain_provider) in providers.iter() { + //println!("Brecht executed: Adding db for chain_id: {}", chain_id); + + let state_provider = chain_provider + .database_provider_ro() + .unwrap(); + let last_block_number = state_provider.last_block_number().unwrap(); + let state_provider = state_provider.state_provider_by_block_number(last_block_number).unwrap(); + + //let chain_provider = BundleStateProvider::new(state_provider, bundle_state_data_provider); + //chain_providers.push(chain_provider); + + //let boxed: Box = Box::new(state_provider); + //let state_provider = StateProviderDatabase::new(boxed); + super_db.add_db(chain_id, StateProviderDatabase::new(state_provider)); + } + + let mut sync_db = CachedDBSyncStateProvider::new(super_db); // Apply any state overrides if specified. if let Some(state_override) = state_override { - apply_state_overrides(state_override, &mut db).map_err(Self::Error::from_eth_err)?; + apply_state_overrides(chain_id, state_override, &mut sync_db.0) + .map_err(Self::Error::from_eth_err)?; } // Optimize for simple transfer transactions, potentially reducing the gas estimate. if env.tx.data.is_empty() { if let TransactTo::Call(to) = env.tx.transact_to { - if let Ok(code) = db.db.account_code(to) { + if let Ok(code) = sync_db.get_db_mut(chain_id).account_code(to.1) { let no_code_callee = code.map(|code| code.is_empty()).unwrap_or(true); if no_code_callee { // If the tx is a simple transfer (call to an account with no code) we can @@ -593,7 +650,7 @@ pub trait Call: LoadState + SpawnBlocking { // with the minimum gas limit to make sure. let mut env = env.clone(); env.tx.gas_limit = MIN_TRANSACTION_GAS; - if let Ok((res, _)) = self.transact(&mut db, env) { + if let Ok((res, _)) = self.transact(&mut sync_db.0, env) { if res.result.is_success() { return Ok(U256::from(MIN_TRANSACTION_GAS)) } @@ -603,13 +660,16 @@ pub trait Call: LoadState + SpawnBlocking { } } + let mut sync_db = sync_db.0; + // Check funds of the sender (only useful to check if transaction gas price is more than 0). // // The caller allowance is check by doing `(account.balance - tx.value) / tx.gas_price` if env.tx.gas_price > U256::ZERO { // cap the highest gas limit by max gas caller can afford with given gas price - highest_gas_limit = highest_gas_limit - .min(caller_gas_allowance(&mut db, &env.tx).map_err(Self::Error::from_eth_err)?); + highest_gas_limit = highest_gas_limit.min( + caller_gas_allowance(&mut sync_db, &env.tx).map_err(Self::Error::from_eth_err)?, + ); } // We can now normalize the highest gas limit to a u64 @@ -622,7 +682,7 @@ pub trait Call: LoadState + SpawnBlocking { trace!(target: "rpc::eth::estimate", ?env, "Starting gas estimation"); // Execute the transaction with the highest possible gas limit. - let (mut res, mut env) = match self.transact(&mut db, env.clone()) { + let (mut res, mut env) = match self.transact(&mut sync_db, env.clone()) { // Handle the exceptional case where the transaction initialization uses too much gas. // If the gas price or gas limit was specified in the request, retry the transaction // with the block's gas limit to determine if the failure was due to @@ -631,7 +691,7 @@ pub trait Call: LoadState + SpawnBlocking { if err.is_gas_too_high() && (tx_request_gas_limit.is_some() || tx_request_gas_price.is_some()) => { - return Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) + return Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut sync_db)) } // Propagate other results (successful or other errors). ethres => ethres?, @@ -648,7 +708,7 @@ pub trait Call: LoadState + SpawnBlocking { // if price or limit was included in the request then we can execute the request // again with the block's gas limit to check if revert is gas related or not return if tx_request_gas_limit.is_some() || tx_request_gas_price.is_some() { - Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) + Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut sync_db)) } else { // the transaction did revert Err(RpcInvalidTransactionError::Revert(RevertError::new(output)).into_eth_err()) @@ -681,7 +741,7 @@ pub trait Call: LoadState + SpawnBlocking { env.tx.gas_limit = optimistic_gas_limit; // Re-execute the transaction with the new gas limit and update the result and // environment. - (res, env) = self.transact(&mut db, env)?; + (res, env) = self.transact(&mut sync_db, env)?; // Update the gas used based on the new result. gas_used = res.result.gas_used(); // Update the gas limit estimates (highest and lowest) based on the execution result. @@ -716,7 +776,7 @@ pub trait Call: LoadState + SpawnBlocking { env.tx.gas_limit = mid_gas_limit; // Execute transaction and handle potential gas errors, adjusting limits accordingly. - match self.transact(&mut db, env.clone()) { + match self.transact(&mut sync_db, env.clone()) { Err(err) if err.is_gas_too_high() => { // Increase the lowest gas limit if gas is too high lowest_gas_limit = mid_gas_limit; @@ -798,7 +858,7 @@ pub trait Call: LoadState + SpawnBlocking { &self, env_gas_limit: U256, mut env: EnvWithHandlerCfg, - db: &mut CacheDB>, + db: &mut CacheDB>, ) -> Self::Error where S: StateProvider, @@ -857,6 +917,7 @@ pub trait Call: LoadState + SpawnBlocking { .. } = request; + let chain_id_inner = chain_id.expect("chain id unknown"); let CallFees { max_priority_fee_per_gas, gas_price, max_fee_per_blob_gas } = CallFees::ensure_fees( gas_price.map(U256::from), @@ -877,16 +938,19 @@ pub trait Call: LoadState + SpawnBlocking { .map_err(|_| RpcInvalidTransactionError::GasUintOverflow) .map_err(Self::Error::from_eth_err)?, nonce, - caller: from.unwrap_or_default(), + caller: ChainAddress(chain_id_inner, from.unwrap_or_default()), gas_price, gas_priority_fee: max_priority_fee_per_gas, - transact_to: to.unwrap_or(TxKind::Create), + transact_to: to.map_or(TransactTo::Create, |to| convert_tx_kind(to, chain_id_inner)), value: value.unwrap_or_default(), data: input .try_into_unique_input() .map_err(Self::Error::from_eth_err)? .unwrap_or_default(), - chain_id, + chain_ids: Some(std::iter::once(L1_CHAIN_ID) + .chain((0..NUM_L2_CHAINS) + .map(|i| BASE_CHAIN_ID + i)) + .collect::>()), access_list: access_list.unwrap_or_default().into(), // EIP-4844 fields blob_hashes: blob_versioned_hashes.unwrap_or_default(), @@ -909,6 +973,13 @@ pub trait Call: LoadState + SpawnBlocking { block: BlockEnv, request: TransactionRequest, ) -> Result { + let mut request = request; + + // set chain_id to the config chain id if unknown + if request.chain_id == None { + request.chain_id = Some(cfg.chain_id); + } + let tx = self.create_txn_env(&block, request)?; Ok(EnvWithHandlerCfg::new_with_cfg_env(cfg, block, tx)) } @@ -937,9 +1008,10 @@ pub trait Call: LoadState + SpawnBlocking { overrides: EvmOverrides, ) -> Result where - DB: DatabaseRef, - EthApiError: From<::Error>, + DB: SyncDatabaseRef, + EthApiError: From<::Error>, { + let chain_id = cfg.chain_id; // we want to disable this in eth_call, since this is common practice used by other node // impls and providers cfg.disable_block_gas_limit = true; @@ -961,10 +1033,13 @@ pub trait Call: LoadState + SpawnBlocking { if let Some(mut block_overrides) = overrides.block { if let Some(block_hashes) = block_overrides.block_hash.take() { // override block hashes - db.block_hashes - .extend(block_hashes.into_iter().map(|(num, hash)| (U256::from(num), hash))) + db.block_hashes.extend( + block_hashes + .into_iter() + .map(|(num, hash)| ((cfg.chain_id, U256::from(num)), hash)), + ) } - apply_block_overrides(*block_overrides, &mut block); + apply_block_overrides(chain_id, *block_overrides, &mut block); } let request_gas = request.gas; @@ -972,7 +1047,7 @@ pub trait Call: LoadState + SpawnBlocking { // apply state overrides if let Some(state_overrides) = overrides.state { - apply_state_overrides(state_overrides, db)?; + apply_state_overrides(chain_id, state_overrides, db)?; } if request_gas.is_none() { @@ -995,3 +1070,10 @@ pub trait Call: LoadState + SpawnBlocking { Ok(env) } } + +fn convert_tx_kind(kind: TxKind, chain_id: u64) -> TransactTo { + match kind { + TxKind::Call(to) => TransactTo::Call(ChainAddress(chain_id, to)), + TxKind::Create => TransactTo::Create, + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index bcbbf576a763..ccb5ade3e1b6 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -6,6 +6,7 @@ use std::time::{Duration, Instant}; use crate::{EthApiTypes, FromEthApiError, FromEvmError}; use futures::Future; use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_errors::{DatabaseError, RethError}; use reth_evm::{ system_calls::{pre_block_beacon_root_contract_call, pre_block_blockhashes_contract_call}, ConfigureEvm, ConfigureEvmEnv, @@ -27,12 +28,17 @@ use reth_provider::{ ReceiptProvider, StateProviderFactory, }; use reth_revm::{ - database::StateProviderDatabase, state_change::post_block_withdrawals_balance_increments, + database::{StateProviderDatabase, SyncStateProviderDatabase}, + state_change::post_block_withdrawals_balance_increments, }; use reth_rpc_eth_types::{EthApiError, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}; use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; use reth_trie::HashedPostState; -use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State}; +use revm::{ + db::{states::bundle_state::BundleRetention, State}, + DatabaseCommit, +}; +use revm_primitives::ChainAddress; use tokio::sync::Mutex; use tracing::debug; @@ -235,9 +241,13 @@ pub trait LoadPendingBlock: EthApiTypes { .provider() .history_by_block_hash(parent_hash) .map_err(Self::Error::from_eth_err)?; - let state = StateProviderDatabase::new(state_provider); + let state = SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state_provider), + ); let mut db = State::builder().with_database(state).with_bundle_update().build(); + let chain_id = cfg.chain_id; let mut cumulative_gas_used = 0; let mut sum_blob_gas_used = 0; let block_gas_limit: u64 = block_env.gas_limit.to::(); @@ -286,7 +296,6 @@ pub trait LoadPendingBlock: EthApiTypes { origin.header().hash(), ) .map_err(|err| EthApiError::Internal(err.into()))?; - let mut receipts = Vec::new(); while let Some(pool_tx) = best_txs.next() { @@ -398,12 +407,14 @@ pub trait LoadPendingBlock: EthApiTypes { db.merge_transitions(BundleRetention::PlainState); let execution_outcome = ExecutionOutcome::new( + chain_spec.chain().id(), db.take_bundle(), vec![receipts.clone()].into(), block_number, Vec::new(), ); - let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state); + let hashed_state = + HashedPostState::from_bundle_state(&execution_outcome.current_state().state); let receipts_root = self.receipts_root(&block_env, &execution_outcome, block_number); @@ -412,8 +423,14 @@ pub trait LoadPendingBlock: EthApiTypes { // calculate the state root let state_provider = &db.database; - let state_root = - state_provider.state_root(hashed_state).map_err(Self::Error::from_eth_err)?; + let state_root = state_provider + .get_db(chain_spec.chain().id()) + .ok_or( + ProviderError::Database(DatabaseError::Other("Database not found".to_string())) + .into(), + )? + .state_root(hashed_state) + .map_err(Self::Error::from_eth_err)?; // create the block header let transactions_root = calculate_transaction_root(&executed_txs); @@ -434,7 +451,7 @@ pub trait LoadPendingBlock: EthApiTypes { let header = Header { parent_hash, ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: block_env.coinbase, + beneficiary: block_env.coinbase.1, state_root, transactions_root, receipts_root, diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs index 5145bbade648..d3f2284967d5 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -255,7 +255,7 @@ pub trait LoadState: EthApiTypes { let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash.into()).await?; let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE; - self.evm_config().fill_block_env(&mut block_env, header, after_merge); + self.evm_config().fill_block_env(cfg.chain_id, &mut block_env, header, after_merge); Ok((cfg, block_env)) } diff --git a/crates/rpc/rpc-eth-api/src/helpers/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs index 09ad7f22fa21..f45f0e7e0dc9 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/trace.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -3,13 +3,13 @@ use futures::Future; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; use reth_primitives::B256; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_rpc_eth_types::{ cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper}, EthApiError, }; use reth_rpc_types::{BlockId, TransactionInfo}; -use revm::{db::CacheDB, Database, DatabaseCommit, GetInspector, Inspector}; +use revm::{db::CacheDB, DatabaseCommit, GetInspector, Inspector, SyncDatabase}; use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use revm_primitives::{EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState}; @@ -33,7 +33,7 @@ pub trait Trace: LoadState { inspector: I, ) -> Result<(ResultAndState, EnvWithHandlerCfg), Self::Error> where - DB: Database, + DB: SyncDatabase, EthApiError: From, I: GetInspector, { @@ -52,7 +52,7 @@ pub trait Trace: LoadState { inspector: I, ) -> Result<(ResultAndState, EnvWithHandlerCfg, DB), Self::Error> where - DB: Database, + DB: SyncDatabase, EthApiError: From, I: GetInspector, @@ -81,8 +81,12 @@ pub trait Trace: LoadState { Self: Call, F: FnOnce(TracingInspector, ResultAndState) -> Result, { + let chain_id = env.env.cfg.chain_id; self.with_state_at_block(at, |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(state), + )); let mut inspector = TracingInspector::new(config); let (res, _) = self.inspect(&mut db, env, &mut inspector)?; f(inspector, res) @@ -110,9 +114,13 @@ pub trait Trace: LoadState { + 'static, R: Send + 'static, { + let chain_id = env.env.cfg.chain_id; let this = self.clone(); self.spawn_with_state_at_block(at, move |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(state), + )); let mut inspector = TracingInspector::new(config); let (res, _) = this.inspect(StateCacheDbRefMutWrapper(&mut db), env, &mut inspector)?; f(inspector, res, db) @@ -190,10 +198,14 @@ pub trait Trace: LoadState { // block the transaction is included in let parent_block = block.parent_hash; let block_txs = block.into_transactions_ecrecovered(); + let chain_id = cfg.chain_id; let this = self.clone(); self.spawn_with_state_at_block(parent_block.into(), move |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(state), + )); // replay all transactions prior to the targeted transaction this.replay_transactions_until( @@ -332,8 +344,10 @@ pub trait Trace: LoadState { // now get the state let state = this.state_at_block_id(state_at.into())?; - let mut db = - CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state))); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(StateProviderTraitObjWrapper(&state)), + )); while let Some((tx_info, tx)) = transactions.next() { let env = diff --git a/crates/rpc/rpc-eth-types/src/cache/db.rs b/crates/rpc/rpc-eth-types/src/cache/db.rs index 2437f99864a6..67c6a103c081 100644 --- a/crates/rpc/rpc-eth-types/src/cache/db.rs +++ b/crates/rpc/rpc-eth-types/src/cache/db.rs @@ -2,15 +2,19 @@ //! in default implementation of //! `reth_rpc_eth_api::helpers::Call`. +use reth_chainspec::Chain; use reth_errors::ProviderResult; use reth_primitives::{Address, B256, U256}; -use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef}; +use reth_revm::{ + database::SyncStateProviderDatabase, db::CacheDB, Database, DatabaseRef, SyncDatabase, + SyncDatabaseRef, +}; use reth_storage_api::StateProvider; use reth_trie::HashedStorage; -use revm::Database; +use revm_primitives::ChainAddress; /// Helper alias type for the state's [`CacheDB`] -pub type StateCacheDb<'a> = CacheDB>>; +pub type StateCacheDb<'a> = CacheDB>>; /// Hack to get around 'higher-ranked lifetime error', see /// @@ -156,55 +160,55 @@ impl<'a> StateProvider for StateProviderTraitObjWrapper<'a> { #[allow(missing_debug_implementations)] pub struct StateCacheDbRefMutWrapper<'a, 'b>(pub &'b mut StateCacheDb<'a>); -impl<'a, 'b> Database for StateCacheDbRefMutWrapper<'a, 'b> { - type Error = as Database>::Error; +impl<'a, 'b> SyncDatabase for StateCacheDbRefMutWrapper<'a, 'b> { + type Error = as SyncDatabase>::Error; fn basic( &mut self, - address: revm_primitives::Address, + address: ChainAddress, ) -> Result, Self::Error> { self.0.basic(address) } - fn code_by_hash(&mut self, code_hash: B256) -> Result { - self.0.code_by_hash(code_hash) + fn code_by_hash( + &mut self, + chain_id: u64, + code_hash: B256, + ) -> Result { + self.0.code_by_hash(chain_id, code_hash) } - fn storage( - &mut self, - address: revm_primitives::Address, - index: U256, - ) -> Result { + fn storage(&mut self, address: ChainAddress, index: U256) -> Result { self.0.storage(address, index) } - fn block_hash(&mut self, number: u64) -> Result { - self.0.block_hash(number) + fn block_hash(&mut self, chain_id: u64, number: u64) -> Result { + self.0.block_hash(chain_id, number) } } -impl<'a, 'b> DatabaseRef for StateCacheDbRefMutWrapper<'a, 'b> { - type Error = as Database>::Error; +impl<'a, 'b> SyncDatabaseRef for StateCacheDbRefMutWrapper<'a, 'b> { + type Error = as SyncDatabase>::Error; fn basic_ref( &self, - address: revm_primitives::Address, + address: ChainAddress, ) -> Result, Self::Error> { self.0.basic_ref(address) } - fn code_by_hash_ref(&self, code_hash: B256) -> Result { - self.0.code_by_hash_ref(code_hash) + fn code_by_hash_ref( + &self, + chain_id: u64, + code_hash: B256, + ) -> Result { + self.0.code_by_hash_ref(chain_id, code_hash) } - fn storage_ref( - &self, - address: revm_primitives::Address, - index: U256, - ) -> Result { + fn storage_ref(&self, address: ChainAddress, index: U256) -> Result { self.0.storage_ref(address, index) } - fn block_hash_ref(&self, number: u64) -> Result { - self.0.block_hash_ref(number) + fn block_hash_ref(&self, chain_id: u64, number: u64) -> Result { + self.0.block_hash_ref(chain_id, number) } -} +} \ No newline at end of file diff --git a/crates/rpc/rpc-eth-types/src/error.rs b/crates/rpc/rpc-eth-types/src/error.rs index 74fc15ffe557..f98cbc685b79 100644 --- a/crates/rpc/rpc-eth-types/src/error.rs +++ b/crates/rpc/rpc-eth-types/src/error.rs @@ -17,6 +17,7 @@ use reth_transaction_pool::error::{ }; use revm::primitives::{EVMError, ExecutionResult, HaltReason, OutOfGasError}; use revm_inspectors::tracing::MuxError; +use revm_primitives::ChainAddress; use tracing::error; /// Result alias @@ -76,7 +77,7 @@ pub enum EthApiError { InvalidBlockData(#[from] BlockError), /// Thrown when an `AccountOverride` contains conflicting `state` and `stateDiff` fields #[error("account {0:?} has both 'state' and 'stateDiff'")] - BothStateAndStateDiffInOverride(Address), + BothStateAndStateDiffInOverride(ChainAddress), /// Other internal error #[error(transparent)] Internal(RethError), diff --git a/crates/rpc/rpc-eth-types/src/revm_utils.rs b/crates/rpc/rpc-eth-types/src/revm_utils.rs index 52ae7ee0a167..4cba48e408f6 100644 --- a/crates/rpc/rpc-eth-types/src/revm_utils.rs +++ b/crates/rpc/rpc-eth-types/src/revm_utils.rs @@ -1,5 +1,6 @@ //! utilities for working with revm +use futures::io::Chain; use reth_primitives::{Address, B256, U256}; use reth_rpc_types::{ state::{AccountOverride, StateOverride}, @@ -8,10 +9,10 @@ use reth_rpc_types::{ use revm::{ db::CacheDB, precompile::{PrecompileSpecId, Precompiles}, - primitives::{db::DatabaseRef, Bytecode, SpecId, TxEnv}, - Database, + primitives::{db::SyncDatabaseRef, Bytecode, SpecId, TxEnv}, + SyncDatabase, }; -use revm_primitives::BlockEnv; +use revm_primitives::{BlockEnv, ChainAddress}; use std::cmp::min; use super::{EthApiError, EthResult, RpcInvalidTransactionError}; @@ -26,8 +27,8 @@ pub fn get_precompiles(spec_id: SpecId) -> impl IntoIterator { /// Caps the configured [`TxEnv`] `gas_limit` with the allowance of the caller. pub fn cap_tx_gas_limit_with_caller_allowance(db: &mut DB, env: &mut TxEnv) -> EthResult<()> where - DB: Database, - EthApiError: From<::Error>, + DB: SyncDatabase, + EthApiError: From<::Error>, { if let Ok(gas_limit) = caller_gas_allowance(db, env)?.try_into() { env.gas_limit = gas_limit; @@ -44,8 +45,8 @@ where /// Caution: This assumes non-zero `env.gas_price`. Otherwise, zero allowance will be returned. pub fn caller_gas_allowance(db: &mut DB, env: &TxEnv) -> EthResult where - DB: Database, - EthApiError: From<::Error>, + DB: SyncDatabase, + EthApiError: From<::Error>, { Ok(db // Get the caller account. @@ -203,7 +204,7 @@ impl CallFees { } /// Applies the given block overrides to the env -pub fn apply_block_overrides(overrides: BlockOverrides, env: &mut BlockEnv) { +pub fn apply_block_overrides(chain_id: u64, overrides: BlockOverrides, env: &mut BlockEnv) { let BlockOverrides { number, difficulty, @@ -228,7 +229,7 @@ pub fn apply_block_overrides(overrides: BlockOverrides, env: &mut BlockEnv) { env.gas_limit = U256::from(gas_limit); } if let Some(coinbase) = coinbase { - env.coinbase = coinbase; + env.coinbase = ChainAddress(chain_id, coinbase); } if let Some(random) = random { env.prevrandao = Some(random); @@ -239,30 +240,34 @@ pub fn apply_block_overrides(overrides: BlockOverrides, env: &mut BlockEnv) { } /// Applies the given state overrides (a set of [`AccountOverride`]) to the [`CacheDB`]. -pub fn apply_state_overrides(overrides: StateOverride, db: &mut CacheDB) -> EthResult<()> +pub fn apply_state_overrides( + chain_id: u64, + overrides: StateOverride, + db: &mut CacheDB, +) -> EthResult<()> where - DB: DatabaseRef, - EthApiError: From<::Error>, + DB: SyncDatabaseRef, + EthApiError: From<::Error>, { for (account, account_overrides) in overrides { - apply_account_override(account, account_overrides, db)?; + apply_account_override(ChainAddress(chain_id, account), account_overrides, db)?; } Ok(()) } /// Applies a single [`AccountOverride`] to the [`CacheDB`]. fn apply_account_override( - account: Address, + account: ChainAddress, account_override: AccountOverride, db: &mut CacheDB, ) -> EthResult<()> where - DB: DatabaseRef, - EthApiError: From<::Error>, + DB: SyncDatabaseRef, + EthApiError: From<::Error>, { - // we need to fetch the account via the `DatabaseRef` to not update the state of the account, - // which is modified via `Database::basic_ref` - let mut account_info = DatabaseRef::basic_ref(db, account)?.unwrap_or_default(); + // we need to fetch the account via the `SyncDatabaseRef` to not update the state of the + // account, which is modified via `Database::basic_ref` + let mut account_info = SyncDatabaseRef::basic_ref(db, account)?.unwrap_or_default(); if let Some(nonce) = account_override.nonce { account_info.nonce = nonce; diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index 933beb985561..5a17f3eebabf 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -14,9 +14,10 @@ use reth_rpc_types::engine::{ /// Converts [`ExecutionPayloadV1`] to [`Block`] pub fn try_payload_v1_to_block(payload: ExecutionPayloadV1) -> Result { - if payload.extra_data.len() > MAXIMUM_EXTRA_DATA_SIZE { - return Err(PayloadError::ExtraData(payload.extra_data)) - } + // TODO(Brecht) + // if payload.extra_data.len() > MAXIMUM_EXTRA_DATA_SIZE { + // return Err(PayloadError::ExtraData(payload.extra_data)) + // } if payload.base_fee_per_gas.is_zero() { return Err(PayloadError::BaseFee(payload.base_fee_per_gas)) diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 44cbdef1b7d9..3eff5a3deed7 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -13,7 +13,7 @@ use reth_provider::{ BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, HeaderProvider, StateProofProvider, StateProviderFactory, TransactionVariant, }; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_rpc_api::DebugApiServer; use reth_rpc_eth_api::{ helpers::{Call, EthApiSpec, EthTransactions, TraceExt}, @@ -102,7 +102,10 @@ where .spawn_with_state_at_block(at, move |state| { let block_hash = at.as_block_hash(); let mut results = Vec::with_capacity(transactions.len()); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state), + )); let mut transactions = transactions.into_iter().enumerate().peekable(); while let Some((index, tx)) = transactions.next() { let tx_hash = tx.hash; @@ -244,7 +247,10 @@ where // configure env for the target transaction let tx = transaction.into_recovered(); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state), + )); // replay all transactions prior to the targeted transaction let index = this.eth_api().replay_transactions_until( &mut db, @@ -355,7 +361,7 @@ where let frame = inspector .with_transaction_gas_limit(env.tx.gas_limit) .into_geth_builder() - .geth_prestate_traces(&res, prestate_config, db) + .geth_prestate_traces(&res, &prestate_config, db) .map_err(Eth::Error::from_eth_err)?; Ok(frame) }) @@ -389,6 +395,7 @@ where .await?; return Ok(frame) } + _ => unimplemented!(), }, #[cfg(not(feature = "js-tracer"))] GethDebugTracerType::JsTracer(_) => { @@ -494,7 +501,10 @@ where .spawn_with_state_at_block(at.into(), move |state| { // the outer vec for the bundles let mut all_bundles = Vec::with_capacity(bundles.len()); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state), + )); if replay_block_txs { // only need to replay the transactions in the block if not all transactions are @@ -581,7 +591,10 @@ where .spawn_with_state_at_block(block.parent_hash.into(), move |state| { let evm_config = Call::evm_config(this.eth_api()).clone(); let mut db = StateBuilder::new() - .with_database(StateProviderDatabase::new(state)) + .with_database(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state), + )) .with_bundle_update() .build(); @@ -634,7 +647,7 @@ where // referenced accounts + storage slots. let mut hashed_state = HashedPostState::from_bundle_state(&bundle_state.state); for (address, account) in db.cache.accounts { - let hashed_address = keccak256(address); + let hashed_address = keccak256(address.1); hashed_state.accounts.insert( hashed_address, account.account.as_ref().map(|a| a.info.clone().into()), @@ -655,7 +668,7 @@ where // Generate an execution witness for the aggregated state of accessed accounts. // Destruct the cache database to retrieve the state provider. - let state_provider = db.database.into_inner(); + let state_provider = db.database.get_default_db().unwrap(); let witness = state_provider .witness(HashedPostState::default(), hashed_state) .map_err(Into::into)?; @@ -720,7 +733,7 @@ where let frame = inspector .with_transaction_gas_limit(env.tx.gas_limit) .into_geth_builder() - .geth_prestate_traces(&res, prestate_config, db) + .geth_prestate_traces(&res, &prestate_config, db) .map_err(Eth::Error::from_eth_err)?; return Ok((frame.into(), res.state)) @@ -742,6 +755,8 @@ where .map_err(Eth::Error::from_eth_err)?; return Ok((frame.into(), res.state)) } + // FIX(Cecilia): fucking alloy version not matching + _ => unimplemented!(), }, #[cfg(not(feature = "js-tracer"))] GethDebugTracerType::JsTracer(_) => { diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index 9cabc1f6f5fd..e1d01d047a0f 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -9,13 +9,14 @@ use reth_primitives::{ revm_primitives::db::{DatabaseCommit, DatabaseRef}, PooledTransactionsElement, U256, }; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_rpc_eth_api::{FromEthApiError, FromEvmError}; use reth_rpc_types::mev::{EthCallBundle, EthCallBundleResponse, EthCallBundleTransactionResult}; use reth_tasks::pool::BlockingTaskGuard; use revm::{ db::CacheDB, primitives::{ResultAndState, TxEnv}, + SyncDatabaseRef, }; use revm_primitives::{EnvKzgSettings, EnvWithHandlerCfg, SpecId, MAX_BLOB_GAS_PER_BLOCK}; @@ -149,10 +150,14 @@ where .spawn_with_state_at_block(at, move |state| { let coinbase = block_env.coinbase; let basefee = Some(block_env.basefee.to::()); + let chain_id = cfg.chain_id; let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, TxEnv::default()); - let db = CacheDB::new(StateProviderDatabase::new(state)); + let db = CacheDB::new(SyncStateProviderDatabase::new( + Some(chain_id), + StateProviderDatabase::new(state), + )); - let initial_coinbase = DatabaseRef::basic_ref(&db, coinbase) + let initial_coinbase = SyncDatabaseRef::basic_ref(&db, coinbase) .map_err(Eth::Error::from_eth_err)? .map(|acc| acc.balance) .unwrap_or_default(); @@ -231,7 +236,7 @@ where if transactions.peek().is_some() { // need to apply the state changes of this call before executing // the next call - evm.context.evm.db.commit(state) + evm.context.evm.inner.db.commit(state) } } diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 06b95c2e1498..f473b8bbcd93 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -112,6 +112,8 @@ where TransferKind::Create => OperationType::OpCreate, TransferKind::Create2 => OperationType::OpCreate2, TransferKind::SelfDestruct => OperationType::OpSelfDestruct, + // FIX(Cecilia): seems like reth version > alloy, 'EofCreate' unconvered + TransferKind::EofCreate => OperationType::OpCreate, }, }) .collect::>() diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index cb9f0ab269bd..ff0f66bd0280 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -9,7 +9,7 @@ use reth_consensus_common::calc::{ use reth_evm::ConfigureEvmEnv; use reth_primitives::{BlockId, Bytes, Header, B256, U256}; use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_rpc_api::TraceApiServer; use reth_rpc_eth_api::{ helpers::{Call, TraceExt}, @@ -157,7 +157,10 @@ where self.eth_api() .spawn_with_state_at_block(at, move |state| { let mut results = Vec::with_capacity(calls.len()); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut db = CacheDB::new(SyncStateProviderDatabase::new( + Some(cfg.chain_id), + StateProviderDatabase::new(state), + )); let mut calls = calls.into_iter().peekable(); diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index b3d2122661d2..3923a1bf0f9f 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -15,7 +15,7 @@ use reth_provider::{ ProviderError, StateWriter, StatsReader, TransactionVariant, }; use reth_prune_types::PruneModes; -use reth_revm::database::StateProviderDatabase; +use reth_revm::database::{StateProviderDatabase, SyncStateProviderDatabase}; use reth_stages_api::{ BlockErrorKind, CheckpointBlockRange, EntitiesCheckpoint, ExecInput, ExecOutput, ExecutionCheckpoint, ExecutionStageThresholds, MetricEvent, MetricEventsSender, Stage, @@ -200,6 +200,7 @@ where if input.target_reached() { return Ok(ExecOutput::done(input.checkpoint())) } + println!("ExecutionStage::execute"); let start_block = input.next_block(); let max_block = input.target(); @@ -224,7 +225,9 @@ where provider.tx_ref(), provider.static_file_provider().clone(), )); - let mut executor = self.executor_provider.batch_executor(db); + // TODO(Cecilia): risk of wrong chain id + let mut executor = + self.executor_provider.batch_executor(SyncStateProviderDatabase::new(None, db)); executor.set_tip(max_block); executor.set_prune_modes(prune_modes); @@ -324,8 +327,9 @@ where // prepare execution output for writing let time = Instant::now(); - let ExecutionOutcome { bundle, receipts, requests, first_block } = executor.finalize(); - let state = ExecutionOutcome::new(bundle, receipts, first_block, requests); + let state = executor.finalize().filter_current_chain(); + // TODO(Cecilia): If building for other chains, get the ExecutionOutcome of other chains by + // doing this: let other_states = state.filter_chain(other_chain_id); let write_preparation_duration = time.elapsed(); // log the gas per second for the range we just executed diff --git a/crates/storage/db-common/src/init.rs b/crates/storage/db-common/src/init.rs index b43653f18cbf..d65ae9e9134a 100644 --- a/crates/storage/db-common/src/init.rs +++ b/crates/storage/db-common/src/init.rs @@ -203,13 +203,15 @@ pub fn insert_state<'a, 'b, DB: Database>( let all_reverts_init: RevertsInit = HashMap::from([(block, reverts_init)]); let execution_outcome = ExecutionOutcome::new_init( + provider.chain_spec().chain().id(), state_init, all_reverts_init, contracts.into_iter().collect(), Receipts::default(), block, Vec::new(), - ); + ) + .filter_current_chain(); let mut storage_writer = UnifiedStorageWriter::from_database(provider); storage_writer.write_to_storage(execution_outcome, OriginalValuesKnown::Yes)?; diff --git a/crates/storage/db/src/mdbx.rs b/crates/storage/db/src/mdbx.rs index d6947e10bd2b..a8140ce74515 100644 --- a/crates/storage/db/src/mdbx.rs +++ b/crates/storage/db/src/mdbx.rs @@ -31,7 +31,7 @@ pub fn create_db>(path: P, args: DatabaseArguments) -> eyre::Resu /// Opens up an existing database or creates a new one at the specified path. Creates tables if /// necessary. Read/Write mode. pub fn init_db>(path: P, args: DatabaseArguments) -> eyre::Result { - let client_version = args.client_version().clone(); + let client_version: reth_db_api::models::ClientVersion = args.client_version().clone(); let db = create_db(path, args)?; db.create_tables()?; db.record_client_version(client_version)?; diff --git a/crates/storage/errors/src/db.rs b/crates/storage/errors/src/db.rs index 079a7d56fd79..e66dcb245534 100644 --- a/crates/storage/errors/src/db.rs +++ b/crates/storage/errors/src/db.rs @@ -50,6 +50,9 @@ pub enum DatabaseError { /// Failed to use the specified log level, as it's not available. #[display("log level {_0:?} is not available")] LogLevelUnavailable(LogLevel), + /// Failed to get sync database given `chain_id` + #[display("failed to get sync database with chain_id: {_0}")] + GetSyncDatabase(u64), /// Other unspecified error. #[display("{_0}")] Other(String), diff --git a/crates/storage/nippy-jar/src/lib.rs b/crates/storage/nippy-jar/src/lib.rs index 056f456eb2b7..db3f3a2dbf0a 100644 --- a/crates/storage/nippy-jar/src/lib.rs +++ b/crates/storage/nippy-jar/src/lib.rs @@ -49,7 +49,7 @@ const NIPPY_JAR_VERSION: usize = 1; const INDEX_FILE_EXTENSION: &str = "idx"; const OFFSETS_FILE_EXTENSION: &str = "off"; -const CONFIG_FILE_EXTENSION: &str = "conf"; +pub const CONFIG_FILE_EXTENSION: &str = "conf"; /// A [`RefRow`] is a list of column value slices pointing to either an internal buffer or a /// memory-mapped file. diff --git a/crates/storage/provider/Cargo.toml b/crates/storage/provider/Cargo.toml index 1393df536744..f5432b44fc62 100644 --- a/crates/storage/provider/Cargo.toml +++ b/crates/storage/provider/Cargo.toml @@ -55,11 +55,13 @@ dashmap = { workspace = true, features = ["inline"] } strum.workspace = true # test-utils -once_cell = { workspace = true, optional = true } +once_cell.workspace = true # parallel utils rayon.workspace = true +notify = "6.1.1" + [dev-dependencies] reth-db = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true, features = ["arbitrary", "test-utils"] } @@ -70,7 +72,7 @@ parking_lot.workspace = true tempfile.workspace = true assert_matches.workspace = true rand.workspace = true -once_cell.workspace = true +#once_cell.workspace = true eyre.workspace = true [features] @@ -81,5 +83,5 @@ test-utils = [ "reth-nippy-jar/test-utils", "reth-trie/test-utils", "reth-chain-state/test-utils", - "once_cell", + #"once_cell", ] diff --git a/crates/storage/provider/src/lib.rs b/crates/storage/provider/src/lib.rs index 894a41620c52..fa9c74f34e23 100644 --- a/crates/storage/provider/src/lib.rs +++ b/crates/storage/provider/src/lib.rs @@ -14,6 +14,12 @@ /// Various provider traits. mod traits; +use std::{collections::HashMap, sync::{Arc, LazyLock}}; + +use providers::BlockchainProvider; +use reth_db::{test_utils::TempDatabase, DatabaseEnv}; +use std::sync::Mutex; +use once_cell::sync::Lazy; pub use traits::*; /// Provider trait implementations. @@ -61,3 +67,19 @@ pub(crate) fn to_range>(bounds: R) -> std::ops::Ra start..end } + +/// All chain providers being synced in this node +// pub static NODES: LazyLock>>> = LazyLock::new(|| Mutex::new(HashMap::new())); +// pub static NODES: LazyLock>>>>>> = LazyLock::new(|| Mutex::new(HashMap::new())); + + +pub static NODES: LazyLock>>>> = LazyLock::new(|| Mutex::new(HashMap::new())); +//pub static NODES: LazyLock>>>> = LazyLock::new(|| Mutex::new(HashMap::new())); + +// pub static NODES: LazyLock>>>>>> = LazyLock::new(|| Mutex::new(HashMap::new())); + +pub static mut GWYNETH_SYNCED_L1_BLOCK_IDX: u64 = 0; +pub static GWYNETH_SYNCED_L2_BLOCK_IDX: Lazy>> = Lazy::new(|| { + let map = HashMap::new(); + Mutex::new(map) +}); diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index a5f8432bc302..f9ad61dbc066 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -1462,9 +1462,9 @@ mod tests { }; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ - BlockHashOrNumber, BlockNumHash, BlockNumberOrTag, BlockWithSenders, Receipt, SealedBlock, - SealedBlockWithSenders, StaticFileSegment, TransactionMeta, TransactionSignedNoHash, - Withdrawals, B256, + constants::ETHEREUM_CHAIN_ID, BlockHashOrNumber, BlockNumHash, BlockNumberOrTag, + BlockWithSenders, Receipt, SealedBlock, SealedBlockWithSenders, StaticFileSegment, + TransactionMeta, TransactionSignedNoHash, Withdrawals, B256, }; use reth_storage_api::{ BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, @@ -3160,13 +3160,22 @@ mod tests { ExecutionOutcome { bundle: BundleState::new( database_state.into_iter().map(|(address, (account, _))| { - (address, None, Some(account.into()), Default::default()) + ( + ChainAddress(ETHEREUM_CHAIN_ID, address), + None, + Some(account.into()), + Default::default(), + ) }), database_changesets .iter() .map(|block_changesets| { block_changesets.iter().map(|(address, account, _)| { - (*address, Some(Some((*account).into())), []) + ( + ChainAddress(ETHEREUM_CHAIN_ID, *address), + Some(Some((*account).into())), + [], + ) }) }) .collect::>(), @@ -3194,10 +3203,19 @@ mod tests { Arc::new(ExecutionOutcome { bundle: BundleState::new( in_memory_state.into_iter().map(|(address, (account, _))| { - (address, None, Some(account.into()), Default::default()) + ( + ChainAddress(ETHEREUM_CHAIN_ID, address), + None, + Some(account.into()), + Default::default(), + ) }), [in_memory_changesets.iter().map(|(address, account, _)| { - (*address, Some(Some((*account).into())), Vec::new()) + ( + ChainAddress(ETHEREUM_CHAIN_ID, *address), + Some(Some((*account).into())), + Vec::new(), + ) })], [], ), diff --git a/crates/storage/provider/src/providers/bundle_state_provider.rs b/crates/storage/provider/src/providers/bundle_state_provider.rs index 50c88a51fcd3..6244c10e0670 100644 --- a/crates/storage/provider/src/providers/bundle_state_provider.rs +++ b/crates/storage/provider/src/providers/bundle_state_provider.rs @@ -1,13 +1,16 @@ use crate::{ AccountReader, BlockHashReader, ExecutionDataProvider, StateProvider, StateRootProvider, }; -use reth_primitives::{Account, Address, BlockNumber, Bytecode, Bytes, B256}; +use reth_primitives::{ + Account, Address, BlockNumber, Bytecode, Bytes, B256, +}; use reth_storage_api::{StateProofProvider, StorageRootProvider}; use reth_storage_errors::provider::ProviderResult; use reth_trie::{ prefix_set::TriePrefixSetsMut, updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, }; +use revm::{db::BundleAccount, primitives::ChainAddress}; use std::collections::HashMap; /// A state provider that resolves to data from either a wrapped [`crate::ExecutionOutcome`] @@ -29,6 +32,11 @@ impl BundleStateProvider pub const fn new(state_provider: SP, block_execution_data_provider: EDP) -> Self { Self { state_provider, block_execution_data_provider } } + + pub fn filter_bundle_state(&self) -> HashMap { + let chain_id = self.block_execution_data_provider.execution_outcome().chain_id; + self.block_execution_data_provider.execution_outcome().current_state().state + } } /* Implement StateProvider traits */ @@ -69,8 +77,8 @@ impl StateRootProvider for BundleStateProvider { fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult { - let bundle_state = self.block_execution_data_provider.execution_outcome().state(); - let mut state = HashedPostState::from_bundle_state(&bundle_state.state); + let bundle_state = self.filter_bundle_state(); + let mut state = HashedPostState::from_bundle_state(&bundle_state); state.extend(hashed_state); self.state_provider.state_root(state) } @@ -88,8 +96,8 @@ impl StateRootProvider &self, hashed_state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { - let bundle_state = self.block_execution_data_provider.execution_outcome().state(); - let mut state = HashedPostState::from_bundle_state(&bundle_state.state); + let bundle_state = self.filter_bundle_state(); + let mut state = HashedPostState::from_bundle_state(&bundle_state); state.extend(hashed_state); self.state_provider.state_root_with_updates(state) } @@ -100,8 +108,8 @@ impl StateRootProvider hashed_state: HashedPostState, prefix_sets: TriePrefixSetsMut, ) -> ProviderResult<(B256, TrieUpdates)> { - let bundle_state = self.block_execution_data_provider.execution_outcome().state(); - let mut state = HashedPostState::from_bundle_state(&bundle_state.state); + let bundle_state = self.filter_bundle_state(); + let mut state = HashedPostState::from_bundle_state(&bundle_state); let mut state_prefix_sets = state.construct_prefix_sets(); state.extend(hashed_state); state_prefix_sets.extend(prefix_sets); @@ -117,9 +125,10 @@ impl StorageRootProvider address: Address, hashed_storage: HashedStorage, ) -> ProviderResult { - let bundle_state = self.block_execution_data_provider.execution_outcome().state(); + let chain_id = self.block_execution_data_provider.execution_outcome().chain_id; + let bundle_state = self.block_execution_data_provider.execution_outcome().current_state(); let mut storage = bundle_state - .account(&address) + .account(&ChainAddress(chain_id, address)) .map(|account| { HashedStorage::from_plain_storage( account.status, @@ -141,7 +150,8 @@ impl StateProofProvider address: Address, slots: &[B256], ) -> ProviderResult { - let bundle_state = self.block_execution_data_provider.execution_outcome().state(); + let bundle_state = + self.block_execution_data_provider.execution_outcome().current_state(); let mut state = HashedPostState::from_bundle_state(&bundle_state.state); state.extend(hashed_state); self.state_provider.proof(state, address, slots) @@ -152,8 +162,8 @@ impl StateProofProvider overlay: HashedPostState, target: HashedPostState, ) -> ProviderResult> { - let bundle_state = self.block_execution_data_provider.execution_outcome().state(); - let mut state = HashedPostState::from_bundle_state(&bundle_state.state); + let bundle_state = self.filter_bundle_state(); + let mut state = HashedPostState::from_bundle_state(&bundle_state); state.extend(overlay); self.state_provider.witness(state, target) } diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 15e920178ac3..1fd2e76169bc 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -831,6 +831,7 @@ impl DatabaseProvider { } Ok(ExecutionOutcome::new_init( + self.chain_spec().chain().id(), state, reverts, Vec::new(), @@ -1129,6 +1130,7 @@ impl DatabaseProvider { } Ok(ExecutionOutcome::new_init( + self.chain_spec().chain().id(), state, reverts, Vec::new(), @@ -2697,7 +2699,7 @@ impl StateChangeWriter for DatabaseProvider { for (address, info) in account_block_reverts { account_changeset_cursor.append_dup( block_number, - AccountBeforeTx { address, info: info.map(Into::into) }, + AccountBeforeTx { address: address, info: info.map(Into::into) }, )?; } } @@ -2706,6 +2708,9 @@ impl StateChangeWriter for DatabaseProvider { } fn write_state_changes(&self, mut changes: StateChangeset) -> ProviderResult<()> { + println!("Writing state changes"); + + //changes.filter_for_chain(self.chain_spec.chain().id()); // sort all entries so they can be written to database in more performant way. // and take smaller memory footprint. changes.accounts.par_sort_by_key(|a| a.0); @@ -3206,7 +3211,7 @@ impl HistoryWriter for DatabaseProvider { // storage history stage { - let indices = self.changed_storages_and_blocks_with_range(range)?; + let mut indices = self.changed_storages_and_blocks_with_range(range)?; self.insert_storage_history_index(indices)?; } diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 3b85a80865e5..0860dba0696e 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -70,7 +70,7 @@ pub use blockchain_provider::BlockchainProvider2; #[allow(missing_debug_implementations)] pub struct BlockchainProvider { /// Provider type used to access the database. - database: ProviderFactory, + pub database: ProviderFactory, /// The blockchain tree instance. tree: Arc, /// Tracks the chain info wrt forkchoice updates diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 523fdf18fa7a..df7e4a05ec54 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -22,7 +22,7 @@ use reth_db_api::{ table::Table, transaction::DbTx, }; -use reth_nippy_jar::NippyJar; +use reth_nippy_jar::{NippyJar, CONFIG_FILE_EXTENSION}; use reth_primitives::{ keccak256, static_file::{find_fixed_range, HighestStaticFiles, SegmentHeader, SegmentRangeInclusive}, @@ -41,6 +41,7 @@ use std::{ }; use strum::IntoEnumIterator; use tracing::{info, trace, warn}; +use notify::{RecommendedWatcher, RecursiveMode, Watcher}; /// Alias type for a map that can be queried for block ranges from a transaction /// segment respectively. It uses `TxNumber` to represent the transaction end of a static file @@ -82,14 +83,106 @@ impl StaticFileProvider { } /// Creates a new [`StaticFileProvider`] with read-only access. - pub fn read_only(path: impl AsRef) -> ProviderResult { - Self::new(path, StaticFileAccess::RO) + /// + /// Set `watch_directory` to `true` to track the most recent changes in static files. Otherwise, + /// new data won't be detected or queryable. + pub fn read_only(path: impl AsRef, watch_directory: bool) -> ProviderResult { + let provider = Self::new(path, StaticFileAccess::RO)?; + + if watch_directory { + provider.watch_directory(); + } + + Ok(provider) } /// Creates a new [`StaticFileProvider`] with read-write access. pub fn read_write(path: impl AsRef) -> ProviderResult { Self::new(path, StaticFileAccess::RW) } + + /// Watches the directory for changes and updates the in-memory index when modifications + /// are detected. + /// + /// This may be necessary, since a non-node process that owns a [`StaticFileProvider`] does not + /// receive `update_index` notifications from a node that appends/truncates data. + pub fn watch_directory(&self) { + let provider = self.clone(); + std::thread::spawn(move || { + let (tx, rx) = std::sync::mpsc::channel(); + let mut watcher = RecommendedWatcher::new( + move |res| tx.send(res).unwrap(), + notify::Config::default(), + ) + .expect("failed to create watcher"); + + watcher + .watch(&provider.path, RecursiveMode::NonRecursive) + .expect("failed to watch path"); + + // Some backends send repeated modified events + let mut last_event_timestamp = None; + + while let Ok(res) = rx.recv() { + match res { + Ok(event) => { + // We only care about modified data events + if !matches!( + event.kind, + notify::EventKind::Modify(notify::event::ModifyKind::Data(_)) + ) { + continue + } + + // We only trigger a re-initialization if a configuration file was + // modified. This means that a + // static_file_provider.commit() was called on the node after + // appending/truncating rows + for segment in event.paths { + // Ensure it's a file with the .conf extension + #[allow(clippy::nonminimal_bool)] + if !segment + .extension() + .is_some_and(|s| s.to_str() == Some(CONFIG_FILE_EXTENSION)) + { + continue + } + + // Ensure it's well formatted static file name + if StaticFileSegment::parse_filename( + &segment.file_stem().expect("qed").to_string_lossy(), + ) + .is_none() + { + continue + } + + // If we can read the metadata and modified timestamp, ensure this is + // not an old or repeated event. + if let Ok(current_modified_timestamp) = + std::fs::metadata(&segment).and_then(|m| m.modified()) + { + if last_event_timestamp.is_some_and(|last_timestamp| { + last_timestamp >= current_modified_timestamp + }) { + continue + } + last_event_timestamp = Some(current_modified_timestamp); + } + + info!(target: "providers::static_file", updated_file = ?segment.file_stem(), "re-initializing static file provider index"); + if let Err(err) = provider.initialize_index() { + warn!(target: "providers::static_file", "failed to re-initialize index: {err}"); + } + break + } + } + + Err(err) => warn!(target: "providers::watcher", "watch error: {err:?}"), + } + } + }); + } } impl Deref for StaticFileProvider { diff --git a/crates/storage/provider/src/test_utils/blocks.rs b/crates/storage/provider/src/test_utils/blocks.rs index 8c913da66afe..67603719d656 100644 --- a/crates/storage/provider/src/test_utils/blocks.rs +++ b/crates/storage/provider/src/test_utils/blocks.rs @@ -5,14 +5,15 @@ use once_cell::sync::Lazy; use reth_db::tables; use reth_db_api::{database::Database, models::StoredBlockBodyIndices}; use reth_primitives::{ - alloy_primitives, b256, hex_literal::hex, Account, Address, BlockNumber, Bytes, Header, - Receipt, Requests, SealedBlock, SealedBlockWithSenders, SealedHeader, Signature, Transaction, - TransactionSigned, TxKind, TxLegacy, TxType, Withdrawal, Withdrawals, B256, U256, + alloy_primitives, b256, constants::ETHEREUM_CHAIN_ID, hex_literal::hex, Account, Address, + BlockNumber, Bytes, Header, Receipt, Requests, SealedBlock, SealedBlockWithSenders, + SealedHeader, Signature, Transaction, TransactionSigned, TxKind, TxLegacy, TxType, Withdrawal, + Withdrawals, B256, U256, }; use reth_trie::root::{state_root_unhashed, storage_root_unhashed}; use revm::{ db::BundleState, - primitives::{AccountInfo, HashMap}, + primitives::{AccountInfo, ChainAddress, HashMap}, }; use std::str::FromStr; @@ -184,12 +185,13 @@ fn bundle_state_root(execution_outcome: &ExecutionOutcome) -> B256 { /// Block one that points to genesis fn block1(number: BlockNumber) -> (SealedBlockWithSenders, ExecutionOutcome) { // block changes - let account1: Address = [0x60; 20].into(); - let account2: Address = [0x61; 20].into(); + let account1: ChainAddress = ChainAddress(ETHEREUM_CHAIN_ID, [0x60; 20].into()); + let account2: ChainAddress = ChainAddress(ETHEREUM_CHAIN_ID, [0x61; 20].into()); let slot = U256::from(5); let info = AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() }; let execution_outcome = ExecutionOutcome::new( + ETHEREUM_CHAIN_ID, BundleState::builder(number..=number) .state_present_account_info(account1, info.clone()) .revert_account_info(number, account1, Some(None)) @@ -240,10 +242,11 @@ fn block2( prev_execution_outcome: &ExecutionOutcome, ) -> (SealedBlockWithSenders, ExecutionOutcome) { // block changes - let account: Address = [0x60; 20].into(); + let account: ChainAddress = ChainAddress(ETHEREUM_CHAIN_ID, [0x60; 20].into()); let slot = U256::from(5); let execution_outcome = ExecutionOutcome::new( + ETHEREUM_CHAIN_ID, BundleState::builder(number..=number) .state_present_account_info( account, @@ -308,7 +311,7 @@ fn block3( let mut bundle_state_builder = BundleState::builder(number..=number); for idx in address_range { - let address = Address::with_last_byte(idx); + let address = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(idx)); bundle_state_builder = bundle_state_builder .state_present_account_info( address, @@ -326,6 +329,7 @@ fn block3( .revert_storage(number, address, Vec::new()); } let execution_outcome = ExecutionOutcome::new( + ETHEREUM_CHAIN_ID, bundle_state_builder.build(), vec![vec![Some(Receipt { tx_type: TxType::Eip1559, @@ -373,7 +377,7 @@ fn block4( let mut bundle_state_builder = BundleState::builder(number..=number); for idx in address_range { - let address = Address::with_last_byte(idx); + let address = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(idx)); // increase balance for every even account and destroy every odd bundle_state_builder = if idx % 2 == 0 { bundle_state_builder @@ -417,6 +421,7 @@ fn block4( ); } let execution_outcome = ExecutionOutcome::new( + ETHEREUM_CHAIN_ID, bundle_state_builder.build(), vec![vec![Some(Receipt { tx_type: TxType::Eip1559, @@ -464,7 +469,7 @@ fn block5( let mut bundle_state_builder = BundleState::builder(number..=number); for idx in address_range { - let address = Address::with_last_byte(idx); + let address = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(idx)); // update every even account and recreate every odd only with half of slots bundle_state_builder = bundle_state_builder .state_present_account_info( @@ -503,6 +508,7 @@ fn block5( }; } let execution_outcome = ExecutionOutcome::new( + ETHEREUM_CHAIN_ID, bundle_state_builder.build(), vec![vec![Some(Receipt { tx_type: TxType::Eip1559, diff --git a/crates/storage/provider/src/writer/mod.rs b/crates/storage/provider/src/writer/mod.rs index db24674197b4..00e50627b865 100644 --- a/crates/storage/provider/src/writer/mod.rs +++ b/crates/storage/provider/src/writer/mod.rs @@ -492,6 +492,7 @@ where execution_outcome: ExecutionOutcome, is_value_known: OriginalValuesKnown, ) -> ProviderResult<()> { + println!("write_to_storage"); let (plain_state, reverts) = execution_outcome.bundle.into_plain_state_and_reverts(is_value_known); @@ -521,7 +522,8 @@ mod tests { transaction::{DbTx, DbTxMut}, }; use reth_primitives::{ - keccak256, Account, Address, Receipt, Receipts, StorageEntry, B256, U256, + constants::ETHEREUM_CHAIN_ID, keccak256, Account, Address, Receipt, Receipts, StorageEntry, + B256, U256, }; use reth_trie::{ test_utils::{state_root, storage_root_prehashed}, @@ -533,12 +535,13 @@ mod tests { states::{ bundle_state::BundleRetention, changes::PlainStorageRevert, PlainStorageChangeset, }, - BundleState, EmptyDB, + BundleState, EmptyDB, State, }, primitives::{ - Account as RevmAccount, AccountInfo as RevmAccountInfo, AccountStatus, EvmStorageSlot, + Account as RevmAccount, AccountInfo as RevmAccountInfo, AccountStatus, ChainAddress, + EvmStorageSlot, }, - DatabaseCommit, State, + DatabaseCommit, }; use std::{ collections::{BTreeMap, HashMap}, @@ -601,8 +604,8 @@ mod tests { let factory = create_test_provider_factory(); let provider = factory.provider_rw().unwrap(); - let address_a = Address::ZERO; - let address_b = Address::repeat_byte(0xff); + let address_a = ChainAddress(ETHEREUM_CHAIN_ID, Address::ZERO); + let address_b = ChainAddress(ETHEREUM_CHAIN_ID, Address::repeat_byte(0xff)); let account_a = RevmAccountInfo { balance: U256::from(1), nonce: 1, ..Default::default() }; let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() }; @@ -652,12 +655,12 @@ mod tests { // Check plain state assert_eq!( - provider.basic_account(address_a).expect("Could not read account state"), + provider.basic_account(address_a.1).expect("Could not read account state"), Some(reth_account_a), "Account A state is wrong" ); assert_eq!( - provider.basic_account(address_b).expect("Could not read account state"), + provider.basic_account(address_b.1).expect("Could not read account state"), Some(reth_account_b_changed), "Account B state is wrong" ); @@ -669,12 +672,12 @@ mod tests { .expect("Could not open changeset cursor"); assert_eq!( changeset_cursor.seek_exact(1).expect("Could not read account change set"), - Some((1, AccountBeforeTx { address: address_a, info: None })), + Some((1, AccountBeforeTx { address: address_a.1, info: None })), "Account A changeset is wrong" ); assert_eq!( changeset_cursor.next_dup().expect("Changeset table is malformed"), - Some((1, AccountBeforeTx { address: address_b, info: Some(reth_account_b) })), + Some((1, AccountBeforeTx { address: address_b.1, info: Some(reth_account_b) })), "Account B changeset is wrong" ); @@ -713,7 +716,7 @@ mod tests { // Check new plain state for account B assert_eq!( - provider.basic_account(address_b).expect("Could not read account state"), + provider.basic_account(address_b.1).expect("Could not read account state"), None, "Account B should be deleted" ); @@ -721,7 +724,7 @@ mod tests { // Check change set assert_eq!( changeset_cursor.seek_exact(2).expect("Could not read account change set"), - Some((2, AccountBeforeTx { address: address_b, info: Some(reth_account_b_changed) })), + Some((2, AccountBeforeTx { address: address_b.1, info: Some(reth_account_b_changed) })), "Account B changeset is wrong after deletion" ); } @@ -731,8 +734,8 @@ mod tests { let factory = create_test_provider_factory(); let provider = factory.provider_rw().unwrap(); - let address_a = Address::ZERO; - let address_b = Address::repeat_byte(0xff); + let address_a = ChainAddress(ETHEREUM_CHAIN_ID, Address::ZERO); + let address_b = ChainAddress(ETHEREUM_CHAIN_ID, Address::repeat_byte(0xff)); let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() }; @@ -785,7 +788,7 @@ mod tests { state.merge_transitions(BundleRetention::Reverts); let outcome = - ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 1, Vec::new()); + ExecutionOutcome::new(None, state.take_bundle(), Receipts::default(), 1, Vec::new()); let mut writer = UnifiedStorageWriter::from_database(&provider); writer .write_to_storage(outcome, OriginalValuesKnown::Yes) @@ -798,14 +801,14 @@ mod tests { .expect("Could not open plain storage state cursor"); assert_eq!( - storage_cursor.seek_exact(address_a).unwrap(), - Some((address_a, StorageEntry { key: B256::ZERO, value: U256::from(1) })), + storage_cursor.seek_exact(address_a.1).unwrap(), + Some((address_a.1, StorageEntry { key: B256::ZERO, value: U256::from(1) })), "Slot 0 for account A should be 1" ); assert_eq!( storage_cursor.next_dup().unwrap(), Some(( - address_a, + address_a.1, StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) } )), "Slot 1 for account A should be 2" @@ -817,9 +820,9 @@ mod tests { ); assert_eq!( - storage_cursor.seek_exact(address_b).unwrap(), + storage_cursor.seek_exact(address_b.1).unwrap(), Some(( - address_b, + address_b.1, StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) } )), "Slot 1 for account B should be 2" @@ -836,9 +839,9 @@ mod tests { .cursor_dup_read::() .expect("Could not open storage changeset cursor"); assert_eq!( - changeset_cursor.seek_exact(BlockNumberAddress((1, address_a))).unwrap(), + changeset_cursor.seek_exact(BlockNumberAddress((1, address_a.1))).unwrap(), Some(( - BlockNumberAddress((1, address_a)), + BlockNumberAddress((1, address_a.1)), StorageEntry { key: B256::ZERO, value: U256::from(0) } )), "Slot 0 for account A should have changed from 0" @@ -846,7 +849,7 @@ mod tests { assert_eq!( changeset_cursor.next_dup().unwrap(), Some(( - BlockNumberAddress((1, address_a)), + BlockNumberAddress((1, address_a.1)), StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(0) } )), "Slot 1 for account A should have changed from 0" @@ -858,9 +861,9 @@ mod tests { ); assert_eq!( - changeset_cursor.seek_exact(BlockNumberAddress((1, address_b))).unwrap(), + changeset_cursor.seek_exact(BlockNumberAddress((1, address_b.1))).unwrap(), Some(( - BlockNumberAddress((1, address_b)), + BlockNumberAddress((1, address_b.1)), StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(1) } )), "Slot 1 for account B should have changed from 1" @@ -886,22 +889,22 @@ mod tests { state.merge_transitions(BundleRetention::Reverts); let outcome = - ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 2, Vec::new()); + ExecutionOutcome::new(None, state.take_bundle(), Receipts::default(), 2, Vec::new()); let mut writer = UnifiedStorageWriter::from_database(&provider); writer .write_to_storage(outcome, OriginalValuesKnown::Yes) .expect("Could not write bundle state to DB"); assert_eq!( - storage_cursor.seek_exact(address_a).unwrap(), + storage_cursor.seek_exact(address_a.1).unwrap(), None, "Account A should have no storage slots after deletion" ); assert_eq!( - changeset_cursor.seek_exact(BlockNumberAddress((2, address_a))).unwrap(), + changeset_cursor.seek_exact(BlockNumberAddress((2, address_a.1))).unwrap(), Some(( - BlockNumberAddress((2, address_a)), + BlockNumberAddress((2, address_a.1)), StorageEntry { key: B256::ZERO, value: U256::from(1) } )), "Slot 0 for account A should have changed from 1 on deletion" @@ -909,7 +912,7 @@ mod tests { assert_eq!( changeset_cursor.next_dup().unwrap(), Some(( - BlockNumberAddress((2, address_a)), + BlockNumberAddress((2, address_a.1)), StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) } )), "Slot 1 for account A should have changed from 2 on deletion" @@ -926,7 +929,7 @@ mod tests { let factory = create_test_provider_factory(); let provider = factory.provider_rw().unwrap(); - let address1 = Address::random(); + let address1 = ChainAddress(ETHEREUM_CHAIN_ID, Address::random()); let account_info = RevmAccountInfo { nonce: 1, ..Default::default() }; // Block #0: initial state. @@ -953,8 +956,13 @@ mod tests { )])); init_state.merge_transitions(BundleRetention::Reverts); - let outcome = - ExecutionOutcome::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new()); + let outcome = ExecutionOutcome::new( + None, + init_state.take_bundle(), + Receipts::default(), + 0, + Vec::new(), + ); let mut writer = UnifiedStorageWriter::from_database(&provider); writer .write_to_storage(outcome, OriginalValuesKnown::Yes) @@ -1102,7 +1110,7 @@ mod tests { let bundle = state.take_bundle(); - let outcome = ExecutionOutcome::new(bundle, Receipts::default(), 1, Vec::new()); + let outcome = ExecutionOutcome::new(None, bundle, Receipts::default(), 1, Vec::new()); let mut writer = UnifiedStorageWriter::from_database(&provider); writer .write_to_storage(outcome, OriginalValuesKnown::Yes) @@ -1126,14 +1134,14 @@ mod tests { assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((0, address1)), + BlockNumberAddress((0, address1.1)), StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO } ))) ); assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((0, address1)), + BlockNumberAddress((0, address1.1)), StorageEntry { key: B256::with_last_byte(1), value: U256::ZERO } ))) ); @@ -1143,7 +1151,7 @@ mod tests { assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((1, address1)), + BlockNumberAddress((1, address1.1)), StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) } ))) ); @@ -1154,14 +1162,14 @@ mod tests { assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((2, address1)), + BlockNumberAddress((2, address1.1)), StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) } ))) ); assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((2, address1)), + BlockNumberAddress((2, address1.1)), StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) } ))) ); @@ -1176,21 +1184,21 @@ mod tests { assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((4, address1)), + BlockNumberAddress((4, address1.1)), StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO } ))) ); assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((4, address1)), + BlockNumberAddress((4, address1.1)), StorageEntry { key: B256::with_last_byte(2), value: U256::ZERO } ))) ); assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((4, address1)), + BlockNumberAddress((4, address1.1)), StorageEntry { key: B256::with_last_byte(6), value: U256::ZERO } ))) ); @@ -1202,21 +1210,21 @@ mod tests { assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((5, address1)), + BlockNumberAddress((5, address1.1)), StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) } ))) ); assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((5, address1)), + BlockNumberAddress((5, address1.1)), StorageEntry { key: B256::with_last_byte(2), value: U256::from(4) } ))) ); assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((5, address1)), + BlockNumberAddress((5, address1.1)), StorageEntry { key: B256::with_last_byte(6), value: U256::from(6) } ))) ); @@ -1229,7 +1237,7 @@ mod tests { assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((7, address1)), + BlockNumberAddress((7, address1.1)), StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO } ))) ); @@ -1241,7 +1249,7 @@ mod tests { let factory = create_test_provider_factory(); let provider = factory.provider_rw().unwrap(); - let address1 = Address::random(); + let address1 = ChainAddress(ETHEREUM_CHAIN_ID, Address::random()); let account1 = RevmAccountInfo { nonce: 1, ..Default::default() }; // Block #0: initial state. @@ -1267,8 +1275,13 @@ mod tests { }, )])); init_state.merge_transitions(BundleRetention::Reverts); - let outcome = - ExecutionOutcome::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new()); + let outcome = ExecutionOutcome::new( + None, + init_state.take_bundle(), + Receipts::default(), + 0, + Vec::new(), + ); let mut writer = UnifiedStorageWriter::from_database(&provider); writer .write_to_storage(outcome, OriginalValuesKnown::Yes) @@ -1316,7 +1329,7 @@ mod tests { // Commit block #1 changes to the database. state.merge_transitions(BundleRetention::Reverts); let outcome = - ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 1, Vec::new()); + ExecutionOutcome::new(None, state.take_bundle(), Receipts::default(), 1, Vec::new()); let mut writer = UnifiedStorageWriter::from_database(&provider); writer .write_to_storage(outcome, OriginalValuesKnown::Yes) @@ -1332,14 +1345,14 @@ mod tests { assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((1, address1)), + BlockNumberAddress((1, address1.1)), StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) } ))) ); assert_eq!( storage_changes.next(), Some(Ok(( - BlockNumberAddress((1, address1)), + BlockNumberAddress((1, address1.1)), StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) } ))) ); @@ -1349,6 +1362,7 @@ mod tests { #[test] fn revert_to_indices() { let base = ExecutionOutcome { + chain_id: ETHEREUM_CHAIN_ID, bundle: BundleState::default(), receipts: vec![vec![Some(Receipt::default()); 2]; 7].into(), first_block: 10, @@ -1415,6 +1429,7 @@ mod tests { StateRoot::overlay_root( tx, ExecutionOutcome::new( + None, state.bundle_state.clone(), Receipts::default(), 0, @@ -1435,8 +1450,8 @@ mod tests { assert_state_root(&state, &prestate, "empty"); // destroy account 1 - let address1 = Address::with_last_byte(1); - let account1_old = prestate.remove(&address1).unwrap(); + let address1 = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(1)); + let account1_old = prestate.remove(&address1.1).unwrap(); state.insert_account(address1, account1_old.0.into()); state.commit(HashMap::from([( address1, @@ -1450,10 +1465,10 @@ mod tests { assert_state_root(&state, &prestate, "destroyed account"); // change slot 2 in account 2 - let address2 = Address::with_last_byte(2); + let address2 = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(2)); let slot2 = U256::from(2); let slot2_key = B256::from(slot2); - let account2 = prestate.get_mut(&address2).unwrap(); + let account2 = prestate.get_mut(&address2.1).unwrap(); let account2_slot2_old_value = *account2.1.get(&slot2_key).unwrap(); state.insert_account_with_storage( address2, @@ -1478,8 +1493,8 @@ mod tests { assert_state_root(&state, &prestate, "changed storage"); // change balance of account 3 - let address3 = Address::with_last_byte(3); - let account3 = prestate.get_mut(&address3).unwrap(); + let address3 = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(3)); + let account3 = prestate.get_mut(&address3.1).unwrap(); state.insert_account(address3, account3.0.into()); account3.0.balance = U256::from(24); @@ -1495,8 +1510,8 @@ mod tests { assert_state_root(&state, &prestate, "changed balance"); // change nonce of account 4 - let address4 = Address::with_last_byte(4); - let account4 = prestate.get_mut(&address4).unwrap(); + let address4 = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(4)); + let account4 = prestate.get_mut(&address4.1).unwrap(); state.insert_account(address4, account4.0.into()); account4.0.nonce = 128; @@ -1514,7 +1529,7 @@ mod tests { // recreate account 1 let account1_new = Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) }; - prestate.insert(address1, (account1_new, BTreeMap::default())); + prestate.insert(address1.1, (account1_new, BTreeMap::default())); state.commit(HashMap::from([( address1, RevmAccount { @@ -1530,7 +1545,7 @@ mod tests { let slot20 = U256::from(20); let slot20_key = B256::from(slot20); let account1_slot20_value = U256::from(12345); - prestate.get_mut(&address1).unwrap().1.insert(slot20_key, account1_slot20_value); + prestate.get_mut(&address1.1).unwrap().1.insert(slot20_key, account1_slot20_value); state.commit(HashMap::from([( address1, RevmAccount { @@ -1548,8 +1563,8 @@ mod tests { #[test] fn prepend_state() { - let address1 = Address::random(); - let address2 = Address::random(); + let address1 = ChainAddress(ETHEREUM_CHAIN_ID, Address::random()); + let address2 = ChainAddress(ETHEREUM_CHAIN_ID, Address::random()); let account1 = RevmAccountInfo { nonce: 1, ..Default::default() }; let account1_changed = RevmAccountInfo { nonce: 1, ..Default::default() }; @@ -1566,6 +1581,7 @@ mod tests { assert_eq!(previous_state.reverts.len(), 1); let mut test = ExecutionOutcome { + chain_id: ETHEREUM_CHAIN_ID, bundle: present_state, receipts: vec![vec![Some(Receipt::default()); 2]; 1].into(), first_block: 2, @@ -1575,7 +1591,7 @@ mod tests { test.prepend_state(previous_state); assert_eq!(test.receipts.len(), 1); - let end_state = test.state(); + let end_state = test.all_states(); assert_eq!(end_state.state.len(), 2); // reverts num should stay the same. assert_eq!(end_state.reverts.len(), 1); @@ -1587,8 +1603,8 @@ mod tests { #[test] fn hashed_state_storage_root() { - let address = Address::random(); - let hashed_address = keccak256(address); + let address = ChainAddress(ETHEREUM_CHAIN_ID, Address::random()); + let hashed_address = keccak256(address.1); let provider_factory = create_test_provider_factory(); let provider_rw = provider_factory.provider_rw().unwrap(); let tx = provider_rw.tx_ref(); @@ -1632,7 +1648,8 @@ mod tests { provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap(); // re-calculate database storage root - let storage_root = StorageRoot::overlay_root(tx, address, updated_storage.clone()).unwrap(); + let storage_root = + StorageRoot::overlay_root(tx, address.1, updated_storage.clone()).unwrap(); assert_eq!(storage_root, storage_root_prehashed(updated_storage.storage)); } } diff --git a/crates/storage/storage-api/src/state.rs b/crates/storage/storage-api/src/state.rs index adf0601eb9a2..cd14e742f752 100644 --- a/crates/storage/storage-api/src/state.rs +++ b/crates/storage/storage-api/src/state.rs @@ -9,10 +9,17 @@ use reth_primitives::{ StorageValue, B256, KECCAK_EMPTY, U256, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; +use std::fmt::Debug; /// Type alias of boxed [`StateProvider`]. pub type StateProviderBox = Box; +impl Debug for dyn StateProvider { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("StateProviderBox").finish() + } +} + /// An abstraction for a type that provides state data. #[auto_impl(&, Arc, Box)] pub trait StateProvider: diff --git a/crates/transaction-pool/src/maintain.rs b/crates/transaction-pool/src/maintain.rs index e9db4fb4c81b..e4a9f6a1df07 100644 --- a/crates/transaction-pool/src/maintain.rs +++ b/crates/transaction-pool/src/maintain.rs @@ -415,7 +415,7 @@ pub async fn maintain_transaction_pool( continue } - let mut changed_accounts = Vec::with_capacity(state.state().len()); + let mut changed_accounts = Vec::with_capacity(state.current_state().len()); for acc in state.changed_accounts() { // we can always clear the dirty flag for this account dirty_addresses.remove(&acc.address); diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index 892d42b9d4c3..018688f46268 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -1491,6 +1491,7 @@ impl AllTransactions { on_chain_balance: U256, on_chain_nonce: u64, ) -> InsertResult { + // TODO(Brecht): reorg assert!(on_chain_nonce <= transaction.nonce(), "Invalid transaction"); let mut transaction = self.ensure_valid(transaction)?; diff --git a/crates/transaction-pool/src/validate/constants.rs b/crates/transaction-pool/src/validate/constants.rs index 489677057aff..388d5da3eda0 100644 --- a/crates/transaction-pool/src/validate/constants.rs +++ b/crates/transaction-pool/src/validate/constants.rs @@ -9,7 +9,8 @@ pub const TX_SLOT_BYTE_SIZE: usize = 32 * 1024; /// more expensive to propagate; larger transactions also take more resources /// to validate whether they fit into the pool or not. Default is 4 times [`TX_SLOT_BYTE_SIZE`], /// which defaults to 32 KiB, so 128 KiB. -pub const DEFAULT_MAX_TX_INPUT_BYTES: usize = 4 * TX_SLOT_BYTE_SIZE; // 128KB +/// TODO(Brecht): revert back to 4 after optimizing state diff +pub const DEFAULT_MAX_TX_INPUT_BYTES: usize = 1024 * TX_SLOT_BYTE_SIZE; // 128KB /// Maximum bytecode to permit for a contract. pub const MAX_CODE_BYTE_SIZE: usize = 24576; diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 1c0e1cc8262e..bfaf65cfd873 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -328,13 +328,14 @@ where // Signer account shouldn't have bytecode. Presence of bytecode means this is a // smartcontract. - if account.has_bytecode() { - return TransactionValidationOutcome::Invalid( - transaction, - InvalidTransactionError::SignerAccountHasBytecode.into(), - ) - } - + // if account.has_bytecode() { + // return TransactionValidationOutcome::Invalid( + // transaction, + // InvalidTransactionError::SignerAccountHasBytecode.into(), + // ) + // } + + // TODO(Brecht): reorg // Checks for nonce if transaction.nonce() < account.nonce { return TransactionValidationOutcome::Invalid( diff --git a/crates/trie/db/src/state.rs b/crates/trie/db/src/state.rs index a138ee5791fe..d1fbd8e96452 100644 --- a/crates/trie/db/src/state.rs +++ b/crates/trie/db/src/state.rs @@ -283,14 +283,16 @@ mod tests { use super::*; use reth_db::test_utils::create_test_rw_db; use reth_db_api::database::Database; - use reth_primitives::{hex, revm_primitives::AccountInfo, Address, U256}; - use revm::db::BundleState; + use reth_primitives::{ + constants::ETHEREUM_CHAIN_ID, hex, revm_primitives::AccountInfo, Address, U256, + }; + use revm::{db::BundleState, primitives::ChainAddress}; use std::collections::HashMap; #[test] fn from_bundle_state_with_rayon() { - let address1 = Address::with_last_byte(1); - let address2 = Address::with_last_byte(2); + let address1 = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(1)); + let address2 = ChainAddress(ETHEREUM_CHAIN_ID, Address::with_last_byte(2)); let slot1 = U256::from(1015); let slot2 = U256::from(2015); diff --git a/crates/trie/trie/benches/hash_post_state.rs b/crates/trie/trie/benches/hash_post_state.rs index 636ce4462173..07f9cf647ef6 100644 --- a/crates/trie/trie/benches/hash_post_state.rs +++ b/crates/trie/trie/benches/hash_post_state.rs @@ -1,9 +1,9 @@ #![allow(missing_docs, unreachable_pub)] use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; -use reth_primitives::{keccak256, Address, B256, U256}; +use reth_primitives::{constants::ETHEREUM_CHAIN_ID, keccak256, Address, B256, U256}; use reth_trie::{HashedPostState, HashedStorage}; -use revm::db::{states::BundleBuilder, BundleAccount}; +use revm::{db::{states::BundleBuilder, BundleAccount}, primitives::ChainAddress}; use std::collections::HashMap; pub fn hash_post_state(c: &mut Criterion) { @@ -25,11 +25,11 @@ pub fn hash_post_state(c: &mut Criterion) { } } -fn from_bundle_state_seq(state: &HashMap) -> HashedPostState { +fn from_bundle_state_seq(state: &HashMap) -> HashedPostState { let mut this = HashedPostState::default(); for (address, account) in state { - let hashed_address = keccak256(address); + let hashed_address = keccak256(address.1); this.accounts.insert(hashed_address, account.info.clone().map(Into::into)); let hashed_storage = HashedStorage::from_iter( @@ -44,7 +44,7 @@ fn from_bundle_state_seq(state: &HashMap) -> HashedPostS this } -fn generate_test_data(size: usize) -> HashMap { +fn generate_test_data(size: usize) -> HashMap { let storage_size = 1_000; let mut runner = TestRunner::new(ProptestConfig::default()); @@ -68,7 +68,7 @@ fn generate_test_data(size: usize) -> HashMap { let mut bundle_builder = BundleBuilder::default(); for (address, storage) in state { - bundle_builder = bundle_builder.state_storage(address, storage); + bundle_builder = bundle_builder.state_storage(ChainAddress(ETHEREUM_CHAIN_ID, address), storage); } let bundle_state = bundle_builder.build(); diff --git a/crates/trie/trie/src/state.rs b/crates/trie/trie/src/state.rs index 1677e3b4931d..6130d10c6465 100644 --- a/crates/trie/trie/src/state.rs +++ b/crates/trie/trie/src/state.rs @@ -5,7 +5,10 @@ use crate::{ use itertools::Itertools; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use reth_primitives::{keccak256, Account, Address, B256, U256}; -use revm::db::{states::CacheAccount, AccountStatus, BundleAccount}; +use revm::{ + db::{states::CacheAccount, AccountStatus, BundleAccount}, + primitives::ChainAddress, +}; use std::{ borrow::Cow, collections::{hash_map, HashMap, HashSet}, @@ -25,11 +28,12 @@ impl HashedPostState { /// Hashes all changed accounts and storage entries that are currently stored in the bundle /// state. pub fn from_bundle_state<'a>( - state: impl IntoParallelIterator, + state: impl IntoParallelIterator, ) -> Self { let hashed = state .into_par_iter() .map(|(address, account)| { + let address = address.1; let hashed_address = keccak256(address); let hashed_account = account.info.clone().map(Into::into); let hashed_storage = HashedStorage::from_plain_storage( diff --git a/ecosystem/examples/uniswapV2/README.md b/ecosystem/examples/uniswapV2/README.md new file mode 100644 index 000000000000..503d8811e880 --- /dev/null +++ b/ecosystem/examples/uniswapV2/README.md @@ -0,0 +1,77 @@ +# Uniswap Local Deployment Guide + +This guide explains how to deploy and run Uniswap locally or from a local repository using the following components: + +- **Smart Contracts** +- **SDK** (with chain support) +- **Interface/UI** + +--- + +## ⚠️ Important Note + +The deployment addresses (`FACTORY_ADDRESS`, `WETH`) below are valid **only if the first transactions made with the specified private key (`53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710`)** are the Uniswap contract deployments. +- **Do not use this private key for any other transactions before deploying the Uniswap contracts.** +- Otherwise, you must update the **Interface** and **SDK** repositories with the new deployment addresses. + +--- + +## 1. Uniswap Smart Contracts + +1. Clone the repository: + ```bash + git clone https://github.com/taikoxyz/uniswap-v2 +2. Init submodules and build the bindings + ```bash + git submodule init + forge build +3. Deploy the contracts on L1 (and L2A and L2B too for sync comp). + ```bash + $ forge script script/UniswapDeployer.s.sol --rpc-url http://localhost:32002(5 or 6) --broadcast --legacy + $ forge script script/DeployTokens.s.sol --rpc-url http://localhost:32002(5 or 6) --broadcast --legacy +4. On L2s, we need UniswapPortal contracts too. + $ forge script script/DeployPortal.s.sol --rpc-url http://localhost:32005 (6) --broadcast --legacy +## 2. Uniswap SDK + +1. Clone the repository and switch to the `gwyneth_uniswapV2` branch: + ```bash + git clone https://github.com/adaki2004/v2-sdk && cd v2-sdk + git checkout gwyneth_uniswapV2 +2. Build the SDK: + ```bash + yarn && yarn build +> **_NOTE:_** Ensure that the contracts are deployed first before interacting with this repository using the specified private key. + +## 3. Uniswap Interface/UI +> **_NOTE:_** Ensure that the SDK repository is in the same root directory as one, as it is referenced in `package.json` like this: +`"@uniswap/sdk": "file:../v2-sdk"`. + +1. Clone the repository: + ```bash + git clone https://github.com/adaki2004/interface + +2. Switch to the `gwyneth_uniswapV2` branch: + ```bash + git checkout gwyneth_uniswapV2 +3. Install dependencies + ```bash + npm install +4. Deploy the contracts + ```bash + yarn + export NODE_OPTIONS=--openssl-legacy-provider + yarn start +## Additional Notes +Ensure that the repositories are properly structured in your working directory for dependency resolution. +If deployment addresses change, you will need to update the Interface and SDK configurations. + +## One example E2E testing, you should be doing the following: + +1. On `gwynethification` branch in the smart contract repository (https://github.com/taikoxyz/uniswap-v2), deploy the contracts: (before, do a git submodule init and update!) + ```bash + ./script/deployContracts.sh +2. On Uniswap Interface/UI repository, change to `xTransfer_UI` branch and shoot up the UI as described above. +Add liquidity (manually): a pool with 1M SLOTH + 200K Taiko tokens (amount not important, but tokens should be) - both on L1 and L2A. +3. Initiate a cross-swap in the smart contract repository with the command: + ```bash + forge script script/CrossSwap.s.sol --rpc-url http://localhost:32005 --broadcast --legacy -vvv --gas-estimate-multiplier 200 diff --git a/etc/assertoor/assertoor-template.yaml b/etc/assertoor/assertoor-template.yaml index 16e4be914e7e..7341e2434045 100644 --- a/etc/assertoor/assertoor-template.yaml +++ b/etc/assertoor/assertoor-template.yaml @@ -7,7 +7,7 @@ participants: - el_type: reth el_image: ghcr.io/paradigmxyz/reth cl_type: teku - cl_image: consensys/teku:latest + cl_image: sigp/lighthouse:latest count: 1 - el_type: reth el_image: ghcr.io/paradigmxyz/reth diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index 9980be374f40..5da821d9f166 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -170,6 +170,7 @@ impl PayloadTypes for CustomEngineTypes { type BuiltPayload = EthBuiltPayload; type PayloadAttributes = CustomPayloadAttributes; type PayloadBuilderAttributes = CustomPayloadBuilderAttributes; + type SyncProvider = (); } impl EngineTypes for CustomEngineTypes { diff --git a/examples/custom-evm/src/main.rs b/examples/custom-evm/src/main.rs index c8b8a20f7a4c..ca073fa7dfec 100644 --- a/examples/custom-evm/src/main.rs +++ b/examples/custom-evm/src/main.rs @@ -14,7 +14,7 @@ use reth::{ handler::register::EvmHandler, inspector_handle_register, precompile::{Precompile, PrecompileOutput, PrecompileSpecId}, - ContextPrecompiles, Database, Evm, EvmBuilder, GetInspector, + ContextPrecompiles, Evm, EvmBuilder, GetInspector, SyncDatabase as Database, }, tasks::TaskManager, }; @@ -197,4 +197,4 @@ async fn main() -> eyre::Result<()> { println!("Node started"); handle.node_exit_future.await -} +} \ No newline at end of file diff --git a/examples/custom-inspector/src/main.rs b/examples/custom-inspector/src/main.rs index b6721eded67c..effa938774ad 100644 --- a/examples/custom-inspector/src/main.rs +++ b/examples/custom-inspector/src/main.rs @@ -19,7 +19,7 @@ use reth::{ revm::{ inspector_handle_register, interpreter::{Interpreter, OpCode}, - Database, Evm, EvmContext, Inspector, + Evm, EvmContext, Inspector, SyncDatabase, }, rpc::{api::eth::helpers::Call, compat::transaction::transaction_to_call_request}, transaction_pool::TransactionPool, @@ -122,7 +122,7 @@ struct DummyInspector { impl Inspector for DummyInspector where - DB: Database, + DB: SyncDatabase, { /// This method is called at each step of the EVM execution. /// It checks if the current opcode is valid and if so, it stores the opcode and its diff --git a/examples/stateful-precompile/src/main.rs b/examples/stateful-precompile/src/main.rs index 5505f6d16c01..7963a8398e33 100644 --- a/examples/stateful-precompile/src/main.rs +++ b/examples/stateful-precompile/src/main.rs @@ -14,7 +14,7 @@ use reth::{ handler::register::EvmHandler, inspector_handle_register, precompile::{Precompile, PrecompileSpecId}, - ContextPrecompile, ContextPrecompiles, Database, Evm, EvmBuilder, GetInspector, + ContextPrecompile, ContextPrecompiles, Evm, EvmBuilder, GetInspector, SyncDatabase as Database, }, tasks::TaskManager, }; diff --git a/packages/package.json b/packages/package.json new file mode 100644 index 000000000000..1439b95ab7f7 --- /dev/null +++ b/packages/package.json @@ -0,0 +1,10 @@ +{ + "name": "gwyneth", + "version": "1.0.0", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "Taiko Labs", + "license": "MIT" +} diff --git a/packages/protocol/.env b/packages/protocol/.env new file mode 100644 index 000000000000..3c9120f4d2e4 --- /dev/null +++ b/packages/protocol/.env @@ -0,0 +1,3 @@ +L2_GENESIS_HASH=0x71e653779ab26fe93812ee92085e203bd1e2feeb8404b51d5a33ad8fa639c51f +PRIVATE_KEY=0xbcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31 +MAINNET_CONTRACT_OWNER=0x8943545177806ED17B9F23F0a21ee5948eCaa776 \ No newline at end of file diff --git a/packages/protocol/.env_sample b/packages/protocol/.env_sample new file mode 100644 index 000000000000..3289806d9c1a --- /dev/null +++ b/packages/protocol/.env_sample @@ -0,0 +1,3 @@ +L2_GENESIS_HASH=0xdf90a9c4daa571aa308e967c9a6b4bf21ba8842d95d73d28be112b6fe0618e8c +PRIVATE_KEY=0xbcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31 +MAINNET_CONTRACT_OWNER=0x8943545177806ED17B9F23F0a21ee5948eCaa776 \ No newline at end of file diff --git a/packages/protocol/.github/workflows/test.yml b/packages/protocol/.github/workflows/test.yml new file mode 100644 index 000000000000..9282e82944e8 --- /dev/null +++ b/packages/protocol/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: test + +on: workflow_dispatch + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Foundry project + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Forge build + run: | + forge --version + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test diff --git a/packages/protocol/.gitignore b/packages/protocol/.gitignore new file mode 100644 index 000000000000..d4dfc4c9e51a --- /dev/null +++ b/packages/protocol/.gitignore @@ -0,0 +1,15 @@ +# Compiler files +cache/ +out/ +node_modules/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/packages/protocol/Makefile b/packages/protocol/Makefile new file mode 100644 index 000000000000..4c267eea37eb --- /dev/null +++ b/packages/protocol/Makefile @@ -0,0 +1,9 @@ +# build/Makefile + +.PHONY: install + +install: + ./scripts/setup_deps.sh + +propose: + ./scripts/propose_block.sh \ No newline at end of file diff --git a/packages/protocol/README.md b/packages/protocol/README.md new file mode 100644 index 000000000000..9265b4558406 --- /dev/null +++ b/packages/protocol/README.md @@ -0,0 +1,66 @@ +## Foundry + +**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** + +Foundry consists of: + +- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. + +## Documentation + +https://book.getfoundry.sh/ + +## Usage + +### Build + +```shell +$ forge build +``` + +### Test + +```shell +$ forge test +``` + +### Format + +```shell +$ forge fmt +``` + +### Gas Snapshots + +```shell +$ forge snapshot +``` + +### Anvil + +```shell +$ anvil +``` + +### Deploy + +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` + +### Cast + +```shell +$ cast +``` + +### Help + +```shell +$ forge --help +$ anvil --help +$ cast --help +``` diff --git a/packages/protocol/contracts/4844/BlobHashReader.yulp b/packages/protocol/contracts/4844/BlobHashReader.yulp new file mode 100644 index 000000000000..7490d5c1c8fe --- /dev/null +++ b/packages/protocol/contracts/4844/BlobHashReader.yulp @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +// An implemenatation of IBlobHashReader +object "BlobHashReader" { + code { + datacopy(0, dataoffset("runtime"), datasize("runtime")) + return(0, datasize("runtime")) + } + object "runtime" { + code { + // Match against the keccak of the ABI function signature needed. + switch shr(0xe0,calldataload(0)) + // bytes4(keccak("function getFirstBlobHash()")) + // Returns the versioned hash for the first blob in this transaction. + case 0xfd122ecf { + // DATAHASH opcode has hex value 0x49 + let hash := verbatim_1i_1o(hex"49", 0) + mstore(0, hash) + return(0, 32) + } + } + } +} \ No newline at end of file diff --git a/packages/protocol/contracts/4844/IBlobHashReader.sol b/packages/protocol/contracts/4844/IBlobHashReader.sol new file mode 100644 index 000000000000..eb88b6e19350 --- /dev/null +++ b/packages/protocol/contracts/4844/IBlobHashReader.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +/// @title IBlobHashReader +/// @dev Labeled in AddressResolver as "blob_hash_reader" +/// @dev This interface and its corresponding implementation may deprecate once +/// solidity supports the new BLOBHASH opcode natively. +interface IBlobHashReader { + /// @notice Returns the versioned hash for the first blob in this + /// transaction. If there is no blob found, 0x0 is returned. + function getFirstBlobHash() external view returns (bytes32); +} diff --git a/packages/protocol/contracts/4844/Lib4844.sol b/packages/protocol/contracts/4844/Lib4844.sol new file mode 100644 index 000000000000..64ae752c17ff --- /dev/null +++ b/packages/protocol/contracts/4844/Lib4844.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +/// @title Lib4844 +/// @notice A library for handling EIP-4844 blobs +/// `solc contracts/libs/Lib4844.sol --ir > contracts/libs/Lib4844.yul` +library Lib4844 { + address public constant POINT_EVALUATION_PRECOMPILE_ADDRESS = address(0x0A); + uint32 public constant FIELD_ELEMENTS_PERBLOB = 4096; + uint256 public constant BLS_MODULUS = + 52_435_875_175_126_190_479_447_740_508_185_965_837_690_552_500_527_637_822_603_658_699_938_581_184_513; + + error EVAL_FAILED(); + error POINT_X_TOO_LARGE(); + error POINT_Y_TOO_LARGE(); + + /// @notice Evaluates the 4844 point using the precompile. + /// @param blobHash The versioned hash + /// @param x The evaluation point + /// @param y The expected output + /// @param commitment The input kzg point + /// @param pointProof The quotient kzg + function evaluatePoint( + bytes32 blobHash, + uint256 x, + uint256 y, + bytes1[48] memory commitment, + bytes1[48] memory pointProof + ) + internal + view + { + if (x >= BLS_MODULUS) revert POINT_X_TOO_LARGE(); + if (y >= BLS_MODULUS) revert POINT_Y_TOO_LARGE(); + + (bool ok,) = POINT_EVALUATION_PRECOMPILE_ADDRESS.staticcall( + abi.encodePacked(blobHash, x, y, commitment, pointProof) + ); + if (!ok) revert EVAL_FAILED(); + } +} diff --git a/packages/protocol/contracts/L1/ChainProver.sol b/packages/protocol/contracts/L1/ChainProver.sol new file mode 100644 index 000000000000..5b8e2a0cf270 --- /dev/null +++ b/packages/protocol/contracts/L1/ChainProver.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "../common/EssentialContract.sol"; +import "../libs/LibAddress.sol"; +import "./TaikoData.sol"; +import "./TaikoErrors.sol"; +import "./VerifierRegistry.sol"; +import "./verifiers/IVerifier.sol"; + +/// @title ChainProver +/// @notice The prover contract for Taiko. +contract ChainProver is EssentialContract, TaikoErrors { + using LibAddress for address; + + /// @dev Struct representing transition to be proven. + struct ProofData { + IVerifier verifier; + bytes proof; + } + + /// @dev Struct representing transition to be proven. + struct ProofBatch { + // These 2 keccak(new_l1_blockhash, new_root)) will be the new state (hash) + // and the transition hash it the old and the new, hashed together. + uint64 newL1BlockNumber; // Which L1 block is "covered" (proved) with this transaction + bytes32 newL1Root; // The new root hash + ProofData[] proofs; + address prover; + } + + // New, and only state var + bytes32 public currentStateHash; //equals to: keccak(newL1BlockNumber, newL1Root) + + function init(address _owner, address _addressManager) external initializer { + if (_addressManager == address(0)) { + revert L1_INVALID_ADDRESS(); + } + __Essential_init(_owner, _addressManager); + } + + /// @dev Proves up until a specific L1 block + function prove(bytes calldata data) external nonReentrant whenNotPaused { + // Decode the block data + ProofBatch memory proofBatch = abi.decode(data, (ProofBatch)); + // This is hwo we get the transition hash + bytes32 l1BlockHash = blockhash(proofBatch.newL1BlockNumber); + bytes32 newStateHash = keccak256(abi.encode(l1BlockHash, proofBatch.newL1Root)); + + VerifierRegistry verifierRegistry = VerifierRegistry(resolve("verifier_registry", false)); + // Verify the proofs + uint160 prevVerifier = uint160(0); + for (uint256 i = 0; i < proofBatch.proofs.length; i++) { + IVerifier verifier = proofBatch.proofs[i].verifier; + // Make sure each verifier is unique + if (prevVerifier >= uint160(address(verifier))) { + revert L1_INVALID_OR_DUPLICATE_VERIFIER(); + } + // Make sure it's a valid verifier + require(verifierRegistry.isVerifier(address(verifier)), "invalid verifier"); + // Verify the proof + verifier.verifyProof( + keccak256(abi.encode(currentStateHash, newStateHash)), + proofBatch.prover, + proofBatch.proofs[i].proof + ); + prevVerifier = uint160(address(verifier)); + } + + // Make sure the supplied proofs are sufficient. + // Can use some custom logic here. but let's keep it simple + require(proofBatch.proofs.length >= 3, "insufficient number of proofs"); + + currentStateHash = newStateHash; + //todo(@Brecht, @Dani) If somebody still gets an invalid proof through, we have to have + // another safety mechanisms! (e.g.: guardians, etc.) + } +} diff --git a/packages/protocol/contracts/L1/ExtensionOracle.sol b/packages/protocol/contracts/L1/ExtensionOracle.sol new file mode 100644 index 000000000000..2cf58de976d1 --- /dev/null +++ b/packages/protocol/contracts/L1/ExtensionOracle.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.28; + +import "./GwynethData.sol"; + +contract ExtensionOracle { + + struct ReturnData { + bytes data; + bool isRevert; + } + + uint private transient returndataCounter; + // TODO(Brecht): change to transient, solidity doesn't support this yet + ReturnData[] private returndata; + + address payable private constant gwyneth = payable(0x9fCF7D13d10dEdF17d0f24C62f0cf4ED462f65b7); + + fallback() external payable { + _returnData(); + } + + receive() external payable { + _returnData(); + } + + function _returnData() internal { + if (msg.sender == gwyneth) { + returndata = abi.decode(msg.data, (ReturnData[])); + returndataCounter = 0; + } else { + //require(returndataCounter < returndata.length, "invalid call pattern"); + + // Allow forge simulation to work + if (returndataCounter >= returndata.length) { + (bool success, bytes memory data) = msg.sender.call(msg.data); + if (!success) { + assembly { + revert(add(data, 32), mload(data)) + } + } else { + assembly { + return(add(data, 32), mload(data)) + } + } + } + + // Collect all ETH in the Gwyneth contract + if (msg.value > 0) { + (bool success, ) = gwyneth.call{value: msg.value }(""); + require(success, "Failed to send Ether"); + } + + ReturnData memory returnData = returndata[returndataCounter++]; + bytes memory data = returnData.data; + if (returnData.isRevert) { + assembly { + revert(add(data, 32), mload(data)) + } + } else { + assembly { + return(add(data, 32), mload(data)) + } + } + } + } +} \ No newline at end of file diff --git a/packages/protocol/contracts/L1/Gwyneth.sol b/packages/protocol/contracts/L1/Gwyneth.sol new file mode 100644 index 000000000000..104aea89cabd --- /dev/null +++ b/packages/protocol/contracts/L1/Gwyneth.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import "./IGwyneth.sol"; +import "./GwynethData.sol"; +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + + +/// @title Gwyneth +contract Gwyneth is IGwyneth { + address public owner; + // We don't really need to store this but let's do it anyway for now + bytes32 public ultraHash; + // Temporary proposer map + mapping(address proposer => bool whitelisted) public proposers; + + /// @dev Emitted when a block is proposed. + /// @param block The block metadata containing information about the proposed + /// block. + event BlockProposed(GwynethData.UltraBlock block); + + event Executed(address to, uint256 value, bytes data, bool success, bytes result, uint gas); + + /// @notice Initializes the rollup. + /// @param _genesisUltraHash The hash of the genesis ultra block. + function init( + address _owner, + bytes32 _genesisUltraHash + ) + external + { + owner = _owner; + ultraHash = _genesisUltraHash; + proposers[0xE25583099BA105D9ec0A67f5Ae86D90e50036425] = true; + } + + function propose(GwynethData.UltraBlock calldata _block, GwynethData.Proof calldata proof) + external + payable + override + { + require(_block.parentL1BlockHash == blockhash(block.number - 1), "included in an unexpected L1 block"); + //require(_block.parentUltraHash == ultraHash, "parent ULTRA hash mismatch"); + + // for (uint i = 0; i < _block.blobHashes.length; i++) { + // require(blobhash(i) == _block.blobHashes[i], "unexpected blob hash"); + // } + + for (uint i = 0; i < _block.blocks.length; i++) { + _propose(_block.blocks[i]); + } + _prove(_block, proof); + + ultraHash = _block.ultraHash; + + emit BlockProposed({ block: _block }); + } + + function _propose(GwynethData.Block calldata _block) + private + { + // Apply L1 state updates + for (uint i = 0; i < _block.l1Block.transactions.length; i++) { + GwynethData.Transaction calldata _tx = _block.l1Block.transactions[i]; + + (bool success, bytes memory result) = payable(_tx.addr).call{value: _tx.value, gas: _tx.gas }(_tx.data); + emit Executed(_tx.addr, _tx.value, _tx.data, success, result, _tx.gas); + + // if (!_tx.reverts && !success) { + // assembly { + // revert(add(result, 32), mload(result)) + // } + // } + } + } + + function _prove(GwynethData.UltraBlock calldata _block, GwynethData.Proof calldata proof) + view + private + { + bytes32 inputHash = keccak256(abi.encode(_block)); + require(proposers[ECDSA.recover(inputHash, proof.proof)] == true, "invalid proof"); + } + + // This contract stores all L2 ETH + receive() external payable {} + + + function setProposer(address proposer, bool whitelisted) + external + { + require(msg.sender == owner); + proposers[proposer] = whitelisted; + } +} diff --git a/packages/protocol/contracts/L1/GwynethData.sol b/packages/protocol/contracts/L1/GwynethData.sol new file mode 100644 index 000000000000..e5b26d465404 --- /dev/null +++ b/packages/protocol/contracts/L1/GwynethData.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +/// @title GwynethData +/// @notice This library defines various data structures used in the Gwyneth +/// protocol. +library GwynethData { + /// @dev ULTRA TX + struct UltraBlock { + bytes32 ultraHash; + bytes32 parentUltraHash; + bytes32 parentL1BlockHash; + + bytes32[] blobHashes; + bytes da; + + Block[] blocks; + } + + /// @dev Struct containing all block data + struct Block { + L1Block l1Block; + + bytes32 extraData; + address coinbase; + + uint24 daByteOffset; + uint24 daByteSize; + } + + /// @dev Struct representing the state that has to be applied to L1 in sequential order + struct L1Block { + Transaction[] transactions; + } + + struct Transaction { + address addr; + bytes data; + uint256 value; + uint64 gas; + bool reverts; + } + + struct StateDiffAccount { + StateDiffStorageSlot[] storageSlots; + uint balanceChange; + } + + struct StateDiffStorageSlot { + bytes32 key; + bytes32 value; + } + + struct Proof { + bytes proof; + } +} diff --git a/packages/protocol/contracts/L1/IGwyneth.sol b/packages/protocol/contracts/L1/IGwyneth.sol new file mode 100644 index 000000000000..0f9b932816b2 --- /dev/null +++ b/packages/protocol/contracts/L1/IGwyneth.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "./GwynethData.sol"; + +/// @title IGwyneth +/// @custom:security-contact security@taiko.xyz +interface IGwyneth { + /// @notice Proposes a Gwyneth block + function propose(GwynethData.UltraBlock calldata _block, GwynethData.Proof calldata proof) + external + payable; +} diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol new file mode 100644 index 000000000000..0076f903cb71 --- /dev/null +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +/// @title TaikoData +/// @notice This library defines various data structures used in the Taiko +/// protocol. +library TaikoData { + /// @dev Struct holding Taiko configuration parameters. See {TaikoConfig}. + struct Config { + // The chain ID of the network where Taiko contracts are deployed. + uint64 chainId; + // The maximum gas limit allowed for a block. + uint32 blockMaxGasLimit; + // The maximum allowed bytes for the proposed transaction list calldata. + uint24 blockMaxTxListBytes; + } + + /// @dev Struct containing data only required for proving a block + struct BlockMetadata { + bytes32 blockHash; + bytes32 parentBlockHash; + bytes32 parentMetaHash; + bytes32 l1Hash; + uint256 difficulty; + bytes32 blobHash; + bytes32 extraData; + address coinbase; + uint64 l2BlockNumber; + uint32 gasLimit; + uint32 l1StateBlockNumber; + uint64 timestamp; + uint24 txListByteOffset; + uint24 txListByteSize; + // todo: Do we need this below ? + // bytes32 blobId OR blobHash; ? as per in current taiko-mono's preconfirmation branch ? + bool blobUsed; + bytes txList; + bytes stateDiffs; + StateDiff l1StateDiff; + } + + /// @dev Struct representing the state delta that has to be applied to L1 + struct StateDiff { + StateDiffAccount[] accounts; + } + + struct StateDiffAccount { + address addr; + StateDiffStorageSlot[] slots; + } + + struct StateDiffStorageSlot { + bytes32 key; + bytes32 value; + } + + /// @dev Struct representing transition to be proven. + struct Transition { + bytes32 parentBlockHash; + bytes32 blockHash; + } + + /// @dev Struct representing state transition data. + struct TransitionState { + bytes32 blockHash; //Might be removed.. + uint64 timestamp; + address prover; + uint64 verifiableAfter; + bool isProven; + } + + /// @dev Struct containing data required for verifying a block. + struct Block { + bytes32 blockHash; + bytes32 metaHash; + uint64 blockId; + uint64 timestamp; + uint32 l1StateBlockNumber; + } + + /// @dev Struct holding the state variables for the {TaikoL1} contract. + struct State { + mapping(uint256 blockId => Block) blocks; + mapping(uint256 blockId => mapping(bytes32 parentBlockHash => TransitionState)) transitions; + uint64 genesisHeight; + uint64 genesisTimestamp; + uint64 numBlocks; + uint64 lastVerifiedBlockId; + bool provingPaused; + uint64 lastUnpausedAt; + uint256[143] __gap; + } +} \ No newline at end of file diff --git a/packages/protocol/contracts/L1/TaikoErrors.sol b/packages/protocol/contracts/L1/TaikoErrors.sol new file mode 100644 index 000000000000..545a9843ab41 --- /dev/null +++ b/packages/protocol/contracts/L1/TaikoErrors.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +/// @title TaikoErrors +/// @notice This abstract contract provides custom error declartions used in +/// the Taiko protocol. Each error corresponds to specific situations where +/// exceptions might be thrown. +abstract contract TaikoErrors { + // NOTE: The following custom errors must match the definitions in + // `L1/libs/*.sol`. + error L1_ALREADY_CONTESTED(); + error L1_ALREADY_PROVED(); + error L1_ASSIGNED_PROVER_NOT_ALLOWED(); + error L1_BLOB_FOR_DA_DISABLED(); + error L1_BLOB_NOT_FOUND(); + error L1_BLOB_NOT_REUSEABLE(); + error L1_BLOCK_MISMATCH(); + error L1_INCORRECT_BLOCK(); + error L1_INSUFFICIENT_TOKEN(); + error L1_INVALID_ADDRESS(); + error L1_INVALID_AMOUNT(); + error L1_INVALID_BLOCK_ID(); + error L1_INVALID_CONFIG(); + error L1_INVALID_ETH_DEPOSIT(); + error L1_INVALID_L1_STATE_BLOCK(); + error L1_INVALID_OR_DUPLICATE_VERIFIER(); + error L1_INVALID_PARAM(); + error L1_INVALID_PAUSE_STATUS(); + error L1_INVALID_PROOF(); + error L1_INVALID_PROPOSER(); + error L1_INVALID_PROVER(); + error L1_INVALID_TIER(); + error L1_INVALID_TIMESTAMP(); + error L1_INVALID_TRANSITION(); + error L1_LIVENESS_BOND_NOT_RECEIVED(); + error L1_NOT_ASSIGNED_PROVER(); + error L1_PROPOSER_NOT_EOA(); + error L1_PROVING_PAUSED(); + error L1_RECEIVE_DISABLED(); + error L1_TOO_MANY_BLOCKS(); + error L1_TOO_MANY_TIERS(); + error L1_TRANSITION_ID_ZERO(); + error L1_TRANSITION_NOT_FOUND(); + error L1_TXLIST_OFFSET_SIZE(); + error L1_TXLIST_TOO_LARGE(); + error L1_UNAUTHORIZED(); + error L1_UNEXPECTED_PARENT(); + error L1_UNEXPECTED_TRANSITION_ID(); + error L1_UNEXPECTED_TRANSITION_TIER(); +} diff --git a/packages/protocol/contracts/L1/VerifierBattleRoyale.sol b/packages/protocol/contracts/L1/VerifierBattleRoyale.sol new file mode 100644 index 000000000000..bbb8ba7e8dac --- /dev/null +++ b/packages/protocol/contracts/L1/VerifierBattleRoyale.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "../common/AddressResolver.sol"; +import "../common/EssentialContract.sol"; +import "../libs/LibAddress.sol"; +import "./verifiers/IVerifier.sol"; +import "./VerifierRegistry.sol"; +import "./TaikoData.sol"; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/// @title VerifierBattleRoyale +/// @notice A permissionless bounty to claim a reward for breaking a prover +contract VerifierBattleRoyale is EssentialContract { + struct Bounty { + uint256 startedAt; + uint256 rate; // per second + uint256 maxReward; + uint256 claimedAt; + address winner; + } + + /// @dev Struct representing transition to be proven. + struct ProofData { + IVerifier verifier; + bytes32 postRoot; // post root from this hashing: keccak(new_l1_blockhash, new_root) + bytes proof; + } + + struct ProofBatch { + bytes32 preTransitionHash; //(l1BlockHash and root) // This has to be same for all + // proofData, and we need to prove that we can achieve different post state -> which + // should not be allowed. + bytes32 postL1BlockHash; + ProofData[] proofs; + address prover; + } + + uint256 public constant PERCENTAGE_CLAIMED_IMMEDIATELY = 25; + + VerifierRegistry public verifierRegistry; + mapping(address verifier => Bounty) public bounties; + + function init(address _addressManager) external initializer { + __Essential_init(_addressManager); + } + + /// @dev Proposes a Taiko L2 block. + function openBounty(address verifier, Bounty memory bounty) external onlyOwner { + require(bounty.winner == address(0), "winner needs to be set to 0"); + bounties[verifier] = bounty; + } + + // Allows anyone to claim the bounty be proving that some verifier is broken + function claimBounty(address brokenVerifier, bytes calldata data) external { + require(bounties[brokenVerifier].startedAt != 0, "bounty doesn't exist"); + require(bounties[brokenVerifier].winner == address(0), "bounty already claimed"); + + // Decode the block data + ProofBatch memory proofBatch = abi.decode(data, (ProofBatch)); + + // Verify the all the proofs + for (uint256 i = 0; i < proofBatch.proofs.length; i++) { + IVerifier verifier = proofBatch.proofs[i].verifier; + require(verifierRegistry.isVerifier(address(verifier)), "invalid verifier"); + + bytes32 transitionToBeVerified = keccak256( + abi.encode( + proofBatch.preTransitionHash, + keccak256(abi.encode(proofBatch.postL1BlockHash, proofBatch.proofs[i].postRoot)) + ) + ); + + verifier.verifyProof( + transitionToBeVerified, proofBatch.prover, proofBatch.proofs[i].proof + ); + } + + if (proofBatch.proofs.length == 2) { + /* Same verifier, same block, but different blockhashes/signalroots */ + require( + proofBatch.proofs[0].verifier == proofBatch.proofs[1].verifier, + "verifiers not the same" + ); + require( + address(proofBatch.proofs[0].verifier) == brokenVerifier, + "incorrect broken verifier address" + ); + + require( + proofBatch.proofs[0].postRoot != proofBatch.proofs[1].postRoot, + "post state is the same" + ); + } else if (proofBatch.proofs.length == 3) { + /* Multiple verifiers in a consensus show that another verifier is faulty */ + + // Check that all verifiers are unique + // Verify the proofs + uint160 prevVerifier = 0; + for (uint256 i = 0; i < proofBatch.proofs.length; i++) { + require( + prevVerifier >= uint160(address(proofBatch.proofs[i].verifier)), + "duplicated verifier" + ); + prevVerifier = uint160(address(proofBatch.proofs[i].verifier)); + } + + // Reference proofs need to be placed first in the array, the faulty proof is listed + // last + require( + proofBatch.proofs[0].postRoot == proofBatch.proofs[1].postRoot, "incorrect order" + ); + require( + proofBatch.proofs[1].postRoot != proofBatch.proofs[2].postRoot, "incorrect order" + ); + + //require also that brokenVerifier is the same as the 3rd's verifier address + require( + proofBatch.proofs[1].postRoot != proofBatch.proofs[2].postRoot, "incorrect order" + ); + require( + address(proofBatch.proofs[1].verifier) == brokenVerifier, + "incorrect broken verifier address" + ); + } else { + revert("unsupported claim"); + } + + // Mark the bounty as claimed + bounties[brokenVerifier].claimedAt = block.timestamp; + bounties[brokenVerifier].winner = msg.sender; + + // Distribute part of the reward immediately + uint256 initialReward = + (calculateTotalReward(bounties[brokenVerifier]) * PERCENTAGE_CLAIMED_IMMEDIATELY) / 100; + IERC20 tko = IERC20(resolve("taiko_token", false)); + tko.transfer(bounties[brokenVerifier].winner, initialReward); + + // Poison the verifier so it cannot be used anymore + verifierRegistry.poisonVerifier(brokenVerifier); + } + + // Called after the one who claimed a bounty has either disclosed + // how the prover was broken or not + function closeBounty(address verifier, bool disclosed) external onlyOwner { + require(bounties[verifier].winner != address(0), "bounty not claimed yet"); + + // Transfer out the remaining locked part only the winner has disclosed how the prover was + // broken + if (disclosed) { + // Distribute the remaining part of the reward + uint256 remainingReward = ( + calculateTotalReward(bounties[verifier]) * (100 - PERCENTAGE_CLAIMED_IMMEDIATELY) + ) / 100; + IERC20 tko = IERC20(resolve("taiko_token", false)); + tko.transfer(bounties[verifier].winner, remainingReward); + } + + // Delete the bounty + // A new bounty needs to be started for the verifier + delete bounties[verifier]; + } + + function calculateTotalReward(Bounty memory bounty) internal pure returns (uint256) { + uint256 accumulated = (bounty.claimedAt - bounty.startedAt) * bounty.rate; + if (accumulated > bounty.maxReward) { + accumulated = bounty.maxReward; + } + return accumulated; + } +} diff --git a/packages/protocol/contracts/L1/VerifierRegistry.sol b/packages/protocol/contracts/L1/VerifierRegistry.sol new file mode 100644 index 000000000000..c50145e98419 --- /dev/null +++ b/packages/protocol/contracts/L1/VerifierRegistry.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "../common/AddressResolver.sol"; +import "../common/EssentialContract.sol"; + +/// @title VerifierRegistry +/// @notice A registry for handling all known verifiers +contract VerifierRegistry is EssentialContract { + struct Verifier { + uint16 id; + bytes4 tag; + bool poisoned; + } + + mapping(address verifier => Verifier) public verifiers; + mapping(address verifier => uint256 id) public verifierId; + mapping(uint256 id => address verifier) public verifierAddress; + + uint16 public verifierIdGenerator; + + function init(address _owner, address _addressManager) external initializer { + __Essential_init(_owner, _addressManager); + verifierIdGenerator = 1; + } + + /// Adds a verifier + function addVerifier(address verifier, bytes4 tag) external onlyOwner { + // Generate a unique id + uint16 id = verifierIdGenerator++; + verifiers[verifier] = Verifier({ id: id, tag: tag, poisoned: false }); + verifierId[verifier] = id; + verifierAddress[id] = verifier; + } + + /// Makes a verifier unusable + function poisonVerifier(address verifier) external onlyFromOwnerOrNamed("verifier_watchdog") { + delete verifiers[verifier]; + } + + function isVerifier(address addr) external view returns (bool) { + return verifiers[addr].id != 0 && !verifiers[addr].poisoned; + } +} diff --git a/packages/protocol/contracts/L1/verifiers/GuardianVerifier.sol b/packages/protocol/contracts/L1/verifiers/GuardianVerifier.sol new file mode 100644 index 000000000000..7f1cf7b64a96 --- /dev/null +++ b/packages/protocol/contracts/L1/verifiers/GuardianVerifier.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "../../common/EssentialContract.sol"; +import "../TaikoData.sol"; +import "./IVerifier.sol"; + +/// @title GuardianVerifier +contract GuardianVerifier is EssentialContract, IVerifier { + uint256[50] private __gap; + + error PERMISSION_DENIED(); + + /// @notice Initializes the contract with the provided address manager. + /// @param _addressManager The address of the address manager contract. + function init(address _addressManager) external initializer { + __Essential_init(_addressManager); + } + + /// @inheritdoc IVerifier + function verifyProof( + bytes32, /*transitionHash*/ + address prover, + bytes calldata /*proof*/ + ) + external + view + { + if (prover != resolve("guardian_prover", false)) { + revert PERMISSION_DENIED(); + } + } +} diff --git a/packages/protocol/contracts/L1/verifiers/IVerifier.sol b/packages/protocol/contracts/L1/verifiers/IVerifier.sol new file mode 100644 index 000000000000..85a8e8f69f9b --- /dev/null +++ b/packages/protocol/contracts/L1/verifiers/IVerifier.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "../TaikoData.sol"; + +/// @title IVerifier Interface +/// @notice Defines the function that handles proof verification. +interface IVerifier { + function verifyProof( + bytes32 transitionHash, // keccak(keccak(current_l1_blockhash, current_root), + // keccak(new_l1_blockhash, new_root)) + address prover, + bytes calldata proof + ) + external; +} diff --git a/packages/protocol/contracts/L1/verifiers/SgxVerifier.sol b/packages/protocol/contracts/L1/verifiers/SgxVerifier.sol new file mode 100644 index 000000000000..d5e69d83971d --- /dev/null +++ b/packages/protocol/contracts/L1/verifiers/SgxVerifier.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "../../common/EssentialContract.sol"; +import "../../automata-attestation/interfaces/IAttestation.sol"; +import "../../automata-attestation/lib/QuoteV3Auth/V3Struct.sol"; +import "./libs/LibPublicInput.sol"; +import "./IVerifier.sol"; + +/// @title SgxVerifier +/// @notice This contract is the implementation of verifying SGX signature proofs +/// onchain. +/// @dev Please see references below: +/// - Reference #1: https://ethresear.ch/t/2fa-zk-rollups-using-sgx/14462 +/// - Reference #2: https://github.com/gramineproject/gramine/discussions/1579 +/// @custom:security-contact security@taiko.xyz +contract SgxVerifier is EssentialContract, IVerifier { + /// @dev Each public-private key pair (Ethereum address) is generated within + /// the SGX program when it boots up. The off-chain remote attestation + /// ensures the validity of the program hash and has the capability of + /// bootstrapping the network with trustworthy instances. + struct Instance { + address addr; + uint64 validSince; + } + + /// @notice The expiry time for the SGX instance. + uint64 public constant INSTANCE_EXPIRY = 365 days; + + /// @notice A security feature, a delay until an instance is enabled when using onchain RA + /// verification + uint64 public constant INSTANCE_VALIDITY_DELAY = 0; + + /// @dev For gas savings, we shall assign each SGX instance with an id that when we need to + /// set a new pub key, just write storage once. + /// Slot 1. + uint256 public nextInstanceId; + + /// @dev One SGX instance is uniquely identified (on-chain) by it's ECDSA public key + /// (or rather ethereum address). Once that address is used (by proof verification) it has to be + /// overwritten by a new one (representing the same instance). This is due to side-channel + /// protection. Also this public key shall expire after some time + /// (for now it is a long enough 6 months setting). + /// Slot 2. + mapping(uint256 instanceId => Instance instance) public instances; + + /// @dev One address shall be registered (during attestation) only once, otherwise it could + /// bypass this contract's expiry check by always registering with the same attestation and + /// getting multiple valid instanceIds. While during proving, it is technically possible to + /// register the old addresses, it is less of a problem, because the instanceId would be the + /// same for those addresses and if deleted - the attestation cannot be reused anyways. + /// Slot 3. + mapping(address instanceAddress => bool alreadyAttested) public addressRegistered; + + uint256[47] private __gap; + + /// @notice Emitted when a new SGX instance is added to the registry, or replaced. + /// @param id The ID of the SGX instance. + /// @param instance The address of the SGX instance. + /// @param replaced The address of the SGX instance that was replaced. If it is the first + /// instance, this value is zero address. + /// @param validSince The time since the instance is valid. + event InstanceAdded( + uint256 indexed id, address indexed instance, address indexed replaced, uint256 validSince + ); + + /// @notice Emitted when an SGX instance is deleted from the registry. + /// @param id The ID of the SGX instance. + /// @param instance The address of the SGX instance. + event InstanceDeleted(uint256 indexed id, address indexed instance); + + error SGX_ALREADY_ATTESTED(); + error SGX_INVALID_ATTESTATION(); + error SGX_INVALID_INSTANCE(); + error SGX_INVALID_PROOF(); + error SGX_RA_NOT_SUPPORTED(); + + /// @notice Initializes the contract. + /// @param _owner The owner of this contract. msg.sender will be used if this value is zero. + /// @param _addressManager The address of the {AddressManager} contract. + function init(address _owner, address _addressManager) external initializer { + __Essential_init(_owner, _addressManager); + } + + /// @notice Adds trusted SGX instances to the registry. + /// @param _instances The address array of trusted SGX instances. + /// @return The respective instanceId array per addresses. + function addInstances(address[] calldata _instances) + external + onlyOwner + returns (uint256[] memory) + { + return _addInstances(_instances, true); + } + + /// @notice Deletes SGX instances from the registry. + /// @param _ids The ids array of SGX instances. + function deleteInstances(uint256[] calldata _ids) + external + onlyFromOwnerOrNamed("sgx_watchdog") + { + for (uint256 i; i < _ids.length; ++i) { + uint256 idx = _ids[i]; + + if (instances[idx].addr == address(0)) revert SGX_INVALID_INSTANCE(); + + emit InstanceDeleted(idx, instances[idx].addr); + + delete instances[idx]; + } + } + + /// @notice Adds an SGX instance after the attestation is verified + /// @param _attestation The parsed attestation quote. + /// @return The respective instanceId + function registerInstance(V3Struct.ParsedV3QuoteStruct calldata _attestation) + external + returns (uint256) + { + address automataDcapAttestation = resolve("automata_dcap_attestation", true); + + if (automataDcapAttestation == address(0)) { + revert SGX_RA_NOT_SUPPORTED(); + } + + (bool verified,) = IAttestation(automataDcapAttestation).verifyParsedQuote(_attestation); + + if (!verified) revert SGX_INVALID_ATTESTATION(); + + address[] memory _address = new address[](1); + _address[0] = address(bytes20(_attestation.localEnclaveReport.reportData)); + + return _addInstances(_address, false)[0]; + } + + /// @inheritdoc IVerifier + function verifyProof( + bytes32 transitionHash, + address prover, + bytes calldata proof + ) + external + onlyFromNamed("taiko") + { + // Size is: 89 bytes + // 4 bytes + 20 bytes + 65 bytes (signature) = 89 + if (proof.length != 89) revert SGX_INVALID_PROOF(); + + uint32 id = uint32(bytes4(proof[:4])); + address newInstance = address(bytes20(proof[4:24])); + bytes memory signature = proof[24:]; + + uint64 chainId = uint64(block.chainid); + + address oldInstance = ECDSA.recover( + LibPublicInput.hashPublicInputs( + transitionHash, address(this), newInstance, prover, chainId + ), + signature + ); + + if (!_isInstanceValid(id, oldInstance)) revert SGX_INVALID_INSTANCE(); + + if (oldInstance != newInstance) { + _replaceInstance(id, oldInstance, newInstance); + } + } + + function _addInstances( + address[] memory _instances, + bool instantValid + ) + private + returns (uint256[] memory ids) + { + ids = new uint256[](_instances.length); + + uint64 validSince = uint64(block.timestamp); + + if (!instantValid) { + validSince += INSTANCE_VALIDITY_DELAY; + } + + for (uint256 i; i < _instances.length; ++i) { + if (addressRegistered[_instances[i]]) revert SGX_ALREADY_ATTESTED(); + + addressRegistered[_instances[i]] = true; + + if (_instances[i] == address(0)) revert SGX_INVALID_INSTANCE(); + + instances[nextInstanceId] = Instance(_instances[i], validSince); + ids[i] = nextInstanceId; + + emit InstanceAdded(nextInstanceId, _instances[i], address(0), validSince); + + ++nextInstanceId; + } + } + + function _replaceInstance(uint256 id, address oldInstance, address newInstance) private { + // Replacing an instance means, it went through a cooldown (if added by on-chain RA) so no + // need to have a cooldown + instances[id] = Instance(newInstance, uint64(block.timestamp)); + emit InstanceAdded(id, newInstance, oldInstance, block.timestamp); + } + + function _isInstanceValid(uint256 id, address instance) private view returns (bool) { + if (instance == address(0)) return false; + if (instance != instances[id].addr) return false; + return instances[id].validSince <= block.timestamp + && block.timestamp <= instances[id].validSince + INSTANCE_EXPIRY; + } +} diff --git a/packages/protocol/contracts/L1/verifiers/libs/LibPublicInput.sol b/packages/protocol/contracts/L1/verifiers/libs/LibPublicInput.sol new file mode 100644 index 000000000000..5b8803545dcc --- /dev/null +++ b/packages/protocol/contracts/L1/verifiers/libs/LibPublicInput.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "../../TaikoData.sol"; + +/// @title LibPublicInput +/// @notice A library for handling hashing the so-called public input hash, used by sgx and zk +/// proofs. +/// @custom:security-contact security@taiko.xyz +library LibPublicInput { + /// @notice Hashes the public input for the proof verification. + /// @param _transitionHash The new state hash transition. + /// @param _verifierContract The contract address which as current verifier. + /// @param _newInstance The new instance address. For SGX it is the new signer address, for ZK + /// this variable is not used and must have value address(0). + /// @param _prover The prover address. + /// @param _chainId The chain id. + /// @return The public input hash. + function hashPublicInputs( + bytes32 _transitionHash, + address _verifierContract, + address _newInstance, + address _prover, + uint64 _chainId + ) + internal + pure + returns (bytes32) + { + return keccak256( + abi.encode( + "VERIFY_PROOF", _chainId, _verifierContract, _transitionHash, _newInstance, _prover + ) + ); + } +} diff --git a/packages/protocol/contracts/automata-attestation/AutomataDcapV3Attestation.sol b/packages/protocol/contracts/automata-attestation/AutomataDcapV3Attestation.sol new file mode 100644 index 000000000000..758384f6d91d --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/AutomataDcapV3Attestation.sol @@ -0,0 +1,508 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { V3Struct } from "./lib/QuoteV3Auth/V3Struct.sol"; +import { V3Parser } from "./lib/QuoteV3Auth/V3Parser.sol"; +import { IPEMCertChainLib } from "./lib/interfaces/IPEMCertChainLib.sol"; +import { PEMCertChainLib } from "./lib/PEMCertChainLib.sol"; +import { TCBInfoStruct } from "./lib/TCBInfoStruct.sol"; +import { EnclaveIdStruct } from "./lib/EnclaveIdStruct.sol"; +import { IAttestation } from "./interfaces/IAttestation.sol"; + +// Internal Libraries +import { Base64 } from "solady/src/utils/Base64.sol"; +import { LibString } from "solady/src/utils/LibString.sol"; +import { BytesUtils } from "./utils/BytesUtils.sol"; + +// External Libraries +import { ISigVerifyLib } from "./interfaces/ISigVerifyLib.sol"; + +import { EssentialContract } from "../common/EssentialContract.sol"; + +/// @title AutomataDcapV3Attestation +/// @custom:security-contact security@taiko.xyz +contract AutomataDcapV3Attestation is IAttestation, EssentialContract { + using BytesUtils for bytes; + + // https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/e7604e02331b3377f3766ed3653250e03af72d45/QuoteVerification/QVL/Src/AttestationLibrary/src/CertVerification/X509Constants.h#L64 + uint256 internal constant CPUSVN_LENGTH = 16; + + // keccak256(hex"0ba9c4c0c0c86193a3fe23d6b02cda10a8bbd4e88e48b4458561a36e705525f567918e2edc88e40d860bd0cc4ee26aacc988e505a953558c453f6b0904ae7394") + // the uncompressed (0x04) prefix is not included in the pubkey pre-image + bytes32 internal constant ROOTCA_PUBKEY_HASH = + 0x89f72d7c488e5b53a77c23ebcb36970ef7eb5bcf6658e9b8292cfbe4703a8473; + + uint8 internal constant INVALID_EXIT_CODE = 255; + + ISigVerifyLib public sigVerifyLib; // slot 1 + IPEMCertChainLib public pemCertLib; // slot 2 + + bool public checkLocalEnclaveReport; // slot 3 + mapping(bytes32 enclave => bool trusted) public trustedUserMrEnclave; // slot 4 + mapping(bytes32 signer => bool trusted) public trustedUserMrSigner; // slot 5 + + // Quote Collateral Configuration + + // Index definition: + // 0 = Quote PCKCrl + // 1 = RootCrl + mapping(uint256 idx => mapping(bytes serialNum => bool revoked)) public serialNumIsRevoked; // slot + // 6 + // fmspc => tcbInfo + mapping(string fmspc => TCBInfoStruct.TCBInfo tcbInfo) public tcbInfo; // slot 7 + EnclaveIdStruct.EnclaveId public qeIdentity; // takes 4 slots, slot 8,9,10,11 + + uint256[39] __gap; + + event MrSignerUpdated(bytes32 indexed mrSigner, bool trusted); + event MrEnclaveUpdated(bytes32 indexed mrEnclave, bool trusted); + event TcbInfoJsonConfigured(string indexed fmspc, TCBInfoStruct.TCBInfo tcbInfoInput); + event QeIdentityConfigured(EnclaveIdStruct.EnclaveId qeIdentityInput); + event LocalReportCheckToggled(bool checkLocalEnclaveReport); + event RevokedCertSerialNumAdded(uint256 indexed index, bytes serialNum); + event RevokedCertSerialNumRemoved(uint256 indexed index, bytes serialNum); + + // @notice Initializes the contract. + /// @param sigVerifyLibAddr Address of the signature verification library. + /// @param pemCertLibAddr Address of certificate library. + function init( + address owner, + address sigVerifyLibAddr, + address pemCertLibAddr + ) + external + initializer + { + __Essential_init(owner); + sigVerifyLib = ISigVerifyLib(sigVerifyLibAddr); + pemCertLib = PEMCertChainLib(pemCertLibAddr); + } + + function setMrSigner(bytes32 _mrSigner, bool _trusted) external onlyOwner { + trustedUserMrSigner[_mrSigner] = _trusted; + emit MrSignerUpdated(_mrSigner, _trusted); + } + + function setMrEnclave(bytes32 _mrEnclave, bool _trusted) external onlyOwner { + trustedUserMrEnclave[_mrEnclave] = _trusted; + emit MrEnclaveUpdated(_mrEnclave, _trusted); + } + + function addRevokedCertSerialNum( + uint256 index, + bytes[] calldata serialNumBatch + ) + external + onlyOwner + { + for (uint256 i; i < serialNumBatch.length; ++i) { + if (serialNumIsRevoked[index][serialNumBatch[i]]) { + continue; + } + serialNumIsRevoked[index][serialNumBatch[i]] = true; + emit RevokedCertSerialNumAdded(index, serialNumBatch[i]); + } + } + + function removeRevokedCertSerialNum( + uint256 index, + bytes[] calldata serialNumBatch + ) + external + onlyOwner + { + for (uint256 i; i < serialNumBatch.length; ++i) { + if (!serialNumIsRevoked[index][serialNumBatch[i]]) { + continue; + } + delete serialNumIsRevoked[index][serialNumBatch[i]]; + emit RevokedCertSerialNumRemoved(index, serialNumBatch[i]); + } + } + + function configureTcbInfoJson( + string calldata fmspc, + TCBInfoStruct.TCBInfo calldata tcbInfoInput + ) + public + onlyOwner + { + // 2.2M gas + tcbInfo[fmspc] = tcbInfoInput; + emit TcbInfoJsonConfigured(fmspc, tcbInfoInput); + } + + function configureQeIdentityJson(EnclaveIdStruct.EnclaveId calldata qeIdentityInput) + external + onlyOwner + { + // 250k gas + qeIdentity = qeIdentityInput; + emit QeIdentityConfigured(qeIdentityInput); + } + + function toggleLocalReportCheck() external onlyOwner { + checkLocalEnclaveReport = !checkLocalEnclaveReport; + emit LocalReportCheckToggled(checkLocalEnclaveReport); + } + + function _attestationTcbIsValid(TCBInfoStruct.TCBStatus status) + internal + pure + virtual + returns (bool valid) + { + return status == TCBInfoStruct.TCBStatus.OK + || status == TCBInfoStruct.TCBStatus.TCB_SW_HARDENING_NEEDED + || status == TCBInfoStruct.TCBStatus.TCB_CONFIGURATION_AND_SW_HARDENING_NEEDED + || status == TCBInfoStruct.TCBStatus.TCB_OUT_OF_DATE + || status == TCBInfoStruct.TCBStatus.TCB_OUT_OF_DATE_CONFIGURATION_NEEDED; + } + + function verifyAttestation(bytes calldata data) external view override returns (bool success) { + (success,) = _verify(data); + } + + /// @dev Provide the raw quote binary as input + /// @dev The attestation data (or the returned data of this method) + /// is constructed depending on the validity of the quote verification. + /// @dev After confirming that a quote has been verified, the attestation's validity then + /// depends on the + /// status of the associated TCB. + /// @dev Example scenarios as below: + /// -------------------------------- + /// @dev Invalid quote verification: returns (false, INVALID_EXIT_CODE) + /// + /// @dev For all valid quote verification, the validity of the attestation depends on the status + /// of a + /// matching TCBInfo and this is defined in the _attestationTcbIsValid() method, which can be + /// overwritten + /// in derived contracts. (Except for "Revoked" status, which also returns (false, + /// INVALID_EXIT_CODE) value) + /// @dev For all valid quote verification, returns the following data: + /// (_attestationTcbIsValid(), abi.encodePacked(sha256(quote), uint8 exitCode)) + /// @dev exitCode is defined in the {{ TCBInfoStruct.TCBStatus }} enum + function _verify(bytes calldata quote) private view returns (bool, bytes memory) { + bytes memory retData = abi.encodePacked(INVALID_EXIT_CODE); + + // Step 1: Parse the quote input = 152k gas + (bool successful, V3Struct.ParsedV3QuoteStruct memory parsedV3Quote) = + V3Parser.parseInput(quote, address(pemCertLib)); + if (!successful) { + return (false, retData); + } + + return _verifyParsedQuote(parsedV3Quote); + } + + function _verifyQEReportWithIdentity(V3Struct.EnclaveReport memory quoteEnclaveReport) + private + view + returns (bool, EnclaveIdStruct.EnclaveIdStatus status) + { + EnclaveIdStruct.EnclaveId memory enclaveId = qeIdentity; + bool miscselectMatched = + quoteEnclaveReport.miscSelect & enclaveId.miscselectMask == enclaveId.miscselect; + + bool attributesMatched = + quoteEnclaveReport.attributes & enclaveId.attributesMask == enclaveId.attributes; + bool mrsignerMatched = quoteEnclaveReport.mrSigner == enclaveId.mrsigner; + + bool isvprodidMatched = quoteEnclaveReport.isvProdId == enclaveId.isvprodid; + + bool tcbFound; + for (uint256 i; i < enclaveId.tcbLevels.length; ++i) { + EnclaveIdStruct.TcbLevel memory tcb = enclaveId.tcbLevels[i]; + if (tcb.tcb.isvsvn <= quoteEnclaveReport.isvSvn) { + tcbFound = true; + status = tcb.tcbStatus; + break; + } + } + return ( + miscselectMatched && attributesMatched && mrsignerMatched && isvprodidMatched + && tcbFound, + status + ); + } + + function _checkTcbLevels( + IPEMCertChainLib.PCKCertificateField memory pck, + TCBInfoStruct.TCBInfo memory tcb + ) + private + pure + returns (bool, TCBInfoStruct.TCBStatus status) + { + for (uint256 i; i < tcb.tcbLevels.length; ++i) { + TCBInfoStruct.TCBLevelObj memory current = tcb.tcbLevels[i]; + bool pceSvnIsHigherOrGreater = pck.sgxExtension.pcesvn >= current.pcesvn; + bool cpuSvnsAreHigherOrGreater = _isCpuSvnHigherOrGreater( + pck.sgxExtension.sgxTcbCompSvnArr, current.sgxTcbCompSvnArr + ); + if (pceSvnIsHigherOrGreater && cpuSvnsAreHigherOrGreater) { + status = current.status; + bool tcbIsRevoked = status == TCBInfoStruct.TCBStatus.TCB_REVOKED; + return (!tcbIsRevoked, status); + } + } + return (true, TCBInfoStruct.TCBStatus.TCB_UNRECOGNIZED); + } + + function _isCpuSvnHigherOrGreater( + uint256[] memory pckCpuSvns, + uint8[] memory tcbCpuSvns + ) + private + pure + returns (bool) + { + if (pckCpuSvns.length != CPUSVN_LENGTH || tcbCpuSvns.length != CPUSVN_LENGTH) { + return false; + } + for (uint256 i; i < CPUSVN_LENGTH; ++i) { + if (pckCpuSvns[i] < tcbCpuSvns[i]) { + return false; + } + } + return true; + } + + function _verifyCertChain(IPEMCertChainLib.ECSha256Certificate[] memory certs) + private + view + returns (bool) + { + uint256 n = certs.length; + bool certRevoked; + bool certNotExpired; + bool verified; + bool certChainCanBeTrusted; + + for (uint256 i; i < n; ++i) { + IPEMCertChainLib.ECSha256Certificate memory issuer; + if (i == n - 1) { + // rootCA + issuer = certs[i]; + } else { + issuer = certs[i + 1]; + if (i == n - 2) { + // this cert is expected to be signed by the root + certRevoked = serialNumIsRevoked[uint256(IPEMCertChainLib.CRL.ROOT)][certs[i] + .serialNumber]; + } else if (certs[i].isPck) { + certRevoked = + serialNumIsRevoked[uint256(IPEMCertChainLib.CRL.PCK)][certs[i].serialNumber]; + } + if (certRevoked) { + break; + } + } + + certNotExpired = + block.timestamp > certs[i].notBefore && block.timestamp < certs[i].notAfter; + if (!certNotExpired) { + break; + } + + verified = sigVerifyLib.verifyES256Signature( + certs[i].tbsCertificate, certs[i].signature, issuer.pubKey + ); + if (!verified) { + break; + } + + bytes32 issuerPubKeyHash = keccak256(issuer.pubKey); + + if (issuerPubKeyHash == ROOTCA_PUBKEY_HASH) { + certChainCanBeTrusted = true; + break; + } + } + + return !certRevoked && certNotExpired && verified && certChainCanBeTrusted; + } + + function _enclaveReportSigVerification( + bytes memory pckCertPubKey, + bytes memory signedQuoteData, + V3Struct.ECDSAQuoteV3AuthData memory authDataV3, + V3Struct.EnclaveReport memory qeEnclaveReport + ) + private + view + returns (bool) + { + bytes32 expectedAuthDataHash = bytes32(qeEnclaveReport.reportData.substring(0, 32)); + bytes memory concatOfAttestKeyAndQeAuthData = + abi.encodePacked(authDataV3.ecdsaAttestationKey, authDataV3.qeAuthData.data); + bytes32 computedAuthDataHash = sha256(concatOfAttestKeyAndQeAuthData); + + bool qeReportDataIsValid = expectedAuthDataHash == computedAuthDataHash; + if (qeReportDataIsValid) { + bytes memory pckSignedQeReportBytes = + V3Parser.packQEReport(authDataV3.pckSignedQeReport); + bool qeSigVerified = sigVerifyLib.verifyES256Signature( + pckSignedQeReportBytes, authDataV3.qeReportSignature, pckCertPubKey + ); + bool quoteSigVerified = sigVerifyLib.verifyES256Signature( + signedQuoteData, authDataV3.ecdsa256BitSignature, authDataV3.ecdsaAttestationKey + ); + return qeSigVerified && quoteSigVerified; + } else { + return false; + } + } + + /// --------------- validate parsed quote --------------- + + /// @dev Provide the parsed quote binary as input + /// @dev The attestation data (or the returned data of this method) + /// is constructed depending on the validity of the quote verification. + /// @dev After confirming that a quote has been verified, the attestation's validity then + /// depends on the + /// status of the associated TCB. + /// @dev Example scenarios as below: + /// -------------------------------- + /// @dev Invalid quote verification: returns (false, INVALID_EXIT_CODE) + /// + /// @dev For all valid quote verification, the validity of the attestation depends on the status + /// of a + /// matching TCBInfo and this is defined in the _attestationTcbIsValid() method, which can be + /// overwritten + /// in derived contracts. (Except for "Revoked" status, which also returns (false, + /// INVALID_EXIT_CODE) value) + /// @dev For all valid quote verification, returns the following data: + /// (_attestationTcbIsValid()) + /// @dev exitCode is defined in the {{ TCBInfoStruct.TCBStatus }} enum + function verifyParsedQuote(V3Struct.ParsedV3QuoteStruct calldata v3quote) + external + view + override + returns (bool, bytes memory) + { + return _verifyParsedQuote(v3quote); + } + + function _verifyParsedQuote(V3Struct.ParsedV3QuoteStruct memory v3quote) + internal + view + returns (bool, bytes memory) + { + bytes memory retData = abi.encodePacked(INVALID_EXIT_CODE); + + // // Step 1: Parse the quote input = 152k gas + ( + bool successful, + , + , + bytes memory signedQuoteData, + V3Struct.ECDSAQuoteV3AuthData memory authDataV3 + ) = V3Parser.validateParsedInput(v3quote); + if (!successful) { + return (false, retData); + } + + // Step 2: Verify application enclave report MRENCLAVE and MRSIGNER + { + if (checkLocalEnclaveReport) { + // 4k gas + bool mrEnclaveIsTrusted = trustedUserMrEnclave[v3quote.localEnclaveReport.mrEnclave]; + bool mrSignerIsTrusted = trustedUserMrSigner[v3quote.localEnclaveReport.mrSigner]; + + if (!mrEnclaveIsTrusted || !mrSignerIsTrusted) { + return (false, retData); + } + } + } + + // Step 3: Verify enclave identity = 43k gas + EnclaveIdStruct.EnclaveIdStatus qeTcbStatus; + { + bool verifiedEnclaveIdSuccessfully; + (verifiedEnclaveIdSuccessfully, qeTcbStatus) = + _verifyQEReportWithIdentity(v3quote.v3AuthData.pckSignedQeReport); + if (!verifiedEnclaveIdSuccessfully) { + return (false, retData); + } + if ( + !verifiedEnclaveIdSuccessfully + || qeTcbStatus == EnclaveIdStruct.EnclaveIdStatus.SGX_ENCLAVE_REPORT_ISVSVN_REVOKED + ) { + return (false, retData); + } + } + + // Step 4: Parse Quote CertChain + IPEMCertChainLib.ECSha256Certificate[] memory parsedQuoteCerts; + TCBInfoStruct.TCBInfo memory fetchedTcbInfo; + { + // 536k gas + parsedQuoteCerts = new IPEMCertChainLib.ECSha256Certificate[](3); + for (uint256 i; i < 3; ++i) { + bool isPckCert = i == 0; // additional parsing for PCKCert + bool certDecodedSuccessfully; + // todo! move decodeCert offchain + (certDecodedSuccessfully, parsedQuoteCerts[i]) = pemCertLib.decodeCert( + authDataV3.certification.decodedCertDataArray[i], isPckCert + ); + if (!certDecodedSuccessfully) { + return (false, retData); + } + } + } + + // Step 5: basic PCK and TCB check = 381k gas + { + string memory parsedFmspc = parsedQuoteCerts[0].pck.sgxExtension.fmspc; + fetchedTcbInfo = tcbInfo[parsedFmspc]; + bool tcbConfigured = LibString.eq(parsedFmspc, fetchedTcbInfo.fmspc); + if (!tcbConfigured) { + return (false, retData); + } + + IPEMCertChainLib.ECSha256Certificate memory pckCert = parsedQuoteCerts[0]; + bool pceidMatched = LibString.eq(pckCert.pck.sgxExtension.pceid, fetchedTcbInfo.pceid); + if (!pceidMatched) { + return (false, retData); + } + } + + // Step 6: Verify TCB Level + TCBInfoStruct.TCBStatus tcbStatus; + { + // 4k gas + bool tcbVerified; + (tcbVerified, tcbStatus) = _checkTcbLevels(parsedQuoteCerts[0].pck, fetchedTcbInfo); + if (!tcbVerified) { + return (false, retData); + } + } + + // Step 7: Verify cert chain for PCK + { + // 660k gas (rootCA pubkey is trusted) + bool pckCertChainVerified = _verifyCertChain(parsedQuoteCerts); + if (!pckCertChainVerified) { + return (false, retData); + } + } + + // Step 8: Verify the local attestation sig and qe report sig = 670k gas + { + bool enclaveReportSigsVerified = _enclaveReportSigVerification( + parsedQuoteCerts[0].pubKey, + signedQuoteData, + authDataV3, + v3quote.v3AuthData.pckSignedQeReport + ); + if (!enclaveReportSigsVerified) { + return (false, retData); + } + } + + retData = abi.encodePacked(sha256(abi.encode(v3quote)), tcbStatus); + + return (_attestationTcbIsValid(tcbStatus), retData); + } +} diff --git a/packages/protocol/contracts/automata-attestation/README.md b/packages/protocol/contracts/automata-attestation/README.md new file mode 100644 index 000000000000..448c4bcd42fb --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/README.md @@ -0,0 +1,5 @@ +# Readme + +Original code (main branch) forked from https://github.com/automata-network/automata-dcap-v3-attestation and applied some gas optimizations here: https://github.com/smtmfft/automata-dcap-v3-attestation/tree/parse-quote-offline, which then got merged into taiko-mono. +The corresponding upstream PR is: https://github.com/automata-network/automata-dcap-v3-attestation/pull/6, waiting to be merged. +Atomata's attestation shall be 100% identical to taiko-mono's attestation code at this point. diff --git a/packages/protocol/contracts/automata-attestation/interfaces/IAttestation.sol b/packages/protocol/contracts/automata-attestation/interfaces/IAttestation.sol new file mode 100644 index 000000000000..e5a960a4af87 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/interfaces/IAttestation.sol @@ -0,0 +1,13 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { V3Struct } from "../lib/QuoteV3Auth/V3Struct.sol"; + +/// @title IAttestation +/// @custom:security-contact security@taiko.xyz +interface IAttestation { + function verifyAttestation(bytes calldata data) external returns (bool); + function verifyParsedQuote(V3Struct.ParsedV3QuoteStruct calldata v3quote) + external + returns (bool success, bytes memory retData); +} diff --git a/packages/protocol/contracts/automata-attestation/interfaces/ISigVerifyLib.sol b/packages/protocol/contracts/automata-attestation/interfaces/ISigVerifyLib.sol new file mode 100644 index 000000000000..3170d0649a9b --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/interfaces/ISigVerifyLib.sol @@ -0,0 +1,15 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title ISigVerifyLib +/// @custom:security-contact security@taiko.xyz +interface ISigVerifyLib { + function verifyES256Signature( + bytes memory tbs, + bytes memory signature, + bytes memory publicKey + ) + external + view + returns (bool sigValid); +} diff --git a/packages/protocol/contracts/automata-attestation/lib/EnclaveIdStruct.sol b/packages/protocol/contracts/automata-attestation/lib/EnclaveIdStruct.sol new file mode 100644 index 000000000000..d41be6d96710 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/lib/EnclaveIdStruct.sol @@ -0,0 +1,30 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title EnclaveIdStruct +/// @custom:security-contact security@taiko.xyz +library EnclaveIdStruct { + struct EnclaveId { + bytes4 miscselect; // Slot 1: + bytes4 miscselectMask; + uint16 isvprodid; + bytes16 attributes; // Slot 2 + bytes16 attributesMask; + bytes32 mrsigner; // Slot 3 + TcbLevel[] tcbLevels; // Slot 4 + } + + struct TcbLevel { + TcbObj tcb; + EnclaveIdStatus tcbStatus; + } + + struct TcbObj { + uint16 isvsvn; + } + + enum EnclaveIdStatus { + OK, + SGX_ENCLAVE_REPORT_ISVSVN_REVOKED + } +} diff --git a/packages/protocol/contracts/automata-attestation/lib/PEMCertChainLib.sol b/packages/protocol/contracts/automata-attestation/lib/PEMCertChainLib.sol new file mode 100644 index 000000000000..0fcc99f0a391 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/lib/PEMCertChainLib.sol @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { LibString } from "solady/src/utils/LibString.sol"; +import { Asn1Decode, NodePtr } from "../utils/Asn1Decode.sol"; +import { BytesUtils } from "../utils/BytesUtils.sol"; +import { X509DateUtils } from "../utils/X509DateUtils.sol"; +import { IPEMCertChainLib } from "./interfaces/IPEMCertChainLib.sol"; + +/// @title PEMCertChainLib +/// @custom:security-contact security@taiko.xyz +contract PEMCertChainLib is IPEMCertChainLib { + using Asn1Decode for bytes; + using NodePtr for uint256; + using BytesUtils for bytes; + + string internal constant HEADER = "-----BEGIN CERTIFICATE-----"; + string internal constant FOOTER = "-----END CERTIFICATE-----"; + uint256 internal constant HEADER_LENGTH = 27; + uint256 internal constant FOOTER_LENGTH = 25; + + string internal constant PCK_COMMON_NAME = "Intel SGX PCK Certificate"; + string internal constant PLATFORM_ISSUER_NAME = "Intel SGX PCK Platform CA"; + string internal constant PROCESSOR_ISSUER_NAME = "Intel SGX PCK Processor CA"; + bytes internal constant SGX_EXTENSION_OID = hex"2A864886F84D010D01"; + bytes internal constant TCB_OID = hex"2A864886F84D010D0102"; + bytes internal constant PCESVN_OID = hex"2A864886F84D010D010211"; + bytes internal constant PCEID_OID = hex"2A864886F84D010D0103"; + bytes internal constant FMSPC_OID = hex"2A864886F84D010D0104"; + + // https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/e7604e02331b3377f3766ed3653250e03af72d45/QuoteVerification/QVL/Src/AttestationLibrary/src/CertVerification/X509Constants.h#L64 + uint256 constant SGX_TCB_CPUSVN_SIZE = 16; + + struct PCKTCBFlags { + bool fmspcFound; + bool pceidFound; + bool tcbFound; + } + + function splitCertificateChain( + bytes memory pemChain, + uint256 size + ) + external + pure + returns (bool success, bytes[] memory certs) + { + certs = new bytes[](size); + string memory pemChainStr = string(pemChain); + + uint256 index = 0; + uint256 len = pemChain.length; + + for (uint256 i; i < size; ++i) { + string memory input; + if (i != 0) { + input = LibString.slice(pemChainStr, index, index + len); + } else { + input = pemChainStr; + } + uint256 increment; + (success, certs[i], increment) = _removeHeadersAndFooters(input); + + if (!success) { + return (false, certs); + } + + index += increment; + } + + success = true; + } + + function decodeCert( + bytes memory der, + bool isPckCert + ) + external + pure + returns (bool success, ECSha256Certificate memory cert) + { + uint256 root = der.root(); + + // Entering tbsCertificate sequence + uint256 tbsParentPtr = der.firstChildOf(root); + + // Begin iterating through the descendants of tbsCertificate + uint256 tbsPtr = der.firstChildOf(tbsParentPtr); + + // The Serial Number is located one element below Version + + // The issuer commonName value is contained in the Issuer sequence + // which is 3 elements below the first element of the tbsCertificate sequence + + // The Validity sequence is located 4 elements below the first element of the tbsCertificate + // sequence + + // The subject commanName value is contained in the Subject sequence + // which is 5 elements below the first element of the tbsCertificate sequence + + // The PublicKey is located in the second element of subjectPublicKeyInfo sequence + // which is 6 elements below the first element of the tbsCertificate sequence + + tbsPtr = der.nextSiblingOf(tbsPtr); + + { + bytes memory serialNumBytes = der.bytesAt(tbsPtr); + cert.serialNumber = serialNumBytes; + } + + tbsPtr = der.nextSiblingOf(tbsPtr); + tbsPtr = der.nextSiblingOf(tbsPtr); + + if (isPckCert) { + uint256 issuerPtr = der.firstChildOf(tbsPtr); + issuerPtr = der.firstChildOf(issuerPtr); + issuerPtr = der.firstChildOf(issuerPtr); + issuerPtr = der.nextSiblingOf(issuerPtr); + cert.pck.issuerName = string(der.bytesAt(issuerPtr)); + bool issuerNameIsValid = LibString.eq(cert.pck.issuerName, PLATFORM_ISSUER_NAME) + || LibString.eq(cert.pck.issuerName, PROCESSOR_ISSUER_NAME); + if (!issuerNameIsValid) { + return (false, cert); + } + } + + tbsPtr = der.nextSiblingOf(tbsPtr); + + { + uint256 notBeforePtr = der.firstChildOf(tbsPtr); + uint256 notAfterPtr = der.nextSiblingOf(notBeforePtr); + bytes1 notBeforeTag = der[notBeforePtr.ixs()]; + bytes1 notAfterTag = der[notAfterPtr.ixs()]; + if ( + (notBeforeTag != 0x17 && notBeforeTag != 0x18) + || (notAfterTag != 0x17 && notAfterTag != 0x18) + ) { + return (false, cert); + } + cert.notBefore = X509DateUtils.toTimestamp(der.bytesAt(notBeforePtr)); + cert.notAfter = X509DateUtils.toTimestamp(der.bytesAt(notAfterPtr)); + } + + tbsPtr = der.nextSiblingOf(tbsPtr); + + if (isPckCert) { + uint256 subjectPtr = der.firstChildOf(tbsPtr); + subjectPtr = der.firstChildOf(subjectPtr); + subjectPtr = der.firstChildOf(subjectPtr); + subjectPtr = der.nextSiblingOf(subjectPtr); + cert.pck.commonName = string(der.bytesAt(subjectPtr)); + if (!LibString.eq(cert.pck.commonName, PCK_COMMON_NAME)) { + return (false, cert); + } + } + + tbsPtr = der.nextSiblingOf(tbsPtr); + + { + // Entering subjectPublicKeyInfo sequence + uint256 subjectPublicKeyInfoPtr = der.firstChildOf(tbsPtr); + subjectPublicKeyInfoPtr = der.nextSiblingOf(subjectPublicKeyInfoPtr); + + // The Signature sequence is located two sibling elements below the tbsCertificate + // element + uint256 sigPtr = der.nextSiblingOf(tbsParentPtr); + sigPtr = der.nextSiblingOf(sigPtr); + + // Skip three bytes to the right + // the three bytes in question: 0x034700 or 0x034800 or 0x034900 + sigPtr = NodePtr.getPtr(sigPtr.ixs() + 3, sigPtr.ixf() + 3, sigPtr.ixl()); + + sigPtr = der.firstChildOf(sigPtr); + bytes memory sigX = _trimBytes(der.bytesAt(sigPtr), 32); + + sigPtr = der.nextSiblingOf(sigPtr); + bytes memory sigY = _trimBytes(der.bytesAt(sigPtr), 32); + + cert.tbsCertificate = der.allBytesAt(tbsParentPtr); + cert.pubKey = _trimBytes(der.bytesAt(subjectPublicKeyInfoPtr), 64); + cert.signature = abi.encodePacked(sigX, sigY); + } + + if (isPckCert) { + // entering Extension sequence + tbsPtr = der.nextSiblingOf(tbsPtr); + + // check for the extension tag + if (der[tbsPtr.ixs()] != 0xA3) { + return (false, cert); + } + + tbsPtr = der.firstChildOf(tbsPtr); + tbsPtr = der.firstChildOf(tbsPtr); + + bool sgxExtnTraversedSuccessfully; + uint256 pcesvn; + uint256[] memory cpuSvns; + bytes memory fmspcBytes; + bytes memory pceidBytes; + (sgxExtnTraversedSuccessfully, pcesvn, cpuSvns, fmspcBytes, pceidBytes) = + _findPckTcbInfo(der, tbsPtr, tbsParentPtr); + if (!sgxExtnTraversedSuccessfully) { + return (false, cert); + } + cert.pck.sgxExtension.pcesvn = pcesvn; + cert.pck.sgxExtension.sgxTcbCompSvnArr = cpuSvns; + cert.pck.sgxExtension.pceid = LibString.toHexStringNoPrefix(pceidBytes); + cert.pck.sgxExtension.fmspc = LibString.toHexStringNoPrefix(fmspcBytes); + cert.isPck = true; + } + + success = true; + } + + function _removeHeadersAndFooters(string memory pemData) + private + pure + returns (bool success, bytes memory extracted, uint256 endIndex) + { + // Check if the input contains the "BEGIN" and "END" headers + uint256 beginPos = LibString.indexOf(pemData, HEADER); + uint256 endPos = LibString.indexOf(pemData, FOOTER); + + bool headerFound = beginPos != LibString.NOT_FOUND; + bool footerFound = endPos != LibString.NOT_FOUND; + + if (!headerFound || !footerFound) { + return (false, extracted, endIndex); + } + + // Extract the content between the headers + uint256 contentStart = beginPos + HEADER_LENGTH; + + // Extract and return the content + bytes memory contentBytes; + + // do not include newline + bytes memory delimiter = hex"0a"; + string memory contentSlice = LibString.slice(pemData, contentStart, endPos); + string[] memory split = LibString.split(contentSlice, string(delimiter)); + string memory contentStr; + + for (uint256 i; i < split.length; ++i) { + contentStr = LibString.concat(contentStr, split[i]); + } + + contentBytes = bytes(contentStr); + return (true, contentBytes, endPos + FOOTER_LENGTH); + } + + function _trimBytes( + bytes memory input, + uint256 expectedLength + ) + private + pure + returns (bytes memory output) + { + uint256 n = input.length; + + if (n <= expectedLength) { + return input; + } + uint256 lengthDiff = n - expectedLength; + output = input.substring(lengthDiff, expectedLength); + } + + function _findPckTcbInfo( + bytes memory der, + uint256 tbsPtr, + uint256 tbsParentPtr + ) + private + pure + returns ( + bool success, + uint256 pcesvn, + uint256[] memory cpusvns, + bytes memory fmspcBytes, + bytes memory pceidBytes + ) + { + // iterate through the elements in the Extension sequence + // until we locate the SGX Extension OID + while (tbsPtr != 0) { + uint256 internalPtr = der.firstChildOf(tbsPtr); + if (der[internalPtr.ixs()] != 0x06) { + return (false, pcesvn, cpusvns, fmspcBytes, pceidBytes); + } + + if (BytesUtils.compareBytes(der.bytesAt(internalPtr), SGX_EXTENSION_OID)) { + // 1.2.840.113741.1.13.1 + internalPtr = der.nextSiblingOf(internalPtr); + uint256 extnValueParentPtr = der.rootOfOctetStringAt(internalPtr); + uint256 extnValuePtr = der.firstChildOf(extnValueParentPtr); + + // Copy flags to memory to avoid stack too deep + PCKTCBFlags memory flags; + + while (!(flags.fmspcFound && flags.pceidFound && flags.tcbFound)) { + uint256 extnValueOidPtr = der.firstChildOf(extnValuePtr); + if (der[extnValueOidPtr.ixs()] != 0x06) { + return (false, pcesvn, cpusvns, fmspcBytes, pceidBytes); + } + if (BytesUtils.compareBytes(der.bytesAt(extnValueOidPtr), TCB_OID)) { + // 1.2.840.113741.1.13.1.2 + (flags.tcbFound, pcesvn, cpusvns) = _findTcb(der, extnValueOidPtr); + } + if (BytesUtils.compareBytes(der.bytesAt(extnValueOidPtr), PCEID_OID)) { + // 1.2.840.113741.1.13.1.3 + uint256 pceidPtr = der.nextSiblingOf(extnValueOidPtr); + pceidBytes = der.bytesAt(pceidPtr); + flags.pceidFound = true; + } + if (BytesUtils.compareBytes(der.bytesAt(extnValueOidPtr), FMSPC_OID)) { + // 1.2.840.113741.1.13.1.4 + uint256 fmspcPtr = der.nextSiblingOf(extnValueOidPtr); + fmspcBytes = der.bytesAt(fmspcPtr); + flags.fmspcFound = true; + } + + if (extnValuePtr.ixl() < extnValueParentPtr.ixl()) { + extnValuePtr = der.nextSiblingOf(extnValuePtr); + } else { + break; + } + } + success = flags.fmspcFound && flags.pceidFound && flags.tcbFound; + break; + } + + if (tbsPtr.ixl() < tbsParentPtr.ixl()) { + tbsPtr = der.nextSiblingOf(tbsPtr); + } else { + tbsPtr = 0; // exit + } + } + } + + function _findTcb( + bytes memory der, + uint256 oidPtr + ) + private + pure + returns (bool success, uint256 pcesvn, uint256[] memory cpusvns) + { + // sibling of tcbOid + uint256 tcbPtr = der.nextSiblingOf(oidPtr); + // get the first svn object in the sequence + uint256 svnParentPtr = der.firstChildOf(tcbPtr); + cpusvns = new uint256[](SGX_TCB_CPUSVN_SIZE); + for (uint256 i; i < SGX_TCB_CPUSVN_SIZE + 1; ++i) { + uint256 svnPtr = der.firstChildOf(svnParentPtr); // OID + uint256 svnValuePtr = der.nextSiblingOf(svnPtr); // value + bytes memory svnValueBytes = der.bytesAt(svnValuePtr); + uint16 svnValue = svnValueBytes.length < 2 + ? uint16(bytes2(svnValueBytes)) / 256 + : uint16(bytes2(svnValueBytes)); + if (BytesUtils.compareBytes(der.bytesAt(svnPtr), PCESVN_OID)) { + // pcesvn is 4 bytes in size + pcesvn = uint256(svnValue); + } else { + // each cpusvn is at maximum two bytes in size + uint256 cpusvn = uint256(svnValue); + cpusvns[i] = cpusvn; + } + + // iterate to the next svn object in the sequence + svnParentPtr = der.nextSiblingOf(svnParentPtr); + } + success = true; + } +} diff --git a/packages/protocol/contracts/automata-attestation/lib/QuoteV3Auth/V3Parser.sol b/packages/protocol/contracts/automata-attestation/lib/QuoteV3Auth/V3Parser.sol new file mode 100644 index 000000000000..59e95ef1f403 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/lib/QuoteV3Auth/V3Parser.sol @@ -0,0 +1,306 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { Base64 } from "solady/src/utils/Base64.sol"; +import { BytesUtils } from "../../utils/BytesUtils.sol"; +import { IPEMCertChainLib, PEMCertChainLib } from "../../lib/PEMCertChainLib.sol"; +import { V3Struct } from "./V3Struct.sol"; + +/// @title V3Parser +/// @custom:security-contact security@taiko.xyz +library V3Parser { + using BytesUtils for bytes; + + uint256 internal constant MINIMUM_QUOTE_LENGTH = 1020; + bytes2 internal constant SUPPORTED_QUOTE_VERSION = 0x0300; + bytes2 internal constant SUPPORTED_ATTESTATION_KEY_TYPE = 0x0200; + // SGX only + bytes4 internal constant SUPPORTED_TEE_TYPE = 0; + bytes16 internal constant VALID_QE_VENDOR_ID = 0x939a7233f79c4ca9940a0db3957f0607; + + error V3PARSER_INVALID_QUOTE_LENGTN(); + error V3PARSER_INVALID_QUOTE_MEMBER_LENGTN(); + error V3PARSER_INVALID_QEREPORT_LENGTN(); + error V3PARSER_UNSUPPORT_CERTIFICATION_TYPE(); + error V3PARSER_INVALID_CERTIFICATION_CHAIN_SIZE(); + error V3PARSER_INVALID_CERTIFICATION_CHAIN_DATA(); + error V3PARSER_INVALID_ECDSA_SIGNATURE(); + error V3PARSER_INVALID_QEAUTHDATA_SIZE(); + + function parseInput( + bytes memory quote, + address pemCertLibAddr + ) + internal + pure + returns (bool success, V3Struct.ParsedV3QuoteStruct memory v3ParsedQuote) + { + if (quote.length <= MINIMUM_QUOTE_LENGTH) { + return (false, v3ParsedQuote); + } + + uint256 localAuthDataSize = littleEndianDecode(quote.substring(432, 4)); + if (quote.length - 436 != localAuthDataSize) { + return (false, v3ParsedQuote); + } + + bytes memory rawHeader = quote.substring(0, 48); + (bool headerVerifiedSuccessfully, V3Struct.Header memory header) = + parseAndVerifyHeader(rawHeader); + if (!headerVerifiedSuccessfully) { + return (false, v3ParsedQuote); + } + + (bool authDataVerifiedSuccessfully, V3Struct.ECDSAQuoteV3AuthData memory authDataV3) = + parseAuthDataAndVerifyCertType(quote.substring(436, localAuthDataSize), pemCertLibAddr); + if (!authDataVerifiedSuccessfully) { + return (false, v3ParsedQuote); + } + + bytes memory rawLocalEnclaveReport = quote.substring(48, 384); + V3Struct.EnclaveReport memory localEnclaveReport = parseEnclaveReport(rawLocalEnclaveReport); + + v3ParsedQuote = V3Struct.ParsedV3QuoteStruct({ + header: header, + localEnclaveReport: localEnclaveReport, + v3AuthData: authDataV3 + }); + success = true; + } + + function validateParsedInput(V3Struct.ParsedV3QuoteStruct memory v3Quote) + internal + pure + returns ( + bool success, + V3Struct.Header memory header, + V3Struct.EnclaveReport memory localEnclaveReport, + bytes memory signedQuoteData, // concatenation of header and local enclave report bytes + V3Struct.ECDSAQuoteV3AuthData memory authDataV3 + ) + { + success = true; + localEnclaveReport = v3Quote.localEnclaveReport; + V3Struct.EnclaveReport memory pckSignedQeReport = v3Quote.v3AuthData.pckSignedQeReport; + + if ( + localEnclaveReport.reserved3.length != 96 || localEnclaveReport.reserved4.length != 60 + || localEnclaveReport.reportData.length != 64 + ) revert V3PARSER_INVALID_QUOTE_MEMBER_LENGTN(); + + if ( + pckSignedQeReport.reserved3.length != 96 || pckSignedQeReport.reserved4.length != 60 + || pckSignedQeReport.reportData.length != 64 + ) { + revert V3PARSER_INVALID_QEREPORT_LENGTN(); + } + + if (v3Quote.v3AuthData.certification.certType != 5) { + revert V3PARSER_UNSUPPORT_CERTIFICATION_TYPE(); + } + + if (v3Quote.v3AuthData.certification.decodedCertDataArray.length != 3) { + revert V3PARSER_INVALID_CERTIFICATION_CHAIN_SIZE(); + } + + if ( + v3Quote.v3AuthData.ecdsa256BitSignature.length != 64 + || v3Quote.v3AuthData.ecdsaAttestationKey.length != 64 + || v3Quote.v3AuthData.qeReportSignature.length != 64 + ) { + revert V3PARSER_INVALID_ECDSA_SIGNATURE(); + } + + if ( + v3Quote.v3AuthData.qeAuthData.parsedDataSize + != v3Quote.v3AuthData.qeAuthData.data.length + ) { + revert V3PARSER_INVALID_QEAUTHDATA_SIZE(); + } + + uint32 totalQuoteSize = 48 // header + + 384 // local QE report + + 64 // ecdsa256BitSignature + + 64 // ecdsaAttestationKey + + 384 // QE report + + 64 // qeReportSignature + + 2 // sizeof(v3Quote.v3AuthData.qeAuthData.parsedDataSize) + + v3Quote.v3AuthData.qeAuthData.parsedDataSize + 2 // sizeof(v3Quote.v3AuthData.certification.certType) + + 4 // sizeof(v3Quote.v3AuthData.certification.certDataSize) + + v3Quote.v3AuthData.certification.certDataSize; + if (totalQuoteSize <= MINIMUM_QUOTE_LENGTH) { + revert V3PARSER_INVALID_QUOTE_LENGTN(); + } + + header = v3Quote.header; + bytes memory headerBytes = abi.encodePacked( + header.version, + header.attestationKeyType, + header.teeType, + header.qeSvn, + header.pceSvn, + header.qeVendorId, + header.userData + ); + + signedQuoteData = abi.encodePacked(headerBytes, V3Parser.packQEReport(localEnclaveReport)); + authDataV3 = v3Quote.v3AuthData; + } + + function parseEnclaveReport(bytes memory rawEnclaveReport) + internal + pure + returns (V3Struct.EnclaveReport memory enclaveReport) + { + enclaveReport.cpuSvn = bytes16(rawEnclaveReport.substring(0, 16)); + enclaveReport.miscSelect = bytes4(rawEnclaveReport.substring(16, 4)); + enclaveReport.reserved1 = bytes28(rawEnclaveReport.substring(20, 28)); + enclaveReport.attributes = bytes16(rawEnclaveReport.substring(48, 16)); + enclaveReport.mrEnclave = bytes32(rawEnclaveReport.substring(64, 32)); + enclaveReport.reserved2 = bytes32(rawEnclaveReport.substring(96, 32)); + enclaveReport.mrSigner = bytes32(rawEnclaveReport.substring(128, 32)); + enclaveReport.reserved3 = rawEnclaveReport.substring(160, 96); + enclaveReport.isvProdId = uint16(littleEndianDecode(rawEnclaveReport.substring(256, 2))); + enclaveReport.isvSvn = uint16(littleEndianDecode(rawEnclaveReport.substring(258, 2))); + enclaveReport.reserved4 = rawEnclaveReport.substring(260, 60); + enclaveReport.reportData = rawEnclaveReport.substring(320, 64); + } + + function littleEndianDecode(bytes memory encoded) private pure returns (uint256 decoded) { + for (uint256 i; i < encoded.length; ++i) { + uint256 digits = uint256(uint8(bytes1(encoded[i]))); + uint256 upperDigit = digits / 16; + uint256 lowerDigit = digits % 16; + + uint256 acc = lowerDigit * (16 ** (2 * i)); + acc += upperDigit * (16 ** ((2 * i) + 1)); + + decoded += acc; + } + } + + function parseAndVerifyHeader(bytes memory rawHeader) + private + pure + returns (bool success, V3Struct.Header memory header) + { + bytes2 version = bytes2(rawHeader.substring(0, 2)); + if (version != SUPPORTED_QUOTE_VERSION) { + return (false, header); + } + + bytes2 attestationKeyType = bytes2(rawHeader.substring(2, 2)); + if (attestationKeyType != SUPPORTED_ATTESTATION_KEY_TYPE) { + return (false, header); + } + + bytes4 teeType = bytes4(rawHeader.substring(4, 4)); + if (teeType != SUPPORTED_TEE_TYPE) { + return (false, header); + } + + bytes16 qeVendorId = bytes16(rawHeader.substring(12, 16)); + if (qeVendorId != VALID_QE_VENDOR_ID) { + return (false, header); + } + + header = V3Struct.Header({ + version: version, + attestationKeyType: attestationKeyType, + teeType: teeType, + qeSvn: bytes2(rawHeader.substring(8, 2)), + pceSvn: bytes2(rawHeader.substring(10, 2)), + qeVendorId: qeVendorId, + userData: bytes20(rawHeader.substring(28, 20)) + }); + + success = true; + } + + function parseAuthDataAndVerifyCertType( + bytes memory rawAuthData, + address pemCertLibAddr + ) + private + pure + returns (bool success, V3Struct.ECDSAQuoteV3AuthData memory authDataV3) + { + V3Struct.QEAuthData memory qeAuthData; + qeAuthData.parsedDataSize = uint16(littleEndianDecode(rawAuthData.substring(576, 2))); + qeAuthData.data = rawAuthData.substring(578, qeAuthData.parsedDataSize); + + uint256 offset = 578 + qeAuthData.parsedDataSize; + V3Struct.CertificationData memory cert; + cert.certType = uint16(littleEndianDecode(rawAuthData.substring(offset, 2))); + if (cert.certType < 1 || cert.certType > 5) { + return (false, authDataV3); + } + offset += 2; + cert.certDataSize = uint32(littleEndianDecode(rawAuthData.substring(offset, 4))); + offset += 4; + bytes memory certData = rawAuthData.substring(offset, cert.certDataSize); + cert.decodedCertDataArray = parseCerificationChainBytes(certData, pemCertLibAddr); + + authDataV3.ecdsa256BitSignature = rawAuthData.substring(0, 64); + authDataV3.ecdsaAttestationKey = rawAuthData.substring(64, 64); + bytes memory rawQeReport = rawAuthData.substring(128, 384); + authDataV3.pckSignedQeReport = parseEnclaveReport(rawQeReport); + authDataV3.qeReportSignature = rawAuthData.substring(512, 64); + authDataV3.qeAuthData = qeAuthData; + authDataV3.certification = cert; + + success = true; + } + + /// enclaveReport to bytes for hash calculation. + /// the only difference between enclaveReport and packedQEReport is the + /// order of isvProdId and isvSvn. enclaveReport is in little endian, while + /// in bytes should be in big endian according to Intel spec. + /// @param enclaveReport enclave report + /// @return packedQEReport enclave report in bytes + function packQEReport(V3Struct.EnclaveReport memory enclaveReport) + internal + pure + returns (bytes memory packedQEReport) + { + uint16 isvProdIdPackBE = (enclaveReport.isvProdId >> 8) | (enclaveReport.isvProdId << 8); + uint16 isvSvnPackBE = (enclaveReport.isvSvn >> 8) | (enclaveReport.isvSvn << 8); + packedQEReport = abi.encodePacked( + enclaveReport.cpuSvn, + enclaveReport.miscSelect, + enclaveReport.reserved1, + enclaveReport.attributes, + enclaveReport.mrEnclave, + enclaveReport.reserved2, + enclaveReport.mrSigner, + enclaveReport.reserved3, + isvProdIdPackBE, + isvSvnPackBE, + enclaveReport.reserved4, + enclaveReport.reportData + ); + } + + function parseCerificationChainBytes( + bytes memory certBytes, + address pemCertLibAddr + ) + internal + pure + returns (bytes[3] memory certChainData) + { + IPEMCertChainLib pemCertLib = PEMCertChainLib(pemCertLibAddr); + IPEMCertChainLib.ECSha256Certificate[] memory parsedQuoteCerts; + (bool certParsedSuccessfully, bytes[] memory quoteCerts) = + pemCertLib.splitCertificateChain(certBytes, 3); + if (!certParsedSuccessfully) { + revert V3PARSER_INVALID_CERTIFICATION_CHAIN_DATA(); + } + parsedQuoteCerts = new IPEMCertChainLib.ECSha256Certificate[](3); + for (uint256 i; i < 3; ++i) { + quoteCerts[i] = Base64.decode(string(quoteCerts[i])); + } + + certChainData = [quoteCerts[0], quoteCerts[1], quoteCerts[2]]; + } +} diff --git a/packages/protocol/contracts/automata-attestation/lib/QuoteV3Auth/V3Struct.sol b/packages/protocol/contracts/automata-attestation/lib/QuoteV3Auth/V3Struct.sol new file mode 100644 index 000000000000..9ecb75729477 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/lib/QuoteV3Auth/V3Struct.sol @@ -0,0 +1,61 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title V3Struct +/// @custom:security-contact security@taiko.xyz +library V3Struct { + struct Header { + bytes2 version; + bytes2 attestationKeyType; + bytes4 teeType; + bytes2 qeSvn; + bytes2 pceSvn; + bytes16 qeVendorId; + bytes20 userData; + } + + struct EnclaveReport { + bytes16 cpuSvn; + bytes4 miscSelect; + bytes28 reserved1; + bytes16 attributes; + bytes32 mrEnclave; + bytes32 reserved2; + bytes32 mrSigner; + bytes reserved3; // 96 bytes + uint16 isvProdId; + uint16 isvSvn; + bytes reserved4; // 60 bytes + bytes reportData; // 64 bytes - For QEReports, this contains the hash of the concatenation + // of attestation key and QEAuthData + } + + struct QEAuthData { + uint16 parsedDataSize; + bytes data; + } + + struct CertificationData { + uint16 certType; + // todo! In encoded path, we need to calculate the size of certDataArray + // certDataSize = len(join((BEGIN_CERT, certArray[i], END_CERT) for i in 0..3)) + // But for plain bytes path, we don't need that. + uint32 certDataSize; + bytes[3] decodedCertDataArray; // base64 decoded cert bytes array + } + + struct ECDSAQuoteV3AuthData { + bytes ecdsa256BitSignature; // 64 bytes + bytes ecdsaAttestationKey; // 64 bytes + EnclaveReport pckSignedQeReport; // 384 bytes + bytes qeReportSignature; // 64 bytes + QEAuthData qeAuthData; + CertificationData certification; + } + + struct ParsedV3QuoteStruct { + Header header; + EnclaveReport localEnclaveReport; + ECDSAQuoteV3AuthData v3AuthData; + } +} diff --git a/packages/protocol/contracts/automata-attestation/lib/TCBInfoStruct.sol b/packages/protocol/contracts/automata-attestation/lib/TCBInfoStruct.sol new file mode 100644 index 000000000000..b450853c5b47 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/lib/TCBInfoStruct.sol @@ -0,0 +1,29 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title TCBInfoStruct +/// @custom:security-contact security@taiko.xyz +library TCBInfoStruct { + struct TCBInfo { + string pceid; + string fmspc; + TCBLevelObj[] tcbLevels; + } + + struct TCBLevelObj { + uint256 pcesvn; + uint8[] sgxTcbCompSvnArr; + TCBStatus status; + } + + enum TCBStatus { + OK, + TCB_SW_HARDENING_NEEDED, + TCB_CONFIGURATION_AND_SW_HARDENING_NEEDED, + TCB_CONFIGURATION_NEEDED, + TCB_OUT_OF_DATE, + TCB_OUT_OF_DATE_CONFIGURATION_NEEDED, + TCB_REVOKED, + TCB_UNRECOGNIZED + } +} diff --git a/packages/protocol/contracts/automata-attestation/lib/interfaces/IPEMCertChainLib.sol b/packages/protocol/contracts/automata-attestation/lib/interfaces/IPEMCertChainLib.sol new file mode 100644 index 000000000000..eeca3b929474 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/lib/interfaces/IPEMCertChainLib.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title IPEMCertChainLib +/// @custom:security-contact security@taiko.xyz +interface IPEMCertChainLib { + struct ECSha256Certificate { + uint256 notBefore; + uint256 notAfter; + bytes serialNumber; + bytes tbsCertificate; + bytes pubKey; + bytes signature; + bool isPck; + PCKCertificateField pck; + } + + struct PCKCertificateField { + string commonName; + string issuerName; + PCKTCBInfo sgxExtension; + } + + struct PCKTCBInfo { + string pceid; + string fmspc; + uint256 pcesvn; + uint256[] sgxTcbCompSvnArr; + } + + enum CRL { + PCK, + ROOT + } + + function splitCertificateChain( + bytes memory pemChain, + uint256 size + ) + external + pure + returns (bool success, bytes[] memory certs); + + function decodeCert( + bytes memory der, + bool isPckCert + ) + external + pure + returns (bool success, ECSha256Certificate memory cert); +} diff --git a/packages/protocol/contracts/automata-attestation/utils/Asn1Decode.sol b/packages/protocol/contracts/automata-attestation/utils/Asn1Decode.sol new file mode 100644 index 000000000000..30edd958e7f0 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/utils/Asn1Decode.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +// Original source: https://github.com/JonahGroendal/asn1-decode +pragma solidity ^0.8.24; + +// Inspired by PufferFinance/rave - Apache-2.0 license +// https://github.com/JonahGroendal/asn1-decode/blob/5c2d1469fc678513753786acb441e597969192ec/contracts/Asn1Decode.sol + +import "./BytesUtils.sol"; + +/// @title NodePtr +/// @custom:security-contact security@taiko.xyz +library NodePtr { + // Unpack first byte index + function ixs(uint256 self) internal pure returns (uint256) { + return uint80(self); + } + + // Unpack first content byte index + function ixf(uint256 self) internal pure returns (uint256) { + return uint80(self >> 80); + } + + // Unpack last content byte index + function ixl(uint256 self) internal pure returns (uint256) { + return uint80(self >> 160); + } + + // Pack 3 uint80s into a uint256 + function getPtr(uint256 _ixs, uint256 _ixf, uint256 _ixl) internal pure returns (uint256) { + _ixs |= _ixf << 80; + _ixs |= _ixl << 160; + return _ixs; + } +} + +/// @title Asn1Decode +/// @custom:security-contact security@taiko.xyz +library Asn1Decode { + using NodePtr for uint256; + using BytesUtils for bytes; + + /* + * @dev Get the root node. First step in traversing an ASN1 structure + * @param der The DER-encoded ASN1 structure + * @return A pointer to the outermost node + */ + function root(bytes memory der) internal pure returns (uint256) { + return _readNodeLength(der, 0); + } + + /* + * @dev Get the root node of an ASN1 structure that's within an octet string value + * @param der The DER-encoded ASN1 structure + * @return A pointer to the outermost node + */ + function rootOfOctetStringAt(bytes memory der, uint256 ptr) internal pure returns (uint256) { + require(der[ptr.ixs()] == 0x04, "Not type OCTET STRING"); + return _readNodeLength(der, ptr.ixf()); + } + + /* + * @dev Get the next sibling node + * @param der The DER-encoded ASN1 structure + * @param ptr Points to the indices of the current node + * @return A pointer to the next sibling node + */ + function nextSiblingOf(bytes memory der, uint256 ptr) internal pure returns (uint256) { + return _readNodeLength(der, ptr.ixl() + 1); + } + + /* + * @dev Get the first child node of the current node + * @param der The DER-encoded ASN1 structure + * @param ptr Points to the indices of the current node + * @return A pointer to the first child node + */ + function firstChildOf(bytes memory der, uint256 ptr) internal pure returns (uint256) { + require(der[ptr.ixs()] & 0x20 == 0x20, "Not a constructed type"); + return _readNodeLength(der, ptr.ixf()); + } + + /* + * @dev Extract value of node from DER-encoded structure + * @param der The der-encoded ASN1 structure + * @param ptr Points to the indices of the current node + * @return Value bytes of node + */ + function bytesAt(bytes memory der, uint256 ptr) internal pure returns (bytes memory) { + return der.substring(ptr.ixf(), ptr.ixl() + 1 - ptr.ixf()); + } + + /* + * @dev Extract entire node from DER-encoded structure + * @param der The DER-encoded ASN1 structure + * @param ptr Points to the indices of the current node + * @return All bytes of node + */ + function allBytesAt(bytes memory der, uint256 ptr) internal pure returns (bytes memory) { + return der.substring(ptr.ixs(), ptr.ixl() + 1 - ptr.ixs()); + } + + function keccakOfBytesAt(bytes memory der, uint256 ptr) internal pure returns (bytes32) { + return der.keccak(ptr.ixf(), ptr.ixl() + 1 - ptr.ixf()); + } + + function keccakOfAllBytesAt(bytes memory der, uint256 ptr) internal pure returns (bytes32) { + return der.keccak(ptr.ixs(), ptr.ixl() + 1 - ptr.ixs()); + } + + function _readNodeLength(bytes memory der, uint256 ix) private pure returns (uint256) { + uint256 length; + uint80 ixFirstContentByte; + uint80 ixLastContentByte; + if ((der[ix + 1] & 0x80) == 0) { + length = uint8(der[ix + 1]); + ixFirstContentByte = uint80(ix + 2); + ixLastContentByte = uint80(ixFirstContentByte + length - 1); + } else { + uint8 lengthbytesLength = uint8(der[ix + 1] & 0x7F); + if (lengthbytesLength == 1) { + length = der.readUint8(ix + 2); + } else if (lengthbytesLength == 2) { + length = der.readUint16(ix + 2); + } else { + length = uint256( + der.readBytesN(ix + 2, lengthbytesLength) >> (32 - lengthbytesLength) * 8 + ); + } + ixFirstContentByte = uint80(ix + 2 + lengthbytesLength); + ixLastContentByte = uint80(ixFirstContentByte + length - 1); + } + return NodePtr.getPtr(ix, ixFirstContentByte, ixLastContentByte); + } +} diff --git a/packages/protocol/contracts/automata-attestation/utils/BytesUtils.sol b/packages/protocol/contracts/automata-attestation/utils/BytesUtils.sol new file mode 100644 index 000000000000..22469685e0d3 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/utils/BytesUtils.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: BSD 2-Clause License +pragma solidity ^0.8.24; + +// Inspired by ensdomains/dnssec-oracle - BSD-2-Clause license +// https://github.com/ensdomains/dnssec-oracle/blob/master/contracts/BytesUtils.sol +/// @title BytesUtils +/// @custom:security-contact security@taiko.xyz +library BytesUtils { + /* + * @dev Returns the keccak-256 hash of a byte range. + * @param self The byte string to hash. + * @param offset The position to start hashing at. + * @param len The number of bytes to hash. + * @return The hash of the byte range. + */ + function keccak( + bytes memory self, + uint256 offset, + uint256 len + ) + internal + pure + returns (bytes32 ret) + { + require(offset + len <= self.length, "invalid offset"); + assembly { + ret := keccak256(add(add(self, 32), offset), len) + } + } + + /* + * @dev Returns true if the two byte ranges are equal. + * @param self The first byte range to compare. + * @param offset The offset into the first byte range. + * @param other The second byte range to compare. + * @param otherOffset The offset into the second byte range. + * @param len The number of bytes to compare + * @return true if the byte ranges are equal, false otherwise. + */ + function equals( + bytes memory self, + uint256 offset, + bytes memory other, + uint256 otherOffset, + uint256 len + ) + internal + pure + returns (bool) + { + return keccak(self, offset, len) == keccak(other, otherOffset, len); + } + + /* + * @dev Returns the 8-bit number at the specified index of self. + * @param self The byte string. + * @param idx The index into the bytes + * @return The specified 8 bits of the string, interpreted as an integer. + */ + function readUint8(bytes memory self, uint256 idx) internal pure returns (uint8 ret) { + return uint8(self[idx]); + } + + /* + * @dev Returns the 16-bit number at the specified index of self. + * @param self The byte string. + * @param idx The index into the bytes + * @return The specified 16 bits of the string, interpreted as an integer. + */ + function readUint16(bytes memory self, uint256 idx) internal pure returns (uint16 ret) { + require(idx + 2 <= self.length, "invalid idx"); + assembly { + ret := and(mload(add(add(self, 2), idx)), 0xFFFF) + } + } + + /* + * @dev Returns the n byte value at the specified index of self. + * @param self The byte string. + * @param idx The index into the bytes. + * @param len The number of bytes. + * @return The specified 32 bytes of the string. + */ + function readBytesN( + bytes memory self, + uint256 idx, + uint256 len + ) + internal + pure + returns (bytes32 ret) + { + require(len <= 32, "unexpected len"); + require(idx + len <= self.length, "unexpected idx"); + assembly { + let mask := not(sub(exp(256, sub(32, len)), 1)) + ret := and(mload(add(add(self, 32), idx)), mask) + } + } + + function memcpy(uint256 dest, uint256 src, uint256 len) private pure { + assembly { + mcopy(dest, src, len) + } + } + + /* + * @dev Copies a substring into a new byte string. + * @param self The byte string to copy from. + * @param offset The offset to start copying at. + * @param len The number of bytes to copy. + */ + function substring( + bytes memory self, + uint256 offset, + uint256 len + ) + internal + pure + returns (bytes memory) + { + require(offset + len <= self.length, "unexpected offset"); + + bytes memory ret = new bytes(len); + uint256 dest; + uint256 src; + + assembly { + dest := add(ret, 32) + src := add(add(self, 32), offset) + } + memcpy(dest, src, len); + + return ret; + } + + function compareBytes(bytes memory a, bytes memory b) internal pure returns (bool) { + return keccak256(a) == keccak256(b); + } +} diff --git a/packages/protocol/contracts/automata-attestation/utils/SHA1.sol b/packages/protocol/contracts/automata-attestation/utils/SHA1.sol new file mode 100644 index 000000000000..6c39a7d25dc0 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/utils/SHA1.sol @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: BSD 2-Clause License + +pragma solidity ^0.8.24; + +// Inspired by ensdomains/solsha1 - BSD 2-Clause License +// https://github.com/ensdomains/solsha1/blob/master/contracts/SHA1.sol + +/// @title SHA1 +/// @custom:security-contact security@taiko.xyz +library SHA1 { + function sha1(bytes memory data) internal pure returns (bytes20 ret) { + assembly { + // Get a safe scratch location + let scratch := mload(0x40) + + // Get the data length, and point data at the first byte + let len := mload(data) + data := add(data, 32) + + // Find the length after padding + let totallen := add(and(add(len, 1), 0xFFFFFFFFFFFFFFC0), 64) + switch lt(sub(totallen, len), 9) + case 1 { totallen := add(totallen, 64) } + + let h := 0x6745230100EFCDAB890098BADCFE001032547600C3D2E1F0 + + function readword(ptr, off, count) -> result { + result := 0 + if lt(off, count) { + result := mload(add(ptr, off)) + count := sub(count, off) + if lt(count, 32) { + let mask := not(sub(exp(256, sub(32, count)), 1)) + result := and(result, mask) + } + } + } + + for { let i := 0 } lt(i, totallen) { i := add(i, 64) } { + mstore(scratch, readword(data, i, len)) + mstore(add(scratch, 32), readword(data, add(i, 32), len)) + + // If we loaded the last byte, store the terminator byte + switch lt(sub(len, i), 64) + case 1 { mstore8(add(scratch, sub(len, i)), 0x80) } + + // If this is the last block, store the length + switch eq(i, sub(totallen, 64)) + case 1 { mstore(add(scratch, 32), or(mload(add(scratch, 32)), mul(len, 8))) } + + // Expand the 16 32-bit words into 80 + for { let j := 64 } lt(j, 128) { j := add(j, 12) } { + let temp := + xor( + xor(mload(add(scratch, sub(j, 12))), mload(add(scratch, sub(j, 32)))), + xor(mload(add(scratch, sub(j, 56))), mload(add(scratch, sub(j, 64)))) + ) + temp := + or( + and( + mul(temp, 2), + 0xFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFE + ), + and( + div(temp, 0x80000000), + 0x0000000100000001000000010000000100000001000000010000000100000001 + ) + ) + mstore(add(scratch, j), temp) + } + for { let j := 128 } lt(j, 320) { j := add(j, 24) } { + let temp := + xor( + xor(mload(add(scratch, sub(j, 24))), mload(add(scratch, sub(j, 64)))), + xor(mload(add(scratch, sub(j, 112))), mload(add(scratch, sub(j, 128)))) + ) + temp := + or( + and( + mul(temp, 4), + 0xFFFFFFFCFFFFFFFCFFFFFFFCFFFFFFFCFFFFFFFCFFFFFFFCFFFFFFFCFFFFFFFC + ), + and( + div(temp, 0x40000000), + 0x0000000300000003000000030000000300000003000000030000000300000003 + ) + ) + mstore(add(scratch, j), temp) + } + + let x := h + let f := 0 + let k := 0 + for { let j := 0 } lt(j, 80) { j := add(j, 1) } { + switch div(j, 20) + case 0 { + // f = d xor (b and (c xor d)) + f := xor(div(x, 0x100000000000000000000), div(x, 0x10000000000)) + f := and(div(x, 0x1000000000000000000000000000000), f) + f := xor(div(x, 0x10000000000), f) + k := 0x5A827999 + } + case 1 { + // f = b xor c xor d + f := + xor( + div(x, 0x1000000000000000000000000000000), + div(x, 0x100000000000000000000) + ) + f := xor(div(x, 0x10000000000), f) + k := 0x6ED9EBA1 + } + case 2 { + // f = (b and c) or (d and (b or c)) + f := + or( + div(x, 0x1000000000000000000000000000000), + div(x, 0x100000000000000000000) + ) + f := and(div(x, 0x10000000000), f) + f := + or( + and( + div(x, 0x1000000000000000000000000000000), + div(x, 0x100000000000000000000) + ), + f + ) + k := 0x8F1BBCDC + } + case 3 { + // f = b xor c xor d + f := + xor( + div(x, 0x1000000000000000000000000000000), + div(x, 0x100000000000000000000) + ) + f := xor(div(x, 0x10000000000), f) + k := 0xCA62C1D6 + } + // temp = (a leftrotate 5) + f + e + k + w[i] + let temp := and(div(x, 0x80000000000000000000000000000000000000000000000), 0x1F) + temp := + or(and(div(x, 0x800000000000000000000000000000000000000), 0xFFFFFFE0), temp) + temp := add(f, temp) + temp := add(and(x, 0xFFFFFFFF), temp) + temp := add(k, temp) + temp := + add( + div( + mload(add(scratch, mul(j, 4))), + 0x100000000000000000000000000000000000000000000000000000000 + ), + temp + ) + x := + or( + div(x, 0x10000000000), + mul(temp, 0x10000000000000000000000000000000000000000) + ) + x := + or( + and(x, 0xFFFFFFFF00FFFFFFFF000000000000FFFFFFFF00FFFFFFFF), + mul( + or( + and(div(x, 0x4000000000000), 0xC0000000), + and(div(x, 0x400000000000000000000), 0x3FFFFFFF) + ), + 0x100000000000000000000 + ) + ) + } + + h := and(add(h, x), 0xFFFFFFFF00FFFFFFFF00FFFFFFFF00FFFFFFFF00FFFFFFFF) + } + ret := + mul( + or( + or( + or( + or( + and(div(h, 0x100000000), 0xFFFFFFFF00000000000000000000000000000000), + and(div(h, 0x1000000), 0xFFFFFFFF000000000000000000000000) + ), + and(div(h, 0x10000), 0xFFFFFFFF0000000000000000) + ), + and(div(h, 0x100), 0xFFFFFFFF00000000) + ), + and(h, 0xFFFFFFFF) + ), + 0x1000000000000000000000000 + ) + } + } +} diff --git a/packages/protocol/contracts/automata-attestation/utils/SigVerifyLib.sol b/packages/protocol/contracts/automata-attestation/utils/SigVerifyLib.sol new file mode 100644 index 000000000000..85bae00b99d0 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/utils/SigVerifyLib.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.24; + +import "../interfaces/ISigVerifyLib.sol"; +import "./BytesUtils.sol"; + +/// @title SigVerifyLib +/// @custom:security-contact security@taiko.xyz +// Library for verifying signatures +contract SigVerifyLib is ISigVerifyLib { + using BytesUtils for bytes; + + address private immutable __es256Verifier; + + constructor(address es256Verifier) { + __es256Verifier = es256Verifier; + } + + function verifyES256Signature( + bytes calldata tbs, + bytes calldata signature, + bytes calldata publicKey + ) + external + view + returns (bool sigValid) + { + // Parse signature + if (signature.length != 64) { + return false; + } + uint256 r = uint256(bytes32(signature.substring(0, 32))); + uint256 s = uint256(bytes32(signature.substring(32, 32))); + // Parse public key + if (publicKey.length != 64) { + return false; + } + uint256 gx = uint256(bytes32(publicKey.substring(0, 32))); + uint256 gy = uint256(bytes32(publicKey.substring(32, 32))); + + // Verify signature + bytes memory args = abi.encode(sha256(tbs), r, s, gx, gy); + (bool success, bytes memory ret) = __es256Verifier.staticcall(args); + assert(success); // never reverts, always returns 0 or 1 + + return abi.decode(ret, (uint256)) == 1; + } +} diff --git a/packages/protocol/contracts/automata-attestation/utils/X509DateUtils.sol b/packages/protocol/contracts/automata-attestation/utils/X509DateUtils.sol new file mode 100644 index 000000000000..ac7ef6bc9617 --- /dev/null +++ b/packages/protocol/contracts/automata-attestation/utils/X509DateUtils.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @title X509DateUtils +/// @custom:security-contact security@taiko.xyz +library X509DateUtils { + function toTimestamp(bytes memory x509Time) internal pure returns (uint256) { + uint16 yrs; + uint8 mnths; + uint8 dys; + uint8 hrs; + uint8 mins; + uint8 secs; + uint8 offset; + + if (x509Time.length == 13) { + if (uint8(x509Time[0]) - 48 < 5) yrs += 2000; + else yrs += 1900; + } else { + yrs += (uint8(x509Time[0]) - 48) * 1000 + (uint8(x509Time[1]) - 48) * 100; + offset = 2; + } + yrs += (uint8(x509Time[offset + 0]) - 48) * 10 + uint8(x509Time[offset + 1]) - 48; + mnths = (uint8(x509Time[offset + 2]) - 48) * 10 + uint8(x509Time[offset + 3]) - 48; + dys += (uint8(x509Time[offset + 4]) - 48) * 10 + uint8(x509Time[offset + 5]) - 48; + hrs += (uint8(x509Time[offset + 6]) - 48) * 10 + uint8(x509Time[offset + 7]) - 48; + mins += (uint8(x509Time[offset + 8]) - 48) * 10 + uint8(x509Time[offset + 9]) - 48; + secs += (uint8(x509Time[offset + 10]) - 48) * 10 + uint8(x509Time[offset + 11]) - 48; + + return toUnixTimestamp(yrs, mnths, dys, hrs, mins, secs); + } + + function toUnixTimestamp( + uint16 year, + uint8 month, + uint8 day, + uint8 hour, + uint8 minute, + uint8 second + ) + internal + pure + returns (uint256) + { + uint256 timestamp = 0; + + for (uint16 i = 1970; i < year; ++i) { + if (isLeapYear(i)) { + timestamp += 31_622_400; // Leap year in seconds + } else { + timestamp += 31_536_000; // Normal year in seconds + } + } + + uint8[12] memory monthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + if (isLeapYear(year)) monthDays[1] = 29; + + for (uint8 i = 1; i < month; ++i) { + timestamp += uint256(monthDays[i - 1]) * 86_400; // Days in seconds + } + + timestamp += uint256(day - 1) * 86_400; // Days in seconds + timestamp += uint256(hour) * 3600; // Hours in seconds + timestamp += uint256(minute) * 60; // Minutes in seconds + timestamp += second; + + return timestamp; + } + + function isLeapYear(uint16 year) internal pure returns (bool) { + if (year % 4 != 0) return false; + if (year % 100 != 0) return true; + if (year % 400 != 0) return false; + return true; + } +} diff --git a/packages/protocol/contracts/common/AddressManager.sol b/packages/protocol/contracts/common/AddressManager.sol new file mode 100644 index 000000000000..5d997e162586 --- /dev/null +++ b/packages/protocol/contracts/common/AddressManager.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "./EssentialContract.sol"; + +/// @title AddressManager +/// @notice See the documentation in {IAddressManager}. +/// @custom:security-contact security@taiko.xyz +contract AddressManager is EssentialContract, IAddressManager { + /// @dev Mapping of chainId to mapping of name to address. + mapping(uint256 chainId => mapping(bytes32 name => address addr)) private __addresses; + + uint256[49] private __gap; + + /// @notice Emitted when an address is set. + /// @param chainId The chainId for the address mapping. + /// @param name The name for the address mapping. + /// @param newAddress The new address. + /// @param oldAddress The old address. + event AddressSet( + uint64 indexed chainId, bytes32 indexed name, address newAddress, address oldAddress + ); + + error AM_ADDRESS_ALREADY_SET(); + + /// @notice Initializes the contract. + /// @param _owner The owner of this contract. msg.sender will be used if this value is zero. + function init(address _owner) external initializer { + __Essential_init(_owner); + addressManager = address(this); + } + + function init2() external onlyOwner reinitializer(2) { + addressManager = address(this); + } + + /// @notice Sets the address for a specific chainId-name pair. + /// @param _chainId The chainId to which the address will be mapped. + /// @param _name The name to which the address will be mapped. + /// @param _newAddress The Ethereum address to be mapped. + function setAddress( + uint64 _chainId, + bytes32 _name, + address _newAddress + ) + external + virtual + onlyOwner + { + address oldAddress = __addresses[_chainId][_name]; + if (_newAddress == oldAddress) revert AM_ADDRESS_ALREADY_SET(); + __addresses[_chainId][_name] = _newAddress; + emit AddressSet(_chainId, _name, _newAddress, oldAddress); + } + + /// @inheritdoc IAddressManager + function getAddress(uint64 _chainId, bytes32 _name) external view override returns (address) { + address addr = _getOverride(_chainId, _name); + if (addr != address(0)) return addr; + else return __addresses[_chainId][_name]; + } + + /// @notice Gets the address mapped to a specific chainId-name pair. + /// @dev Sub-contracts can override this method to avoid reading from storage. + function _getOverride(uint64 _chainId, bytes32 _name) internal pure virtual returns (address) { } + + function _authorizePause(address, bool) internal pure override notImplemented { } +} diff --git a/packages/protocol/contracts/common/AddressResolver.sol b/packages/protocol/contracts/common/AddressResolver.sol new file mode 100644 index 000000000000..a4b0c81dc0a1 --- /dev/null +++ b/packages/protocol/contracts/common/AddressResolver.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "./IAddressManager.sol"; +import "./IAddressResolver.sol"; + +/// @title AddressResolver +/// @notice See the documentation in {IAddressResolver}. +/// @custom:security-contact security@taiko.xyz +abstract contract AddressResolver is IAddressResolver, Initializable { + /// @notice Address of the AddressManager. + address public addressManager; + uint256[49] private __gap; + + error RESOLVER_DENIED(); + error RESOLVER_INVALID_MANAGER(); + error RESOLVER_UNEXPECTED_CHAINID(); + error RESOLVER_ZERO_ADDR(uint64 chainId, bytes32 name); + + /// @dev Modifier that ensures the caller is the resolved address of a given + /// name. + /// @param _name The name to check against. + modifier onlyFromNamed(bytes32 _name) { + if (msg.sender != resolve(_name, true)) revert RESOLVER_DENIED(); + _; + } + + /// @dev Modifier that ensures the caller is a resolved address to either _name1 or _name2 + /// name. + /// @param _name1 The first name to check against. + /// @param _name2 The second name to check against. + modifier onlyFromNamedEither(bytes32 _name1, bytes32 _name2) { + if (msg.sender != resolve(_name1, true) && msg.sender != resolve(_name2, true)) { + revert RESOLVER_DENIED(); + } + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @inheritdoc IAddressResolver + function resolve( + bytes32 _name, + bool _allowZeroAddress + ) + public + view + virtual + returns (address payable) + { + return _resolve(uint64(block.chainid), _name, _allowZeroAddress); + } + + /// @inheritdoc IAddressResolver + function resolve( + uint64 _chainId, + bytes32 _name, + bool _allowZeroAddress + ) + public + view + virtual + returns (address payable) + { + return _resolve(_chainId, _name, _allowZeroAddress); + } + + /// @dev Initialization method for setting up AddressManager reference. + /// @param _addressManager Address of the AddressManager. + function __AddressResolver_init(address _addressManager) internal virtual onlyInitializing { + if (block.chainid > type(uint64).max) { + revert RESOLVER_UNEXPECTED_CHAINID(); + } + addressManager = _addressManager; + } + + /// @dev Helper method to resolve name-to-address. + /// @param _chainId The chainId of interest. + /// @param _name Name whose address is to be resolved. + /// @param _allowZeroAddress If set to true, does not throw if the resolved + /// address is `address(0)`. + /// @return addr_ Address associated with the given name on the specified + /// chain. + function _resolve( + uint64 _chainId, + bytes32 _name, + bool _allowZeroAddress + ) + private + view + returns (address payable addr_) + { + address _addressManager = addressManager; + if (_addressManager == address(0)) revert RESOLVER_INVALID_MANAGER(); + + addr_ = payable(IAddressManager(_addressManager).getAddress(_chainId, _name)); + + if (!_allowZeroAddress && addr_ == address(0)) { + revert RESOLVER_ZERO_ADDR(_chainId, _name); + } + } +} diff --git a/packages/protocol/contracts/common/AuthorizableContract.sol b/packages/protocol/contracts/common/AuthorizableContract.sol new file mode 100644 index 000000000000..82e57a24be9f --- /dev/null +++ b/packages/protocol/contracts/common/AuthorizableContract.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "../common/EssentialContract.sol"; + +/// @title AuthorizableContract +abstract contract AuthorizableContract is EssentialContract { + mapping(address => bytes32 label) public authorizedAddresses; + uint256[49] private __gap; + + event Authorized(address indexed addr, bytes32 oldLabel, bytes32 newLabel); + + error INVALID_ADDRESS(); + error INVALID_LABEL(); + + function authorize(address addr, bytes32 label) external onlyOwner { + if (addr == address(0)) revert INVALID_ADDRESS(); + + bytes32 oldLabel = authorizedAddresses[addr]; + if (oldLabel == label) revert INVALID_LABEL(); + authorizedAddresses[addr] = label; + + emit Authorized(addr, oldLabel, label); + } + + function isAuthorizedAs(address addr, bytes32 label) public view returns (bool) { + return label != 0 && authorizedAddresses[addr] == label; + } +} diff --git a/packages/protocol/contracts/common/EssentialContract.sol b/packages/protocol/contracts/common/EssentialContract.sol new file mode 100644 index 000000000000..fcbdf28ddc61 --- /dev/null +++ b/packages/protocol/contracts/common/EssentialContract.sol @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import "./AddressResolver.sol"; +import "../libs/LibNetwork.sol"; + +/// @title EssentialContract +/// @custom:security-contact security@taiko.xyz +abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable, AddressResolver { + uint8 private constant _FALSE = 1; + + uint8 private constant _TRUE = 2; + + /// @dev The slot in transient storage of the reentry lock. + /// This is the result of keccak256("ownerUUPS.reentry_slot") plus 1. The addition aims to + /// prevent hash collisions with slots defined in EIP-1967, where slots are derived by + /// keccak256("something") - 1, and with slots in SignalService, calculated directly with + /// keccak256("something"). + bytes32 private constant _REENTRY_SLOT = + 0xa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b; + + /// @dev Slot 1. + uint8 private __reentry; + uint8 private __paused; + uint64 public lastUnpausedAt; + + uint256[49] private __gap; + + /// @notice Emitted when the contract is paused. + /// @param account The account that paused the contract. + event Paused(address account); + + /// @notice Emitted when the contract is unpaused. + /// @param account The account that unpaused the contract. + event Unpaused(address account); + + error INVALID_PAUSE_STATUS(); + error FUNC_NOT_IMPLEMENTED(); + error REENTRANT_CALL(); + error ZERO_ADDRESS(); + error ZERO_VALUE(); + + /// @dev Modifier that ensures the caller is the owner or resolved address of a given name. + /// @param _name The name to check against. + modifier onlyFromOwnerOrNamed(bytes32 _name) { + if (msg.sender != owner() && msg.sender != resolve(_name, true)) revert RESOLVER_DENIED(); + _; + } + + modifier notImplemented() { + revert FUNC_NOT_IMPLEMENTED(); + _; + } + + modifier nonReentrant() { + if (_loadReentryLock() == _TRUE) revert REENTRANT_CALL(); + _storeReentryLock(_TRUE); + _; + _storeReentryLock(_FALSE); + } + + modifier whenPaused() { + if (!paused()) revert INVALID_PAUSE_STATUS(); + _; + } + + modifier whenNotPaused() { + if (paused()) revert INVALID_PAUSE_STATUS(); + _; + } + + modifier nonZeroAddr(address _addr) { + if (_addr == address(0)) revert ZERO_ADDRESS(); + _; + } + + modifier nonZeroValue(bytes32 _value) { + if (_value == 0) revert ZERO_VALUE(); + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @notice Pauses the contract. + function pause() public virtual { + _pause(); + // We call the authorize function here to avoid: + // Warning (5740): Unreachable code. + _authorizePause(msg.sender, true); + } + + /// @notice Unpauses the contract. + function unpause() public virtual { + _unpause(); + // We call the authorize function here to avoid: + // Warning (5740): Unreachable code. + _authorizePause(msg.sender, false); + } + + function impl() public view returns (address) { + return _getImplementation(); + } + + /// @notice Returns true if the contract is paused, and false otherwise. + /// @return true if paused, false otherwise. + function paused() public view returns (bool) { + return __paused == _TRUE; + } + + function inNonReentrant() public view returns (bool) { + return _loadReentryLock() == _TRUE; + } + + /// @notice Initializes the contract. + /// @param _owner The owner of this contract. msg.sender will be used if this value is zero. + /// @param _addressManager The address of the {AddressManager} contract. + function __Essential_init( + address _owner, + address _addressManager + ) + internal + nonZeroAddr(_addressManager) + { + __Essential_init(_owner); + __AddressResolver_init(_addressManager); + } + + function __Essential_init(address _owner) internal virtual onlyInitializing { + __Context_init(); + _transferOwnership(_owner == address(0) ? msg.sender : _owner); + __paused = _FALSE; + } + + function _pause() internal whenNotPaused { + __paused = _TRUE; + emit Paused(msg.sender); + } + + function _unpause() internal whenPaused { + __paused = _FALSE; + lastUnpausedAt = uint64(block.timestamp); + emit Unpaused(msg.sender); + } + + function _authorizeUpgrade(address) internal virtual override onlyOwner { } + + function _authorizePause(address, bool) internal virtual onlyOwner { } + + // Stores the reentry lock + function _storeReentryLock(uint8 _reentry) internal virtual { + if (LibNetwork.isDencunSupported(block.chainid)) { + assembly { + tstore(_REENTRY_SLOT, _reentry) + } + } else { + __reentry = _reentry; + } + } + + // Loads the reentry lock + function _loadReentryLock() internal view virtual returns (uint8 reentry_) { + if (LibNetwork.isDencunSupported(block.chainid)) { + assembly { + reentry_ := tload(_REENTRY_SLOT) + } + } else { + reentry_ = __reentry; + } + } +} diff --git a/packages/protocol/contracts/common/IAddressManager.sol b/packages/protocol/contracts/common/IAddressManager.sol new file mode 100644 index 000000000000..46ee14781560 --- /dev/null +++ b/packages/protocol/contracts/common/IAddressManager.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title IAddressManager +/// @notice Manages a mapping of (chainId, name) pairs to Ethereum addresses. +/// @custom:security-contact security@taiko.xyz +interface IAddressManager { + /// @notice Gets the address mapped to a specific chainId-name pair. + /// @dev Note that in production, this method shall be a pure function + /// without any storage access. + /// @param _chainId The chainId for which the address needs to be fetched. + /// @param _name The name for which the address needs to be fetched. + /// @return Address associated with the chainId-name pair. + function getAddress(uint64 _chainId, bytes32 _name) external view returns (address); +} diff --git a/packages/protocol/contracts/common/IAddressResolver.sol b/packages/protocol/contracts/common/IAddressResolver.sol new file mode 100644 index 000000000000..7103eac64447 --- /dev/null +++ b/packages/protocol/contracts/common/IAddressResolver.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title IAddressResolver +/// @notice This contract acts as a bridge for name-to-address resolution. +/// It delegates the resolution to the AddressManager. By separating the logic, +/// we can maintain flexibility in address management without affecting the +/// resolving process. +/// @dev Note that the address manager should be changed using upgradability, there +/// is no setAddressManager() function to guarantee atomicity across all +/// contracts that are resolvers. +/// @custom:security-contact security@taiko.xyz +interface IAddressResolver { + /// @notice Resolves a name to its address deployed on this chain. + /// @param _name Name whose address is to be resolved. + /// @param _allowZeroAddress If set to true, does not throw if the resolved + /// address is `address(0)`. + /// @return Address associated with the given name. + function resolve( + bytes32 _name, + bool _allowZeroAddress + ) + external + view + returns (address payable); + + /// @notice Resolves a name to its address deployed on a specified chain. + /// @param _chainId The chainId of interest. + /// @param _name Name whose address is to be resolved. + /// @param _allowZeroAddress If set to true, does not throw if the resolved + /// address is `address(0)`. + /// @return Address associated with the given name on the specified + /// chain. + function resolve( + uint64 _chainId, + bytes32 _name, + bool _allowZeroAddress + ) + external + view + returns (address payable); +} diff --git a/packages/protocol/contracts/examples/DelegateContract.sol b/packages/protocol/contracts/examples/DelegateContract.sol new file mode 100644 index 000000000000..0107848c40c1 --- /dev/null +++ b/packages/protocol/contracts/examples/DelegateContract.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.12 <0.9.0; + +import "./xERC20.sol"; + +contract DelegateContract { + event Executed(address indexed to, uint256 value, bytes data); + + struct SubCall { + bytes data; + address to; + uint256 value; + } + + function execute(SubCall[] memory calls) external payable { + for (uint256 i = 0; i < calls.length; i++) { + SubCall memory call = calls[i]; + (bool success, bytes memory result) = call.to.call{value: call.value}(call.data); + require(success, string(result)); + emit Executed(call.to, call.value, call.data); + } + } + + receive() external payable {} +} \ No newline at end of file diff --git a/packages/protocol/contracts/examples/EVM.sol b/packages/protocol/contracts/examples/EVM.sol new file mode 100644 index 000000000000..7487d26e5132 --- /dev/null +++ b/packages/protocol/contracts/examples/EVM.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.12 <0.9.0; +// EVM library +library EVM { + address constant xCallOptionsAddress = address(0x04D2); + bytes4 constant xCallOptionsMagic = bytes4(keccak256("XCALLOPTIONS")); + address payable constant extensionOracle = payable(0x1ADB9959EB142bE128E6dfEcc8D571f07cd66DeE); + + uint constant l1ChainId = 1; + uint16 constant version = 1; + + function xCallOnL1() + internal + view + returns (bool) + { + return xCallOptions(l1ChainId); + } + + function xCallOnL1(bool sandbox) + internal + view + returns (bool) + { + return xCallOptions(l1ChainId, sandbox); + } + + function xCallOptions(uint chainID) + internal + view + returns (bool) + { + return xCallOptions(chainID, false); + } + + function xCallOptions(uint chainID, bool sandbox) + internal + view + returns (bool) + { + return xCallOptions(chainID, sandbox, tx.origin, address(this)); + } + + function xCallOptions(uint chainID, bool sandbox, address txOrigin, address msgSender) + internal + view + returns (bool) + { + return xCallOptions(chainID, sandbox, txOrigin, msgSender, 0x0, ""); + } + + function xCallOptions(uint chainID, bool sandbox, bytes32 blockHash, bytes memory proof) + internal + view + returns (bool) + { + return xCallOptions(chainID, sandbox, address(0), address(0), blockHash, proof); + } + + function xCallOptions(uint chainID, bool sandbox, address txOrigin, address msgSender, bytes32 blockHash, bytes memory proof) + internal + view + returns (bool) + { + // If we're already on the target chain, don't do anything + if (chainID == block.chainid) { + return true; + } + + // Call the custom precompile + bytes memory input = abi.encodePacked(version, uint64(chainID), sandbox, txOrigin, msgSender, blockHash, proof); + (bool success, bytes memory result) = xCallOptionsAddress.staticcall(input); + return success && bytes4(result) == xCallOptionsMagic; + } + + + function isOnL1() internal view returns (bool) { + return chainId() == l1ChainId; + } + + function chainId() internal view returns (uint256) { + return block.chainid; + } + + + function onChain(address addr, uint chainID) + internal + view + returns (address) + { + (bool success, bytes memory result) = address(0x09).staticcall{gas: 1000}(new bytes(0)); + bool is_simulation = !success || result.length > 1; + + bool xCallOptionsAvailable = xCallOptions(chainID, false); + + if (xCallOptionsAvailable || is_simulation) { + return addr; + } else { + return extensionOracle; + } + } +} \ No newline at end of file diff --git a/packages/protocol/contracts/examples/xERC20.sol b/packages/protocol/contracts/examples/xERC20.sol new file mode 100644 index 000000000000..668d122d6835 --- /dev/null +++ b/packages/protocol/contracts/examples/xERC20.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "./EVM.sol"; +import "../gwyneth/GwynethContract.sol"; + +contract xERC20 is GwynethContract { + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + constructor(uint256 totalSupply) { + balanceOf[msg.sender] = totalSupply; + } + + using EVM for address; + using EVM for address payable; + + function ChainAddress(uint256 chainId, xERC20 contractAddr) internal view returns (xERC20) { + return xERC20(address(contractAddr).onChain(chainId)); + } + + function on(uint256 chainId) internal view returns (xERC20) { + return ChainAddress(chainId, this); + } + + function transfer(address to, uint256 value) public returns (uint256) { + require(balanceOf[msg.sender] >= value, "Insufficient balance"); + balanceOf[msg.sender] -= value; + balanceOf[to] += value; + emit Transfer(msg.sender, to, value); + return value; + } + + function xTransfer(uint256 fromChain, uint256 toChain, address to, uint256 value) public returns (uint256) { + return on(fromChain)._xTransfer(msg.sender, toChain, to, value); + } + + function _transfer(address from, address to, uint256 value) public returns (uint256) { + //require(msg.sender == address(this), "Only this contract can mint"); + balanceOf[from] -= value; + balanceOf[to] += value; + return value; + } + + function _mint(address to, uint256 value) public returns (uint256) { + //require(msg.sender == address(this), "Only this contract can mint"); + balanceOf[to] += value; + return value; + } + + function _xTransfer(address from, uint256 chain, address to, uint256 value) external returns (uint256) { + //require(msg.sender == address(this), "Only contract itself can call this function"); + balanceOf[from] -= value; + return on(chain)._mint(to, value); + } + + function xTransfer(uint256 chain, address to, uint256 value) public returns (uint256) { + balanceOf[msg.sender] -= value; + return on(chain)._mint(to, value); + } + + function sandboxedTransfer(uint256 chain, address to, uint256 value) public returns (uint256) { + EVM.xCallOptions(chain, true); + return this._transfer(msg.sender, to, value); + } + + function approve(address spender, uint256 value) public returns (uint256) { + allowance[msg.sender][spender] = value; + emit Approval(msg.sender, spender, value); + return value; + } + + function _approve(address owner, address spender, uint256 value) public returns (uint256) { + // require(msg.sender == address(this), "Only contract itself can call this function"); + allowance[owner][spender] = value; + emit Approval(owner, spender, value); + return value; + } + + function xApprove(uint256 chain, address spender, uint256 value) public returns (uint256) { + return on(chain)._approve(msg.sender, spender, value); + } + + function transferFrom(address from, address to, uint256 value) public returns (uint256) { + require(balanceOf[from] >= value, "Insufficient balance"); + if (from != msg.sender) { + require(allowance[from][msg.sender] >= value, "Allowance exceeded"); + } + balanceOf[from] -= value; + balanceOf[to] += value; + if (from != msg.sender) { + allowance[from][msg.sender] -= value; + } + emit Transfer(from, to, value); + return value; + } + + function xTransferFrom(address from, uint256 chain, address to, uint256 value) public returns (bool) { + require(balanceOf[from] >= value, "Insufficient balance"); + if (from != msg.sender) { + require(allowance[from][msg.sender] >= value, "Allowance exceeded"); + allowance[from][msg.sender] -= value; + } + balanceOf[from] -= value; + // Neeed to deduct on the source chain. + emit Transfer(msg.sender,address(0x0), value); + on(chain)._mint(to, value); + + emit Transfer(from, to, value); + return true; + } + + function sendETH(uint256 chain, address payable to) external payable { + (bool success, ) = to.onChain(chain).call{value: msg.value}(""); + require(success); + } +} diff --git a/packages/protocol/contracts/gwyneth/GwynethContract.sol b/packages/protocol/contracts/gwyneth/GwynethContract.sol new file mode 100644 index 000000000000..3d5f20d0875f --- /dev/null +++ b/packages/protocol/contracts/gwyneth/GwynethContract.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + + +import "../L1/GwynethData.sol"; + +contract GwynethContract { + function applyStateDelta(GwynethData.StateDiffAccount calldata accountChanges) + external + payable + { + //require(msg.sender == gwyneth, "not from gwyneth contract"); + // Run over all state changes + for (uint256 i = 0; i < accountChanges.storageSlots.length; i++) { + // Apply the updated state to the storage + bytes32 key = accountChanges.storageSlots[i].key; + bytes32 value = accountChanges.storageSlots[i].value; + // Possible to check the slot against any variable.slot + // to e.g. throw a custom event + assembly { + sstore(key, value) + } + } + + if (accountChanges.balanceChange > 0) { + (bool success, ) = msg.sender.call{value: accountChanges.balanceChange }(""); + require(success, "Failed to send Ether"); + } + } +} \ No newline at end of file diff --git a/packages/protocol/contracts/libs/LibAddress.sol b/packages/protocol/contracts/libs/LibAddress.sol new file mode 100644 index 000000000000..7425d407ef80 --- /dev/null +++ b/packages/protocol/contracts/libs/LibAddress.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "@openzeppelin/contracts/interfaces/IERC1271.sol"; + +/// @title LibAddress +/// @dev Provides utilities for address-related operations. +/// @custom:security-contact security@taiko.xyz +library LibAddress { + bytes4 private constant EIP1271_MAGICVALUE = 0x1626ba7e; + + error ETH_TRANSFER_FAILED(); + + /// @dev Sends Ether to the specified address. This method will not revert even if sending ether + /// fails. + /// This function is inspired by + /// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol + /// @param _to The recipient address. + /// @param _amount The amount of Ether to send in wei. + /// @param _gasLimit The max amount gas to pay for this transaction. + /// @return success_ true if the call is successful, false otherwise. + function sendEther( + address _to, + uint256 _amount, + uint256 _gasLimit, + bytes memory _calldata + ) + internal + returns (bool success_) + { + // Check for zero-address transactions + if (_to == address(0)) revert ETH_TRANSFER_FAILED(); + // dispatch message to recipient + // by assembly calling "handle" function + // we call via assembly to avoid memcopying a very large returndata + // returned by a malicious contract + assembly { + success_ := + call( + _gasLimit, // gas + _to, // recipient + _amount, // ether value + add(_calldata, 0x20), // inloc + mload(_calldata), // inlen + 0, // outloc + 0 // outlen + ) + } + } + + /// @dev Sends Ether to the specified address. This method will revert if sending ether fails. + /// @param _to The recipient address. + /// @param _amount The amount of Ether to send in wei. + /// @param _gasLimit The max amount gas to pay for this transaction. + function sendEtherAndVerify(address _to, uint256 _amount, uint256 _gasLimit) internal { + if (_amount == 0) return; + if (!sendEther(_to, _amount, _gasLimit, "")) { + revert ETH_TRANSFER_FAILED(); + } + } + + /// @dev Sends Ether to the specified address. This method will revert if sending ether fails. + /// @param _to The recipient address. + /// @param _amount The amount of Ether to send in wei. + function sendEtherAndVerify(address _to, uint256 _amount) internal { + sendEtherAndVerify(_to, _amount, gasleft()); + } + + function supportsInterface( + address _addr, + bytes4 _interfaceId + ) + internal + view + returns (bool result_) + { + if (!Address.isContract(_addr)) return false; + + try IERC165(_addr).supportsInterface(_interfaceId) returns (bool _result) { + result_ = _result; + } catch { } + } + + function isValidSignature( + address addr, + bytes32 hash, + bytes memory sig + ) + internal + view + returns (bool valid) + { + if (Address.isContract(addr)) { + return IERC1271(addr).isValidSignature(hash, sig) == EIP1271_MAGICVALUE; + } else { + return ECDSA.recover(hash, sig) == addr; + } + } +} diff --git a/packages/protocol/contracts/libs/LibBytes.sol b/packages/protocol/contracts/libs/LibBytes.sol new file mode 100644 index 000000000000..e88183215613 --- /dev/null +++ b/packages/protocol/contracts/libs/LibBytes.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +library LibBytes { + error INNER_ERROR(bytes innerError); + + // Function body taken from: + // https://github.com/clober-dex/core/blob/main/contracts/utils/BoringERC20.sol#L17-L33 + /// @notice Function to convert returned data to string + /// returns '' as fallback value. + function toString(bytes memory _data) internal pure returns (string memory) { + if (_data.length >= 64) { + return abi.decode(_data, (string)); + } else if (_data.length == 32) { + uint8 i = 0; + while (i < 32 && _data[i] != 0) { + i++; + } + bytes memory bytesArray = new bytes(i); + for (i = 0; i < 32 && _data[i] != 0; i++) { + bytesArray[i] = _data[i]; + } + return string(bytesArray); + } else { + return ""; + } + } + + // Taken from: + // https://github.com/boringcrypto/BoringSolidity/blob/master/contracts/BoringBatchable.sol + /// @dev Helper function to extract a useful revert message from a failed call. + /// If the returned data is malformed or not correctly abi encoded then this call can fail + /// itself. + function revertWithExtractedError(bytes memory _returnData) internal pure { + // If the _res length is less than 68, then + // the transaction failed with custom error or silently (without a revert message) + if (_returnData.length < 68) revert INNER_ERROR(_returnData); + + assembly { + // Slice the sighash. + _returnData := add(_returnData, 0x04) + } + revert(abi.decode(_returnData, (string))); // All that remains is the revert string + } +} diff --git a/packages/protocol/contracts/libs/LibDeploy.sol b/packages/protocol/contracts/libs/LibDeploy.sol new file mode 100644 index 000000000000..9a3fafd174d8 --- /dev/null +++ b/packages/protocol/contracts/libs/LibDeploy.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +/// @title LibDeploy +/// @dev Provides utilities for deploying contracts +library LibDeploy { + error NULL_IMPL_ADDR(); + + function deployERC1967Proxy( + address impl, + address owner, + bytes memory data + ) + internal + returns (address proxy) + { + if (impl == address(0)) revert NULL_IMPL_ADDR(); + proxy = address(new ERC1967Proxy(impl, data)); + + if (owner != address(0) && owner != OwnableUpgradeable(proxy).owner()) { + OwnableUpgradeable(proxy).transferOwnership(owner); + } + } +} diff --git a/packages/protocol/contracts/libs/LibMath.sol b/packages/protocol/contracts/libs/LibMath.sol new file mode 100644 index 000000000000..1de714ba3310 --- /dev/null +++ b/packages/protocol/contracts/libs/LibMath.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +/// @title LibMath +/// @dev This library offers additional math functions for uint256. +library LibMath { + /// @dev Returns the smaller of the two given values. + /// @param a The first number to compare. + /// @param b The second number to compare. + /// @return The smaller of the two numbers. + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? b : a; + } + + /// @dev Returns the larger of the two given values. + /// @param a The first number to compare. + /// @param b The second number to compare. + /// @return The larger of the two numbers. + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } +} diff --git a/packages/protocol/contracts/libs/LibNetwork.sol b/packages/protocol/contracts/libs/LibNetwork.sol new file mode 100644 index 000000000000..0683f27135fa --- /dev/null +++ b/packages/protocol/contracts/libs/LibNetwork.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title LibNetwork +library LibNetwork { + uint256 internal constant MAINNET = 1; + uint256 internal constant ROPSTEN = 2; + uint256 internal constant RINKEBY = 4; + uint256 internal constant GOERLI = 5; + uint256 internal constant KOVAN = 42; + uint256 internal constant HOLESKY = 17_000; + uint256 internal constant SEPOLIA = 11_155_111; + + uint64 internal constant TAIKO_MAINNET = 167_000; + uint64 internal constant TAIKO_HEKLA = 167_009; + + /// @dev Checks if the chain ID represents an Ethereum testnet. + /// @param _chainId The chain ID. + /// @return true if the chain ID represents an Ethereum testnet, false otherwise. + function isEthereumTestnet(uint256 _chainId) internal pure returns (bool) { + return _chainId == LibNetwork.ROPSTEN || _chainId == LibNetwork.RINKEBY + || _chainId == LibNetwork.GOERLI || _chainId == LibNetwork.KOVAN + || _chainId == LibNetwork.HOLESKY || _chainId == LibNetwork.SEPOLIA; + } + + /// @dev Checks if the chain ID represents an Ethereum testnet or the Etheruem mainnet. + /// @param _chainId The chain ID. + /// @return true if the chain ID represents an Ethereum testnet or the Etheruem mainnet, false + /// otherwise. + function isEthereumMainnetOrTestnet(uint256 _chainId) internal pure returns (bool) { + return _chainId == LibNetwork.MAINNET || isEthereumTestnet(_chainId); + } + + /// @dev Checks if the chain ID represents the Taiko L2 mainnet. + /// @param _chainId The chain ID. + /// @return true if the chain ID represents the Taiko L2 mainnet. + function isTaikoMainnet(uint256 _chainId) internal pure returns (bool) { + return _chainId == TAIKO_MAINNET; + } + + /// @dev Checks if the chain ID represents an internal Taiko devnet's base layer. + /// @param _chainId The chain ID. + /// @return true if the chain ID represents an internal Taiko devnet's base layer, false + /// otherwise. + function isTaikoDevnet(uint256 _chainId) internal pure returns (bool) { + return _chainId >= 32_300 && _chainId <= 32_400; + } + + /// @dev Checks if the chain supports Dencun hardfork. Note that this check doesn't need to be + /// exhaustive. + /// @param _chainId The chain ID. + /// @return true if the chain supports Dencun hardfork, false otherwise. + function isDencunSupported(uint256 _chainId) internal pure returns (bool) { + return _chainId == LibNetwork.MAINNET || _chainId == LibNetwork.HOLESKY + || _chainId == LibNetwork.SEPOLIA || isTaikoDevnet(_chainId); + } +} diff --git a/packages/protocol/contracts/test/erc20/FreeMintERC20.sol b/packages/protocol/contracts/test/erc20/FreeMintERC20.sol new file mode 100644 index 000000000000..72f18bf3bda9 --- /dev/null +++ b/packages/protocol/contracts/test/erc20/FreeMintERC20.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +// An ERC20 Token with a mint function anyone can call, for free, to receive +// 5 tokens. +contract FreeMintERC20 is ERC20 { + mapping(address minter => bool hasMinted) public minters; + + error HasMinted(); + + constructor(string memory name, string memory symbol) ERC20(name, symbol) { } + + function mint(address to) public { + if (minters[to]) { + revert HasMinted(); + } + + minters[to] = true; + _mint(to, 50 * (10 ** decimals())); + } +} diff --git a/packages/protocol/contracts/test/erc20/MayFailFreeMintERC20.sol b/packages/protocol/contracts/test/erc20/MayFailFreeMintERC20.sol new file mode 100644 index 000000000000..fd4c75794205 --- /dev/null +++ b/packages/protocol/contracts/test/erc20/MayFailFreeMintERC20.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +// An ERC20 token for testing the Taiko Bridge on testnets. +// This token has 50% of failure on transfers so we can +// test the bridge's error handling. +contract MayFailFreeMintERC20 is ERC20 { + mapping(address minter => bool hasMinted) public minters; + + error HasMinted(); + error Failed(); + + constructor(string memory name, string memory symbol) ERC20(name, symbol) { } + + function mint(address to) public { + if (minters[msg.sender]) { + revert HasMinted(); + } + + minters[msg.sender] = true; + _mint(to, 50 * (10 ** decimals())); + } + + function transfer(address to, uint256 amount) public override returns (bool) { + _mayFail(); + return ERC20.transfer(to, amount); + } + + function transferFrom( + address from, + address to, + uint256 amount + ) + public + override + returns (bool) + { + _mayFail(); + return ERC20.transferFrom(from, to, amount); + } + + // Have a 50% change of failure. + function _mayFail() private view { + if (block.number % 2 == 0) { + revert Failed(); + } + } +} diff --git a/packages/protocol/contracts/test/erc20/RegularERC20.sol b/packages/protocol/contracts/test/erc20/RegularERC20.sol new file mode 100644 index 000000000000..ff3be495bd55 --- /dev/null +++ b/packages/protocol/contracts/test/erc20/RegularERC20.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract RegularERC20 is ERC20 { + constructor(uint256 initialSupply) ERC20("RegularERC20", "RGL") { + _mint(msg.sender, initialSupply); + } +} diff --git a/packages/protocol/contracts/thirdparty/LibBytesUtils.sol b/packages/protocol/contracts/thirdparty/LibBytesUtils.sol new file mode 100644 index 000000000000..24210d7c8fbc --- /dev/null +++ b/packages/protocol/contracts/thirdparty/LibBytesUtils.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT +// Taken from +// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/utils/LibBytesUtils.sol +// (The MIT License) +// +// Copyright 2020-2021 Optimism +// Copyright 2022-2023 Taiko Labs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +pragma solidity ^0.8.20; + +/** + * @title LibBytesUtils + */ +library LibBytesUtils { + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) + internal + pure + returns (bytes memory) + { + require(_length + 31 >= _length, "slice_overflow"); + require(_start + _length >= _start, "slice_overflow"); + require(_bytes.length >= _start + _length, "slice_outOfBounds"); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes + // as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact + // purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { mstore(mc, mload(cc)) } + + mstore(tempBytes, _length) + + // update free-memory pointer allocating the array padded to 32 + // bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + // if we want a zero-length slice let's just return a zero-length + // array + default { + tempBytes := mload(0x40) + + // zero out the 32 bytes slice we are about to return + // we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } + + function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) { + if (_start >= _bytes.length) { + return bytes(""); + } + + return slice(_bytes, _start, _bytes.length - _start); + } + + function toBytes32(bytes memory _bytes) internal pure returns (bytes32) { + if (_bytes.length < 32) { + bytes32 ret; + assembly { + ret := mload(add(_bytes, 32)) + } + return ret; + } + + return abi.decode(_bytes, (bytes32)); // will truncate if input length > + // 32 bytes + } + + function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) { + bytes memory nibbles = new bytes(_bytes.length * 2); + + for (uint256 i; i < _bytes.length; ++i) { + nibbles[i * 2] = _bytes[i] >> 4; + nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16); + } + + return nibbles; + } + + function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) { + return keccak256(_bytes) == keccak256(_other); + } +} diff --git a/packages/protocol/contracts/thirdparty/README.md b/packages/protocol/contracts/thirdparty/README.md new file mode 100644 index 000000000000..0102fe8cd679 --- /dev/null +++ b/packages/protocol/contracts/thirdparty/README.md @@ -0,0 +1,9 @@ +# ABOUT THIRDPARTY CODE + +- /optimism: code copied from `packages/contracts-bedrock/src/libraries` in https://github.com/ethereum-optimism/optimism/releases/tag/op-batcher%2Fv1.4.3 as-is with only solidity pragma changed. + +- /solmate: code copied from https://github.com/transmissions11/solmate/blob/v7/src/utils/FixedPointMathLib.sol as-is with only solidity pragma changed. + +- /nomad-xyz: code copied from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol with unused coded removed and solidity pragma changed. + +- /risczero: interface copied from https://sepolia.etherscan.io/address/0x83c2e9cd64b2a16d3908e94c7654f3864212e2f8#code as per: https://dev.risczero.com/api/blockchain-integration/contracts/verifier diff --git a/packages/protocol/contracts/thirdparty/risczero/IRiscZeroReceiptVerifier.sol b/packages/protocol/contracts/thirdparty/risczero/IRiscZeroReceiptVerifier.sol new file mode 100644 index 000000000000..b604f0d80178 --- /dev/null +++ b/packages/protocol/contracts/thirdparty/risczero/IRiscZeroReceiptVerifier.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @notice Verifier interface for RISC Zero receipts of execution. +/// https://github.com/risc0/risc0-ethereum/blob/release-0.7/contracts/src/IRiscZeroVerifier.sol +interface IRiscZeroReceiptVerifier { + /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the + /// given image ID, post-state digest, and journal digest. + /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no + /// committed input), the exit code is (Halted, 0), and there are no assumptions (i.e. the + /// receipt is unconditional). + /// @param seal The encoded cryptographic proof (i.e. SNARK). + /// @param imageId The identifier for the guest program. + /// @param postStateDigest A hash of the final memory state. Required to run the verifier, but + /// otherwise can be left unconstrained for most use cases. + /// @param journalDigest The SHA-256 digest of the journal bytes. + /// @return true if the receipt passes the verification checks. The return code must be checked. + function verify( + bytes calldata seal, + bytes32 imageId, + bytes32 postStateDigest, + bytes32 journalDigest + ) + external + view + returns (bool); +} diff --git a/packages/protocol/contracts/tko/TaikoToken.sol b/packages/protocol/contracts/tko/TaikoToken.sol new file mode 100644 index 000000000000..825fc3ca5a9f --- /dev/null +++ b/packages/protocol/contracts/tko/TaikoToken.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "./TaikoTokenBase.sol"; + +/// @title TaikoToken +/// @notice The TaikoToken (TKO), in the protocol is used for prover collateral +/// in the form of bonds. It is an ERC20 token with 18 decimal places of precision. +/// @dev Labeled in AddressResolver as "taiko_token" +/// @dev On Ethereum, this contract is deployed behind a proxy at +/// 0x10dea67478c5F8C5E2D90e5E9B26dBe60c54d800 (token.taiko.eth) +/// @custom:security-contact security@taiko.xyz +contract TaikoToken is TaikoTokenBase { + address private constant _TAIKO_L1 = 0x06a9Ab27c7e2255df1815E6CC0168d7755Feb19a; + address private constant _ERC20_VAULT = 0x996282cA11E5DEb6B5D122CC3B9A1FcAAD4415Ab; + + error TT_INVALID_PARAM(); + + /// @notice Initializes the contract. + /// @param _owner The owner of this contract. msg.sender will be used if this value is zero. + /// @param _recipient The address to receive initial token minting. + function init(address _owner, address _recipient) public initializer { + __Essential_init(_owner); + __ERC20_init("Taiko Token", "TKO"); + __ERC20Votes_init(); + __ERC20Permit_init("Taiko Token"); + // Mint 1 billion tokens + _mint(_recipient, 1_000_000_000 ether); + } +} diff --git a/packages/protocol/contracts/tko/TaikoTokenBase.sol b/packages/protocol/contracts/tko/TaikoTokenBase.sol new file mode 100644 index 000000000000..b94f32984bad --- /dev/null +++ b/packages/protocol/contracts/tko/TaikoTokenBase.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; +import "../common/EssentialContract.sol"; + +/// @notice TaikoToken was `EssentialContract, ERC20SnapshotUpgradeable, ERC20VotesUpgradeable`. +/// We use this contract to take 50 more slots to remove `ERC20SnapshotUpgradeable` from the parent +/// contract list. +/// We can simplify the code since we no longer need to maintain upgradability with Hekla. +abstract contract TaikoTokenBase0 is EssentialContract { + // solhint-disable var-name-mixedcase + uint256[50] private __slots_previously_used_by_ERC20SnapshotUpgradeable; +} + +/// @title TaikoTokenBase +/// @notice The base contract for both the canonical and the bridged Taiko token. +/// @custom:security-contact security@taiko.xyz +abstract contract TaikoTokenBase is TaikoTokenBase0, ERC20VotesUpgradeable { + uint256[50] private __gap; + + function clock() public view override returns (uint48) { + return SafeCastUpgradeable.toUint48(block.timestamp); + } + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public pure override returns (string memory) { + // See https://eips.ethereum.org/EIPS/eip-6372 + return "mode=timestamp"; + } + + function symbol() public pure override returns (string memory) { + return "TAIKO"; + } +} diff --git a/packages/protocol/deployments/deploy_l1.json b/packages/protocol/deployments/deploy_l1.json new file mode 100644 index 000000000000..7741733c17e2 --- /dev/null +++ b/packages/protocol/deployments/deploy_l1.json @@ -0,0 +1,11 @@ +{ + "chain_prover": "0x373E0B8B80A15cdf587C1263654c6B5edd195a43", + "rollup_address_manager": "0x8F0342A7060e76dfc7F6e9dEbfAD9b9eC919952c", + "shared_address_manager": "0x17435ccE3d1B4fA2e5f8A08eD921D57C6762A180", + "taiko": "0x9fCF7D13d10dEdF17d0f24C62f0cf4ED462f65b7", + "taiko_token": "0x422A3492e218383753D8006C7Bfa97815B44373F", + "tier_sgx1": "0x1ADB9959EB142bE128E6dfEcc8D571f07cd66DeE", + "tier_sgx2": "0x3A8C1bd531b5C1aeFBB9ebc3e021C1251cF4Ccb1", + "tier_sgx3": "0x80741a37E3644612F0465145C9709a90B6D77Ee3", + "verifier_registry": "0x9ECB6f04D47FA2599449AaA523bF84476f7aD80f" +} \ No newline at end of file diff --git a/packages/protocol/deployments/local_deployment.md b/packages/protocol/deployments/local_deployment.md new file mode 100644 index 000000000000..3424cba2f7cb --- /dev/null +++ b/packages/protocol/deployments/local_deployment.md @@ -0,0 +1,67 @@ +# How to deploy Gwyneth locally - on a reth-based private network + +The first part is coming from [Reth Book](https://reth.rs/run/private-testnet.html), but if you want to dig deeper, please visit the website, otherwise it is not necessary. + +### 0. Pre-requisites: +- have docker installed (and docker daemon running) +- have Kurtosis installed, on Mac, e.g.: +```shell +brew install kurtosis-tech/tap/kurtosis-cli +``` + +### 1. Define the network config parameters + +Create a `network_params.yaml` file. + +```shell +participants: + - el_type: reth + el_image: taiko_reth # We can use custom image, (remote, e.g.: ethpandaops/reth:main-9c0bc84 or locally: taiko_reth) + cl_type: lighthouse + cl_image: sigp/lighthouse:latest + - el_type: reth + el_image: taiko_reth # We can use custom image, (remote, e.g.: ethpandaops/reth:main-9c0bc84 or locally: taiko_reth) + cl_type: teku + cl_image: consensys/teku:latest +network_params: + network_id: '160010' +``` + +#### 1.1 Local reth-based network + +1. Go to the root of the repository, and build the image, e.g.: +```shell +docker build . -t taiko_reth +``` + +2. Use simply the `taiko_reth` image, in `el_image` variable of the network yaml file. + +### 2. Spin up the network + +```shell +kurtosis run github.com/ethpandaops/ethereum-package --args-file YOUR_NETWORK_FILE_PATH/network_params.yaml +``` + +It will show you a lot of information in the terminal - along with the genesis info, network id, addresses with pre-funded ETH, etc. + +### 3. Set .env vars and run contract deployment script +Paste one PK and ADDR pair from anvil output to .env file and set the correct corresponding (PRIVATE_KEY and MAINNET_CONTRACT_OWNER) variables. + +Run script: + +```shell +$ forge script --rpc-url http://127.0.0.1:YOUR_PORT scripts/DeployL1Locally.s.sol -vvvv --broadcast --private-key --legacy +``` + +Important: shall be the same PK as you set in the ENV file. + +### 4. Test interaction with the blockchain + +Shoot it with simple RPC commands e.g. via `curl`, to see the blockchain is operational. + +```shell +curl http://127.0.0.1:YOUR_EXPOSED_PORT \ + -X POST \ + -H "Content-Type: application/json" \ + --data '{"method":"eth_getBlockByNumber","params":["0x0",false],"id":1,"jsonrpc":"2.0"}' +``` \ No newline at end of file diff --git a/packages/protocol/foundry.toml b/packages/protocol/foundry.toml new file mode 100644 index 000000000000..09ff9bc71941 --- /dev/null +++ b/packages/protocol/foundry.toml @@ -0,0 +1,53 @@ +[profile.default] +src = "contracts" +out = "out" +test = "test" +script = "script" +gas_price = 10_000_000_000 # 10 Gwei +gas_limit = "18446744073709551615" # u64::MAX +optimizer = true +optimizer_runs = 200 +ffi = true +memory_limit = 2_073_741_824 +solc_version = "0.8.28" +evm_version = "cancun" +via_ir = true +remappings = [ + "@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/", + "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", + "solady/=node_modules/solady/", + "forge-std/=node_modules/forge-std/", + "ds-test/=node_modules/ds-test/src/", + "p256-verifier/=node_modules/p256-verifier/", +] + +# Do not change the block_gas_limit value, TaikoL2.t.sol depends on it. +# For mainnet_mock tokenomics test we need a huge value to run lots of iterations. +# Use 30M for TaikoL2.t.sol related tests, only use this number with mainnet simulation. +block_gas_limit = 80_000_000 + +fs_permissions = [ + { access = "read", path = "./out" }, + { access = "read-write", path = "./deployments" }, + { access = "read", path = "./test" }, + { access = "read", path = "./genesis" }, +] + +# 2394: Transient storage warning +# 3860: Contract initcode size is xxx bytes and exceeds 49152 bytes +# 5574: Contract code size is xxx bytes and exceeds 24576 byte +# 5740: Unreachable code +ignored_error_codes = [2394, 3860, 5574, 5740] + +[fuzz] +runs = 200 + +[fmt] +bracket_spacing = true +line_length = 100 +multiline_func_header = "all" +number_underscore = "thousands" +wrap_comments = true + +[profile.genesis] +test = "genesis" \ No newline at end of file diff --git a/packages/protocol/package.json b/packages/protocol/package.json new file mode 100644 index 000000000000..f8d77a060b9a --- /dev/null +++ b/packages/protocol/package.json @@ -0,0 +1,63 @@ +{ + "name": "@taiko/gwyneth_protocol", + "version": "1.0.0", + "private": true, + "scripts": { + "buildMerkle": "ts-node ./utils/airdrop/buildMerkleTree.ts ./utils/airdrop/airdrop_db/example_claimList.json", + "clean": "rm -rf abis cache && forge clean", + "compile": "forge build", + "compile:hardhat": "pnpm hardhat compile", + "deploy:foundry": "./script/download_solc.sh && ./script/test_deploy_on_l1.sh", + "eslint": "pnpm exec eslint --ignore-path .eslintignore --ext .js,.ts .", + "eslint:fix": "pnpm exec eslint --ignore-path .eslintignore --ext .js,.ts . --fix", + "export:abi": "pnpm hardhat clear-abi && pnpm hardhat export-abi", + "fmt:sol": "forge fmt", + "generate:genesis": "ts-node ./utils/generate_genesis/main.ts", + "lint:sol": "forge fmt && pnpm solhint 'contracts/**/*.sol' --fix", + "sizer": "pnpm hardhat size-contracts", + "snapshot": "forge snapshot --match-path 'test/**/*.t.sol'", + "test": "forge test -vvv --match-path test/*.t.sol", + "test:coverage": "mkdir -p coverage && forge coverage --report lcov && lcov --remove ./lcov.info -o ./coverage/lcov.info 'test/' 'script/' 'contracts/thirdparty/' && genhtml coverage/lcov.info --branch-coverage --output-dir coverage --ignore-errors category && open coverage/index.html", + "test:genesis": "pnpm compile && pnpm compile:hardhat && FOUNDRY_PROFILE=genesis ./genesis/generate_genesis.test.sh", + "export:simconf": "forge test --match-test 'test_simulation' -vv > simulation/out/simconf_$(date +%s).txt" + }, + "keywords": [ + "ZKP", + "Zero-Knowledge Proof", + "Decentralized", + "Permissionless", + "Type-1", + "ZK-EVM", + "zkRollup", + "Ethereum", + "Layer2" + ], + "author": "Taiko Labs", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.11.30", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.7.0", + "eslint": "^8.51.0", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-promise": "^6.1.1", + "ethers": "^5.7.2", + "solc": "0.8.24", + "solhint": "^5.0.1", + "ts-node": "^10.9.2", + "typescript": "^5.2.2" + }, + "dependencies": { + "@openzeppelin/contracts": "4.9.6", + "@openzeppelin/contracts-upgradeable": "4.9.6", + "ds-test": "github:dapphub/ds-test#e282159d5170298eb2455a6c05280ab5a73a4ef0", + "forge-std": "github:foundry-rs/forge-std#v1.7.5", + "merkletreejs": "^0.3.11", + "p256-verifier": "github:taikoxyz/p256-verifier#v0.1.0", + "solady": "github:Vectorized/solady#v0.0.167" + } +} diff --git a/packages/protocol/pnpm-lock.yaml b/packages/protocol/pnpm-lock.yaml new file mode 100644 index 000000000000..e534a4990cde --- /dev/null +++ b/packages/protocol/pnpm-lock.yaml @@ -0,0 +1,3735 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@openzeppelin/contracts': + specifier: 4.9.6 + version: 4.9.6 + '@openzeppelin/contracts-upgradeable': + specifier: 4.9.6 + version: 4.9.6 + ds-test: + specifier: github:dapphub/ds-test#e282159d5170298eb2455a6c05280ab5a73a4ef0 + version: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 + forge-std: + specifier: github:foundry-rs/forge-std#v1.7.5 + version: https://codeload.github.com/foundry-rs/forge-std/tar.gz/36c303b7ffdd842d06b1ec2744c9b9b5fb3083f3 + merkletreejs: + specifier: ^0.3.11 + version: 0.3.11 + p256-verifier: + specifier: github:taikoxyz/p256-verifier#v0.1.0 + version: p256-verifier#v0.1.0@https://codeload.github.com/taikoxyz/p256-verifier/tar.gz/6ef45b117642786b08a37b4c37c6a6ce151166da + solady: + specifier: github:Vectorized/solady#v0.0.167 + version: https://codeload.github.com/Vectorized/solady/tar.gz/de0f336d2033d04e0f77c923d639c7fbffd48b6d + devDependencies: + '@types/node': + specifier: ^20.11.30 + version: 20.11.30 + '@typescript-eslint/eslint-plugin': + specifier: ^7.4.0 + version: 7.4.0(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/parser': + specifier: ^7.7.0 + version: 7.7.0(eslint@8.51.0)(typescript@5.2.2) + eslint: + specifier: ^8.51.0 + version: 8.51.0 + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@8.51.0) + eslint-config-standard: + specifier: ^17.1.0 + version: 17.1.0(eslint-plugin-import@2.28.1(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint@8.51.0))(eslint-plugin-n@16.6.2(eslint@8.51.0))(eslint-plugin-promise@6.1.1(eslint@8.51.0))(eslint@8.51.0) + eslint-plugin-import: + specifier: ^2.28.1 + version: 2.28.1(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint@8.51.0) + eslint-plugin-node: + specifier: ^11.1.0 + version: 11.1.0(eslint@8.51.0) + eslint-plugin-prettier: + specifier: ^5.1.3 + version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.51.0))(eslint@8.51.0)(prettier@3.0.3) + eslint-plugin-promise: + specifier: ^6.1.1 + version: 6.1.1(eslint@8.51.0) + ethers: + specifier: ^5.7.2 + version: 5.7.2 + solc: + specifier: 0.8.24 + version: 0.8.24 + solhint: + specifier: ^5.0.1 + version: 5.0.1(typescript@5.2.2) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.11.30)(typescript@5.2.2) + typescript: + specifier: ^5.2.2 + version: 5.2.2 + +packages: + + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.51.0': + resolution: {integrity: sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@ethereumjs/rlp@4.0.1': + resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} + engines: {node: '>=14'} + hasBin: true + + '@ethereumjs/util@8.1.0': + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} + + '@ethersproject/abi@5.7.0': + resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} + + '@ethersproject/abstract-provider@5.7.0': + resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} + + '@ethersproject/abstract-signer@5.7.0': + resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} + + '@ethersproject/address@5.7.0': + resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} + + '@ethersproject/base64@5.7.0': + resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} + + '@ethersproject/basex@5.7.0': + resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} + + '@ethersproject/bignumber@5.7.0': + resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} + + '@ethersproject/bytes@5.7.0': + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + + '@ethersproject/constants@5.7.0': + resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} + + '@ethersproject/contracts@5.7.0': + resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} + + '@ethersproject/hash@5.7.0': + resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} + + '@ethersproject/hdnode@5.7.0': + resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} + + '@ethersproject/json-wallets@5.7.0': + resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} + + '@ethersproject/keccak256@5.7.0': + resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} + + '@ethersproject/logger@5.7.0': + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} + + '@ethersproject/networks@5.7.1': + resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} + + '@ethersproject/pbkdf2@5.7.0': + resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} + + '@ethersproject/properties@5.7.0': + resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} + + '@ethersproject/providers@5.7.2': + resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} + + '@ethersproject/random@5.7.0': + resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} + + '@ethersproject/rlp@5.7.0': + resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} + + '@ethersproject/sha2@5.7.0': + resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} + + '@ethersproject/signing-key@5.7.0': + resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} + + '@ethersproject/solidity@5.7.0': + resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} + + '@ethersproject/strings@5.7.0': + resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} + + '@ethersproject/transactions@5.7.0': + resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} + + '@ethersproject/units@5.7.0': + resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} + + '@ethersproject/wallet@5.7.0': + resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} + + '@ethersproject/web@5.7.1': + resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} + + '@ethersproject/wordlists@5.7.0': + resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@noble/curves@1.4.2': + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@openzeppelin/contracts-upgradeable@4.9.6': + resolution: {integrity: sha512-m4iHazOsOCv1DgM7eD7GupTJ+NFVujRZt1wzddDPSVGpWdKq1SKkla5htKG7+IS4d2XOCtzkUNwRZ7Vq5aEUMA==} + + '@openzeppelin/contracts@4.9.6': + resolution: {integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@pnpm/config.env-replace@1.1.0': + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + + '@pnpm/network.ca-file@1.0.2': + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + + '@pnpm/npm-conf@2.2.2': + resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==} + engines: {node: '>=12'} + + '@scure/base@1.1.7': + resolution: {integrity: sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==} + + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + + '@sindresorhus/is@5.6.0': + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + + '@solidity-parser/parser@0.18.0': + resolution: {integrity: sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==} + + '@szmarczak/http-timer@5.0.1': + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.11.30': + resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} + + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + + '@typescript-eslint/eslint-plugin@7.4.0': + resolution: {integrity: sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@7.7.0': + resolution: {integrity: sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@7.4.0': + resolution: {integrity: sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/scope-manager@7.7.0': + resolution: {integrity: sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/type-utils@7.4.0': + resolution: {integrity: sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@7.4.0': + resolution: {integrity: sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/types@7.7.0': + resolution: {integrity: sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/typescript-estree@7.4.0': + resolution: {integrity: sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@7.7.0': + resolution: {integrity: sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@7.4.0': + resolution: {integrity: sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + + '@typescript-eslint/visitor-keys@7.4.0': + resolution: {integrity: sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/visitor-keys@7.7.0': + resolution: {integrity: sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==} + engines: {node: ^18.18.0 || >=20.0.0} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.3: + resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} + engines: {node: '>=0.4.0'} + + acorn@8.12.0: + resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} + engines: {node: '>=0.4.0'} + hasBin: true + + aes-js@3.0.0: + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.16.0: + resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + antlr4@4.13.1: + resolution: {integrity: sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==} + engines: {node: '>=16'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + ast-parents@0.0.1: + resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + + bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + + bn.js@4.11.6: + resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} + + bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + buffer-reverse@1.0.1: + resolution: {integrity: sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==} + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + builtins@5.1.0: + resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} + + cacheable-lookup@7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + + cacheable-request@10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0: + resolution: {tarball: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0} + version: 1.0.0 + + elliptic@6.5.4: + resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + + eslint-config-prettier@9.1.0: + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-config-standard@17.1.0: + resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: ^8.0.1 + eslint-plugin-import: ^2.25.2 + eslint-plugin-n: '^15.0.0 || ^16.0.0 ' + eslint-plugin-promise: ^6.0.0 + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.8.1: + resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + + eslint-plugin-es@3.0.1: + resolution: {integrity: sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=4.19.1' + + eslint-plugin-import@2.28.1: + resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-n@16.6.2: + resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-node@11.1.0: + resolution: {integrity: sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=5.16.0' + + eslint-plugin-prettier@5.1.3: + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-promise@6.1.1: + resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-utils@2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} + + eslint-visitor-keys@1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.51.0: + resolution: {integrity: sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + ethereum-bloom-filters@1.1.0: + resolution: {integrity: sha512-J1gDRkLpuGNvWYzWslBQR9cDV4nd4kfvVTE/Wy4Kkm4yb3EYRSlyi0eB/inTsSTTVyA0+HyzHgbr95Fn/Z1fSw==} + + ethereum-cryptography@2.2.1: + resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} + + ethers@5.7.2: + resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} + + ethjs-unit@0.1.6: + resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} + engines: {node: '>=6.5.0', npm: '>=3'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/36c303b7ffdd842d06b1ec2744c9b9b5fb3083f3: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/36c303b7ffdd842d06b1ec2744c9b9b5fb3083f3} + version: 1.7.5 + + form-data-encoder@2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + got@12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + + graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + has@1.0.4: + resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} + engines: {node: '>= 0.4.0'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + + http2-wrapper@2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.14.0: + resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hex-prefixed@1.0.0: + resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} + engines: {node: '>=6.5.0', npm: '>=3'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + latest-version@7.0.0: + resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} + engines: {node: '>=14.16'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + lowercase-keys@3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + merkletreejs@0.3.11: + resolution: {integrity: sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ==} + engines: {node: '>= 7.6.0'} + + micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + mimic-response@4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + + number-to-bn@1.7.0: + resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} + engines: {node: '>=6.5.0', npm: '>=3'} + + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + p-cancelable@3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p256-verifier#v0.1.0@https://codeload.github.com/taikoxyz/p256-verifier/tar.gz/6ef45b117642786b08a37b4c37c6a6ce151166da: + resolution: {tarball: https://codeload.github.com/taikoxyz/p256-verifier/tar.gz/6ef45b117642786b08a37b4c37c6a6ce151166da} + version: 0.0.0 + + package-json@8.1.1: + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + engines: {node: '>=14'} + hasBin: true + + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + + regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + registry-auth-token@5.0.2: + resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + engines: {node: '>=14'} + + registry-url@6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + responselike@3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + solady@https://codeload.github.com/Vectorized/solady/tar.gz/de0f336d2033d04e0f77c923d639c7fbffd48b6d: + resolution: {tarball: https://codeload.github.com/Vectorized/solady/tar.gz/de0f336d2033d04e0f77c923d639c7fbffd48b6d} + version: 0.0.167 + + solc@0.8.24: + resolution: {integrity: sha512-G5yUqjTUPc8Np74sCFwfsevhBPlUifUOfhYrgyu6CmYlC6feSw0YS6eZW47XDT23k3JYdKx5nJ+Q7whCEmNcoA==} + engines: {node: '>=10.0.0'} + hasBin: true + + solhint@5.0.1: + resolution: {integrity: sha512-QeQLS9HGCnIiibt+xiOa/+MuP7BWz9N7C5+Mj9pLHshdkNhuo3AzCpWmjfWVZBUuwIUO3YyCRVIcYLR3YOKGfg==} + hasBin: true + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-hex-prefix@1.0.0: + resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} + engines: {node: '>=6.5.0', npm: '>=3'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} + + table@6.8.2: + resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==} + engines: {node: '>=10.0.0'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + treeify@1.1.0: + resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} + engines: {node: '>=0.6'} + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + web3-utils@1.10.4: + resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} + engines: {node: '>=8.0.0'} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.4.6: + resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@babel/code-frame@7.24.7': + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.0.1 + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@eslint-community/eslint-utils@4.4.0(eslint@8.51.0)': + dependencies: + eslint: 8.51.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.11.0': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.3.5 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.51.0': {} + + '@ethereumjs/rlp@4.0.1': {} + + '@ethereumjs/util@8.1.0': + dependencies: + '@ethereumjs/rlp': 4.0.1 + ethereum-cryptography: 2.2.1 + micro-ftch: 0.3.1 + + '@ethersproject/abi@5.7.0': + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + + '@ethersproject/abstract-provider@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/networks': 5.7.1 + '@ethersproject/properties': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/web': 5.7.1 + + '@ethersproject/abstract-signer@5.7.0': + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + + '@ethersproject/address@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/rlp': 5.7.0 + + '@ethersproject/base64@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + + '@ethersproject/basex@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/properties': 5.7.0 + + '@ethersproject/bignumber@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + bn.js: 5.2.1 + + '@ethersproject/bytes@5.7.0': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/constants@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + + '@ethersproject/contracts@5.7.0': + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/transactions': 5.7.0 + + '@ethersproject/hash@5.7.0': + dependencies: + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/base64': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + + '@ethersproject/hdnode@5.7.0': + dependencies: + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/basex': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/pbkdf2': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/wordlists': 5.7.0 + + '@ethersproject/json-wallets@5.7.0': + dependencies: + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/hdnode': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/pbkdf2': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/random': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + aes-js: 3.0.0 + scrypt-js: 3.0.1 + + '@ethersproject/keccak256@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.7.0': {} + + '@ethersproject/networks@5.7.1': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/pbkdf2@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/sha2': 5.7.0 + + '@ethersproject/properties@5.7.0': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/providers@5.7.2': + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/base64': 5.7.0 + '@ethersproject/basex': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/networks': 5.7.1 + '@ethersproject/properties': 5.7.0 + '@ethersproject/random': 5.7.0 + '@ethersproject/rlp': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/web': 5.7.1 + bech32: 1.1.4 + ws: 7.4.6 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@ethersproject/random@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/rlp@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/sha2@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + hash.js: 1.1.7 + + '@ethersproject/signing-key@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + bn.js: 5.2.1 + elliptic: 6.5.4 + hash.js: 1.1.7 + + '@ethersproject/solidity@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/strings': 5.7.0 + + '@ethersproject/strings@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/transactions@5.7.0': + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/rlp': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + + '@ethersproject/units@5.7.0': + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + + '@ethersproject/wallet@5.7.0': + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/hdnode': 5.7.0 + '@ethersproject/json-wallets': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/random': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/wordlists': 5.7.0 + + '@ethersproject/web@5.7.1': + dependencies: + '@ethersproject/base64': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + + '@ethersproject/wordlists@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + + '@humanwhocodes/config-array@0.11.14': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.5 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.4.15': {} + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@noble/curves@1.4.2': + dependencies: + '@noble/hashes': 1.4.0 + + '@noble/hashes@1.4.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@openzeppelin/contracts-upgradeable@4.9.6': {} + + '@openzeppelin/contracts@4.9.6': {} + + '@pkgr/core@0.1.1': {} + + '@pnpm/config.env-replace@1.1.0': {} + + '@pnpm/network.ca-file@1.0.2': + dependencies: + graceful-fs: 4.2.10 + + '@pnpm/npm-conf@2.2.2': + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + + '@scure/base@1.1.7': {} + + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.7 + + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.7 + + '@sindresorhus/is@5.6.0': {} + + '@solidity-parser/parser@0.18.0': {} + + '@szmarczak/http-timer@5.0.1': + dependencies: + defer-to-connect: 2.0.1 + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/http-cache-semantics@4.0.4': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@20.11.30': + dependencies: + undici-types: 5.26.5 + + '@types/semver@7.5.8': {} + + '@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint@8.51.0)(typescript@5.2.2)': + dependencies: + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 7.7.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 7.4.0 + '@typescript-eslint/type-utils': 7.4.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/utils': 7.4.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 7.4.0 + debug: 4.3.5 + eslint: 8.51.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.2.2) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2)': + dependencies: + '@typescript-eslint/scope-manager': 7.7.0 + '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/typescript-estree': 7.7.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 7.7.0 + debug: 4.3.5 + eslint: 8.51.0 + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@7.4.0': + dependencies: + '@typescript-eslint/types': 7.4.0 + '@typescript-eslint/visitor-keys': 7.4.0 + + '@typescript-eslint/scope-manager@7.7.0': + dependencies: + '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/visitor-keys': 7.7.0 + + '@typescript-eslint/type-utils@7.4.0(eslint@8.51.0)(typescript@5.2.2)': + dependencies: + '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.2.2) + '@typescript-eslint/utils': 7.4.0(eslint@8.51.0)(typescript@5.2.2) + debug: 4.3.5 + eslint: 8.51.0 + ts-api-utils: 1.3.0(typescript@5.2.2) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@7.4.0': {} + + '@typescript-eslint/types@7.7.0': {} + + '@typescript-eslint/typescript-estree@7.4.0(typescript@5.2.2)': + dependencies: + '@typescript-eslint/types': 7.4.0 + '@typescript-eslint/visitor-keys': 7.4.0 + debug: 4.3.5 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.2.2) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@7.7.0(typescript@5.2.2)': + dependencies: + '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/visitor-keys': 7.7.0 + debug: 4.3.5 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.2.2) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@7.4.0(eslint@8.51.0)(typescript@5.2.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 7.4.0 + '@typescript-eslint/types': 7.4.0 + '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.2.2) + eslint: 8.51.0 + semver: 7.6.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@7.4.0': + dependencies: + '@typescript-eslint/types': 7.4.0 + eslint-visitor-keys: 3.4.3 + + '@typescript-eslint/visitor-keys@7.7.0': + dependencies: + '@typescript-eslint/types': 7.7.0 + eslint-visitor-keys: 3.4.3 + + acorn-jsx@5.3.2(acorn@8.12.0): + dependencies: + acorn: 8.12.0 + + acorn-walk@8.3.3: + dependencies: + acorn: 8.12.0 + + acorn@8.12.0: {} + + aes-js@3.0.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.16.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + antlr4@4.13.1: {} + + arg@4.1.3: {} + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + + array-union@2.1.0: {} + + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + ast-parents@0.0.1: {} + + astral-regex@2.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + balanced-match@1.0.2: {} + + bech32@1.1.4: {} + + bignumber.js@9.1.2: {} + + bn.js@4.11.6: {} + + bn.js@4.12.0: {} + + bn.js@5.2.1: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brorand@1.1.0: {} + + buffer-reverse@1.0.1: {} + + builtin-modules@3.3.0: {} + + builtins@5.1.0: + dependencies: + semver: 7.6.2 + + cacheable-lookup@7.0.0: {} + + cacheable-request@10.2.14: + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + callsites@3.1.0: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + command-exists@1.2.9: {} + + commander@10.0.1: {} + + commander@8.3.0: {} + + concat-map@0.0.1: {} + + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + cosmiconfig@8.3.6(typescript@5.2.2): + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.2.2 + + create-require@1.1.1: {} + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypto-js@4.2.0: {} + + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.5: + dependencies: + ms: 2.1.2 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + diff@4.0.2: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0: {} + + elliptic@6.5.4: + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + emoji-regex@8.0.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.23.3: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.2 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + eslint-compat-utils@0.5.1(eslint@8.51.0): + dependencies: + eslint: 8.51.0 + semver: 7.6.2 + + eslint-config-prettier@9.1.0(eslint@8.51.0): + dependencies: + eslint: 8.51.0 + + eslint-config-standard@17.1.0(eslint-plugin-import@2.28.1(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint@8.51.0))(eslint-plugin-n@16.6.2(eslint@8.51.0))(eslint-plugin-promise@6.1.1(eslint@8.51.0))(eslint@8.51.0): + dependencies: + eslint: 8.51.0 + eslint-plugin-import: 2.28.1(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint@8.51.0) + eslint-plugin-n: 16.6.2(eslint@8.51.0) + eslint-plugin-promise: 6.1.1(eslint@8.51.0) + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.14.0 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint@8.51.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 7.7.0(eslint@8.51.0)(typescript@5.2.2) + eslint: 8.51.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-es-x@7.8.0(eslint@8.51.0): + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + '@eslint-community/regexpp': 4.11.0 + eslint: 8.51.0 + eslint-compat-utils: 0.5.1(eslint@8.51.0) + + eslint-plugin-es@3.0.1(eslint@8.51.0): + dependencies: + eslint: 8.51.0 + eslint-utils: 2.1.0 + regexpp: 3.2.0 + + eslint-plugin-import@2.28.1(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint@8.51.0): + dependencies: + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.51.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.0(eslint@8.51.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint@8.51.0) + has: 1.0.4 + is-core-module: 2.14.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 7.7.0(eslint@8.51.0)(typescript@5.2.2) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-n@16.6.2(eslint@8.51.0): + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + builtins: 5.1.0 + eslint: 8.51.0 + eslint-plugin-es-x: 7.8.0(eslint@8.51.0) + get-tsconfig: 4.7.5 + globals: 13.24.0 + ignore: 5.3.1 + is-builtin-module: 3.2.1 + is-core-module: 2.14.0 + minimatch: 3.1.2 + resolve: 1.22.8 + semver: 7.6.2 + + eslint-plugin-node@11.1.0(eslint@8.51.0): + dependencies: + eslint: 8.51.0 + eslint-plugin-es: 3.0.1(eslint@8.51.0) + eslint-utils: 2.1.0 + ignore: 5.3.1 + minimatch: 3.1.2 + resolve: 1.22.8 + semver: 6.3.1 + + eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.51.0))(eslint@8.51.0)(prettier@3.0.3): + dependencies: + eslint: 8.51.0 + prettier: 3.0.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.8 + optionalDependencies: + eslint-config-prettier: 9.1.0(eslint@8.51.0) + + eslint-plugin-promise@6.1.1(eslint@8.51.0): + dependencies: + eslint: 8.51.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-utils@2.1.0: + dependencies: + eslint-visitor-keys: 1.3.0 + + eslint-visitor-keys@1.3.0: {} + + eslint-visitor-keys@3.4.3: {} + + eslint@8.51.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.51.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.5 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.5.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + ethereum-bloom-filters@1.1.0: + dependencies: + '@noble/hashes': 1.4.0 + + ethereum-cryptography@2.2.1: + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + + ethers@5.7.2: + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/base64': 5.7.0 + '@ethersproject/basex': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/contracts': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/hdnode': 5.7.0 + '@ethersproject/json-wallets': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/networks': 5.7.1 + '@ethersproject/pbkdf2': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/providers': 5.7.2 + '@ethersproject/random': 5.7.0 + '@ethersproject/rlp': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + '@ethersproject/solidity': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/units': 5.7.0 + '@ethersproject/wallet': 5.7.0 + '@ethersproject/web': 5.7.1 + '@ethersproject/wordlists': 5.7.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + ethjs-unit@0.1.6: + dependencies: + bn.js: 4.11.6 + number-to-bn: 1.7.0 + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + + flatted@3.3.1: {} + + follow-redirects@1.15.6: {} + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/36c303b7ffdd842d06b1ec2744c9b9b5fb3083f3: {} + + form-data-encoder@2.1.4: {} + + fs.realpath@1.0.0: {} + + function-bind@1.1.2: {} + + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functions-have-names@1.2.3: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-stream@6.0.1: {} + + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + get-tsconfig@4.7.5: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + got@12.6.1: + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + + graceful-fs@4.2.10: {} + + graphemer@1.4.0: {} + + has-bigints@1.0.2: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + has@1.0.4: {} + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + http-cache-semantics@4.1.1: {} + + http2-wrapper@2.2.1: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + ignore@5.3.1: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-arrayish@0.2.1: {} + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 + + is-boolean-object@1.1.2: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-builtin-module@3.2.1: + dependencies: + builtin-modules: 3.3.0 + + is-callable@1.2.7: {} + + is-core-module@2.14.0: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hex-prefixed@1.0.0: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + js-sha3@0.8.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + latest-version@7.0.0: + dependencies: + package-json: 8.1.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lines-and-columns@1.2.4: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash.truncate@4.4.2: {} + + lodash@4.17.21: {} + + lowercase-keys@3.0.0: {} + + make-error@1.3.6: {} + + memorystream@0.3.1: {} + + merge2@1.4.1: {} + + merkletreejs@0.3.11: + dependencies: + bignumber.js: 9.1.2 + buffer-reverse: 1.0.1 + crypto-js: 4.2.0 + treeify: 1.1.0 + web3-utils: 1.10.4 + + micro-ftch@0.3.1: {} + + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-response@3.1.0: {} + + mimic-response@4.0.0: {} + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.3: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + ms@2.1.2: {} + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + normalize-url@8.0.1: {} + + number-to-bn@1.7.0: + dependencies: + bn.js: 4.11.6 + strip-hex-prefix: 1.0.0 + + object-inspect@1.13.2: {} + + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + os-tmpdir@1.0.2: {} + + p-cancelable@3.0.0: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p256-verifier#v0.1.0@https://codeload.github.com/taikoxyz/p256-verifier/tar.gz/6ef45b117642786b08a37b4c37c6a6ce151166da: {} + + package-json@8.1.1: + dependencies: + got: 12.6.1 + registry-auth-token: 5.0.2 + registry-url: 6.0.1 + semver: 7.6.2 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.24.7 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-type@4.0.0: {} + + picocolors@1.0.1: {} + + picomatch@2.3.1: {} + + pluralize@8.0.0: {} + + possible-typed-array-names@1.0.0: {} + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@2.8.8: + optional: true + + prettier@3.0.3: {} + + proto-list@1.2.4: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + quick-lru@5.1.1: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + regexp.prototype.flags@1.5.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + regexpp@3.2.0: {} + + registry-auth-token@5.0.2: + dependencies: + '@pnpm/npm-conf': 2.2.2 + + registry-url@6.0.1: + dependencies: + rc: 1.2.8 + + require-from-string@2.0.2: {} + + resolve-alpn@1.2.1: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.14.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@3.0.0: + dependencies: + lowercase-keys: 3.0.0 + + reusify@1.0.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-regex-test@1.0.3: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + scrypt-js@3.0.1: {} + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.6.2: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + + slash@3.0.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + solady@https://codeload.github.com/Vectorized/solady/tar.gz/de0f336d2033d04e0f77c923d639c7fbffd48b6d: {} + + solc@0.8.24: + dependencies: + command-exists: 1.2.9 + commander: 8.3.0 + follow-redirects: 1.15.6 + js-sha3: 0.8.0 + memorystream: 0.3.1 + semver: 5.7.2 + tmp: 0.0.33 + transitivePeerDependencies: + - debug + + solhint@5.0.1(typescript@5.2.2): + dependencies: + '@solidity-parser/parser': 0.18.0 + ajv: 6.12.6 + antlr4: 4.13.1 + ast-parents: 0.0.1 + chalk: 4.1.2 + commander: 10.0.1 + cosmiconfig: 8.3.6(typescript@5.2.2) + fast-diff: 1.3.0 + glob: 8.1.0 + ignore: 5.3.1 + js-yaml: 4.1.0 + latest-version: 7.0.0 + lodash: 4.17.21 + pluralize: 8.0.0 + semver: 7.6.2 + strip-ansi: 6.0.1 + table: 6.8.2 + text-table: 0.2.0 + optionalDependencies: + prettier: 2.8.8 + transitivePeerDependencies: + - typescript + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + strip-hex-prefix@1.0.0: + dependencies: + is-hex-prefixed: 1.0.0 + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.8.8: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.3 + + table@6.8.2: + dependencies: + ajv: 8.16.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + text-table@0.2.0: {} + + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + treeify@1.1.0: {} + + ts-api-utils@1.3.0(typescript@5.2.2): + dependencies: + typescript: 5.2.2 + + ts-node@10.9.2(@types/node@20.11.30)(typescript@5.2.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.11.30 + acorn: 8.12.0 + acorn-walk: 8.3.3 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.2.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.6.3: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + typed-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-byte-offset@1.0.2: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-length@1.0.6: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + typescript@5.2.2: {} + + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + + undici-types@5.26.5: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + utf8@3.0.0: {} + + v8-compile-cache-lib@3.0.1: {} + + web3-utils@1.10.4: + dependencies: + '@ethereumjs/util': 8.1.0 + bn.js: 5.2.1 + ethereum-bloom-filters: 1.1.0 + ethereum-cryptography: 2.2.1 + ethjs-unit: 0.1.6 + number-to-bn: 1.7.0 + randombytes: 2.1.0 + utf8: 3.0.0 + + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + ws@7.4.6: {} + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} diff --git a/packages/protocol/remappings.txt b/packages/protocol/remappings.txt new file mode 100644 index 000000000000..7a0b8a151cbd --- /dev/null +++ b/packages/protocol/remappings.txt @@ -0,0 +1,2 @@ +forge-std/=node_modules/forge-std/src/ +solmate/=node_modules/solmate/src/ \ No newline at end of file diff --git a/packages/protocol/scripts/AuthorizeRemoteTaikoProtocols.s.sol b/packages/protocol/scripts/AuthorizeRemoteTaikoProtocols.s.sol new file mode 100644 index 000000000000..60969210076c --- /dev/null +++ b/packages/protocol/scripts/AuthorizeRemoteTaikoProtocols.s.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; +import "../contracts/signal/SignalService.sol"; + +contract AuthorizeRemoteTaikoProtocols is Script { + uint256 public privateKey = vm.envUint("PRIVATE_KEY"); + address public signalServiceAddress = vm.envAddress("SIGNAL_SERVICE_ADDRESS"); + uint256[] public remoteChainIDs = vm.envUint("REMOTE_CHAIN_IDS", ","); + address[] public remoteTaikoProtocols = vm.envAddress("REMOTE_TAIKO_PROTOCOLS", ","); + + function run() external { + require( + remoteChainIDs.length == remoteTaikoProtocols.length, + "invalid remote taiko protocol addresses length" + ); + + vm.startBroadcast(privateKey); + + SignalService signalService = SignalService(payable(signalServiceAddress)); + for (uint256 i; i < remoteChainIDs.length; ++i) { + console2.log(remoteTaikoProtocols[i], "--->", remoteChainIDs[i]); + if (!signalService.isAuthorizedAs(remoteTaikoProtocols[i], bytes32(remoteChainIDs[i]))) + { + signalService.authorize(remoteTaikoProtocols[i], bytes32(remoteChainIDs[i])); + } + } + + vm.stopBroadcast(); + } +} diff --git a/packages/protocol/scripts/DeployDelegate.s.sol b/packages/protocol/scripts/DeployDelegate.s.sol new file mode 100644 index 000000000000..bdaa6f68febc --- /dev/null +++ b/packages/protocol/scripts/DeployDelegate.s.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.8.20; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../contracts/examples/DelegateContract.sol"; + +// forge script --rpc-url http://127.0.0.1:8545 +//script/DeployOnL1.s.sol -vvvv --broadcast --private-key +// 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +contract DeployXERC20 is Script { + uint256 public adminPrivateKey = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; + + function run() external { + require(adminPrivateKey != 0, "PRIVATE_KEY not set"); + + vm.startBroadcast(adminPrivateKey); + + address delegateContract = address(new DelegateContract()); + + console2.log("DelegateContract address is:", delegateContract); + + vm.stopBroadcast(); + } +} diff --git a/packages/protocol/scripts/DeployL1Locally.s.sol b/packages/protocol/scripts/DeployL1Locally.s.sol new file mode 100644 index 000000000000..5ceb8fc1b569 --- /dev/null +++ b/packages/protocol/scripts/DeployL1Locally.s.sol @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts/utils/Strings.sol"; + +import "../contracts/L1/Gwyneth.sol"; +import "../contracts/L1/ExtensionOracle.sol"; +import "../contracts/L1/ChainProver.sol"; +import "../contracts/L1/VerifierRegistry.sol"; +import "../contracts/tko/TaikoToken.sol"; +//import "../contracts/L1/provers/GuardianProver.sol"; +// import "../contracts/automata-attestation/AutomataDcapV3Attestation.sol"; +// import "../contracts/automata-attestation/utils/SigVerifyLib.sol"; +// import "../contracts/automata-attestation/lib/PEMCertChainLib.sol"; +//import "../contracts/L1/verifiers/SgxVerifier.sol"; +//import "../contracts/L1/verifiers/MockSgxVerifier.sol"; // Avoid proof verification for now! +// import "../test/common/erc20/FreeMintERC20.sol"; +// import "../test/common/erc20/MayFailFreeMintERC20.sol"; +import "../test/DeployCapability.sol"; + +// Actually this one is deployed already on mainnet, but we are now deploying our own (non via-ir) +// version. For mainnet, it is easier to go with one of: +// - https://github.com/daimo-eth/p256-verifier +// - https://github.com/rdubois-crypto/FreshCryptoLib +import { P256Verifier } from "p256-verifier/src/P256Verifier.sol"; + +/// @title DeployOnL1 +/// @notice This script deploys the core Taiko protocol smart contract on L1, +/// initializing the rollup. +contract DeployL1Locally is DeployCapability { + // uint256 public NUM_MIN_MAJORITY_GUARDIANS = vm.envUint("NUM_MIN_MAJORITY_GUARDIANS"); + // uint256 public NUM_MIN_MINORITY_GUARDIANS = vm.envUint("NUM_MIN_MINORITY_GUARDIANS"); + + address public MAINNET_CONTRACT_OWNER = vm.envAddress("MAINNET_CONTRACT_OWNER"); //Dani: Use an address anvil provides, with preminted ETH + + modifier broadcast() { + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + require(privateKey != 0, "invalid priv key"); + vm.startBroadcast(); + _; + vm.stopBroadcast(); + } + + function run() external broadcast { + /* + IMPORTANT NOTICES: + - TaikoL2 deployments (and not only TaikoL2, but all contracts sitting on L2) obviously not done and haven't even dealt with + - SignalService, Bridge, Vaults also not dealt with on L1 + */ + // addressNotNull(vm.envAddress("TAIKO_L2_ADDRESS"), "TAIKO_L2_ADDRESS"); + // addressNotNull(vm.envAddress("L2_SIGNAL_SERVICE"), "L2_SIGNAL_SERVICE"); + // addressNotNull(vm.envAddress("CONTRACT_OWNER"), "CONTRACT_OWNER"); + + require(vm.envBytes32("L2_GENESIS_HASH") != 0, "L2_GENESIS_HASH"); + address contractOwner = MAINNET_CONTRACT_OWNER; + + // --------------------------------------------------------------- + // Deploy shared contracts + (address sharedAddressManager) = deploySharedContracts(contractOwner); + console2.log("sharedAddressManager: ", sharedAddressManager); + // --------------------------------------------------------------- + // Deploy rollup contracts + address rollupAddressManager = deployRollupContracts(sharedAddressManager, contractOwner); + + // // --------------------------------------------------------------- + // // Signal service need to authorize the new rollup + // address signalServiceAddr = AddressManager(sharedAddressManager).getAddress( + // uint64(block.chainid), LibStrings.B_SIGNAL_SERVICE + // ); + // addressNotNull(signalServiceAddr, "signalServiceAddr"); + // SignalService signalService = SignalService(signalServiceAddr); + + address gwynethAddr = AddressManager(rollupAddressManager).getAddress( + uint64(block.chainid), "taiko" + ); + addressNotNull(gwynethAddr, "taikoL1Addr"); + Gwyneth gwyneth = Gwyneth(payable(gwynethAddr)); + + ExtensionOracle extensionOracle = new ExtensionOracle(); + console2.log("extensionOracle: ", address(extensionOracle)); + + // if (vm.envAddress("SHARED_ADDRESS_MANAGER") == address(0)) { + // SignalService(signalServiceAddr).authorize(taikoL1Addr, true); + // } + + // uint64 l2ChainId = taikoL1.getConfig().chainId; + // require(l2ChainId != block.chainid, "same chainid"); + + // console2.log("------------------------------------------"); + // console2.log("msg.sender: ", msg.sender); + // console2.log("address(this): ", address(this)); + // console2.log("signalService.owner(): ", signalService.owner()); + // console2.log("------------------------------------------"); + + // if (signalService.owner() == msg.sender) { + // signalService.transferOwnership(contractOwner); + // } else { + // console2.log("------------------------------------------"); + // console2.log("Warning - you need to transact manually:"); + // console2.log("signalService.authorize(taikoL1Addr, bytes32(block.chainid))"); + // console2.log("- signalService : ", signalServiceAddr); + // console2.log("- taikoL1Addr : ", taikoL1Addr); + // console2.log("- chainId : ", block.chainid); + // } + + // // --------------------------------------------------------------- + // // Register L2 addresses + // register(rollupAddressManager, "taiko", vm.envAddress("TAIKO_L2_ADDRESS"), l2ChainId); + // register( + // rollupAddressManager, "signal_service", vm.envAddress("L2_SIGNAL_SERVICE"), l2ChainId + // ); + + // // --------------------------------------------------------------- + // // Deploy other contracts + // if (block.chainid != 1) { + // deployAuxContracts(); + // } + + // if (AddressManager(sharedAddressManager).owner() == msg.sender) { + // AddressManager(sharedAddressManager).transferOwnership(contractOwner); + // console2.log("** sharedAddressManager ownership transferred to:", contractOwner); + // } + + // AddressManager(rollupAddressManager).transferOwnership(contractOwner); + // console2.log("** rollupAddressManager ownership transferred to:", contractOwner); + + // Sending 10 ETH to Alice + address payable admin = payable(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + (bool success, ) = admin.call{value: 10 ether}(""); + require(success, "Failed to send Ether"); + } + + function deploySharedContracts(address owner) internal returns (address sharedAddressManager) { + addressNotNull(owner, "owner"); + + sharedAddressManager = address(0);// Dani: Can be set tho via ENV var, for now, for anvil, easy to just deploy every time + if (sharedAddressManager == address(0)) { + sharedAddressManager = deployProxy({ + name: "shared_address_manager", + impl: address(new AddressManager()), + data: abi.encodeCall(AddressManager.init, (owner)) + }); + } + + //dataToFeed = abi.encodeCall(TaikoToken.init, ("TAIKO", "TAIKO", MAINNET_CONTRACT_OWNER)); + address taikoToken = address(0); // Later on use this as env. var since already deployed (on testnets): vm.envAddress("TAIKO_TOKEN"); + if (taikoToken == address(0)) { + taikoToken = deployProxy({ + name: "taiko_token", + impl: address(new TaikoToken()), + data: abi.encodeCall(TaikoToken.init, (MAINNET_CONTRACT_OWNER, MAINNET_CONTRACT_OWNER)), + registerTo: sharedAddressManager + }); + } + + // // Deploy Bridging contracts - to be done later. + // deployProxy({ + // name: "signal_service", + // impl: address(new SignalService()), + // data: abi.encodeCall(SignalService.init, (address(0), sharedAddressManager)), + // registerTo: sharedAddressManager + // }); + + // address brdige = deployProxy({ + // name: "bridge", + // impl: address(new Bridge()), + // data: abi.encodeCall(Bridge.init, (address(0), sharedAddressManager)), + // registerTo: sharedAddressManager + // }); + + // if (vm.envBool("PAUSE_BRIDGE")) { + // Bridge(payable(brdige)).pause(); + // } + + // Bridge(payable(brdige)).transferOwnership(owner); + + // console2.log("------------------------------------------"); + // console2.log( + // "Warning - you need to register *all* counterparty bridges to enable multi-hop bridging:" + // ); + // console2.log( + // "sharedAddressManager.setAddress(remoteChainId, \"bridge\", address(remoteBridge))" + // ); + // console2.log("- sharedAddressManager : ", sharedAddressManager); + + // // Deploy Vaults + // deployProxy({ + // name: "erc20_vault", + // impl: address(new ERC20Vault()), + // data: abi.encodeCall(ERC20Vault.init, (owner, sharedAddressManager)), + // registerTo: sharedAddressManager + // }); + + // deployProxy({ + // name: "erc721_vault", + // impl: address(new ERC721Vault()), + // data: abi.encodeCall(ERC721Vault.init, (owner, sharedAddressManager)), + // registerTo: sharedAddressManager + // }); + + // deployProxy({ + // name: "erc1155_vault", + // impl: address(new ERC1155Vault()), + // data: abi.encodeCall(ERC1155Vault.init, (owner, sharedAddressManager)), + // registerTo: sharedAddressManager + // }); + + // console2.log("------------------------------------------"); + // console2.log( + // "Warning - you need to register *all* counterparty vaults to enable multi-hop bridging:" + // ); + // console2.log( + // "sharedAddressManager.setAddress(remoteChainId, \"erc20_vault\", address(remoteERC20Vault))" + // ); + // console2.log( + // "sharedAddressManager.setAddress(remoteChainId, \"erc721_vault\", address(remoteERC721Vault))" + // ); + // console2.log( + // "sharedAddressManager.setAddress(remoteChainId, \"erc1155_vault\", address(remoteERC1155Vault))" + // ); + // console2.log("- sharedAddressManager : ", sharedAddressManager); + + // // Deploy Bridged token implementations + // register(sharedAddressManager, "bridged_erc20", address(new BridgedERC20())); + // register(sharedAddressManager, "bridged_erc721", address(new BridgedERC721())); + // register(sharedAddressManager, "bridged_erc1155", address(new BridgedERC1155())); + } + + function deployRollupContracts( + address _sharedAddressManager, + address owner + ) + internal + returns (address rollupAddressManager) + { + addressNotNull(_sharedAddressManager, "sharedAddressManager"); + addressNotNull(owner, "owner"); + + rollupAddressManager = deployProxy({ + name: "rollup_address_manager", + impl: address(new AddressManager()), + data: abi.encodeCall(AddressManager.init, (owner)) + }); + + // --------------------------------------------------------------- + // Register shared contracts in the new rollup + copyRegister(rollupAddressManager, _sharedAddressManager, "taiko_token"); + // Not deployed yet, so not needed: + // copyRegister(rollupAddressManager, _sharedAddressManager, "signal_service"); + // copyRegister(rollupAddressManager, _sharedAddressManager, "bridge"); + + address gwyneth = deployProxy({ + name: "taiko", + impl: address(new Gwyneth()), + data: abi.encodeCall( + Gwyneth.init, + ( + owner, + vm.envBytes32("L2_GENESIS_HASH") + ) + ), + registerTo: rollupAddressManager + }); + console2.log("gwyneth: ", address(gwyneth)); + + // Enable the proposer + Gwyneth(payable(gwyneth)).setProposer(0xE25583099BA105D9ec0A67f5Ae86D90e50036425, true); + + /* Deploy ChainProver */ + deployProxy({ + name: "chain_prover", + impl: address(new ChainProver()), + data: abi.encodeCall(ChainProver.init, (MAINNET_CONTRACT_OWNER, rollupAddressManager)), + registerTo: rollupAddressManager + }); + + /* Deploy MockSGXVerifier 3 times for now, so that we can call verifyProof without modifications of the protocol code. Later obv. shall be replaced with real verifiers. */ + // address verifier1 = deployProxy({ + // name: "tier_sgx1", + // impl: address(new MockSgxVerifier()), + // data: abi.encodeCall(MockSgxVerifier.init, (MAINNET_CONTRACT_OWNER, rollupAddressManager)), + // registerTo: rollupAddressManager + // }); + // address verifier2 = deployProxy({ + // name: "tier_sgx2", + // impl: address(new MockSgxVerifier()), + // data: abi.encodeCall(MockSgxVerifier.init, (MAINNET_CONTRACT_OWNER, rollupAddressManager)), + // registerTo: rollupAddressManager + // }); + // address verifier3 = deployProxy({ + // name: "tier_sgx3", + // impl: address(new MockSgxVerifier()), + // data: abi.encodeCall(MockSgxVerifier.init, (MAINNET_CONTRACT_OWNER, rollupAddressManager)), + // registerTo: rollupAddressManager + // }); + + // /* Deploy VerifierRegistry */ + // address vieriferRegistry = deployProxy({ + // name: "verifier_registry", + // impl: address(new VerifierRegistry()), + // data: abi.encodeCall(VerifierRegistry.init, (MAINNET_CONTRACT_OWNER, rollupAddressManager)), + // registerTo: rollupAddressManager + // }); + + // // Add those 3 to verifier registry + // VerifierRegistry(vieriferRegistry).addVerifier(verifier1, "sgx1"); + // VerifierRegistry(vieriferRegistry).addVerifier(verifier2, "sgx2"); + // VerifierRegistry(vieriferRegistry).addVerifier(verifier3, "sgx3"); + + // Leave out guardians "tier" for now. + // address guardianProverImpl = address(new GuardianProver()); + + // address guardianProverMinority = deployProxy({ + // name: "guardian_prover_minority", + // impl: guardianProverImpl, + // data: abi.encodeCall(GuardianProver.init, (address(0), rollupAddressManager)) + // }); + + // GuardianProver(guardianProverMinority).enableTaikoTokenAllowance(true); + + // address guardianProver = deployProxy({ + // name: "guardian_prover", + // impl: guardianProverImpl, + // data: abi.encodeCall(GuardianProver.init, (address(0), rollupAddressManager)) + // }); + + // register(rollupAddressManager, "tier_guardian_minority", guardianProverMinority); + // register(rollupAddressManager, "tier_guardian", guardianProver); + // register( + // rollupAddressManager, + // "tier_router", + // address(deployTierProvider(vm.envString("TIER_PROVIDER"))) + // ); + + // address[] memory guardians = vm.envAddress("GUARDIAN_PROVERS", ","); + + // GuardianProver(guardianProverMinority).setGuardians( + // guardians, uint8(NUM_MIN_MINORITY_GUARDIANS), true + // ); + // GuardianProver(guardianProverMinority).transferOwnership(owner); + + // GuardianProver(guardianProver).setGuardians( + // guardians, uint8(NUM_MIN_MAJORITY_GUARDIANS), true + // ); + // GuardianProver(guardianProver).transferOwnership(owner); + + // // No need to proxy these, because they are 3rd party. If we want to modify, we simply + // // change the registerAddress("automata_dcap_attestation", address(attestation)); + // P256Verifier p256Verifier = new P256Verifier(); + // SigVerifyLib sigVerifyLib = new SigVerifyLib(address(p256Verifier)); + // PEMCertChainLib pemCertChainLib = new PEMCertChainLib(); + // address automateDcapV3AttestationImpl = address(new AutomataDcapV3Attestation()); + + // address automataProxy = deployProxy({ + // name: "automata_dcap_attestation", + // impl: automateDcapV3AttestationImpl, + // data: abi.encodeCall( + // AutomataDcapV3Attestation.init, (owner, address(sigVerifyLib), address(pemCertChainLib)) + // ), + // registerTo: rollupAddressManager + // }); + + // // Log addresses for the user to register sgx instance + // console2.log("SigVerifyLib", address(sigVerifyLib)); + // console2.log("PemCertChainLib", address(pemCertChainLib)); + // console2.log("AutomataDcapVaAttestation", automataProxy); + + // deployProxy({ + // name: "prover_set", + // impl: address(new ProverSet()), + // data: abi.encodeCall( + // ProverSet.init, (owner, vm.envAddress("PROVER_SET_ADMIN"), rollupAddressManager) + // ) + // }); + } + + function addressNotNull(address addr, string memory err) private pure { + require(addr != address(0), err); + } +} diff --git a/packages/protocol/scripts/DeployOnL1.s.sol b/packages/protocol/scripts/DeployOnL1.s.sol new file mode 100644 index 000000000000..60627ab98f19 --- /dev/null +++ b/packages/protocol/scripts/DeployOnL1.s.sol @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/utils/Strings.sol"; +/* +import "../contracts/L1/TaikoToken.sol"; +import "../contracts/L1/TaikoL1.sol"; +import "../contracts/L1/provers/GuardianProver.sol"; +import "../contracts/L1/verifiers/PseZkVerifier.sol"; +import "../contracts/L1/verifiers/SgxVerifier.sol"; +import "../contracts/L1/verifiers/SgxAndZkVerifier.sol"; +import "../contracts/L1/verifiers/GuardianVerifier.sol"; +import "../contracts/L1/tiers/TaikoA6TierProvider.sol"; +import "../contracts/L1/actors/StandardProverPayment.sol"; +import "../contracts/L1/gov/TaikoTimelockController.sol"; +import "../contracts/L1/gov/TaikoGovernor.sol"; +import "../contracts/bridge/Bridge.sol"; +import "../contracts/tokenvault/ERC20Vault.sol"; +import "../contracts/tokenvault/ERC1155Vault.sol"; +import "../contracts/tokenvault/ERC721Vault.sol"; +import "../contracts/signal/SignalService.sol"; +import "../contracts/test/erc20/FreeMintERC20.sol"; +import "../contracts/test/erc20/MayFailFreeMintERC20.sol"; +import "../test/DeployCapability.sol"; + +/// @title DeployOnL1 +/// @notice This script deploys the core Taiko protocol smart contract on L1, +/// initializing the rollup. +contract DeployOnL1 is DeployCapability { + uint256 public constant NUM_GUARDIANS = 5; + + address public constant MAINNET_SECURITY_COUNCIL = 0x7C50d60743D3FCe5a39FdbF687AFbAe5acFF49Fd; + + address securityCouncil = + block.chainid == 1 ? MAINNET_SECURITY_COUNCIL : vm.envAddress("SECURITY_COUNCIL"); + + modifier broadcast() { + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + require(privateKey != 0, "invalid priv key"); + vm.startBroadcast(); + _; + vm.stopBroadcast(); + } + + function run() external broadcast { + addressNotNull(vm.envAddress("TAIKO_L2_ADDRESS"), "TAIKO_L2_ADDRESS"); + addressNotNull(vm.envAddress("L2_SIGNAL_SERVICE"), "L2_SIGNAL_SERVICE"); + require(vm.envBytes32("L2_GENESIS_HASH") != 0, "L2_GENESIS_HASH"); + + // --------------------------------------------------------------- + // Deploy shared contracts + (address sharedAddressManager, address timelock) = deploySharedContracts(); + console2.log("sharedAddressManager: ", sharedAddressManager); + console2.log("timelock: ", timelock); + // --------------------------------------------------------------- + // Deploy rollup contracts + address rollupAddressManager = deployRollupContracts(sharedAddressManager, timelock); + + // --------------------------------------------------------------- + // Signal service need to authorize the new rollup + address signalServiceAddr = + AddressManager(sharedAddressManager).getAddress(uint64(block.chainid), "signal_service"); + addressNotNull(signalServiceAddr, "signalServiceAddr"); + SignalService signalService = SignalService(signalServiceAddr); + + address taikoL1Addr = + AddressManager(rollupAddressManager).getAddress(uint64(block.chainid), "taiko"); + addressNotNull(taikoL1Addr, "taikoL1Addr"); + TaikoL1 taikoL1 = TaikoL1(payable(taikoL1Addr)); + + uint64 l2ChainId = taikoL1.getConfig().chainId; + require(l2ChainId != block.chainid, "same chainid"); + + console2.log("------------------------------------------"); + console2.log("msg.sender: ", msg.sender); + console2.log("address(this): ", address(this)); + console2.log("signalService.owner(): ", signalService.owner()); + console2.log("------------------------------------------"); + + if (signalService.owner() == address(this)) { + signalService.authorize(taikoL1Addr, bytes32(block.chainid)); + signalService.authorize(vm.envAddress("TAIKO_L2_ADDRESS"), bytes32(uint256(l2ChainId))); + signalService.transferOwnership(timelock); + } else { + console2.log("------------------------------------------"); + console2.log("Warning - you need to transact manually:"); + console2.log("signalService.authorize(taikoL1Addr, bytes32(block.chainid))"); + console2.log("- signalService : ", signalServiceAddr); + console2.log("- taikoL1Addr : ", taikoL1Addr); + console2.log("- chainId : ", block.chainid); + } + + // --------------------------------------------------------------- + // Register shared contracts in the new rollup + copyRegister(rollupAddressManager, sharedAddressManager, "taiko_token"); + copyRegister(rollupAddressManager, sharedAddressManager, "signal_service"); + copyRegister(rollupAddressManager, sharedAddressManager, "bridge"); + + address proposer = vm.envAddress("PROPOSER"); + if (proposer != address(0)) { + register(rollupAddressManager, "proposer", proposer); + } + + address proposerOne = vm.envAddress("PROPOSER_ONE"); + if (proposerOne != address(0)) { + register(rollupAddressManager, "proposer_one", proposerOne); + } + + // --------------------------------------------------------------- + // Register L2 addresses + register(rollupAddressManager, "taiko", vm.envAddress("TAIKO_L2_ADDRESS"), l2ChainId); + register( + rollupAddressManager, "signal_service", vm.envAddress("L2_SIGNAL_SERVICE"), l2ChainId + ); + + // --------------------------------------------------------------- + // Deploy other contracts + deployAuxContracts(); + + if (AddressManager(sharedAddressManager).owner() == msg.sender) { + AddressManager(sharedAddressManager).transferOwnership(timelock); + console2.log("** sharedAddressManager ownership transferred to timelock:", timelock); + } + + AddressManager(rollupAddressManager).transferOwnership(timelock); + console2.log("** rollupAddressManager ownership transferred to timelock:", timelock); + } + + function deploySharedContracts() + internal + returns (address sharedAddressManager, address timelock) + { + sharedAddressManager = vm.envAddress("SHARED_ADDRESS_MANAGER"); + if (sharedAddressManager != address(0)) { + return (sharedAddressManager, vm.envAddress("TIMELOCK_CONTROLLER")); + } + + // Deploy the timelock + timelock = deployProxy({ + name: "timelock_controller", + impl: address(new TaikoTimelockController()), + data: bytes.concat(TaikoTimelockController.init.selector, abi.encode(7 days)) + }); + + sharedAddressManager = deployProxy({ + name: "shared_address_manager", + impl: address(new AddressManager()), + data: bytes.concat(AddressManager.init.selector) + }); + + address taikoToken = deployProxy({ + name: "taiko_token", + impl: address(new TaikoToken()), + data: bytes.concat( + TaikoToken.init.selector, + abi.encode( + vm.envString("TAIKO_TOKEN_NAME"), + vm.envString("TAIKO_TOKEN_SYMBOL"), + vm.envAddress("TAIKO_TOKEN_PREMINT_RECIPIENT") + ) + ), + registerTo: sharedAddressManager, + owner: timelock + }); + + address governor = deployProxy({ + name: "taiko_governor", + impl: address(new TaikoGovernor()), + data: bytes.concat(TaikoGovernor.init.selector, abi.encode(taikoToken, timelock)), + registerTo: address(0), + owner: timelock + }); + + // Setup time lock roles + TaikoTimelockController _timelock = TaikoTimelockController(payable(timelock)); + _timelock.grantRole(_timelock.PROPOSER_ROLE(), governor); + _timelock.grantRole(_timelock.PROPOSER_ROLE(), securityCouncil); + + _timelock.grantRole(_timelock.EXECUTOR_ROLE(), governor); + _timelock.grantRole(_timelock.EXECUTOR_ROLE(), securityCouncil); + + _timelock.grantRole(_timelock.CANCELLER_ROLE(), governor); + _timelock.grantRole(_timelock.CANCELLER_ROLE(), securityCouncil); + + _timelock.grantRole(_timelock.TIMELOCK_ADMIN_ROLE(), securityCouncil); + _timelock.revokeRole(_timelock.TIMELOCK_ADMIN_ROLE(), address(this)); + _timelock.revokeRole(_timelock.TIMELOCK_ADMIN_ROLE(), msg.sender); + + _timelock.transferOwnership(securityCouncil); + + // Deploy Bridging contracts + deployProxy({ + name: "signal_service", + impl: address(new SignalService()), + data: bytes.concat(SignalService.init.selector), + registerTo: sharedAddressManager, + owner: address(0) + }); + + deployProxy({ + name: "bridge", + impl: address(new Bridge()), + data: bytes.concat(Bridge.init.selector, abi.encode(sharedAddressManager)), + registerTo: sharedAddressManager, + owner: timelock + }); + + console2.log("------------------------------------------"); + console2.log( + "Warning - you need to register *all* counterparty bridges to enable multi-hop bridging:" + ); + console2.log( + "sharedAddressManager.setAddress(remoteChainId, \"bridge\", address(remoteBridge))" + ); + console2.log("- sharedAddressManager : ", sharedAddressManager); + + // Deploy Vaults + deployProxy({ + name: "erc20_vault", + impl: address(new ERC20Vault()), + data: bytes.concat(BaseVault.init.selector, abi.encode(sharedAddressManager)), + registerTo: sharedAddressManager, + owner: timelock + }); + + deployProxy({ + name: "erc721_vault", + impl: address(new ERC721Vault()), + data: bytes.concat(BaseVault.init.selector, abi.encode(sharedAddressManager)), + registerTo: sharedAddressManager, + owner: timelock + }); + + deployProxy({ + name: "erc1155_vault", + impl: address(new ERC1155Vault()), + data: bytes.concat(BaseVault.init.selector, abi.encode(sharedAddressManager)), + registerTo: sharedAddressManager, + owner: timelock + }); + + console2.log("------------------------------------------"); + console2.log( + "Warning - you need to register *all* counterparty vaults to enable multi-hop bridging:" + ); + console2.log( + "sharedAddressManager.setAddress(remoteChainId, \"erc20_vault\", address(remoteERC20Vault))" + ); + console2.log( + "sharedAddressManager.setAddress(remoteChainId, \"erc721_vault\", address(remoteERC721Vault))" + ); + console2.log( + "sharedAddressManager.setAddress(remoteChainId, \"erc1155_vault\", address(remoteERC1155Vault))" + ); + console2.log("- sharedAddressManager : ", sharedAddressManager); + + // Deploy Bridged token implementations + register(sharedAddressManager, "bridged_erc20", address(new BridgedERC20())); + register(sharedAddressManager, "bridged_erc721", address(new BridgedERC721())); + register(sharedAddressManager, "bridged_erc1155", address(new BridgedERC1155())); + } + + function deployRollupContracts( + address _sharedAddressManager, + address timelock + ) + internal + returns (address rollupAddressManager) + { + addressNotNull(_sharedAddressManager, "sharedAddressManager"); + addressNotNull(timelock, "timelock"); + + rollupAddressManager = deployProxy({ + name: "rollup_address_manager", + impl: address(new AddressManager()), + data: bytes.concat(AddressManager.init.selector) + }); + + deployProxy({ + name: "taiko", + impl: address(new TaikoL1()), + data: bytes.concat( + TaikoL1.init.selector, + abi.encode(rollupAddressManager, vm.envBytes32("L2_GENESIS_HASH")) + ), + registerTo: rollupAddressManager, + owner: timelock + }); + + deployProxy({ + name: "assignment_hook", + impl: address(new StandardProverPayment()), + data: bytes.concat(StandardProverPayment.init.selector, abi.encode(rollupAddressManager)), + registerTo: address(0), + owner: timelock + }); + + deployProxy({ + name: "tier_provider", + impl: address(new TaikoA6TierProvider()), + data: bytes.concat(TaikoA6TierProvider.init.selector), + registerTo: rollupAddressManager, + owner: timelock + }); + + deployProxy({ + name: "tier_guardian", + impl: address(new GuardianVerifier()), + data: bytes.concat(GuardianVerifier.init.selector, abi.encode(rollupAddressManager)), + registerTo: rollupAddressManager, + owner: timelock + }); + + deployProxy({ + name: "tier_sgx", + impl: address(new SgxVerifier()), + data: bytes.concat(SgxVerifier.init.selector, abi.encode(rollupAddressManager)), + registerTo: rollupAddressManager, + owner: timelock + }); + + deployProxy({ + name: "tier_sgx_and_pse_zkevm", + impl: address(new SgxAndZkVerifier()), + data: bytes.concat(SgxAndZkVerifier.init.selector, abi.encode(rollupAddressManager)), + registerTo: rollupAddressManager, + owner: timelock + }); + + address pseZkVerifier = deployProxy({ + name: "tier_pse_zkevm", + impl: address(new PseZkVerifier()), + data: bytes.concat(PseZkVerifier.init.selector, abi.encode(rollupAddressManager)), + registerTo: rollupAddressManager, + owner: timelock + }); + + address[] memory plonkVerifiers = new address[](1); + plonkVerifiers[0] = deployYulContract("contracts/L1/verifiers/PlonkVerifier.yulp"); + + for (uint16 i = 0; i < plonkVerifiers.length; ++i) { + register( + rollupAddressManager, + string(abi.encodePacked(PseZkVerifier(pseZkVerifier).getVerifierName(i))), + plonkVerifiers[i] + ); + } + + address guardianProver = deployProxy({ + name: "guardian_prover", + impl: address(new GuardianProver()), + data: bytes.concat(GuardianProver.init.selector, abi.encode(rollupAddressManager)), + registerTo: rollupAddressManager, + owner: address(0) + }); + + address[] memory guardians = vm.envAddress("GUARDIAN_PROVERS", ","); + uint8 minGuardians = uint8(vm.envUint("MIN_GUARDIANS")); + GuardianProver(guardianProver).setGuardians(guardians, minGuardians); + GuardianProver(guardianProver).transferOwnership(timelock); + } + + function deployAuxContracts() private { + address horseToken = address(new FreeMintERC20("Horse Token", "HORSE")); + console2.log("HorseToken", horseToken); + + address bullToken = address(new MayFailFreeMintERC20("Bull Token", "BULL")); + console2.log("BullToken", bullToken); + } + + function deployYulContract(string memory contractPath) private returns (address addr) { + string[] memory cmds = new string[](3); + cmds[0] = "bash"; + cmds[1] = "-c"; + cmds[2] = string.concat( + vm.projectRoot(), + "/bin/solc --yul --bin ", + string.concat(vm.projectRoot(), "/", contractPath), + " | grep -A1 Binary | tail -1" + ); + + bytes memory bytecode = vm.ffi(cmds); + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + addressNotNull(addr, "failed yul deployment"); + console2.log(contractPath, addr); + } + + function addressNotNull(address addr, string memory err) private pure { + require(addr != address(0), err); + } +} +*/ \ No newline at end of file diff --git a/packages/protocol/scripts/DeployXERC20.s.sol b/packages/protocol/scripts/DeployXERC20.s.sol new file mode 100644 index 000000000000..6518ca5b4089 --- /dev/null +++ b/packages/protocol/scripts/DeployXERC20.s.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.8.20; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../contracts/examples/xERC20.sol"; + +// forge script --rpc-url http://127.0.0.1:8545 +//script/DeployOnL1.s.sol -vvvv --broadcast --private-key +// 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +contract DeployXERC20 is Script { + uint256 public adminPrivateKey = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; + + function run() external { + require(adminPrivateKey != 0, "PRIVATE_KEY not set"); + + vm.startBroadcast(adminPrivateKey); + + address xERC20 = address(new xERC20(99999)); + + console2.log("xERC20 address is:", xERC20); + + vm.stopBroadcast(); + } +} diff --git a/packages/protocol/scripts/L2_txn_simulation/CreateXChainTxn.s.sol b/packages/protocol/scripts/L2_txn_simulation/CreateXChainTxn.s.sol new file mode 100644 index 000000000000..088e6ec880ee --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/CreateXChainTxn.s.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../../contracts/examples/xERC20Example.sol"; + +contract CreateXChainTxn is Script { + address public Bob_deployer_and_xchain_sender = 0x8943545177806ED17B9F23F0a21ee5948eCaa776; //Also .env PRIV_KEY is tied to Bob + address public Alice_xchain_receiver = 0xE25583099BA105D9ec0A67f5Ae86D90e50036425; + + function run() external { + vm.startBroadcast(); + + //Deploy a contract and mints 100k for Bob + xERC20Example exampleXChainToken = new xERC20Example("xChainExample", "xCE", Bob_deployer_and_xchain_sender, 100_000 * 1e18); + + // ChainId to send to + uint256 dummyChainId = 12346; // Does not matter at this point + + console2.log("Sender balance (before sending):", exampleXChainToken.balanceOf(Bob_deployer_and_xchain_sender)); + exampleXChainToken.xtransfer(Alice_xchain_receiver, 2 * 1e18, block.chainid, dummyChainId); + + console2.log("Sender balance:", exampleXChainToken.balanceOf(Bob_deployer_and_xchain_sender)); + console2.log("Receiver balance:", exampleXChainToken.balanceOf(Alice_xchain_receiver)); + + vm.stopBroadcast(); + } +} diff --git a/packages/protocol/scripts/L2_txn_simulation/ProposeBlock.s.sol b/packages/protocol/scripts/L2_txn_simulation/ProposeBlock.s.sol new file mode 100644 index 000000000000..61328c80c9fa --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/ProposeBlock.s.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../../contracts/L1/TaikoL1.sol"; + +contract ProposeBlock is Script { + address public taikoL1Address = 0x9fCF7D13d10dEdF17d0f24C62f0cf4ED462f65b7;//address(0);// TaikoL1 proxy address -> Get from the deployment + address sender = 0x8943545177806ED17B9F23F0a21ee5948eCaa776; // With pre-generated eth + + function run() external { + + require(taikoL1Address != address(0), "based operator not set"); + + vm.startBroadcast(); + + bytes[] memory txLists = new bytes[](1); + // The L2 chainId with which i encoded the TXNs were 167011 + // THe nonce was 0 + bytes memory firstAddressSendingNonce0 = hex"02f87683028c6380843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf24188016345785d8a000080c080a08f0f52d943504cecea0d6ce317c2fde8b0c27b1e449d85fcf98ccd2f50ac804ba04d5d56356518c1de0c1ece644a8a2fe64e6cc136cd8db0a21a21f72c167353c6"; + bytes memory secondAddressSendingNonce0 = hex"02f87683028c6380843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf24188016345785d8a000080c080a0622e7060e09afd2100784bdc88ebb838729128bb6eb40f8b7f458430d56dafd4a006fe5d1a466788f941020a2278860c3f2642e44108c666ecd25b30d1b2f7a420"; + bytes memory thirdAddressSendingNonce0 = hex"02f87683028c6380843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf24188016345785d8a000080c001a0558488f3af91777c382d2ab6ac3507f5d6b906431534193c1a45cc2a08b2825ea0495efd571c9ea5a5290f10efaa219f8c31b4e714745737c4e019df76f7a6df4b"; + + // The outcome of the above is the rlp encoded list (not concatenated but RLP encoded with: https://toolkit.abdk.consulting/ethereum#key-to-address,rlp) + txLists[0] = hex"f90171b87902f87683028c6280843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf241880de0b6b3a764000080c080a07f983645ddf8365d14e5fb4e3b07c19fe31e23edd9ee4a737388acc2da7e64a3a072a56043512806a6de5f66f28bb659236eea41c9d66db8493f436804c42723d3b87902f87683028c6280843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf241880de0b6b3a764000080c001a030911ab2ebf76f1e1bfe00d721207d929053efb051d50708a10dd9f66f84bacba07705a7cdb86ff00aa8c131ef3c4cb2ea2f2f4730d93308f1afbb94a04c1c9ae9b87902f87683028c6280843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf241880de0b6b3a764000080c001a07da8dfb5bc3b7b353f9614bcd83733168500d1e06f2bcdac761cc54c85847e6aa03b041b0605e86aa379ff0f58a60743da411dfd1a9d4f1d18422a862f67a57fee"; + + bytes32 txListHash = keccak256(txLists[0]); //Since we not using Blobs, we need this + + // MetaData related + bytes[] memory metasEncoded = new bytes[](1); + TaikoData.BlockMetadata memory meta; + console2.log(txLists[0].length); + + meta = createBlockMetaDataForFirstBlockDebug(sender, 1, uint64(block.timestamp), uint24(txLists[0].length), txListHash); + + metasEncoded[0] = abi.encode(meta); + + TaikoL1(taikoL1Address).proposeBlock{value: 0.1 ether }(metasEncoded, txLists); + + vm.stopBroadcast(); + } + + function createBlockMetaDataForFirstBlockDebug( + address coinbase, + uint64 l2BlockNumber, + uint64 unixTimestamp, + uint24 txListByteSize, + bytes32 txListHash + ) + internal + returns (TaikoData.BlockMetadata memory meta) + { + meta.blockHash = 0xab80a9c4daa571aa308e967c9a6b4bf21ba8842d95d73d28be112b6fe0618e7c; // Randomly set it to smth + + //TaikoData.Block memory parentBlock = L1.getBlock(l2BlockNumber - 1); + meta.parentMetaHash = 0x0000000000000000000000000000000000000000000000000000000000000000; // This is the genesis block's metaHash + meta.parentBlockHash = 0xdf90a9c4daa571aa308e967c9a6b4bf21ba8842d95d73d28be112b6fe0618e8c; // This is the genesis block's blockhash + meta.l1Hash = blockhash(30); //L1 private network's L1 blockheight, submit this block between 30 and 30+128 blcok of L1. + meta.difficulty = block.prevrandao; + meta.blobHash = txListHash; + meta.coinbase = coinbase; + meta.l2BlockNumber = l2BlockNumber; + meta.gasLimit = 15_000_000; + meta.l1StateBlockNumber = uint32(30); // Submit this block between 30 and 30+128 blcok of L1. + meta.timestamp = unixTimestamp; + + meta.txListByteOffset = 0; + meta.txListByteSize = txListByteSize; // Corresponding txn list byte size + meta.blobUsed = false; + } +} diff --git a/packages/protocol/scripts/L2_txn_simulation/check_xchain_balances.py b/packages/protocol/scripts/L2_txn_simulation/check_xchain_balances.py new file mode 100644 index 000000000000..4b6da44e6a8c --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/check_xchain_balances.py @@ -0,0 +1,102 @@ +from web3 import Web3 + +# Connect to the blockchain +RPC_URL_L1 = "http://127.0.0.1:32002" # Replace with your RPC URL +web3_l1 = Web3(Web3.HTTPProvider(RPC_URL_L1)) +RPC_URL_A = "http://127.0.0.1:32005" # Replace with your RPC URL +web3_l2a = Web3(Web3.HTTPProvider(RPC_URL_A)) +RPC_URL_B = "http://127.0.0.1:32006" # Replace with your RPC URL +web3_l2b = Web3(Web3.HTTPProvider(RPC_URL_B)) + +def simulate_blockchain_call(contract_address, abi, function_name, *args): + + # Load the contract + contract = web3_l1.eth.contract(address=web3_l1.to_checksum_address(contract_address), abi=abi) + contract_a = web3_l2a.eth.contract(address=web3_l2a.to_checksum_address(contract_address), abi=abi) + contract_b = web3_l2b.eth.contract(address=web3_l2b.to_checksum_address(contract_address), abi=abi) + + # Get the contract function + contract_function = getattr(contract.functions, function_name)(*args) + contract_a_function = getattr(contract_a.functions, function_name)(*args) + contract_b_function = getattr(contract_b.functions, function_name)(*args) + + # ETH balance + print(f"ETH L1: {web3_l1.eth.get_balance(*args) / 10**18}") + print(f"ETH L2A: {web3_l2a.eth.get_balance(*args) / 10**18}") + print(f"ETH L2B: {web3_l2b.eth.get_balance(*args) / 10**18}") + + # Simulate the call + try: + response = contract_function.call() + print(f"Blockchain call successful. Response, from L1: {response}") + except Exception as e: + print(f"Error during blockchain call: {e}") + + try: + response = contract_a_function.call() + print(f"Blockchain call successful. Response, from L2A: {response}") + except Exception as e: + print(f"Error during blockchain call: {e}") + + try: + response = contract_b_function.call() + print(f"Blockchain call successful. Response, from L2B: {response}") + except Exception as e: + print(f"Error during blockchain call: {e}") + +if __name__ == "__main__": + # a simple ERC20 + example_contract_address = "0x5FbDB2315678afecb367f032d93F642f64180aa3" # xTransfer + example_abi = [ + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "constant": True, + "inputs": [ + {"name": "", "type": "address"} + ], + "name": "balanceOf", + "outputs": [ + {"name": "", "type": "uint256"} + ], + "payable": False, + "stateMutability": "view", + "type": "function" + } + ] + + # Simulate the blockchain call + print("Alice:") + simulate_blockchain_call(example_contract_address, example_abi, "balanceOf", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") + print("Bob:") + simulate_blockchain_call(example_contract_address, example_abi, "balanceOf", "0xE25583099BA105D9ec0A67f5Ae86D90e50036425") + print("Charlie:") + simulate_blockchain_call(example_contract_address, example_abi, "balanceOf", "0x614561D2d143621E126e87831AEF287678B442b8") + print("ExtensionOracle:") + simulate_blockchain_call(example_contract_address, example_abi, "balanceOf", "0x1ADB9959EB142bE128E6dfEcc8D571f07cd66DeE") + print("Gwyneth:") + simulate_blockchain_call(example_contract_address, example_abi, "balanceOf", "0x9fCF7D13d10dEdF17d0f24C62f0cf4ED462f65b7") \ No newline at end of file diff --git a/packages/protocol/scripts/L2_txn_simulation/createL2Txn.py b/packages/protocol/scripts/L2_txn_simulation/createL2Txn.py new file mode 100644 index 000000000000..279a86d3f6ca --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/createL2Txn.py @@ -0,0 +1,50 @@ +from web3 import Web3 +from eth_abi import encode +import argparse + +RPC_URL_L2 = 'http://127.0.0.1:8545' # Anything is fine for now as long as we dont have the L2 network, but if we have we can automate nonce and gas settings +w3_taiko_l2 = Web3(Web3.HTTPProvider(RPC_URL_L2)) + +# Some pre-loaded ETH addresses from Kurtosis private network (NO secret, no harm to use for private testnets!) +sender_addresses = ['0x8943545177806ED17B9F23F0a21ee5948eCaa776', '0xE25583099BA105D9ec0A67f5Ae86D90e50036425', '0x614561D2d143621E126e87831AEF287678B442b8'] +sender_pks = ['bcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31', '39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d', '53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710'] + +receiver = '0xf93Ee4Cf8c6c40b329b0c0626F28333c132CF241' # This address also has pre-loaded ETH addresses + +parser = argparse.ArgumentParser() + +parser.add_argument("-n", "--nonce", help="collective nonce", + type=int, required=True) +parser.add_argument("-c", "--chainid", help="l2 chainId", + type=int, required=True) + +transaction_list = [] + +if __name__ == "__main__": + args = parser.parse_args() + nonce = args.nonce + chainId = args.chainid + + # Build the new tx list + idx = 0 + for sender in sender_addresses: + # Build the tx + transaction = { + 'chainId': chainId, + 'from': sender, + 'to': receiver, + 'value': w3_taiko_l2.to_wei('1', 'ether'), + 'nonce': nonce, # later we can use something like: w3_taiko_l2.eth.get_transaction_count(address1), + 'gas': 200000, + 'maxFeePerGas': 2000000000, # w3_taiko_l2.eth.gas_price or something + 'maxPriorityFeePerGas': 1000000000, + } + + # 2. Sign tx with a private key + signed_txn = w3_taiko_l2.eth.account.sign_transaction(transaction, sender_pks[idx]) + + # Most probably we need to zlib + rlp encode transactions not only just "concatenate" + print("Txn ",idx, " bytes:") + print(signed_txn.rawTransaction.hex()) + transaction_list.append(signed_txn) + idx += 1 \ No newline at end of file diff --git a/packages/protocol/scripts/L2_txn_simulation/readme.md b/packages/protocol/scripts/L2_txn_simulation/readme.md new file mode 100644 index 000000000000..3088ed0b3d7c --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/readme.md @@ -0,0 +1,54 @@ +# Create / simulate L2 transactions (propose transaction and an xtransfer of a dummy xChainToken) + +In order to test the L2 node execution hook functionality, we need create valid L2 transactions and submit those to TaikoL1 - where a hook will be built in, to listen the proposeBlock and execute those transactions. This folder is to create L2 transactions (using the same pre-funded accounts Kurtosis is setting up by default) and submit it to our "L1" while using the local taiko_reth image as the EL. + +## Prerequisites + +Prerequisites can also be found in `deployments/local_deployment.md` file. + +1. Testnet up and running: +```shell +kurtosis run github.com/ethpandaops/ethereum-package --args-file YOUR_PATH_TO_NETWORK_CONFIG/network_params.yaml +``` + +2. Main contracts deployed: +```shell +forge script --rpc-url http://127.0.0.1:PORT scripts/DeployL1Locally.s.sol -vvvv --broadcast --private-key PK --legacy +``` +# ProposeBlock + +## 1. Create and print L2 transactions ("off-chain") + +Run script to gather 3 ether transactions, and print them out. `-n` flag stands for the nonce, and `-c` is for the L2 chainId. + +```shell +$ python3 createL2Txns.py -n -c +``` + +## 2. Prepare the script with proper data and fire away the L1 transaction + +Edit the `ProposeBlock.s.sol` file to to set the valid `basedOperatorAddress` and also add the above generated 3 signed transactions (already in the `ProposeBlock.s.sol` file, not needed to run and add them, unless the network `id` or `nonce` is different), then fire away the L1 transaction with the script below: + +```shell +$ forge script --rpc-url http://127.0.0.1:YOUR_PORT scripts/L2_txn_simulation/ProposeBlock.s.sol -vvvv --broadcast --private-key --legacy +``` + +## 3. In case of TXN failure, you can get the error via the debug trace transaction RPC call + +Command + +```shell +curl http://127.0.0.1:YOUR_PORT \ +-X POST \ +-H "Content-Type: application/json" \ +--data '{"method":"debug_traceTransaction","params":["YOUR_TXN_HASH", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' +``` + + +# Send a dummy xChainToken + +In order to send cross-chain transactions with `xCallOptions()`, when the network is up and running, deploy an `xChainERC20Token` contract and fire away an `xtransfer()` transaction. + +```shell +forge script --rpc-url http://127.0.0.1:YOUR_PORT scripts/L2_txn_simulation/CreateXChainTxn.s.sol -vvvv --broadcast --private-key PK_IN_ENV_FILE --legacy +``` \ No newline at end of file diff --git a/packages/protocol/scripts/L2_txn_simulation/sendTx.py b/packages/protocol/scripts/L2_txn_simulation/sendTx.py new file mode 100755 index 000000000000..a01d8aca4c32 --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/sendTx.py @@ -0,0 +1,69 @@ +from web3 import Web3 +from eth_abi import encode +import argparse + +RPC_URL_L2 = 'http://127.0.0.1:' # Anything is fine for now as long as we dont have the L2 network, but if we have we can automate nonce and gas settings +w3_taiko_l2 = Web3(Web3.HTTPProvider(RPC_URL_L2)) + +# Some pre-loaded ETH addresses from Kurtosis private network (NO secret, no harm to use for private testnets!) +sender_addresses = ['0x8943545177806ED17B9F23F0a21ee5948eCaa776'] +sender_pks = ['bcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31'] + +receiver = '0xf93Ee4Cf8c6c40b329b0c0626F28333c132CF241' # This address also has pre-loaded ETH addresses + +parser = argparse.ArgumentParser() + +parser.add_argument("-p", "--port", help="port on localhost", + type=str, required=True) +# parser.add_argument("-c", "--chainid", help="l2 chainId", +# type=int, required=True) + +transaction_list = [] + +if __name__ == "__main__": + args = parser.parse_args() + port = args.port + w3_taiko_l2 = Web3(Web3.HTTPProvider(RPC_URL_L2+port)) + chainId = 167010 + + # Build the new tx list + idx = 0 + for sender in sender_addresses: + # Build the tx + transaction = { + 'chainId': chainId, + 'from': sender, + 'to': receiver, + 'value': w3_taiko_l2.to_wei('1', 'ether'), + 'nonce': w3_taiko_l2.eth.get_transaction_count(sender), + 'gas': 200000, + 'maxFeePerGas': 2000000000, # w3_taiko_l2.eth.gas_price or something + 'maxPriorityFeePerGas': 1000000000, + } + + # Debug prints of balance + # # Get the balance + # balance_wei = w3_taiko_l2.eth.get_balance(sender) + + # # Convert balance from Wei to Ether + # balance_eth = w3_taiko_l2.from_wei(balance_wei, 'ether') + # print("Balance before:", balance_eth) + + # 2. Sign tx with a private key + signed_txn = w3_taiko_l2.eth.account.sign_transaction(transaction, sender_pks[idx]) + + # print("RawTransaction:") + # print(signed_txn.rawTransaction) + print("RawTransaction.hex():") + print(signed_txn.raw_transaction.hex()) + + txn_hash = w3_taiko_l2.eth.send_raw_transaction(signed_txn.raw_transaction) + print("Txn hash:") + print(txn_hash.hex()) + + # # Get the balance + # balance_wei = w3_taiko_l2.eth.get_balance(sender) + + # # Convert balance from Wei to Ether + # balance_eth = w3_taiko_l2.from_wei(balance_wei, 'ether') + # print("Balance after:", balance_eth) \ No newline at end of file diff --git a/packages/protocol/scripts/SetAddress.s.sol b/packages/protocol/scripts/SetAddress.s.sol new file mode 100644 index 000000000000..d16a533461ed --- /dev/null +++ b/packages/protocol/scripts/SetAddress.s.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../contracts/common/AddressManager.sol"; + +contract SetAddress is Script { + uint256 public adminPrivateKey = vm.envUint("PRIVATE_KEY"); + + address public proxyAddress = vm.envAddress("PROXY_ADDRESS"); + + uint64 public domain = uint64(vm.envUint("DOMAIN")); + + bytes32 public name = vm.envBytes32("NAME"); + + address public addr = vm.envAddress("ADDRESS"); + + AddressManager proxy; + + function run() external { + require(adminPrivateKey != 0, "PRIVATE_KEY not set"); + require(proxyAddress != address(0), "PROXY_ADDRESS not set"); + require(domain != 0, "DOMAIN NOT SET"); + require(name != bytes32(0), "NAME NOT SET"); + require(addr != address(0), "ADDR NOT SET"); + + vm.startBroadcast(adminPrivateKey); + + proxy = AddressManager(payable(proxyAddress)); + + proxy.setAddress(domain, name, addr); + + vm.stopBroadcast(); + } +} diff --git a/packages/protocol/scripts/SetRemoteBridgeSuites.s.sol b/packages/protocol/scripts/SetRemoteBridgeSuites.s.sol new file mode 100644 index 000000000000..b1bc030b42c3 --- /dev/null +++ b/packages/protocol/scripts/SetRemoteBridgeSuites.s.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "../test/DeployCapability.sol"; +import "../contracts/L1/gov/TaikoTimelockController.sol"; + +contract SetRemoteBridgeSuites is DeployCapability { + uint256 public privateKey = vm.envUint("PRIVATE_KEY"); + uint256 public securityCouncilPrivateKey = vm.envUint("SECURITY_COUNCIL_PRIVATE_KEY"); + address public timelockAddress = vm.envAddress("TIMELOCK_ADDRESS"); + address public addressManagerAddress = vm.envAddress("ADDRESS_MANAGER_ADDRESS"); + uint256[] public remoteChainIDs = vm.envUint("REMOTE_CHAIN_IDS", ","); + address[] public remoteBridges = vm.envAddress("REMOTE_BRIDGES", ","); + address[] public remoteERC20Vaults = vm.envAddress("REMOTE_ERC20_VAULTS", ","); + address[] public remoteERC721Vaults = vm.envAddress("REMOTE_ERC721_VAULTS", ","); + address[] public remoteERC1155Vaults = vm.envAddress("REMOTE_ERC1155_VAULTS", ","); + + function run() external { + require( + remoteChainIDs.length == remoteBridges.length, "invalid remote bridge addresses length" + ); + require( + remoteChainIDs.length == remoteERC20Vaults.length, + "invalid remote ERC20Vault addresses length" + ); + require( + remoteChainIDs.length == remoteERC721Vaults.length, + "invalid remote ERC721Vault addresses length" + ); + require( + remoteChainIDs.length == remoteERC1155Vaults.length, + "invalid remote ERC1155Vault addresses length" + ); + + vm.startBroadcast(privateKey); + + for (uint256 i; i < remoteChainIDs.length; ++i) { + uint64 chainid = uint64(remoteChainIDs[i]); + + if (securityCouncilPrivateKey == 0) { + register(addressManagerAddress, "bridge", remoteBridges[i], chainid); + register(addressManagerAddress, "erc20_vault", remoteERC20Vaults[i], chainid); + register(addressManagerAddress, "erc721_vault", remoteERC721Vaults[i], chainid); + register(addressManagerAddress, "erc1155_vault", remoteERC1155Vaults[i], chainid); + continue; + } + + registerByTimelock(addressManagerAddress, "bridge", remoteBridges[i], chainid); + registerByTimelock(addressManagerAddress, "erc20_vault", remoteERC20Vaults[i], chainid); + registerByTimelock( + addressManagerAddress, "erc721_vault", remoteERC721Vaults[i], chainid + ); + registerByTimelock( + addressManagerAddress, "erc1155_vault", remoteERC1155Vaults[i], chainid + ); + } + + vm.stopBroadcast(); + } + + function registerByTimelock( + address registerTo, + string memory name, + address addr, + uint64 chainId + ) + internal + { + bytes32 salt = bytes32(block.timestamp); + + bytes memory payload = abi.encodeWithSelector( + bytes4(keccak256("setAddress(uint64,bytes32,address)")), + chainId, + bytes32(bytes(name)), + addr + ); + + TaikoTimelockController timelock = TaikoTimelockController(payable(timelockAddress)); + + timelock.schedule(registerTo, 0, payload, bytes32(0), salt, 0); + + timelock.execute(registerTo, 0, payload, bytes32(0), salt); + + console2.log("> ", name, "@", registerTo); + console2.log("\t addr : ", addr); + } +} diff --git a/packages/protocol/scripts/confs/network_params.yaml b/packages/protocol/scripts/confs/network_params.yaml new file mode 100644 index 000000000000..445bca9f4603 --- /dev/null +++ b/packages/protocol/scripts/confs/network_params.yaml @@ -0,0 +1,20 @@ +participants: + - el_type: reth + el_image: taiko_reth + cl_type: lighthouse + cl_image: sigp/lighthouse:latest + el_extra_params: ["--num_of_l2s", "2"] + cl_extra_params: [--always-prepare-payload, --prepare-payload-lookahead, "12000"] +network_params: + network_id: '160010' +additional_services: + - blockscout + - blockscout_l2_2 +port_publisher: + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER + el: + enabled: true + public_port_start: 32000 + additional_services: + enabled: true + public_port_start: 64000 \ No newline at end of file diff --git a/packages/protocol/scripts/deploy_and_xtransfer.sh b/packages/protocol/scripts/deploy_and_xtransfer.sh new file mode 100755 index 000000000000..188d7af412f1 --- /dev/null +++ b/packages/protocol/scripts/deploy_and_xtransfer.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to check if contract is deployed +check_contract_deployment() { + local rpc_url=$1 + local contract_addr=$2 + local retries=30 # Number of retries (30 * 2 = 60 seconds max wait) + local deployed=false + + echo -e "${YELLOW}Waiting for contract deployment confirmation...${NC}" + + for i in $(seq 1 $retries); do + # Using curl to check if the contract code exists at the address + result=$(curl -s -X POST -H "Content-Type: application/json" --data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getCode\",\"params\":[\"$contract_addr\", \"latest\"],\"id\":1}" $rpc_url) + + # Check if the result contains more than just "0x" (empty contract) + if [[ $result == *"0x60806040"* ]]; then + deployed=true + break + fi + + echo -e "${YELLOW}Attempt $i/$retries: Contract not yet deployed, waiting...${NC}" + sleep 2 + done + + if [ "$deployed" = true ]; then + echo -e "${GREEN}Contract deployment confirmed!${NC}" + return 0 + else + echo -e "${RED}Contract deployment could not be confirmed after $retries attempts${NC}" + return 1 + fi +} + +echo -e "${GREEN}Executing xSetup...${NC}" +forge script scripts/xSetup.s.sol --rpc-url http://127.0.0.1:32002 -vvvv --broadcast --private-key 0x53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710 --legacy + +sleep 3 + +echo -e "${GREEN}Deploying to L1...${NC}" +# Capture the forge script output +L1_OUTPUT=$(forge script --rpc-url http://127.0.0.1:32002 scripts/DeployXERC20.s.sol -vvvv --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --legacy) + +# Extract the contract address - improved pattern matching +CONTRACT_ADDRESS=$(echo "$L1_OUTPUT" | grep -o '0x[a-fA-F0-9]\{40\}' | head -n 1) + +if [ -z "$CONTRACT_ADDRESS" ]; then + echo -e "${RED}Failed to extract contract address from deployment output${NC}" + exit 1 +fi + +echo -e "${GREEN}Extracted contract address: $CONTRACT_ADDRESS${NC}" + +if [ $? -eq 0 ]; then + # Check if contract is deployed on L1 + if check_contract_deployment "http://127.0.0.1:32002" "$CONTRACT_ADDRESS"; then + echo -e "${GREEN}Verifying L2A contract...${NC}" + # forge verify-contract "$CONTRACT_ADDRESS" "contracts/examples/xERC20.sol:xERC20" --watch --verifier-url "http://localhost:64001/api" --verifier blockscout --chain-id 160010 --libraries contracts/gwyneth/EVM.sol:EVM:0x5FbDB2315678afecb367f032d93F642f64180aa3 + else + echo -e "${RED}L1 deployment verification failed. Stopping.${NC}" + exit 1 + fi +else + echo -e "${RED}L1 deployment failed. Stopping.${NC}" + exit 1 +fi + + +echo -e "${GREEN}Deploying to L2A...${NC}" +# Capture the forge script output +L2A_OUTPUT=$(forge script --rpc-url http://127.0.0.1:32005 scripts/DeployXERC20.s.sol -vvvv --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --legacy) + +# Extract the contract address - improved pattern matching +CONTRACT_ADDRESS=$(echo "$L2A_OUTPUT" | grep -o '0x[a-fA-F0-9]\{40\}' | head -n 1) + +if [ -z "$CONTRACT_ADDRESS" ]; then + echo -e "${RED}Failed to extract contract address from deployment output${NC}" + exit 1 +fi + +echo -e "${GREEN}Extracted contract address: $CONTRACT_ADDRESS${NC}" + +if [ $? -eq 0 ]; then + # Check if contract is deployed on L2A + if check_contract_deployment "http://127.0.0.1:32005" "$CONTRACT_ADDRESS"; then + echo -e "${GREEN}Verifying L2A contract...${NC}" + # forge verify-contract "$CONTRACT_ADDRESS" "contracts/examples/xERC20.sol:xERC20" --watch --verifier-url "http://localhost:64003/api" --verifier blockscout --chain-id 167010 --libraries contracts/gwyneth/EVM.sol:EVM:0x5FbDB2315678afecb367f032d93F642f64180aa3 + else + echo -e "${RED}L2A deployment verification failed. Stopping.${NC}" + exit 1 + fi +else + echo -e "${RED}L2A deployment failed. Stopping.${NC}" + exit 1 +fi + + + +echo -e "${GREEN}Deploying to L2B...${NC}" +forge script --rpc-url http://127.0.0.1:32006 scripts/DeployXERC20.s.sol -vvvv --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --legacy + +if [ $? -eq 0 ]; then + # Check if contract is deployed on L2B + if check_contract_deployment "http://127.0.0.1:32006" "$CONTRACT_ADDRESS"; then + echo -e "${GREEN}Verifying L2B contract...${NC}" + # forge verify-contract "$CONTRACT_ADDRESS" "contracts/examples/xERC20.sol:xERC20" --watch --verifier-url "http://localhost:64005/api" --verifier blockscout --chain-id 167011 --libraries contracts/gwyneth/EVM.sol:EVM:0x5FbDB2315678afecb367f032d93F642f64180aa3 + else + echo -e "${RED}L2B deployment verification failed. Stopping.${NC}" + exit 1 + fi +else + echo -e "${RED}L2B deployment failed. Stopping.${NC}" + exit 1 +fi + + +echo -e "${GREEN}Executing xDeposit...${NC}" +forge script scripts/xDeposit.s.sol --rpc-url http://127.0.0.1:32002 -vvvv --broadcast --private-key 0x53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710 --legacy + +echo -e "${GREEN}Executing xTransfer...${NC}" +forge script scripts/XTransfer.s.sol --rpc-url http://127.0.0.1:32005 -vvvv --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --legacy --gas-estimate-multiplier 500 + +sleep 3 + +echo -e "${GREEN}Executing xWithdraw...${NC}" +forge script scripts/XWithdraw.s.sol --rpc-url http://127.0.0.1:32006 -vvvv --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --legacy --gas-estimate-multiplier 500 \ No newline at end of file diff --git a/packages/protocol/scripts/download_solc.sh b/packages/protocol/scripts/download_solc.sh new file mode 100755 index 000000000000..20c7873391eb --- /dev/null +++ b/packages/protocol/scripts/download_solc.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +set -e + +protocol_dir=$(realpath "$(dirname $0)/..") +solc_bin=${protocol_dir}/bin/solc + +if [ -f "${solc_bin}" ]; then + exit 0 +fi + +mkdir -p "$(dirname ${solc_bin})" + +VERSION=v0.8.18 + +if [ "$(uname)" = 'Darwin' ]; then + SOLC_FILE_NAME=solc-macos +elif [ "$(uname)" = 'Linux' ]; then + SOLC_FILE_NAME=solc-static-linux +else + echo "unsupported platform $(uname)" + exit 1 +fi + +wget -O "${solc_bin}" https://github.com/ethereum/solidity/releases/download/$VERSION/$SOLC_FILE_NAME + +chmod +x "${solc_bin}" diff --git a/packages/protocol/scripts/launch_second_node.sh b/packages/protocol/scripts/launch_second_node.sh new file mode 100755 index 000000000000..ae2c1bb6696d --- /dev/null +++ b/packages/protocol/scripts/launch_second_node.sh @@ -0,0 +1,181 @@ +#!/bin/bash + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check for Docker installation +if ! command_exists docker; then + echo "Docker is not installed. Please install Docker first." + exit 1 +fi + +# Function to get container ID by name prefix +get_container_id() { + docker ps --format '{{.ID}}' --filter "name=$1" +} + +# Function to copy file from container to host +copy_from_container() { + docker cp "$1:$2" "$3" +} + +# Function to get network name from container +get_network_name() { + docker inspect -f '{{range $key, $value := .NetworkSettings.Networks}}{{$key}}{{end}}' "$1" +} + +# Function to get container IP address +get_container_ip() { + docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$1" +} + +clean_directory() { + if [ -d "$1" ]; then + echo "Cleaning directory: $1" + rm -rf "$1"/* + else + echo "Creating directory: $1" + mkdir -p "$1" + fi +} + +# Function to get or create JWT secret +get_or_create_jwt_secret() { + local jwt_path="$HOME/jwt/jwtsecret" + if [ -f "$jwt_path" ]; then + echo "Using existing JWT secret." + else + echo "Creating new JWT secret." + mkdir -p "$(dirname "$jwt_path")" + openssl rand -hex 32 | tr -d "\n" > "$jwt_path" + fi + echo "$jwt_path" +} + +# Get or create JWT secret +JWT_SECRET_PATH=$(get_or_create_jwt_secret) +echo "JWT secret path: $JWT_SECRET_PATH" + +# Get container IDs +EL_CONTAINER_ID=$(get_container_id "el-2-reth-teku") +CL_CONTAINER_ID=$(get_container_id "cl-2-teku-reth") + +if [ -z "$EL_CONTAINER_ID" ] || [ -z "$CL_CONTAINER_ID" ]; then + echo "Failed to find required containers." + exit 1 +fi + +# Get network name +NETWORK_NAME=$(get_network_name "$EL_CONTAINER_ID") +if [ -z "$NETWORK_NAME" ]; then + echo "Failed to get network name." + exit 1 +fi +echo "Using network: $NETWORK_NAME" + +# Get EL container IP +EL_IP=$(get_container_ip "$EL_CONTAINER_ID") + +# Get bootnode from EL container +BOOTNODE=$(docker exec "$EL_CONTAINER_ID" ps aux | grep docker-init | grep -o 'bootnodes=[^ ]*' | cut -d= -f2) + +# Get CL bootnode +CL_BOOTNODE=$(docker exec "$CL_CONTAINER_ID" ps aux | grep docker-init | grep -o 'p2p-discovery-bootnodes=[^ ]*' | cut -d= -f2) + +# Clean and recreate required directories +clean_directory ~/data/reth/execution-data +clean_directory ~/data/teku/teku-beacon-data +clean_directory ~/data/teku/validator-keys/teku-secrets +clean_directory ~/data/teku/validator-keys/teku-keys + +# Create required directories +mkdir -p ~/network-configs ~/jwt + +# Copy required files +copy_from_container "$EL_CONTAINER_ID" "/network-configs/genesis.json" ~/network-configs/ +copy_from_container "$CL_CONTAINER_ID" "/network-configs/genesis.ssz" ~/network-configs/ +copy_from_container "$CL_CONTAINER_ID" "/network-configs/config.yaml" ~/network-configs/ + +# Launch EL container +echo "Launching EL container..." +EL_CONTAINER_ID=$(docker run -d --name reth-node3 --network "$NETWORK_NAME" \ + -v ~/data/reth/execution-data:/data/reth/execution-data \ + -v ~/network-configs:/network-configs \ + -v ~/jwt:/jwt \ + -p 8545:8545 \ + -p 10110:10110 \ + taiko_reth node -vvv --datadir=/data/reth/execution-data \ + --chain=/network-configs/genesis.json \ + --http --http.port=8545 --http.addr=0.0.0.0 \ + --http.corsdomain="*" --http.api=admin,net,eth,web3,debug,trace \ + --ws --ws.addr=0.0.0.0 --ws.port=8550 --ws.api=net,eth \ + --ws.origins="*" --nat=extip:0.0.0.0 \ + --authrpc.port=8551 --authrpc.jwtsecret=/jwt/jwtsecret \ + --authrpc.addr=0.0.0.0 --metrics=0.0.0.0:9003 \ + --discovery.port=42011 --port=42011 \ + --bootnodes="$BOOTNODE") + +if [ -z "$EL_CONTAINER_ID" ]; then + echo "Failed to launch EL container." + exit 1 +fi + +# Get the IP of the newly launched EL container +NEW_EL_IP=$(get_container_ip "$EL_CONTAINER_ID") +if [ -z "$NEW_EL_IP" ]; then + echo "Failed to get IP of the new EL container." + exit 1 +fi + +echo "New EL container IP: $NEW_EL_IP" + +# Wait for the EL container to be ready (you might want to implement a more robust check) +sleep 10 + +# Launch CL container +echo "Launching CL container..." +docker run -d \ + --name teku-node2 \ + --network "$NETWORK_NAME" \ + -v ~/data/teku/teku-beacon-data:/data/teku/teku-beacon-data \ + -v ~/data/teku/validator-keys:/validator-keys/ \ + -v ~/network-configs:/network-configs \ + -v ~/jwt:/jwt/ \ + --entrypoint /bin/sh \ + consensys/teku:latest -c " + MY_IP=\$(hostname -i) && \ + exec /opt/teku/bin/teku \ + --logging=INFO \ + --log-destination=CONSOLE \ + --network=/network-configs/config.yaml \ + --data-path=/data/teku/teku-beacon-data \ + --data-storage-mode=ARCHIVE \ + --p2p-enabled=true \ + --p2p-peer-lower-bound=1 \ + --p2p-advertised-ip=\$MY_IP \ + --p2p-discovery-site-local-addresses-enabled=true \ + --p2p-port=9000 \ + --rest-api-enabled=true \ + --rest-api-docs-enabled=true \ + --rest-api-interface=0.0.0.0 \ + --rest-api-port=4000 \ + --rest-api-host-allowlist=* \ + --data-storage-non-canonical-blocks-enabled=true \ + --ee-jwt-secret-file=/jwt/jwtsecret \ + --ee-endpoint=http://$NEW_EL_IP:8551 \ + --metrics-enabled \ + --metrics-interface=0.0.0.0 \ + --metrics-host-allowlist='*' \ + --metrics-categories=BEACON,PROCESS,LIBP2P,JVM,NETWORK,PROCESS \ + --metrics-port=8008 \ + --ignore-weak-subjectivity-period-enabled=true \ + --initial-state=/network-configs/genesis.ssz \ + --p2p-discovery-bootnodes=$CL_BOOTNODE \ + --validator-keys=/validator-keys/teku-keys:/validator-keys/teku-secrets \ + --validators-proposer-default-fee-recipient=0x8943545177806ED17B9F23F0a21ee5948eCaa776 \ + --validators-graffiti=2-reth-teku + " + +echo "Second node (EL and CL) launched successfully!" \ No newline at end of file diff --git a/packages/protocol/scripts/memory_drainer_logger/drain_el1.py b/packages/protocol/scripts/memory_drainer_logger/drain_el1.py new file mode 100755 index 000000000000..ad574103add0 --- /dev/null +++ b/packages/protocol/scripts/memory_drainer_logger/drain_el1.py @@ -0,0 +1,50 @@ +import requests +import time +import logging +from datetime import datetime +import os +from pathlib import Path + +# Setup logging +log_dir = Path('logs') +log_dir.mkdir(exist_ok=True) + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler(log_dir / 'log_drain.log'), + logging.StreamHandler() + ] +) + +def fetch_logs(): + try: + response = requests.get('http://localhost:32004') + + # Create a timestamp for the filename + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + output_file = log_dir / f'drain_{timestamp}.log' + + # Save the response content + with open(output_file, 'w') as f: + f.write(response.text) + + logging.info(f'Successfully fetched and saved logs to {output_file}') + + except requests.RequestException as e: + logging.error(f'Failed to fetch logs: {str(e)}') + except IOError as e: + logging.error(f'Failed to save logs: {str(e)}') + +def main(): + logging.info('Starting log drain service') + + # Run indefinitely + while True: + fetch_logs() + # Sleep for 1 hour (3600 seconds) + time.sleep(3600) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/packages/protocol/scripts/memory_drainer_logger/drain_el2.py b/packages/protocol/scripts/memory_drainer_logger/drain_el2.py new file mode 100755 index 000000000000..58bad6cc9243 --- /dev/null +++ b/packages/protocol/scripts/memory_drainer_logger/drain_el2.py @@ -0,0 +1,50 @@ +import requests +import time +import logging +from datetime import datetime +import os +from pathlib import Path + +# Setup logging +log_dir = Path('logs2') +log_dir.mkdir(exist_ok=True) + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler(log_dir / 'log_drain.log'), + logging.StreamHandler() + ] +) + +def fetch_logs(): + try: + response = requests.get('http://localhost:32006') + + # Create a timestamp for the filename + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + output_file = log_dir / f'drain_{timestamp}.log' + + # Save the response content + with open(output_file, 'w') as f: + f.write(response.text) + + logging.info(f'Successfully fetched and saved logs to {output_file}') + + except requests.RequestException as e: + logging.error(f'Failed to fetch logs: {str(e)}') + except IOError as e: + logging.error(f'Failed to save logs: {str(e)}') + +def main(): + logging.info('Starting log drain service') + + # Run indefinitely + while True: + fetch_logs() + # Sleep for 1 hour (3600 seconds) + time.sleep(3600) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/packages/protocol/scripts/memory_drainer_logger/memory_logger.py b/packages/protocol/scripts/memory_drainer_logger/memory_logger.py new file mode 100755 index 000000000000..338cfe5e048e --- /dev/null +++ b/packages/protocol/scripts/memory_drainer_logger/memory_logger.py @@ -0,0 +1,77 @@ +import docker +import time +from datetime import datetime +import logging +import sys +import os + +# Configure logging to current directory +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(message)s', + handlers=[ + logging.FileHandler('docker_memory.log'), + logging.StreamHandler(sys.stdout) + ] +) + +def get_container_memory_usage(container_name): + try: + client = docker.from_env() # Fixed: Correct way to initialize Docker client + container = client.containers.get(container_name) + stats = container.stats(stream=False) + + memory_usage = stats['memory_stats']['usage'] + memory_limit = stats['memory_stats']['limit'] + memory_percent = (memory_usage / memory_limit) * 100 + + # Convert to MB + memory_usage_mb = memory_usage / (1024 * 1024) + memory_limit_mb = memory_limit / (1024 * 1024) + + return { + 'usage_mb': round(memory_usage_mb, 2), + 'limit_mb': round(memory_limit_mb, 2), + 'percent': round(memory_percent, 2) + } + except Exception as e: + logging.error(f"Error getting container stats: {str(e)}") + return None + +def monitor_memory(container_name, interval=60): + logging.info(f"Starting memory monitoring for container: {container_name}") + logging.info(f"Logging interval: {interval} seconds") + + # Run in background + if os.fork() != 0: + return + + # Detach from terminal + os.setsid() + + # Close file descriptors + os.close(0) + os.close(1) + os.close(2) + + while True: + try: + stats = get_container_memory_usage(container_name) + if stats: + logging.info( + f"Memory Usage: {stats['usage_mb']}MB / {stats['limit_mb']}MB ({stats['percent']}%)" + ) + except Exception as e: + logging.error(f"Error: {str(e)}") + time.sleep(interval) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python memory_monitor.py [interval_seconds]") + sys.exit(1) + + container_name = sys.argv[1] + interval = int(sys.argv[2]) if len(sys.argv) > 2 else 60 + + monitor_memory(container_name, interval) + print("Monitoring process started in background. Check docker_memory.log for output.") \ No newline at end of file diff --git a/packages/protocol/scripts/merge_contracts.py b/packages/protocol/scripts/merge_contracts.py new file mode 100644 index 000000000000..7722d5d5ebdd --- /dev/null +++ b/packages/protocol/scripts/merge_contracts.py @@ -0,0 +1,27 @@ +import os +import argparse + +def merge_solidity_files(root_dir, output_file='../out/taiko_protocol.md'): + with open(output_file, 'w') as outfile: + for subdir, dirs, files in os.walk(root_dir): + for file in files: + if file.endswith('.sol') and not file.endswith('.t.sol'): + file_path = os.path.join(subdir, file) + if "/test/" in file_path: + continue + print("merging ", file_path) + relative_path = os.path.relpath(file_path, root_dir) + outfile.write(f"## {relative_path}\n") + outfile.write("```solidity\n") + with open(file_path, 'r') as infile: + outfile.write(infile.read()) + outfile.write("\n```\n\n") + + +if __name__ == "__main__": + # parser = argparse.ArgumentParser(description="Merge Solidity files into a Markdown file.") + # parser.add_argument("root_dir", type=str, help="Root directory containing Solidity files") + # args = parser.parse_args() + # merge_solidity_files(args.root_dir) + merge_solidity_files("../contracts") + print("merged into ../out/taiko_protocol.md") diff --git a/packages/protocol/scripts/propose_block.sh b/packages/protocol/scripts/propose_block.sh new file mode 100755 index 000000000000..1f27608c8579 --- /dev/null +++ b/packages/protocol/scripts/propose_block.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Run the setup_deps.sh script to ensure dependencies are set up +#./scripts/setup_deps.sh + +# Read the RPC port from temporary file +RPC_PORT=$(cat /tmp/kurtosis_rpc_port) + +# Load the .env file and extract the PRIVATE_KEY +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) + PRIVATE_KEY=${PRIVATE_KEY} +else + echo ".env file not found. Please create a .env file with your PRIVATE_KEY." + exit 1 +fi + +if [ -z "$PRIVATE_KEY" ]; then + echo "PRIVATE_KEY not found in the .env file." + exit 1 +fi + +# Run the forge foundry script using the extracted RPC port and PRIVATE_KEY +FORGE_COMMAND="forge script --rpc-url http://127.0.0.1:$RPC_PORT scripts/L2_txn_simulation/ProposeBlock.s.sol -vvvv --broadcast --private-key $PRIVATE_KEY --legacy" + +echo "Running forge foundry script..." +eval $FORGE_COMMAND + +echo "Forge script execution completed." diff --git a/packages/protocol/scripts/sendPreminedEth.sh b/packages/protocol/scripts/sendPreminedEth.sh new file mode 100755 index 000000000000..86ff7bc6e350 --- /dev/null +++ b/packages/protocol/scripts/sendPreminedEth.sh @@ -0,0 +1,3 @@ +forge script scripts/sendToDispenser.s.sol --rpc-url http://localhost:32002 -vvvv --broadcast --legacy +forge script scripts/sendToDispenser.s.sol --rpc-url http://localhost:32005 -vvvv --broadcast --legacy +forge script scripts/sendToDispenser.s.sol --rpc-url http://localhost:32006 -vvvv --broadcast --legacy \ No newline at end of file diff --git a/packages/protocol/scripts/sendToDispenser.s.sol b/packages/protocol/scripts/sendToDispenser.s.sol new file mode 100644 index 000000000000..01a1cd9b975e --- /dev/null +++ b/packages/protocol/scripts/sendToDispenser.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +contract sendToDispenser is Script { + //The PK of this is not leaked (yet) and shall be kept secret so we can use this for the faucet. + address constant DISPENSER = 0xE13A023E5704e09Eb36Ba4551864C973e32F1E6E; + + // Array of private keys for all pre-mined accounts + uint256[] private accounts = [ + 0xbcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31, + 0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d, + 0x53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710, + 0xab63b23eb7941c1251757e24b3d2350d2bc05c3c388d06f8fe6feafefb1e8c70, + 0x5d2344259f42259f82d2c140aa66102ba89b57b4883ee441a8b312622bd42491, + 0x27515f805127bebad2fb9b183508bdacb8c763da16f54e0678b16e8f28ef3fff, + 0x7ff1a4c1d57e5e784d327c4c7651e952350bc271f156afb3d00d20f5ef924856, + 0x3a91003acaf4c21b3953d94fa4a6db694fa69e5242b2e37be05dd82761058899, + 0xbb1d0f125b4fb2bb173c318cdead45468474ca71474e2247776b2b4c0fa2d3f5, + 0x850643a0224065ecce3882673c21f56bcf6eef86274cc21cadff15930b59fc8c, + 0x94eb3102993b41ec55c241060f47daa0f6372e2e3ad7e91612ae36c364042e44, + 0xdaf15504c22a352648a71ef2926334fe040ac1d5005019e09f6c979808024dc7, + 0xeaba42282ad33c8ef2524f07277c03a776d98ae19f581990ce75becb7cfa1c23, + 0x3fd98b5187bf6526734efaa644ffbb4e3670d66f5d0268ce0323ec09124bff61, + 0x5288e2f440c7f0cb61a9be8afdeb4295f786383f96f5e35eb0c94ef103996b64, + 0xf296c7802555da2a5a662be70e078cbd38b44f96f8615ae529da41122ce8db05, + 0xbf3beef3bd999ba9f2451e06936f0423cd62b815c9233dd3bc90f7e02a1e8673, + 0x6ecadc396415970e91293726c3f5775225440ea0844ae5616135fd10d66b5954, + 0xa492823c3e193d6c595f37a18e3c06650cf4c74558cc818b16130b293716106f, + 0xc5114526e042343c6d1899cad05e1c00ba588314de9b96929914ee0df18d46b2, + 0x4b9f63ecf84210c5366c66d68fa1f5da1fa4f634fad6dfc86178e4d79ff9e59 + ]; + + function run() public { + for (uint i = 0; i < accounts.length; i++) { + address sender = vm.addr(accounts[i]); + uint256 balance = sender.balance; + + console2.log("Processing address:", sender); + console2.log("Current balance:", balance); + + if (balance > 2 ether) { + uint256 amountToSend = balance - 2 ether; + + vm.startBroadcast(accounts[i]); + + (bool success, ) = DISPENSER.call{value: amountToSend}(""); + require(success, string(abi.encodePacked("Failed to send Ether from address: ", sender))); + + console2.log("Sent amount:", amountToSend); + console2.log("Remaining balance:", sender.balance); + + vm.stopBroadcast(); + } else { + console2.log("Balance too low, skipping address"); + } + + console2.log("-------------------"); + } + } +} \ No newline at end of file diff --git a/packages/protocol/scripts/setup_deps.sh b/packages/protocol/scripts/setup_deps.sh new file mode 100755 index 000000000000..9f672f70d79f --- /dev/null +++ b/packages/protocol/scripts/setup_deps.sh @@ -0,0 +1,234 @@ +#!/bin/bash + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Function to check if Docker daemon is running +is_docker_running() { + docker info >/dev/null 2>&1 +} + +# Check for Docker installation and daemon status +if ! command_exists docker; then + echo "Docker is not installed. Please install Docker first." + exit 1 +elif ! is_docker_running; then + echo "Docker daemon is not running. Please start Docker first." + exit 1 +else + echo "Docker is installed and running." +fi + +# Check if the taiko_reth image exists +# if ! docker image inspect taiko_reth >/dev/null 2>&1; then + echo "Docker image taiko_reth does not exist. Building the image..." + if ! docker build ../../ -t taiko_reth; then + echo "Failed to build the Docker image taiko_reth." + exit 1 + fi +# else +# echo "Docker image taiko_reth already exists." +# fi + +# Function to install Kurtosis on macOS +install_kurtosis_mac() { + if ! command_exists brew; then + echo "Homebrew is not installed. Installing Homebrew..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + fi + echo "Installing Kurtosis CLI with Homebrew..." + brew install kurtosis-tech/tap/kurtosis-cli +} + +# Function to install Kurtosis on Ubuntu +install_kurtosis_ubuntu() { + echo "Installing Kurtosis CLI with apt..." + echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list + sudo apt update + sudo apt install -y kurtosis-cli +} + +# Detect the operating system and install Kurtosis accordingly +if [[ "$OSTYPE" == "darwin"* ]]; then + echo "Detected macOS." + install_kurtosis_mac +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + if [ -f /etc/os-release ]; then + . /etc/os-release + #if [[ "$ID" == "ubuntu" ]]; then + echo "Detected Ubuntu." + install_kurtosis_ubuntu + #else + # echo "This script currently supports only Ubuntu and macOS." + # exit 1 + #fi + else + echo "This script currently supports only Ubuntu and macOS." + exit 1 + fi +else + echo "This script currently supports only Ubuntu and macOS." + exit 1 +fi + +# Check if Kurtosis is installed and its version +if command_exists kurtosis; then + KURTOSIS_VERSION=$(kurtosis version | grep -oP '(?<=CLI Version:\s)[\d.]+') + echo "Kurtosis CLI is already installed. Version: $KURTOSIS_VERSION" +else + echo "Kurtosis CLI installation failed or is not installed correctly." + exit 1 +fi + +# Run the Kurtosis command and capture its output +echo "Running Kurtosis command..." +if [[ "$(uname)" == "Darwin" ]]; then + KURTOSIS_OUTPUT=$(kurtosis run github.com/adaki2004/ethereum-package --args-file ./scripts/confs/network_params.yaml) +else + KURTOSIS_OUTPUT=$(kurtosis run github.com/adaki2004/ethereum-package@update_with_upstream --args-file ./scripts/confs/network_params.yaml) +fi + + +# Extract the Blockscout port +BLOCKSCOUT_PORT=$(echo "$KURTOSIS_OUTPUT" | grep -A 5 "^[a-f0-9]\+ *blockscout " | grep "http:" | sed -E 's/.*-> http:\/\/127\.0\.0\.1:([0-9]+).*/\1/' | head -n 1) + +if [ -z "$BLOCKSCOUT_PORT" ]; then + echo "Failed to extract Blockscout port." + exit 1 +fi + +echo "Extracted Blockscout port: $BLOCKSCOUT_PORT" +echo "$BLOCKSCOUT_PORT" > /tmp/kurtosis_blockscout_port +# # Print the entire Kurtosis output for debugging +echo "Kurtosis Output:" +echo "$KURTOSIS_OUTPUT" + +# Extract the "User Services" section +USER_SERVICES_SECTION=$(echo "$KURTOSIS_OUTPUT" | awk '/^========================================== User Services ==========================================/{flag=1;next}/^$/{flag=0}flag') +# Print the "User Services" section for debugging +echo "User Services Section:" +echo "$USER_SERVICES_SECTION" +echo "$USER_SERVICES_SECTION"> port_config +# Extract the dynamic port assigned to the rpc service for "el-1-reth-lighthouse" +RPC_PORT=$(echo "$USER_SERVICES_SECTION" | grep -A 5 "el-1-reth-lighthouse" | grep "rpc: 8545/tcp" | sed -E 's/.* -> 127.0.0.1:([0-9]+).*/\1/') +if [ -z "$RPC_PORT" ]; then + echo "Failed to extract RPC port from User Services section." + exit 1 +else + echo "Extracted RPC port: $RPC_PORT" + echo "$RPC_PORT" > /tmp/kurtosis_rpc_port +fi + +# Extract the Starlark output section +STARLARK_OUTPUT=$(echo "$KURTOSIS_OUTPUT" | awk '/^Starlark code successfully run. Output was:/{flag=1; next} /^$/{flag=0} flag') + +# Extract the beacon_http_url for cl-1-lighthouse-reth +BEACON_HTTP_URL=$(echo "$STARLARK_OUTPUT" | jq -r '.all_participants[] | select(.cl_context.beacon_service_name == "cl-1-lighthouse-reth") | .cl_context.beacon_http_url') + +if [ -z "$BEACON_HTTP_URL" ]; then + echo "Failed to extract beacon_http_url for cl-1-lighthouse-reth." + exit 1 +else + echo "Extracted beacon_http_url: $BEACON_HTTP_URL" + echo "$BEACON_HTTP_URL" > /tmp/kurtosis_beacon_http_url +fi + +# Find the correct Docker container +CONTAINER_ID=$(docker ps --format '{{.ID}} {{.Names}}' | grep 'el-1-reth-lighthouse--' | awk '{print $1}') + +if [ -z "$CONTAINER_ID" ]; then + echo "Failed to find the el-1-reth-lighthouse container." + exit 1 +else + echo "Found container ID: $CONTAINER_ID" +fi + +# Check if the file exists in the container +FILE_PATH="/app/rbuilder/config-gwyneth-reth.toml" +if ! docker exec "$CONTAINER_ID" test -f "$FILE_PATH"; then + echo "File $FILE_PATH does not exist in the container." + exit 1 +fi + +# Update the cl_node_url in the file, regardless of its current content +ESCAPED_URL=$(echo "$BEACON_HTTP_URL" | sed 's/[\/&]/\\&/g') +UPDATE_COMMAND="sed -i '/^cl_node_url[[:space:]]*=/c\cl_node_url = [\"$ESCAPED_URL\"]' $FILE_PATH" +if docker exec "$CONTAINER_ID" sh -c "$UPDATE_COMMAND"; then + echo "Successfully updated $FILE_PATH in the container." +else + echo "Failed to update $FILE_PATH in the container." + exit 1 +fi + +# Verify the change +VERIFY_COMMAND="grep 'cl_node_url' $FILE_PATH" +VERIFICATION=$(docker exec "$CONTAINER_ID" sh -c "$VERIFY_COMMAND") +echo "Updated line in $FILE_PATH: $VERIFICATION" +# Load the .env file and extract the PRIVATE_KEY +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) + PRIVATE_KEY=${PRIVATE_KEY} +else + echo ".env file not found. Please create a .env file with your PRIVATE_KEY." + exit 1 +fi +if [ -z "$PRIVATE_KEY" ]; then + echo "PRIVATE_KEY not found in the .env file." + exit 1 +fi +# Run the forge foundry script using the extracted RPC port and PRIVATE_KEY +FORGE_COMMAND="forge script --rpc-url http://127.0.0.1:$RPC_PORT scripts/DeployL1Locally.s.sol -vvvv --broadcast --private-key $PRIVATE_KEY --legacy" +echo "Running forge foundry script..." +FORGE_OUTPUT=$(eval $FORGE_COMMAND | tee /dev/tty) +echo "Script execution completed." + +# Extract the path to run-latest.json +RUN_LATEST_PATH=$(echo "$FORGE_OUTPUT" | grep "Transactions saved to:" | sed 's/Transactions saved to: //') + +# Run the verification script +echo "Starting contract verification..." +BLOCKSCOUT_PORT=$(cat /tmp/kurtosis_blockscout_port) +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +# SKIP THIS FOR NOW +# "$SCRIPT_DIR/verify_contracts.sh" "$BLOCKSCOUT_PORT" "$RUN_LATEST_PATH" + +# Ensure the log file exists in the current working directory +touch ./rbuilder.log + +echo "Starting rbuilder and streaming logs to ./rbuilder.log..." +docker exec -d "$CONTAINER_ID" /bin/bash -c " + /app/start_rbuilder.sh > /tmp/rbuilder.log 2>&1 & + RBUILDER_PID=\$! + tail -f /tmp/rbuilder.log & + TAIL_PID=\$! + wait \$RBUILDER_PID +" + +# Start a background process to stream logs from the container to the host file +docker exec "$CONTAINER_ID" tail -f /tmp/rbuilder.log >> ./rbuilder.log & +FILE_LOG_PID=$! + +# Start another process to stream logs to the terminal +docker exec "$CONTAINER_ID" tail -f /tmp/rbuilder.log & +TERMINAL_LOG_PID=$! + +# Set up a trap to handle Ctrl+C (SIGINT) +trap 'echo "Interrupt received. Stopping terminal log streaming, but file logging continues."; kill $TERMINAL_LOG_PID; exit' INT TERM + +echo "rbuilder is running in the container." +echo "Logs are being streamed to ./rbuilder.log and to this terminal." +echo "Press Ctrl+C to stop watching logs in the terminal. rbuilder and file logging will continue." + +# Wait for the terminal log streaming to be manually interrupted +wait $TERMINAL_LOG_PID + +# Check if rbuilder is still running +if docker exec "$CONTAINER_ID" pgrep -f "/app/start_rbuilder.sh" > /dev/null; then + echo "rbuilder is still running in the container. Logs continue to be written to ./rbuilder.log" +else + echo "rbuilder has stopped unexpectedly." + kill $FILE_LOG_PID + exit 1 +fi diff --git a/packages/protocol/scripts/test_deploy_on_l1.sh b/packages/protocol/scripts/test_deploy_on_l1.sh new file mode 100755 index 000000000000..9591cc4ded84 --- /dev/null +++ b/packages/protocol/scripts/test_deploy_on_l1.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# This script is only used by `pnpm deploy:foundry`. +set -e + +PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ +PROPOSER=0x0000000000000000000000000000000000000000 \ +PROPOSER_ONE=0x0000000000000000000000000000000000000000 \ +GUARDIAN_PROVERS="0x1000777700000000000000000000000000000001,0x1000777700000000000000000000000000000002,0x1000777700000000000000000000000000000003,0x1000777700000000000000000000000000000004,0x1000777700000000000000000000000000000005" \ +MIN_GUARDIANS=3 \ +TAIKO_L2_ADDRESS=0x1000777700000000000000000000000000000001 \ +L2_SIGNAL_SERVICE=0x1000777700000000000000000000000000000007 \ +SECURITY_COUNCIL=0x60997970C51812dc3A010C7d01b50e0d17dc79C8 \ +TAIKO_TOKEN_PREMINT_RECIPIENT=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 \ +TAIKO_TOKEN_NAME="Taiko Token Katla" \ +TAIKO_TOKEN_SYMBOL=TTKOk \ +SHARED_ADDRESS_MANAGER=0x0000000000000000000000000000000000000000 \ +L2_GENESIS_HASH=0xee1950562d42f0da28bd4550d88886bc90894c77c9c9eaefef775d4c8223f259 \ +forge script script/DeployOnL1.s.sol:DeployOnL1 \ + --fork-url http://localhost:8545 \ + --broadcast \ + --ffi \ + -vvvv \ + --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ + --block-gas-limit 100000000 diff --git a/packages/protocol/scripts/upgrade_to.sh b/packages/protocol/scripts/upgrade_to.sh new file mode 100755 index 000000000000..9f68e09dce92 --- /dev/null +++ b/packages/protocol/scripts/upgrade_to.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e +: "${FORK_URL:=http://localhost:8545}" + +forge script script/upgrade/Upgrade$CONTRACT.s.sol:Upgrade$CONTRACT \ + --fork-url $FORK_URL \ + --broadcast \ + --ffi \ + -vvvv \ No newline at end of file diff --git a/packages/protocol/scripts/verify_contracts.sh b/packages/protocol/scripts/verify_contracts.sh new file mode 100755 index 000000000000..7ae2e41c8973 --- /dev/null +++ b/packages/protocol/scripts/verify_contracts.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Check if both BLOCKSCOUT_PORT and RUN_LATEST_PATH are provided +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Error: Both BLOCKSCOUT_PORT and RUN_LATEST_PATH must be provided" + echo "Usage: $0 " + exit 1 +fi + +BLOCKSCOUT_PORT="$1" +RUN_LATEST_PATH="$2" + +echo "Using Blockscout port: $BLOCKSCOUT_PORT" +echo "Using run-latest.json path: $RUN_LATEST_PATH" + +# Function to verify a regular contract +verify_contract() { + local address=$1 + local contract_path=$2 + local contract_name=$3 + + echo "Verifying contract: $contract_name at address $address" + forge verify-contract "$address" "$contract_path:$contract_name" \ + --watch --verifier-url "http://localhost:$BLOCKSCOUT_PORT/api" \ + --verifier blockscout --chain-id 160010 +} + +# Function to verify a proxy contract +verify_proxy_contract() { + local address=$1 + local arguments=$2 + + echo "Verifying proxy contract at address: $address" + echo "Constructor arguments: $arguments" + forge verify-contract "$address" "node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy" \ + --watch --verifier-url "http://localhost:$BLOCKSCOUT_PORT/api" \ + --verifier blockscout --chain-id 160010 \ + --constructor-args "$arguments" --skip-is-verified-check +} + +# Read the run-latest.json file +if [ ! -f "$RUN_LATEST_PATH" ]; then + echo "Error: run-latest.json not found at $RUN_LATEST_PATH" + exit 1 +fi + +RUN_LATEST=$(cat "$RUN_LATEST_PATH") + +# Verify regular contracts +verify_all_creates() { + local contract_name=$1 + local contract_path=$2 + + echo "Verifying all instances of $contract_name" + local addresses=$(jq -r ".transactions[] | select(.contractName == \"$contract_name\" and .transactionType == \"CREATE\") | .contractAddress" <<< "$RUN_LATEST") + + if [ -z "$addresses" ]; then + echo "No CREATE transactions found for $contract_name" + else + echo "$addresses" | while read -r address; do + if [ ! -z "$address" ]; then + verify_contract "$address" "$contract_path" "$contract_name" + fi + done + fi +} + +verify_all_creates "AddressManager" "contracts/common/AddressManager.sol" +verify_all_creates "TaikoToken" "contracts/tko/TaikoToken.sol" +verify_all_creates "TaikoL1" "contracts/L1/TaikoL1.sol" +verify_all_creates "ChainProver" "contracts/L1/ChainProver.sol" +verify_all_creates "VerifierRegistry" "contracts/L1/VerifierRegistry.sol" +verify_all_creates "MockSgxVerifier" "contracts/L1/verifiers/MockSgxVerifier.sol" + +# Verify proxy contracts +echo "Verifying ERC1967Proxy contracts:" +PROXY_CONTRACTS=$(jq -r '.transactions[] | select(.contractName == "ERC1967Proxy" and .transactionType == "CREATE")' <<< "$RUN_LATEST") +echo "$PROXY_CONTRACTS" | jq -c '.' | while read -r proxy; do + if [ ! -z "$proxy" ]; then + address=$(echo "$proxy" | jq -r '.contractAddress') + args=$(echo "$proxy" | jq -r '.arguments | join(",")') + if [ ! -z "$address" ] && [ ! -z "$args" ]; then + verify_proxy_contract "$address" "$args" + else + echo "Skipping proxy contract due to missing address or arguments" + fi + fi +done + +echo "All contracts verified." \ No newline at end of file diff --git a/packages/protocol/scripts/xDeposit.s.sol b/packages/protocol/scripts/xDeposit.s.sol new file mode 100644 index 000000000000..a8d7306f4b7f --- /dev/null +++ b/packages/protocol/scripts/xDeposit.s.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../contracts/examples/xERC20.sol"; + +contract XDeposit is Script { + // The deployed contract address (will be the same on both chains due to deterministic deployment) + address constant TOKEN_ADDRESS = 0x5FbDB2315678afecb367f032d93F642f64180aa3; + + address ALICE = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; //Can stay as is - test values anyways + address BOB = 0xE25583099BA105D9ec0A67f5Ae86D90e50036425; //Can stay as is - test values anyways + address CHARLIE = 0x614561D2d143621E126e87831AEF287678B442b8; //Can stay as is - test values anyways + uint256 ALICE_PK = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;//Can stay as is - test values anyways + //uint256 BOB_PK = 0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d;//Can stay as is - test values anyways + uint256 CHARLIE_PK = 0x53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710;//Can stay as is - test values anyways + + function setUp() public {} + + function run() public { + + vm.startBroadcast(ALICE_PK); + + //(bool success, ) = ALICE.call{value: 0.01 ether}(""); + //require(success, "Failed to send Ether"); + + // L1 -> L2 (ETH) + xERC20(TOKEN_ADDRESS).sendETH{value: 4 ether}(167011, payable(ALICE)); + + // L1 -> L2 (ERC20) + xERC20(TOKEN_ADDRESS).xTransfer(167010, BOB, 333); + xERC20(TOKEN_ADDRESS).xTransfer(167011, CHARLIE, 666); + xERC20(TOKEN_ADDRESS).xTransfer(160010, 167011, CHARLIE, 666); + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/packages/protocol/scripts/xSetup.s.sol b/packages/protocol/scripts/xSetup.s.sol new file mode 100644 index 000000000000..280a89323a83 --- /dev/null +++ b/packages/protocol/scripts/xSetup.s.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +contract XSetup is Script { + address ALICE = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + + function setUp() public {} + + function run() public { + vm.startBroadcast(0xbcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31); + + (bool success, ) = ALICE.call{value: 10 ether}(""); + require(success, "Failed to send Ether"); + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/packages/protocol/scripts/xTransfer.s.sol b/packages/protocol/scripts/xTransfer.s.sol new file mode 100644 index 000000000000..5298a9e919f1 --- /dev/null +++ b/packages/protocol/scripts/xTransfer.s.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../contracts/examples/xERC20.sol"; + +contract XTransfer is Script { + // The deployed contract address (will be the same on both chains due to deterministic deployment) + address constant TOKEN_ADDRESS = 0x5FbDB2315678afecb367f032d93F642f64180aa3; + + address ALICE = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; //Can stay as is - test values anyways + address BOB = 0xE25583099BA105D9ec0A67f5Ae86D90e50036425; //Can stay as is - test values anyways + address CHARLIE = 0x614561D2d143621E126e87831AEF287678B442b8; //Can stay as is - test values anyways + uint256 ALICE_PK = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;//Can stay as is - test values anyways + uint256 BOB_PK = 0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d;//Can stay as is - test values anyways + + function setUp() public {} + + function run() public { + vm.startBroadcast(ALICE_PK); + + // Deposit 999 tokens to L2A (L2 -> L1 -> L2) + xERC20(TOKEN_ADDRESS).xTransfer(160010, 167010, ALICE, 999); + + // Transfer 666 tokens to Bob on L2B (chainId: 167011) + xERC20(TOKEN_ADDRESS).xTransfer(167011, BOB, 666); + + // Transfer some ETH to L2A + xERC20(TOKEN_ADDRESS).sendETH{value: 3.77 ether}(167010, payable(CHARLIE)); + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/packages/protocol/scripts/xWithdraw.s.sol b/packages/protocol/scripts/xWithdraw.s.sol new file mode 100644 index 000000000000..12d6e39d7bec --- /dev/null +++ b/packages/protocol/scripts/xWithdraw.s.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../contracts/examples/xERC20.sol"; + +contract XTransfer is Script { + // The deployed contract address (will be the same on both chains due to deterministic deployment) + address constant TOKEN_ADDRESS = 0x5FbDB2315678afecb367f032d93F642f64180aa3; + + address ALICE = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; //Can stay as is - test values anyways + address BOB = 0xE25583099BA105D9ec0A67f5Ae86D90e50036425; //Can stay as is - test values anyways + address CHARLIE = 0x614561D2d143621E126e87831AEF287678B442b8; //Can stay as is - test values anyways + uint256 ALICE_PK = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;//Can stay as is - test values anyways + uint256 BOB_PK = 0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d;//Can stay as is - test values anyways + + function setUp() public {} + + function run() public { + address bob = vm.addr(BOB_PK); + + vm.startBroadcast(BOB_PK); + + // Withdraw some tokens to L1 + xERC20(TOKEN_ADDRESS).xTransfer(160010, CHARLIE, 222); + + // L2 -> L1 (ETH) + xERC20(TOKEN_ADDRESS).sendETH{value: 1.11 ether}(160010, payable(BOB)); + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/packages/protocol/src/Counter.sol b/packages/protocol/src/Counter.sol new file mode 100644 index 000000000000..aded7997b0c3 --- /dev/null +++ b/packages/protocol/src/Counter.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } +} diff --git a/packages/protocol/test/DeployCapability.sol b/packages/protocol/test/DeployCapability.sol new file mode 100644 index 000000000000..e8a214991fa3 --- /dev/null +++ b/packages/protocol/test/DeployCapability.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +import "forge-std/console2.sol"; +import "forge-std/Script.sol"; + +import "../contracts/common/AddressManager.sol"; + +/// @title DeployCapability +abstract contract DeployCapability is Script { + error ADDRESS_NULL(); + + function deployProxy( + string memory name, + address impl, + bytes memory data, + address registerTo + ) + internal + returns (address proxy) + { + proxy = address(new ERC1967Proxy(impl, data)); + + if (registerTo != address(0)) { + AddressManager(registerTo).setAddress( + uint64(block.chainid), bytes32(bytes(name)), proxy + ); + } + + console2.log(">", name, "@", registerTo); + console2.log(" proxy :", proxy); + console2.log(" impl :", impl); + console2.log(" owner :", OwnableUpgradeable(proxy).owner()); + console2.log(" msg.sender :", msg.sender); + console2.log(" this :", address(this)); + + vm.writeJson( + vm.serializeAddress("deployment", name, proxy), + string.concat(vm.projectRoot(), "/deployments/deploy_l1.json") + ); + } + + function deployProxy( + string memory name, + address impl, + bytes memory data + ) + internal + returns (address proxy) + { + return deployProxy(name, impl, data, address(0)); + } + + function register(address registerTo, string memory name, address addr) internal { + register(registerTo, name, addr, uint64(block.chainid)); + } + + function register( + address registerTo, + string memory name, + address addr, + uint64 chainId + ) + internal + { + if (registerTo == address(0)) revert ADDRESS_NULL(); + if (addr == address(0)) revert ADDRESS_NULL(); + AddressManager(registerTo).setAddress(chainId, bytes32(bytes(name)), addr); + console2.log("> ", name, "@", registerTo); + console2.log("\t addr : ", addr); + } + + function copyRegister(address registerTo, address readFrom, string memory name) internal { + if (registerTo == address(0)) revert ADDRESS_NULL(); + if (readFrom == address(0)) revert ADDRESS_NULL(); + + register({ + registerTo: registerTo, + name: name, + addr: AddressManager(readFrom).getAddress(uint64(block.chainid), bytes32(bytes(name))), + chainId: uint64(block.chainid) + }); + } +} diff --git a/packages/protocol/test/TaikoTest.sol b/packages/protocol/test/TaikoTest.sol new file mode 100644 index 000000000000..7a7578a4c270 --- /dev/null +++ b/packages/protocol/test/TaikoTest.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "forge-std/Test.sol"; +import "forge-std/console2.sol"; + +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import "../contracts/tko/TaikoToken.sol"; +import "../contracts/L1/VerifierRegistry.sol"; +import "../contracts/L1/ChainProver.sol"; +/*import "../contracts/L1/TaikoL1.sol"; +import "../contracts/L1/verifiers/GuardianVerifier.sol"; +import "../contracts/L1/verifiers/PseZkVerifier.sol"; +import "../contracts/L1/verifiers/SgxAndZkVerifier.sol"; +import "../contracts/L1/tiers/TaikoA6TierProvider.sol"; +import "../contracts/L1/tiers/ITierProvider.sol"; +import "../contracts/L1/tiers/ITierProvider.sol"; +import "../contracts/L1/provers/GuardianProver.sol";*/ + +// import "../contracts/L2/Lib1559Math.sol"; +//import "../contracts/L2/TaikoL2EIP1559Configurable.sol"; +// import "../contracts/L2/TaikoL2.sol"; + +import "../contracts/test/erc20/FreeMintERC20.sol"; + +import "./DeployCapability.sol"; + +abstract contract TaikoTest is Test, DeployCapability { + uint256 private _seed = 0x12345678; + address internal Alice = vm.addr(0x1); + address internal Bob = vm.addr(0x2); + address internal Carol = vm.addr(0x3); + address internal David = randAddress(); + address internal Emma = randAddress(); + address internal Frank = randAddress(); + address internal Grace = randAddress(); + address internal Henry = randAddress(); + address internal Isabella = randAddress(); + address internal James = randAddress(); + address internal Katherine = randAddress(); + address internal Liam = randAddress(); + address internal Mia = randAddress(); + address internal Noah = randAddress(); + address internal Olivia = randAddress(); + address internal Patrick = randAddress(); + address internal Quinn = randAddress(); + address internal Rachel = randAddress(); + address internal Samuel = randAddress(); + address internal Taylor = randAddress(); + address internal Ulysses = randAddress(); + address internal Victoria = randAddress(); + address internal William = randAddress(); + address internal Xavier = randAddress(); + address internal Yasmine = randAddress(); + address internal Zachary = randAddress(); + address internal SGX_X_0 = vm.addr(0x4); + address internal SGX_X_1 = vm.addr(0x5); + address internal SGX_Y = randAddress(); + address internal SGX_Z = randAddress(); + + function randAddress() internal returns (address) { + bytes32 randomHash = keccak256(abi.encodePacked("address", _seed++)); + return address(bytes20(randomHash)); + } + + function randBytes32() internal returns (bytes32) { + return keccak256(abi.encodePacked("bytes32", _seed++)); + } + + function strToBytes32(string memory input) internal pure returns (bytes32 result) { + require(bytes(input).length <= 32, "String too long"); + // Copy the string's bytes directly into the bytes32 variable + assembly { + result := mload(add(input, 32)) + } + } +} diff --git a/packages/protocol/test/common/EssentialContract.t.sol b/packages/protocol/test/common/EssentialContract.t.sol new file mode 100644 index 000000000000..dc9d90eeae3b --- /dev/null +++ b/packages/protocol/test/common/EssentialContract.t.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "../TaikoTest.sol"; + +contract Target1 is EssentialContract { + uint256 public count; + + function init(address _owner) external initializer { + __Essential_init(_owner); + count = 100; + } + + function adjust() external virtual onlyOwner { + count += 1; + } +} + +contract Target2 is Target1 { + function update() external onlyOwner { + count += 10; + } + + function adjust() external override onlyOwner { + count -= 1; + } +} + +contract TestEssentialContract is TaikoTest { + function test_essential_behind_1967_proxy() external { + bytes memory data = abi.encodeCall(Target1.init, (address(0))); + vm.startPrank(Alice); + ERC1967Proxy proxy = new ERC1967Proxy(address(new Target1()), data); + Target1 target = Target1(address(proxy)); + vm.stopPrank(); + + // Owner is Alice + vm.prank(Carol); + assertEq(target.owner(), Alice); + + // Alice can adjust(); + vm.prank(Alice); + target.adjust(); + assertEq(target.count(), 101); + + // Bob cannot adjust() + vm.prank(Bob); + vm.expectRevert(); + target.adjust(); + + address v2 = address(new Target2()); + data = abi.encodeCall(Target2.update, ()); + + vm.prank(Bob); + vm.expectRevert(); + target.upgradeToAndCall(v2, data); + + vm.prank(Alice); + target.upgradeToAndCall(v2, data); + assertEq(target.count(), 111); + + vm.prank(Alice); + target.adjust(); + assertEq(target.count(), 110); + } +}