diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..2d63675 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +@prestwich @evalir \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e8faa4d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: cargo + directory: "/" + schedule: + interval: "weekly" \ No newline at end of file diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml new file mode 100644 index 0000000..06a8226 --- /dev/null +++ b/.github/workflows/rust-ci.yml @@ -0,0 +1,14 @@ +name: Rust CI + +on: + workflow_dispatch: + push: + branches: [main] + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + rust-base: + uses: init4tech/actions/.github/workflows/rust-base.yml@main \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..618a18d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3420 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alloy-chains" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1752d7d62e2665da650a36d84abbf239f812534475d51f072a49a533513b7cdd" +dependencies = [ + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da374e868f54c7f4ad2ad56829827badca388efd645f8cf5fccc61c2b5343504" +dependencies = [ + "alloy-eips 0.1.4", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.1.4", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-consensus" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58047cc851e58c26224521d1ecda466e3d746ebca0274cd5427aa660a88c353" +dependencies = [ + "alloy-eips 0.2.0", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc6957ff706f9e5f6fd42f52a93e4bce476b726c92d077b348de28c4a76730c" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network 0.1.4", + "alloy-primitives", + "alloy-provider 0.1.4", + "alloy-rpc-types-eth 0.1.4", + "alloy-sol-types", + "alloy-transport 0.1.4", + "futures", + "futures-util", + "thiserror", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413902aa18a97569e60f679c23f46a18db1656d87ab4d4e49d0e1e52042f66df" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow 0.6.15", +] + +[[package]] +name = "alloy-eips" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76ecab54890cdea1e4808fc0891c7e6cfcf71fe1a9fe26810c7280ef768f4ed" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.1.4", + "c-kzg", + "derive_more", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-eips" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32a3e14fa0d152d00bd8daf605eb74ad397efb0f54bd7155585823dddb4401e" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", + "c-kzg", + "k256", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-json-abi" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc05b04ac331a9f07e3a4036ef7926e49a8bf84a99a1ccfc7e2ab55a5fcbb372" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d6f34930b7e3e2744bcc79056c217f00cb2abb33bc5d4ff88da7623c5bb078b" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a9feec2352c78545d1a37415699817bae8dc41654bd1bfe57d6cdd5433bd" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f6895fc31b48fa12306ef9b4f78b7764f8bd6d7d91cdb0a40e233704a0f23f" +dependencies = [ + "alloy-consensus 0.1.4", + "alloy-eips 0.1.4", + "alloy-json-rpc 0.1.4", + "alloy-primitives", + "alloy-rpc-types-eth 0.1.4", + "alloy-serde 0.1.4", + "alloy-signer 0.1.4", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + +[[package]] +name = "alloy-network" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3223d71dc78f464b2743418d0be8b5c894313e272105a6206ad5e867d67b3ce2" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-json-rpc 0.2.0", + "alloy-primitives", + "alloy-rpc-types-eth 0.2.0", + "alloy-serde 0.2.0", + "alloy-signer 0.2.0", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + +[[package]] +name = "alloy-primitives" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c538bfa893d07e27cb4f3c1ab5f451592b7c526d511d62b576a2ce59e146e4a" +dependencies = [ + "alloy-chains", + "alloy-consensus 0.1.4", + "alloy-eips 0.1.4", + "alloy-json-rpc 0.1.4", + "alloy-network 0.1.4", + "alloy-primitives", + "alloy-rpc-client 0.1.4", + "alloy-rpc-types-eth 0.1.4", + "alloy-transport 0.1.4", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "serde", + "serde_json", + "tokio", + "tracing", +] + +[[package]] +name = "alloy-provider" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29da7457d853cb8199ec04b227d5d2ef598be3e59fc2bbad70c8be213292f32" +dependencies = [ + "alloy-chains", + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-json-rpc 0.2.0", + "alloy-network 0.2.0", + "alloy-primitives", + "alloy-rpc-client 0.2.0", + "alloy-rpc-types-eth 0.2.0", + "alloy-transport 0.2.0", + "alloy-transport-http 0.2.0", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a43b18702501396fa9bcdeecd533bc85fac75150d308fc0f6800a01e6234a003" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba31bae67773fd5a60020bea900231f8396202b7feca4d0c70c6b59308ab4a8" +dependencies = [ + "alloy-json-rpc 0.1.4", + "alloy-transport 0.1.4", + "alloy-transport-http 0.1.4", + "futures", + "pin-project", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a9e609524fa31c2c70eb24c0da60796809193ad4787a6dfe6d0db0d3ac112d" +dependencies = [ + "alloy-json-rpc 0.2.0", + "alloy-transport 0.2.0", + "alloy-transport-http 0.2.0", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4123ee21f99ba4bd31bfa36ba89112a18a500f8b452f02b35708b1b951e2b9" +dependencies = [ + "alloy-consensus 0.1.4", + "alloy-eips 0.1.4", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.1.4", + "alloy-sol-types", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605fa8462732bb8fd0645a9941e12961e079d45ae6a44634c826f8229c187bdf" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", + "alloy-sol-types", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-serde" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9416c52959e66ead795a11f4a86c248410e9e368a0765710e57055b8a1774dd6" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c5b9057acc02aee1b8aac2b5a0729cb0f73d080082c111313e5d1f92a96630" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33753c09fa1ad85e5b092b8dc2372f1e337a42e84b9b4cff9fede75ba4adb32" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-signer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37f10592696f4ab8b687d5a8ab55e998a14ea0ca5f8eb20ad74a96ad671bb54a" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-signer-local" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dfc9c26fe6c6f1bad818c9a976de9044dd12e1f75f1f156a801ee3e8148c1b6" +dependencies = [ + "alloy-consensus 0.1.4", + "alloy-network 0.1.4", + "alloy-primitives", + "alloy-signer 0.1.4", + "async-trait", + "k256", + "rand", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.72", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" +dependencies = [ + "serde", + "winnow 0.6.15", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b51a291f949f755e6165c3ed562883175c97423703703355f4faa4b7d0a57c" +dependencies = [ + "alloy-json-rpc 0.1.4", + "base64", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b44b0f6f4a2593b258fa7b6cae8968e6a4c404d9ef4f5bc74401f2d04fa23fa" +dependencies = [ + "alloy-json-rpc 0.2.0", + "base64", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d65871f9f1cafe1ed25cde2f1303be83e6473e995a2d56c275ae4fcce6119c" +dependencies = [ + "alloy-transport 0.1.4", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8f1eefa8cb9e7550740ee330feba4fed303a77ad3085707546f9152a88c380" +dependencies = [ + "alloy-json-rpc 0.2.0", + "alloy-transport 0.2.0", + "reqwest", + "serde_json", + "tower", + "tracing", + "url", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "aurora-engine-modexp" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aef7712851e524f35fbbb74fa6599c5cd8692056a1c36f9ca0d2001b670e7e5" +dependencies = [ + "hex", + "num", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "serde", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bls12_381" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" +dependencies = [ + "ff", + "group", + "pairing", + "rand_core", + "subtle", +] + +[[package]] +name = "blst" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62dc83a094a71d43eeadd254b1ec2d24cb6a0bb6cadce00df51f0db594711a32" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf100c4cea8f207e883ff91ca886d621d8a166cb04971dfaa9bb8fd99ed95df" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "serde", +] + +[[package]] +name = "cc" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 2.0.72", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enumn" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", +] + +[[package]] +name = "keccak-asm" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "kzg-rs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9920cd4460ce3cbca19c62f3bb9a9611562478a4dc9d2c556f4a7d049c5b6b" +dependencies = [ + "bls12_381", + "glob", + "hex", + "once_cell", + "serde", + "serde_derive", + "serde_yaml", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "revm" +version = "12.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cfb48bce8ca2113e157bdbddbd5eeb09daac1c903d79ec17085897c38c7c91" +dependencies = [ + "alloy-eips 0.2.0", + "alloy-provider 0.2.0", + "alloy-transport 0.2.0", + "auto_impl", + "cfg-if", + "dyn-clone", + "revm-interpreter", + "revm-precompile", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "revm-interpreter" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b0daddea06fc6da5346acc39b32a357bbe3579e9e3d94117d9ae125cd596fc" +dependencies = [ + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-precompile" +version = "9.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef55228211251d7b6c7707c3ee13bb70dea4d2fd81ec4034521e4fe31010b2ea" +dependencies = [ + "aurora-engine-modexp", + "blst", + "c-kzg", + "cfg-if", + "k256", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc4311037ee093ec50ec734e1424fcb3e12d535c6cef683b75d1c064639630c" +dependencies = [ + "alloy-eips 0.2.0", + "alloy-primitives", + "auto_impl", + "bitflags", + "bitvec", + "c-kzg", + "cfg-if", + "derive_more", + "dyn-clone", + "enumn", + "hashbrown", + "hex", + "kzg-rs", + "once_cell", + "serde", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +dependencies = [ + "rand", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +dependencies = [ + "cc", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3-asm" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.72", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "trevm" +version = "0.1.0" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-primitives", + "alloy-provider 0.2.0", + "alloy-rlp", + "alloy-signer 0.1.4", + "alloy-signer-local", + "alloy-sol-types", + "alloy-transport 0.2.0", + "eyre", + "revm", + "serde_json", + "tokio", + "zenith-types", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.72", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zenith-types" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631c66a913e55b2b73b08e7271d5c8bea52464040b8f9e38ae183ca2aad79676" +dependencies = [ + "alloy-consensus 0.1.4", + "alloy-contract", + "alloy-eips 0.1.4", + "alloy-primitives", + "alloy-rlp", + "alloy-signer 0.1.4", + "alloy-sol-types", + "serde", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4bff12e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,91 @@ +[package] +name = "trevm" +version = "0.1.0" +rust-version = "1.79.0" +edition = "2021" +authors = ["init4"] +homepage = "https://github.com/init4tech/trevm" +repository = "https://github.com/init4tech/trevm" +license = "MIT OR Apache-2.0" +description = "A typestate API wrapper for the revm EVM implementation" + +[lints.rust] +missing-debug-implementations = "warn" +missing-docs = "warn" +unreachable-pub = "warn" +unused-must-use = "deny" +rust-2018-idioms = "deny" +unnameable-types = "warn" + +[lints.rustdoc] +all = "warn" + +[lints.clippy] +missing-const-for-fn = "warn" +use-self = "warn" +option-if-let-else = "warn" +redundant-clone = "warn" + +[dependencies] +alloy-consensus = { version = "0.2", features = ["k256"] } +alloy-eips = "0.2.0" +alloy-primitives = "0.7.6" +alloy-sol-types = "0.7.7" +revm = { version = "12.0.0", default-features = false, features = ["std"] } +zenith-types = "0.2.2" + +[dev-dependencies] +revm = { version = "12.0.0", features = ["test-utils", "serde-json", "std", "alloydb"] } +tokio = { version = "1.28", features = ["macros", "rt-multi-thread"] } + +# alloydb +alloy-provider = "0.2" +alloy-transport = "0.2" + +alloy-signer = { version = "0.1", default-features = false } +alloy-signer-local = { version = "0.1", default-features = false } + +alloy-rlp = { version = "0.3", default-features = false } + + +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } + + +# misc +eyre = "0.6" + +[features] +default = [ + "revm/std", + "revm/c-kzg", + "revm/blst", + "revm/portable", + "revm/secp256k1" +] + +test-utils = ["revm/test-utils"] + + +secp256k1 = ["revm/secp256k1"] +c-kzg = ["revm/c-kzg"] +blst = ["revm/blst"] + +portable = ["revm/portable"] + +dev = [ + "memory_limit", + "optional_balance_check", + "optional_block_gas_limit", + "optional_eip3607", + "optional_gas_refund", + "optional_no_base_fee", + "optional_beneficiary_reward", +] + +memory_limit = ["revm/memory_limit"] +optional_balance_check = ["revm/optional_balance_check"] +optional_beneficiary_reward = ["revm/optional_beneficiary_reward"] +optional_block_gas_limit = ["revm/optional_block_gas_limit"] +optional_eip3607 = ["revm/optional_eip3607"] +optional_gas_refund = ["revm/optional_gas_refund"] +optional_no_base_fee = ["revm/optional_no_base_fee"] diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,23 @@ +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..810a643 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +## Trevm + +⚠️ Trevm is **experimental** software and not considered ready for production +use. ⚠️ + +Trevm is a [typestate] API wrapper for [revm]. It provides an ergonomic way to +interact with the revm API, shortcuts for common tasks, and straightforward API +extensibility. Trevm does NOT try to provide low-level EVM management, but +rather to shortcut and simplify common tasks like simulating transactions. + +Trevm is NOT a replacement for revm. It is a wrapper around the revm API. It is +NOT a drop-in upgrade, integrating trevm into your project will require changes +to your code. + +See the [documentation on docs.rs] for information on usage. + +## Why use Trevm? + +Trevm is for building complex high-level flows on top of the low-level revm +API. It provides a state machine that ensures you can only take actions that are +valid in the current state. This makes it easier to reason about the state of +your EVM instance and ensures you don't make mistakes. + +Trevm is useful for: + +- full node implementations +- block builders +- searchers +- any other transaction simulation usecase + +## Limitations + +Trevm is a work in progress and is not feature complete. In particular, trevm +does not currently have lifecycle support for blocks before Shanghai. This means +it cannot produce correct post-block states for blocks before Shanghai. + +### The Trevm State Machine + +Trevm provides a state machine that represents the internal state of a revm EVM +instance. It ensures that at each step you can only take actions that are valid +in the current state. This is done by using the [typestate] pattern. + +As you progress between states, the API will change to reflect the available +operations. For example, you can't call `open_block()` on a `EvmNeedsTx` state, +as the block is already open. You can't call `close_block()` on a `EvmReady` +state, without explicitly clearing or running the transaction that has been +ready. + +![typestates are cool](./assets/states.png) + +[typestate]: https://cliffle.com/blog/rust-typestate/ +[revm]: https://github.com/bluealloy/revm +[docs.rs]: https://docs.rs/trevm/latest/trevm/ +[documentation on docs.rs]: https://docs.rs/trevm/latest/trevm/ diff --git a/assets/states.png b/assets/states.png new file mode 100644 index 0000000..a5278d7 Binary files /dev/null and b/assets/states.png differ diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..fda0d7c --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +too-large-for-stack = 128 diff --git a/examples/basic_transact.rs b/examples/basic_transact.rs new file mode 100644 index 0000000..554c966 --- /dev/null +++ b/examples/basic_transact.rs @@ -0,0 +1,71 @@ +//! Simple TREVM example that demonstrates how to execute a transaction on a contract. +//! It simply loads the contract bytecode and executes a transaction. + +use revm::{ + inspector_handle_register, + inspectors::TracerEip3155, + primitives::{hex, AccountInfo, Address, Bytecode, TransactTo, U256}, + EvmBuilder, InMemoryDB, +}; +use trevm::{trevm_aliases, NoopBlock, NoopCfg, Shanghai, TrevmBuilder, Tx}; + +/// Foundry's default Counter.sol contract bytecode. +const CONTRACT_BYTECODE: &str = "0x6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220091e48831e9eee32d4571d6291233a4fdaaa34b7dced8770f36f5368be825c5264736f6c63430008190033"; + +/// The address of Counter.sol +const CONTRACT_ADDR: Address = Address::with_last_byte(32); + +/// The input data for the Counter.sol program. We're calling setNumber(10) +const PROGRAM_INPUT: &str = + "0x3fb5c1cb000000000000000000000000000000000000000000000000000000000000000a"; + +/// The caller address +const CALLER_ADDR: Address = Address::with_last_byte(1); + +struct SampleTx; + +impl Tx for SampleTx { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + tx_env.caller = CALLER_ADDR; + tx_env.transact_to = TransactTo::Call(CONTRACT_ADDR); + tx_env.data = hex::decode(PROGRAM_INPUT).unwrap().into(); + } +} + +// Produce aliases for the Trevm type +trevm_aliases!(TracerEip3155, InMemoryDB); + +fn main() { + let mut db = revm::InMemoryDB::default(); + + let bytecode = Bytecode::new_raw(hex::decode(CONTRACT_BYTECODE).unwrap().into()); + let acc_info = AccountInfo::new(U256::ZERO, 1, bytecode.hash_slow(), bytecode); + + // insert both the contract code to the contract cache, and the account info to the account cache + db.insert_contract(&mut acc_info.clone()); + db.insert_account_info(CONTRACT_ADDR, acc_info); + + let evm = EvmBuilder::default() + .with_db(db) + .with_external_context(TracerEip3155::new(Box::new(std::io::stdout()))) + .append_handler_register(inspector_handle_register) + .build_trevm() + .fill_cfg(&NoopCfg) + .open_block(&NoopBlock, Shanghai::default()) + .unwrap(); + + let account = evm.read_account_ref(CONTRACT_ADDR).unwrap(); + println!("account: {account:?}"); + + let evm = evm.fill_tx(&SampleTx).run(); + + match evm { + Ok(res) => { + let res = res.result_and_state(); + println!("Execution result: {res:#?}"); + } + Err(e) => { + println!("Execution error: {e:?}"); + } + }; +} diff --git a/examples/fork_ref_transact.rs b/examples/fork_ref_transact.rs new file mode 100644 index 0000000..fa83fc0 --- /dev/null +++ b/examples/fork_ref_transact.rs @@ -0,0 +1,86 @@ +//! This example demonstrates how to query storage slots of a contract, using AlloyDB. + +use alloy_eips::BlockId; +use alloy_primitives::Address; +use alloy_provider::ProviderBuilder; +use alloy_sol_types::sol; +use alloy_sol_types::SolCall; +use revm::{ + db::{AlloyDB, CacheDB}, + primitives::{address, TxKind, U256}, + Evm, +}; +use trevm::{NoopBlock, NoopCfg, Shanghai, TrevmBuilder, Tx}; + +sol! { + #[allow(missing_docs)] + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); +} + +struct GetReservesFiller; + +impl Tx for GetReservesFiller { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + tx_env.caller = Address::with_last_byte(0); + // ETH/USDT pair on Uniswap V2 + tx_env.transact_to = TxKind::Call(POOL_ADDRESS); + // calldata formed via alloy's abi encoder + tx_env.data = getReservesCall::new(()).abi_encode().into(); + // transaction value in wei + tx_env.value = U256::from(0); + } +} + +const POOL_ADDRESS: Address = address!("0d4a11d5EEaaC28EC3F61d100daF4d40471f1852"); + +#[tokio::main] +async fn main() -> eyre::Result<()> { + // create ethers client and wrap it in Arc + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + + let client = ProviderBuilder::new().on_http(rpc_url.parse()?); + + // ----------------------------------------------------------- // + // Storage slots of UniV2Pair contract // + // =========================================================== // + // storage[5] = factory: address // + // storage[6] = token0: address // + // storage[7] = token1: address // + // storage[8] = (res0, res1, ts): (uint112, uint112, uint32) // + // storage[9] = price0CumulativeLast: uint256 // + // storage[10] = price1CumulativeLast: uint256 // + // storage[11] = kLast: uint256 // + // =========================================================== // + + // initialize new AlloyDB + let alloydb = AlloyDB::new(client, BlockId::default()).unwrap(); + + // initialise empty in-memory-db + let cache_db = CacheDB::new(alloydb); + + // initialise an empty (default) EVM + let evm = Evm::builder() + .with_db(cache_db) + .build_trevm() + .fill_cfg(&NoopCfg) + .open_block(&NoopBlock, Shanghai::default()) + .unwrap() + .fill_tx(&GetReservesFiller) + .run() + .inspect_err(|e| panic!("Execution error {e:?}")) + .unwrap(); + + // Inspect the outcome of a transaction execution, and get the return value + println!("Execution result: {:#?}", evm.result()); + let output = evm.output().expect("Execution halted"); + + // decode bytes to reserves + ts via alloy's abi decode + let return_vals = getReservesCall::abi_decode_returns(output, true)?; + + // Print emulated getReserves() call output + println!("Reserve0: {:#?}", return_vals.reserve0); + println!("Reserve1: {:#?}", return_vals.reserve1); + println!("Timestamp: {:#?}", return_vals.blockTimestampLast); + + Ok(()) +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..1e491f9 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +reorder_imports = true +use_field_init_shorthand = true +use_small_heuristics = "Max" diff --git a/src/evm.rs b/src/evm.rs new file mode 100644 index 0000000..f4a1b23 --- /dev/null +++ b/src/evm.rs @@ -0,0 +1,1148 @@ +use crate::{ + states::EvmBlockComplete, BasicContext, Block, BlockComplete, BlockContext, Cfg, ErroredState, + EvmErrored, EvmNeedsCfg, EvmNeedsFirstBlock, EvmNeedsNextBlock, EvmNeedsTx, EvmReady, + EvmTransacted, HasCfg, HasOutputs, NeedsBlock, NeedsCfg, NeedsNextBlock, NeedsTx, Ready, + TransactedState, Tx, +}; +use alloy_consensus::constants::KECCAK_EMPTY; +use alloy_primitives::{Address, Bytes, U256}; +use revm::{ + db::{states::bundle_state::BundleRetention, BundleState}, + primitives::{ + Account, AccountInfo, AccountStatus, Bytecode, EVMError, EvmState, EvmStorageSlot, + ExecutionResult, InvalidTransaction, ResultAndState, SpecId, + }, + Database, DatabaseCommit, DatabaseRef, Evm, State, +}; +use std::{convert::Infallible, fmt}; + +/// Trevm provides a type-safe interface to the EVM, using the typestate pattern. +/// +/// See the [crate-level documentation](crate) for more information. +pub struct Trevm<'a, Ext, Db: Database + DatabaseCommit, TrevmState> { + inner: Box>, + state: TrevmState, +} + +impl fmt::Debug for Trevm<'_, Ext, Db, TrevmState> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Trevm").finish_non_exhaustive() + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState> AsRef> + for Trevm<'a, Ext, Db, TrevmState> +{ + fn as_ref(&self) -> &Evm<'a, Ext, Db> { + &self.inner + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit> From> for EvmNeedsCfg<'a, Ext, Db> { + fn from(inner: Evm<'a, Ext, Db>) -> Self { + Self { inner: Box::new(inner), state: NeedsCfg::new() } + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState> Trevm<'a, Ext, Db, TrevmState> { + /// Get a reference to the current [`Evm`]. + pub fn inner(&self) -> &Evm<'a, Ext, Db> { + self.as_ref() + } + + /// Get a mutable reference to the current [`Evm`]. This should be used with + /// caution, as modifying the EVM may lead to inconsistent Trevmstate or invalid + /// execution. + pub fn inner_mut_unchecked(&mut self) -> &mut Evm<'a, Ext, Db> { + &mut self.inner + } + + /// Destructure the [`Trevm`] into its parts. + pub fn into_inner(self) -> Box> { + self.inner + } + + /// Get the id of the currently running hardfork spec. Convenience function + /// calling [`Evm::spec_id`]. + pub fn spec_id(&self) -> SpecId { + self.inner.spec_id() + } + + /// Get the current account info for a specific address. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn try_read_account(&mut self, address: Address) -> Result, Db::Error> { + self.inner.db_mut().basic(address) + } + + /// Get the current nonce for a specific address + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn try_read_nonce(&mut self, address: Address) -> Result { + self.try_read_account(address).map(|a| a.map(|a| a.nonce).unwrap_or_default()) + } + + /// Get the current nonce for a specific address + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn try_read_balance(&mut self, address: Address) -> Result { + self.try_read_account(address).map(|a| a.map(|a| a.balance).unwrap_or_default()) + } + + /// Get the value of a storage slot. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn try_read_storage(&mut self, address: Address, slot: U256) -> Result { + self.inner.db_mut().storage(address, slot) + } + + /// Get the code at the given account, if any. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn try_read_code(&mut self, address: Address) -> Result, Db::Error> { + let acct_info = self.try_read_account(address)?; + match acct_info { + Some(acct) => Ok(Some(self.inner.db_mut().code_by_hash(acct.code_hash)?)), + None => Ok(None), + } + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit + DatabaseRef, TrevmState> + Trevm<'a, Ext, Db, TrevmState> +{ + /// Get the current account info for a specific address. + pub fn try_read_account_ref( + &self, + address: Address, + ) -> Result, ::Error> { + self.inner.db().basic_ref(address) + } + + /// Get the current nonce for a specific address + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn try_read_nonce_ref(&self, address: Address) -> Result::Error> { + self.try_read_account_ref(address).map(|a| a.map(|a| a.nonce).unwrap_or_default()) + } + + /// Get the current nonce for a specific address + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn try_read_balance_ref( + &self, + address: Address, + ) -> Result::Error> { + self.try_read_account_ref(address).map(|a| a.map(|a| a.balance).unwrap_or_default()) + } + + /// Get the value of a storage slot. + pub fn try_read_storage_ref( + &self, + address: Address, + slot: U256, + ) -> Result::Error> { + self.inner.db().storage_ref(address, slot) + } + + /// Get the code at the given account, if any. + pub fn try_read_code_ref( + &self, + address: Address, + ) -> Result, ::Error> { + let acct_info = self.try_read_account_ref(address)?; + match acct_info { + Some(acct) => Ok(Some(self.inner.db().code_by_hash_ref(acct.code_hash)?)), + None => Ok(None), + } + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState> + Trevm<'a, Ext, Db, TrevmState> +{ + /// Get the current account info for a specific address. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_account(&mut self, address: Address) -> Option { + self.inner.db_mut().basic(address).expect("infallible") + } + + /// Get the current nonce for a specific address + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_nonce(&mut self, address: Address) -> u64 { + self.read_account(address).map(|a: AccountInfo| a.nonce).unwrap_or_default() + } + + /// Get the current nonce for a specific address + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_balance(&mut self, address: Address) -> U256 { + self.read_account(address).map(|a: AccountInfo| a.balance).unwrap_or_default() + } + + /// Get the value of a storage slot. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_storage(&mut self, address: Address, slot: U256) -> U256 { + self.inner.db_mut().storage(address, slot).expect("infallible") + } + + /// Get the code at the given account, if any. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_code(&mut self, address: Address) -> Option { + let acct_info = self.read_account(address)?; + Some(self.inner.db_mut().code_by_hash(acct_info.code_hash).expect("infallible")) + } +} + +impl< + 'a, + Ext, + Db: Database + DatabaseRef + DatabaseCommit, + TrevmState, + > Trevm<'a, Ext, Db, TrevmState> +{ + /// Get the current account info for a specific address. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_account_ref(&self, address: Address) -> Option { + self.inner.db().basic_ref(address).expect("infallible") + } + + /// Get the current nonce for a specific address + pub fn read_nonce_ref(&self, address: Address) -> u64 { + self.read_account_ref(address).map(|a: AccountInfo| a.nonce).unwrap_or_default() + } + + /// Get the current nonce for a specific address + pub fn read_balance_ref(&self, address: Address) -> U256 { + self.read_account_ref(address).map(|a: AccountInfo| a.balance).unwrap_or_default() + } + + /// Get the value of a storage slot. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_storage_ref(&self, address: Address, slot: U256) -> U256 { + self.inner.db().storage_ref(address, slot).expect("infallible") + } + + /// Get the code at the given account, if any. + /// + /// Note: due to revm's DB model, this requires a mutable pointer. + pub fn read_code_ref(&self, address: Address) -> Option { + let acct_info = self.read_account_ref(address)?; + Some(self.inner.db().code_by_hash_ref(acct_info.code_hash).expect("infallible")) + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState> Trevm<'a, Ext, Db, TrevmState> { + /// Commit a set of state changes to the database. This is a low-level API, + /// and is not intended for general use. Prefer executing a transaction. + pub fn commit_unchecked(&mut self, state: EvmState) { + self.inner.db_mut().commit(state); + } + + /// Modify an account with a closure and commit the modified account. This + /// is a low-level API, and is not intended for general use. + pub fn try_modify_account_unchecked( + &mut self, + address: Address, + f: F, + ) -> Result { + let db = self.inner_mut_unchecked().db_mut(); + + let mut info = db.basic(address)?.unwrap_or_default(); + let old = info.clone(); + f(&mut info); + + // Make a new account with the modified info + let mut acct = Account { info, status: AccountStatus::Touched, ..Default::default() }; + acct.mark_touch(); + + // Create a state object with the modified account. + let state = [(address, acct)].iter().cloned().collect(); + self.commit_unchecked(state); + + Ok(old) + } + + /// Set the nonce of an account, returning the previous nonce. This is a + /// low-level API, and is not intended for general use. + pub fn try_set_nonce_unchecked( + &mut self, + address: Address, + nonce: u64, + ) -> Result { + self.try_modify_account_unchecked(address, |info| info.nonce = nonce).map(|info| info.nonce) + } + + /// Increment the nonce of an account, returning the previous nonce. This is + /// a low-level API, and is not intended for general use. + /// + /// If the nonce is already at the maximum value, it will not be + /// incremented. + pub fn try_increment_nonce_unchecked(&mut self, address: Address) -> Result { + self.try_modify_account_unchecked(address, |info| info.nonce = info.nonce.saturating_add(1)) + .map(|info| info.nonce) + } + + /// Decrement the nonce of an account, returning the previous nonce. This is + /// a low-level API, and is not intended for general use. + /// + /// If the nonce is already 0, it will not be decremented. + pub fn try_decrement_nonce_unchecked(&mut self, address: Address) -> Result { + self.try_modify_account_unchecked(address, |info| info.nonce = info.nonce.saturating_sub(1)) + .map(|info| info.nonce) + } + + /// Set the EVM storage at a slot. This is a low-level API, and is not + /// intended for general use. + pub fn try_set_storage_unchecked( + &mut self, + address: Address, + slot: U256, + value: U256, + ) -> Result { + let db = self.inner_mut_unchecked().db_mut(); + let info = db.basic(address)?.unwrap_or_default(); + let old = db.storage(address, slot)?; + + let change = EvmStorageSlot::new_changed(old, value); + + // Make a new account with the modified storage + let storage = [(slot, change)].iter().cloned().collect(); + let mut acct = Account { storage, info, ..Default::default() }; + acct.mark_touch(); + + // Create a state object with the modified account. + let state = [(address, acct)].iter().cloned().collect(); + self.commit_unchecked(state); + + Ok(old) + } + + /// Set the bytecode at a specific address, returning the previous bytecode + /// at that address. This is a low-level API, and is not intended for + /// general use. + pub fn try_set_bytecode_unchecked( + &mut self, + address: Address, + bytecode: Bytecode, + ) -> Result, Db::Error> { + let db = self.inner_mut_unchecked().db_mut(); + let mut info = db.basic(address)?.unwrap_or_default(); + + let old = if info.code_hash != KECCAK_EMPTY { + Some(db.code_by_hash(info.code_hash)?) + } else { + None + }; + + info.code_hash = if bytecode.is_empty() { KECCAK_EMPTY } else { bytecode.hash_slow() }; + info.code = Some(bytecode); + + let mut acct = Account { info, ..Default::default() }; + acct.mark_touch(); + let state = [(address, acct)].iter().cloned().collect(); + self.commit_unchecked(state); + + Ok(old) + } + + /// Increase the balance of an account. Returns the previous balance. This + /// is a low-level API, and is not intended for general use. + /// + /// If this would cause an overflow, the balance will be increased to the + /// maximum value. + pub fn try_increase_balance_unchecked( + &mut self, + address: Address, + amount: U256, + ) -> Result { + self.try_modify_account_unchecked(address, |info| { + info.balance = info.balance.saturating_add(amount) + }) + .map(|info| info.balance) + } + + /// Decrease the balance of an account. Returns the previous balance. This + /// is a low-level API, and is not intended for general use. + /// + /// If this would cause an underflow, the balance will be decreased to 0. + pub fn try_decrease_balance_unchecked( + &mut self, + address: Address, + amount: U256, + ) -> Result { + self.try_modify_account_unchecked(address, |info| { + info.balance = info.balance.saturating_sub(amount) + }) + .map(|info| info.balance) + } + + /// Set the balance of an account. Returns the previous balance. This is a + /// low-level API, and is not intended for general use. + pub fn try_set_balance_unchecked( + &mut self, + address: Address, + amount: U256, + ) -> Result { + self.try_modify_account_unchecked(address, |info| info.balance = amount) + .map(|info| info.balance) + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState> + Trevm<'a, Ext, Db, TrevmState> +{ + /// Modify an account with a closure and commit the modified account. This + /// is a low-level API, and is not intended for general use. + pub fn modify_account_unchecked( + &mut self, + address: Address, + f: impl FnOnce(&mut AccountInfo), + ) -> AccountInfo { + self.try_modify_account_unchecked(address, f).expect("infallible") + } + + /// Set the nonce of an account, returning the previous nonce. This is a + /// low-level API, and is not intended for general use. + pub fn set_nonce_unchecked(&mut self, address: Address, nonce: u64) -> u64 { + self.try_set_nonce_unchecked(address, nonce).expect("infallible") + } + + /// Increment the nonce of an account, returning the previous nonce. This is + /// a low-level API, and is not intended for general use. + /// + /// If this would cause the nonce to overflow, the nonce will be set to the + /// maximum value. + pub fn increment_nonce_unchecked(&mut self, address: Address) -> u64 { + self.try_increment_nonce_unchecked(address).expect("infallible") + } + + /// Decrement the nonce of an account, returning the previous nonce. This is + /// a low-level API, and is not intended for general use. + /// + /// If this would cause the nonce to underflow, the nonce will be set to 0. + pub fn decrement_nonce_unchecked(&mut self, address: Address) -> u64 { + self.try_decrement_nonce_unchecked(address).expect("infallible") + } + + /// Set the EVM storage at a slot. This is a low-level API, and is not + /// intended for general use. + pub fn set_storage_unchecked(&mut self, address: Address, slot: U256, value: U256) -> U256 { + self.try_set_storage_unchecked(address, slot, value).expect("infallible") + } + + /// Set the bytecode at a specific address, returning the previous bytecode + /// at that address. This is a low-level API, and is not intended for + /// general use. + pub fn set_bytecode_unchecked( + &mut self, + address: Address, + bytecode: Bytecode, + ) -> Option { + self.try_set_bytecode_unchecked(address, bytecode).expect("infallible") + } + + /// Increase the balance of an account. Returns the previous balance. This + /// is a low-level API, and is not intended for general use. + pub fn increase_balance_unchecked(&mut self, address: Address, amount: U256) -> U256 { + self.try_increase_balance_unchecked(address, amount).expect("infallible") + } + + /// Decrease the balance of an account. Returns the previous balance. This + /// is a low-level API, and is not intended for general use. + pub fn decrease_balance_unchecked(&mut self, address: Address, amount: U256) -> U256 { + self.try_decrease_balance_unchecked(address, amount).expect("infallible") + } + + /// Set the balance of an account. Returns the previous balance. This is a + /// low-level API, and is not intended for general use. + pub fn set_balance_unchecked(&mut self, address: Address, amount: U256) -> U256 { + self.try_set_balance_unchecked(address, amount).expect("infallible") + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, EvmState> Trevm<'a, Ext, State, EvmState> { + /// Set the [EIP-161] state clear flag, activated in the Spurious Dragon + /// hardfork. + pub fn set_state_clear_flag(&mut self, flag: bool) { + self.inner.db_mut().set_state_clear_flag(flag) + } +} + +// --- NEEDS CFG + +impl<'a, Ext, Db: Database + DatabaseCommit> EvmNeedsCfg<'a, Ext, Db> { + /// Fill the configuration environment. + pub fn fill_cfg(mut self, filler: &T) -> EvmNeedsFirstBlock<'a, Ext, Db> { + filler.fill_cfg(&mut self.inner); + // SAFETY: Same size and repr. Only phantomdata type changes + unsafe { std::mem::transmute(self) } + } +} + +// --- HAS CFG + +impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { + /// Set the [EIP-170] contract code size limit. By default this is set to + /// 0x6000 bytes (~25KiB). Contracts whose bytecode is larger than this + /// limit cannot be deployed and will produce a [`CreateInitCodeSizeLimit`] + /// error. + /// + /// [`CreateInitCodeSizeLimit`]: InvalidTransaction::CreateInitCodeSizeLimit + /// [`Eip-170`]: https://eips.ethereum.org/EIPS/eip-170 + pub fn set_code_size_limit(&mut self, limit: usize) -> Option { + let cfg = self.inner.cfg_mut(); + cfg.limit_contract_code_size.replace(limit) + } + + /// Disable the [EIP-170] contract code size limit, returning the previous + /// setting. + /// + /// [`Eip-170`]: https://eips.ethereum.org/EIPS/eip-170 + pub fn disable_code_size_limit(&mut self) -> Option { + self.inner.cfg_mut().limit_contract_code_size.take() + } + + /// Run a closure with the code size limit disabled, then restore the + /// previous setting. + pub fn without_code_size_limit( + mut self, + f: F, + ) -> Trevm<'a, Ext, Db, NewState> + where + F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + { + let limit = self.disable_code_size_limit(); + let mut new = f(self); + if let Some(limit) = limit { + new.set_code_size_limit(limit); + } + new + } + + /// Set the [EIP-170] contract code size limit to the default value of + /// 0x6000 bytes (~25KiB), returning the previous setting. Contracts whose + /// bytecode is larger than this limit cannot be deployed and will produce + /// a [`CreateInitCodeSizeLimit`] error. + /// + /// [`CreateInitCodeSizeLimit`]: InvalidTransaction::CreateInitCodeSizeLimit + /// [`Eip-170`]: https://eips.ethereum.org/EIPS/eip-170 + pub fn set_default_code_size_limit(&mut self) -> Option { + self.set_code_size_limit(0x6000) + } + + /// Set the KZG settings used for point evaluation precompiles. By default + /// this is set to the settings used in the Ethereum mainnet. + /// + /// This is a low-level API, and is not intended for general use. + #[cfg(feature = "c-kzg")] + pub fn set_kzg_settings( + &mut self, + settings: revm::primitives::EnvKzgSettings, + ) -> revm::primitives::EnvKzgSettings { + let cfg = self.inner.cfg_mut(); + std::mem::replace(&mut cfg.kzg_settings, settings) + } + + /// Set a limit beyond which a callframe's memory cannot be resized. + /// Attempting to resize beyond this limit will result in a + /// [OutOfGasError::Memory] error. + /// + /// In cases where the gas limit may be extraordinarily high, it is + /// recommended to set this to a sane value to prevent memory allocation + /// panics. Defaults to `2^32 - 1` bytes per EIP-1985. + /// + /// [OutOfGasError::Memory]: revm::primitives::OutOfGasError::Memory + #[cfg(feature = "memory_limit")] + pub fn set_memory_limit(&mut self, new_limit: u64) -> u64 { + let cfg = self.inner.cfg_mut(); + std::mem::replace(&mut cfg.memory_limit, new_limit) + } + + /// Disable balance checks. If the sender does not have enough balance to + /// cover the transaction, the sender will be given enough ether to ensure + /// execution doesn't fail. + #[cfg(feature = "optional_balance_check")] + pub fn disable_balance_check(&mut self) { + self.inner.cfg_mut().disable_balance_check = true + } + + /// Enable balance checks. See [`Self::disable_balance_check`]. + #[cfg(feature = "optional_balance_check")] + pub fn enable_balance_check(&mut self) { + self.inner.cfg_mut().disable_balance_check = false + } + + /// Run a closure with balance checks disabled, then restore the previous + /// setting. + #[cfg(feature = "optional_balance_check")] + pub fn without_balance_check( + mut self, + f: F, + ) -> Trevm<'a, Ext, Db, NewState> + where + F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + { + let previous = self.inner.cfg().disable_balance_check; + self.disable_balance_check(); + let mut new = f(self); + new.inner.cfg_mut().disable_balance_check = previous; + new + } + + /// Disable block gas limits. This allows transactions to execute even if + /// they gas needs exceed the block gas limit. This is useful for + /// simulating large transactions like forge scripts. + #[cfg(feature = "optional_block_gas_limit")] + pub fn disable_block_gas_limit(&mut self) { + self.inner.cfg_mut().disable_beneficiary_reward = true + } + + /// Enable block gas limits. See [`Self::disable_block_gas_limit`]. + #[cfg(feature = "optional_block_gas_limit")] + pub fn enable_block_gas_limit(&mut self) { + self.inner.cfg_mut().disable_beneficiary_reward = false + } + + /// Run a closure with block gas limits disabled, then restore the previous + /// setting. + #[cfg(feature = "optional_block_gas_limit")] + pub fn without_block_gas_limit( + mut self, + f: F, + ) -> Trevm<'a, Ext, Db, NewState> + where + F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + { + let previous = self.inner.cfg().disable_block_gas_limit; + self.disable_block_gas_limit(); + let mut new = f(self); + new.inner.cfg_mut().disable_block_gas_limit = previous; + new + } + + /// Disable [EIP-3607]. This allows transactions to originate from accounts + /// that contain code. This is useful for simulating smart-contract calls. + /// + /// [EIP-3607]: https://eips.ethereum.org/EIPS/eip-3607 + #[cfg(feature = "optional_eip3607")] + pub fn disable_eip3607(&mut self) { + self.inner.cfg_mut().disable_eip3607 = true + } + + /// Enable [EIP-3607]. See [`Self::disable_eip3607`]. + /// + /// [EIP-3607]: https://eips.ethereum.org/EIPS/eip-3607 + #[cfg(feature = "optional_eip3607")] + pub fn enable_eip3607(&mut self) { + self.inner.cfg_mut().disable_eip3607 = false + } + + /// Run a closure with [EIP-3607] disabled, then restore the previous + /// setting. + #[cfg(feature = "optional_eip3607")] + pub fn without_eip3607(mut self, f: F) -> Trevm<'a, Ext, Db, NewState> + where + F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + { + let previous = self.inner.cfg().disable_eip3607; + self.disable_eip3607(); + let mut new = f(self); + new.inner.cfg_mut().disable_eip3607 = previous; + new + } + + /// Disables all gas refunds. This is useful when using chains that have + /// gas refunds disabled e.g. Avalanche. Reasoning behind removing gas + /// refunds can be found in [EIP-3298]. + /// By default, it is set to `false`. + /// + /// [EIP-3298]: https://eips.ethereum.org/EIPS/eip-3298 + #[cfg(feature = "optional_gas_refund")] + pub fn disable_gas_refund(&mut self) { + self.inner.cfg_mut().disable_gas_refund = true + } + + /// Enable gas refunds. See [`Self::disable_gas_refund`]. + #[cfg(feature = "optional_gas_refund")] + pub fn enable_gas_refund(&mut self) { + self.inner.cfg_mut().disable_gas_refund = false + } + + /// Run a closure with gas refunds disabled, then restore the previous + /// setting. + #[cfg(feature = "optional_gas_refund")] + pub fn without_gas_refund(mut self, f: F) -> Trevm<'a, Ext, Db, NewState> + where + F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + { + let previous = self.inner.cfg().disable_gas_refund; + self.disable_gas_refund(); + let mut new = f(self); + new.inner.cfg_mut().disable_gas_refund = previous; + new + } + + /// Disables [EIP-1559] base fee checks. This is useful for testing method + /// calls with zero gas price. + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + #[cfg(feature = "optional_no_base_fee")] + pub fn disable_base_fee(&mut self) { + self.inner.cfg_mut().disable_base_fee = true; + } + + /// Enable [EIP-1559] base fee checks. See [`Self::disable_base_fee`]. + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + #[cfg(feature = "optional_no_base_fee")] + pub fn enable_base_fee(&mut self) { + self.inner.cfg_mut().disable_base_fee = false + } + + /// Run a closure with [EIP-1559] base fee checks disabled, then restore the + /// previous setting. + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + #[cfg(feature = "optional_no_base_fee")] + pub fn without_base_fee(mut self, f: F) -> Trevm<'a, Ext, Db, NewState> + where + F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + { + let previous = self.inner.cfg().disable_base_fee; + self.disable_base_fee(); + let mut new = f(self); + new.inner.cfg_mut().disable_base_fee = previous; + new + } + + /// Disable the payout of the block and gas fees to the block beneficiary. + #[cfg(feature = "optional_beneficiary_reward")] + pub fn disable_beneficiary_reward(&mut self) { + self.inner.cfg_mut().disable_beneficiary_reward = true; + } + + /// Enable the payout of the block and gas fees to the block beneficiary. + /// See [`Self::disable_beneficiary_reward`]. + #[cfg(feature = "optional_beneficiary_reward")] + pub fn enable_beneficiary_reward(&mut self) { + self.inner.cfg_mut().disable_beneficiary_reward = false + } + + /// Run a closure with the block and gas fees payout disabled, then restore + /// the previous setting. + #[cfg(feature = "optional_beneficiary_reward")] + pub fn without_beneficiary_reward( + mut self, + f: F, + ) -> Trevm<'a, Ext, Db, NewState> + where + F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + { + let previous = self.inner.cfg().disable_beneficiary_reward; + self.disable_beneficiary_reward(); + let mut new = f(self); + new.inner.cfg_mut().disable_beneficiary_reward = previous; + new + } +} + +// --- NEEDS BLOCK + +impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState: NeedsBlock> + Trevm<'a, Ext, Db, TrevmState> +{ + /// Open a block, apply some logic, and return the EVM ready for the next + /// transaction. + /// + /// This is intended to be used for pre-block logic, such as applying + /// pre-block hooks introduced in [EIP-4788] or [EIP-2935]. + /// + /// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 + /// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935 + pub fn open_block( + mut self, + filler: &B, + mut context: C, + ) -> Result, EvmErrored<'a, Ext, Db, C>> + where + B: Block, + C: BlockContext, + Db: Database + DatabaseCommit, + { + let res = context.open_block(self.inner_mut_unchecked(), filler); + + match res { + Ok(_) => Ok(Trevm { inner: self.inner, state: NeedsTx(context) }), + Err(error) => Err(Trevm { inner: self.inner, state: ErroredState { context, error } }), + } + } + + /// Open a block and return the EVM ready for the next transaction. This is + /// a convenience API and uses [`BasicContext`] for the block context. + /// + /// This is a shortcut for `open_block(filler, BasicContext::default())`. + /// It will not perform any pre-block or post-block logic, and will not + /// produce transaction receipts. As such, this cannot be used to produce + /// real blocks on any network, and may produce inconsistent results when + /// applied on networks that require pre-block or post-block logic. + pub fn fill_block(self, filler: &B) -> EvmNeedsTx<'a, Ext, Db, BasicContext> { + self.open_block(filler, BasicContext) + .unwrap_or_else(|_| unreachable!("basic filler is infallible")) + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, Missing: HasOutputs> + Trevm<'a, Ext, State, Missing> +{ + /// Finish execution and return the outputs. + /// + /// ## Panics + /// + /// If the State has not been built with StateBuilder::with_bundle_update. + /// + /// See [`State::merge_transitions`] and [`State::take_bundle`]. + pub fn finish(self) -> BundleState + where + Db: Database + DatabaseCommit, + { + let Self { inner: mut evm, .. } = self; + + evm.db_mut().merge_transitions(BundleRetention::Reverts); + let bundle = evm.db_mut().take_bundle(); + + bundle + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, C> EvmBlockComplete<'a, Ext, Db, C> { + /// Destructure the EVM and return the block context and the EVM ready for + /// the next block. + pub fn take_context(self) -> (C, EvmNeedsNextBlock<'a, Ext, Db>) { + (self.state.0, EvmNeedsNextBlock { inner: self.inner, state: NeedsNextBlock::new() }) + } + + /// Discard the block context and return the EVM ready for the next block. + pub fn discard_context(self) -> EvmNeedsNextBlock<'a, Ext, Db> { + self.take_context().1 + } +} + +// --- NEEDS FIRST TX + +impl<'a, Ext, Db: Database + DatabaseCommit, C: BlockContext> EvmNeedsTx<'a, Ext, Db, C> { + /// Close the current block, applying some logic, and returning the EVM + /// ready for the next block. + /// + /// This is intended to be used for post-block logic, such as applying + /// post-block hooks introduced in [EIP-7002] or [EIP-7251]. + /// + /// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 + /// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 + pub fn close_block( + self, + ) -> Result, EvmErrored<'a, Ext, Db, C>> { + let Trevm { mut inner, state: NeedsTx(mut context) } = self; + + let res = context.close_block(&mut inner); + + inner.block_mut().clear(); + + match res { + Ok(_) => Ok(Trevm { inner, state: BlockComplete(context) }), + Err(error) => Err(Trevm { inner, state: ErroredState { context, error } }), + } + } + + /// Fill the transaction environment. + pub fn fill_tx(mut self, filler: &T) -> EvmReady<'a, Ext, Db, C> { + filler.fill_tx(&mut self.inner); + EvmReady { inner: self.inner, state: Ready(self.state.0) } + } + + /// Execute a transaction. Shortcut for `fill_tx(tx).run_tx()`. + pub fn run_tx( + self, + filler: &T, + ) -> Result, EvmErrored<'a, Ext, Db, C>> { + self.fill_tx(filler).run() + } + + /// Execute a transaction, accept the output, and ignore errors. + pub fn run_tx_ignore_err(self, filler: &T) -> Self { + match self.run_tx(filler) { + Ok(evm) => evm.accept(), + Err(evm) => evm.discard_error(), + } + } +} + +// --- READY + +impl<'a, Ext, Db: Database + DatabaseCommit, C: BlockContext> EvmReady<'a, Ext, Db, C> { + /// Clear the current transaction environment. + pub fn clear_tx(self) -> EvmNeedsTx<'a, Ext, Db, C> { + // NB: we do not clear the tx env here, as we may read it during `BlockContext::post_tx` + EvmNeedsTx { inner: self.inner, state: NeedsTx(self.state.0) } + } + + /// Execute the loaded transaction. + pub fn run(mut self) -> Result, EvmErrored<'a, Ext, Db, C>> { + let result = self.inner.transact(); + + let Trevm { inner, state: Ready(context) } = self; + + match result { + Ok(result) => Ok(Trevm { inner, state: TransactedState { context, result } }), + Err(error) => { + Err(EvmErrored { inner, state: ErroredState { context, error: error.into() } }) + } + } + } + + /// Execute the loaded transaction, accept the output, and ignore errors. + pub fn run_ignore_err(self) -> EvmNeedsTx<'a, Ext, Db, C> { + match self.run() { + Ok(evm) => evm.accept(), + Err(evm) => evm.discard_error(), + } + } +} + +// --- ERRORED + +impl<'a, Ext, Db: Database + DatabaseCommit, C: BlockContext, E> + EvmErrored<'a, Ext, Db, C, E> +{ + /// Get a reference to the error. + pub const fn error(&self) -> &E { + &self.state.error + } + + /// Inspect the error with a closure. + pub fn inspect_error(&self, f: F) -> T + where + F: FnOnce(&E) -> T, + { + f(self.error()) + } + + /// Discard the error and return the EVM. + pub fn discard_error(self) -> EvmNeedsTx<'a, Ext, Db, C> { + Trevm { inner: self.inner, state: NeedsTx(self.state.context) } + } + + /// Convert the error into an [`EVMError`]. + pub fn into_error(self) -> E { + self.state.error + } + + /// Reset the EVM, returning the error and the EVM ready for the next + /// transaction. + pub fn take_error(self) -> (EvmNeedsTx<'a, Ext, Db, C>, E) { + let Trevm { inner, state: ErroredState { context, error } } = self; + (Trevm { inner, state: NeedsTx(context) }, error) + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, C: BlockContext> + EvmErrored<'a, Ext, Db, C, EVMError> +{ + /// Check if the error is a transaction error. This is provided as a + /// convenience function for common cases, as Transaction errors should + /// usually be discarded. + pub const fn is_transaction_error(&self) -> bool { + matches!(self.state.error, EVMError::Transaction(_)) + } + + /// Fallible cast to a [`InvalidTransaction`]. + pub const fn as_transaction_err(&self) -> Option<&InvalidTransaction> { + match &self.state.error { + EVMError::Transaction(err) => Some(err), + _ => None, + } + } + + /// Discard the error if it is a transaction error, returning the EVM. If + /// the error is not a transaction error, return self + pub fn discard_transaction_error(self) -> Result, Self> { + if self.is_transaction_error() { + Ok(self.discard_error()) + } else { + Err(self) + } + } +} + +// --- TRANSACTED + +impl<'a, Ext, Db: Database + DatabaseCommit, C: BlockContext> AsRef + for EvmTransacted<'a, Ext, Db, C> +{ + fn as_ref(&self) -> &ResultAndState { + &self.state.result + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, C: BlockContext> AsRef + for EvmTransacted<'a, Ext, Db, C> +{ + fn as_ref(&self) -> &ExecutionResult { + &self.state.result.result + } +} + +impl<'a, Ext, Db: Database + DatabaseCommit, C: BlockContext> + EvmTransacted<'a, Ext, Db, C> +{ + /// Get a reference to the result. + pub fn result(&self) -> &ExecutionResult { + self.as_ref() + } + + /// Get a mutable reference to the result. Modification of the result is + /// discouraged, as it may lead to inconsistent state. + /// + /// This is primarily intended for use in [`SystemTx`] execution. + /// + /// [`SystemTx`]: crate::syscall::SystemTx + pub fn result_mut_unchecked(&mut self) -> &mut ExecutionResult { + &mut self.state.result.result + } + + /// Get a reference to the state. + pub const fn state(&self) -> &EvmState { + &self.state.result.state + } + + /// Get a mutable reference to the state. Modification of the state is + /// discouraged, as it may lead to inconsistent state. + pub fn state_mut_unchecked(&mut self) -> &mut EvmState { + &mut self.state.result.state + } + + /// Get a reference to the result and state. + pub fn result_and_state(&self) -> &ResultAndState { + self.as_ref() + } + + /// Get a mutable reference to the result and state. Modification of the + /// result and state is discouraged, as it may lead to inconsistent state. + /// + /// This is primarily intended for use in [`SystemTx`] execution. + /// + /// [`SystemTx`]: crate::syscall::SystemTx + pub fn result_and_state_mut_unchecked(&mut self) -> &mut ResultAndState { + &mut self.state.result + } + + /// Get the output of the transaction. This is the return value of the + /// outermost callframe. + pub fn output(&self) -> Option<&Bytes> { + self.result().output() + } + + /// Get the output of the transaction, and decode it as the return value of + /// a [`SolCall`]. If `validate` is true, the output will be type- and + /// range-checked. + /// + /// [`SolCall`]: alloy_sol_types::SolCall + pub fn output_sol( + &self, + validate: bool, + ) -> Option> + where + T::Return: alloy_sol_types::SolType, + { + self.output().map(|output| T::abi_decode_returns(output, validate)) + } + + /// Get the gas used by the transaction. + pub fn gas_used(&self) -> u64 { + self.state.result.result.gas_used() + } + + /// Discard the state changes and return the EVM. + pub fn reject(self) -> EvmNeedsTx<'a, Ext, Db, C> { + Trevm { inner: self.inner, state: NeedsTx(self.state.context) } + } + + /// Accept the state changes, invoking the [`BlockContext::after_tx`] + /// method, and return the EVM ready for the next transaction. + pub fn accept(self) -> EvmNeedsTx<'a, Ext, Db, C> { + let Trevm { mut inner, state: TransactedState { mut context, result } } = self; + + context.after_tx(&mut inner, result); + + Trevm { inner, state: NeedsTx(context) } + } + + /// Accept the state changes, skipping the [`BlockContext::after_tx`] + /// method, and committing them directly to the database. + /// + /// This is a low-level API, and is not intended for general use. It is + /// almost always better to use [`Self::accept`] instead. + pub fn accept_skip_context_unchecked(self) -> EvmNeedsTx<'a, Ext, Db, C> { + let Trevm { mut inner, state: TransactedState { context, result } } = self; + + inner.db_mut().commit(result.state); + + Trevm { inner, state: NeedsTx(context) } + } +} + +// Some code above and documentation is adapted from the revm crate, and is +// reproduced here under the terms of the MIT license. +// +// MIT License +// +// Copyright (c) 2021-2024 draganrakita +// +// 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. + +// Some code above is reproduced from `reth`. It is reused here under the MIT +// license. +// +// The MIT License (MIT) +// +// Copyright (c) 2022-2024 Reth Contributors +// +// 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. diff --git a/src/fill/alloy.rs b/src/fill/alloy.rs new file mode 100644 index 0000000..12f9db0 --- /dev/null +++ b/src/fill/alloy.rs @@ -0,0 +1,323 @@ +use alloy_consensus::Signed; +use alloy_primitives::U256; +use revm::primitives::{BlockEnv, TxEnv}; + +use crate::{Block, Tx}; + +impl Tx for Signed { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + *caller = self.recover_signer().unwrap(); + *gas_limit = self.tx().gas_limit as u64; + *gas_price = U256::from(self.tx().gas_price); + *transact_to = self.tx().to; + *value = self.tx().value; + *data = self.tx().input.clone(); + *nonce = Some(self.tx().nonce); + *chain_id = self.tx().chain_id; + access_list.clear(); + gas_priority_fee.take(); + blob_hashes.clear(); + max_fee_per_blob_gas.take(); + authorization_list.take(); + } +} + +impl Tx for Signed { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + *caller = self.recover_signer().unwrap(); + *gas_limit = self.tx().gas_limit as u64; + *gas_price = U256::from(self.tx().gas_price); + *transact_to = self.tx().to; + *value = self.tx().value; + *data = self.tx().input.clone(); + *nonce = Some(self.tx().nonce); + *chain_id = Some(self.tx().chain_id); + access_list.clone_from(&self.tx().access_list.0); + gas_priority_fee.take(); + blob_hashes.clear(); + max_fee_per_blob_gas.take(); + authorization_list.take(); + } +} + +impl Tx for Signed { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + *caller = self.recover_signer().unwrap(); + *gas_limit = self.tx().gas_limit as u64; + *gas_price = U256::from(self.tx().max_fee_per_gas); + *transact_to = self.tx().to; + *value = self.tx().value; + *data = self.tx().input.clone(); + *nonce = Some(self.tx().nonce); + *chain_id = Some(self.tx().chain_id); + access_list.clone_from(&self.tx().access_list.0); + *gas_priority_fee = Some(U256::from(self.tx().max_priority_fee_per_gas)); + blob_hashes.clear(); + max_fee_per_blob_gas.take(); + authorization_list.take(); + } +} + +impl Tx for Signed { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + *caller = self.recover_signer().unwrap(); + *gas_limit = self.tx().gas_limit as u64; + *gas_price = U256::from(self.tx().max_fee_per_gas); + *transact_to = self.tx().to.into(); + *value = self.tx().value; + *data = self.tx().input.clone(); + *nonce = Some(self.tx().nonce); + *chain_id = Some(self.tx().chain_id); + access_list.clone_from(&self.tx().access_list.0); + *gas_priority_fee = Some(U256::from(self.tx().max_priority_fee_per_gas)); + blob_hashes.clone_from(&self.tx().blob_versioned_hashes); + *max_fee_per_blob_gas = Some(U256::from(self.tx().max_fee_per_blob_gas)); + authorization_list.take(); + } +} + +impl Tx for Signed { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + *caller = self.recover_signer().unwrap(); + *gas_limit = self.tx().tx.gas_limit as u64; + *gas_price = U256::from(self.tx().tx.max_fee_per_gas); + *transact_to = self.tx().tx.to.into(); + *value = self.tx().tx.value; + *data = self.tx().tx.input.clone(); + *nonce = Some(self.tx().tx.nonce); + *chain_id = Some(self.tx().tx.chain_id); + access_list.clone_from(&self.tx().tx.access_list.0); + *gas_priority_fee = Some(U256::from(self.tx().tx.max_priority_fee_per_gas)); + blob_hashes.clone_from(&self.tx().tx.blob_versioned_hashes); + *max_fee_per_blob_gas = Some(U256::from(self.tx().tx.max_fee_per_blob_gas)); + authorization_list.take(); + } +} + +impl Tx for Signed { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + let tx = match self.tx() { + alloy_consensus::TxEip4844Variant::TxEip4844(tx) => tx, + alloy_consensus::TxEip4844Variant::TxEip4844WithSidecar(tx) => &tx.tx, + }; + *caller = self.recover_signer().unwrap(); + *gas_limit = tx.gas_limit as u64; + *gas_price = U256::from(tx.max_fee_per_gas); + *transact_to = tx.to.into(); + *value = tx.value; + *data = tx.input.clone(); + *nonce = Some(tx.nonce); + *chain_id = Some(tx.chain_id); + access_list.clone_from(&tx.access_list.0); + *gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); + blob_hashes.clone_from(&tx.blob_versioned_hashes); + *max_fee_per_blob_gas = Some(U256::from(tx.max_fee_per_blob_gas)); + authorization_list.take(); + } +} + +impl Tx for alloy_consensus::TxEnvelope { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + match self { + Self::Legacy(t) => t.fill_tx_env(tx_env), + Self::Eip2930(t) => t.fill_tx_env(tx_env), + Self::Eip1559(t) => t.fill_tx_env(tx_env), + Self::Eip4844(t) => t.fill_tx_env(tx_env), + _ => panic!("Unsupported transaction type"), + } + } +} + +impl Block for alloy_consensus::Header { + fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) { + let BlockEnv { + number, + coinbase, + timestamp, + gas_limit, + basefee, + difficulty, + prevrandao, + blob_excess_gas_and_price: _, + } = block_env; + *number = U256::from(self.number); + *coinbase = self.beneficiary; + *timestamp = U256::from(self.timestamp); + *gas_limit = U256::from(self.gas_limit); + *basefee = self.base_fee_per_gas.map_or_else(Default::default, U256::from); + + *difficulty = self.difficulty; + *prevrandao = if self.difficulty.is_zero() { Some(self.mix_hash) } else { None }; + + if let Some(excess_blob_gas) = self.excess_blob_gas { + block_env.set_blob_excess_gas_and_price(excess_blob_gas as u64); + } + } + + fn tx_count_hint(&self) -> Option { + None + } +} + +#[cfg(test)] +mod tests { + use crate::{NoopBlock, NoopCfg, TrevmBuilder}; + use alloy_consensus::{Header, TxEnvelope, EMPTY_ROOT_HASH}; + + use alloy_rlp::Decodable; + + use revm::{Evm, InMemoryDB}; + + #[test] + // Test vector from https://etherscan.io/tx/0xce4dc6d7a7549a98ee3b071b67e970879ff51b5b95d1c340bacd80fa1e1aab31 + fn test_live_tx_1559_fill() { + let raw_tx = alloy_primitives::hex::decode("02f86f0102843b9aca0085029e7822d68298f094d9e1459a7a482635700cbc20bbaf52d495ab9c9680841b55ba3ac080a0c199674fcb29f353693dd779c017823b954b3c69dffa3cd6b2a6ff7888798039a028ca912de909e7e6cdef9cdcaf24c54dd8c1032946dfa1d85c206b32a9064fe8").unwrap(); + let tx = TxEnvelope::decode(&mut raw_tx.as_slice()).unwrap(); + + let _ = Evm::builder() + .with_db(InMemoryDB::default()) + .build_trevm() + .fill_cfg(&NoopCfg) + .fill_block(&NoopBlock) + .fill_tx(&tx); + } + + #[test] + // Test vector from https://etherscan.io/tx/0x280cde7cdefe4b188750e76c888f13bd05ce9a4d7767730feefe8a0e50ca6fc4 + fn test_live_tx_legacy_fill() { + let raw_tx = alloy_primitives::hex::decode("f9015482078b8505d21dba0083022ef1947a250d5630b4cf539739df2c5dacb4c659f2488d880c46549a521b13d8b8e47ff36ab50000000000000000000000000000000000000000000066ab5a608bd00a23f2fe000000000000000000000000000000000000000000000000000000000000008000000000000000000000000048c04ed5691981c42154c6167398f95e8f38a7ff00000000000000000000000000000000000000000000000000000000632ceac70000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006c6ee5e31d828de241282b9606c8e98ea48526e225a0c9077369501641a92ef7399ff81c21639ed4fd8fc69cb793cfa1dbfab342e10aa0615facb2f1bcf3274a354cfe384a38d0cc008a11c2dd23a69111bc6930ba27a8").unwrap(); + let tx = TxEnvelope::decode(&mut raw_tx.as_slice()).unwrap(); + + let _ = Evm::builder() + .with_db(InMemoryDB::default()) + .build_trevm() + .fill_cfg(&NoopCfg) + .fill_block(&NoopBlock) + .fill_tx(&tx); + } + + #[test] + // Test vector from https://sepolia.etherscan.io/tx/0x9a22ccb0029bc8b0ddd073be1a1d923b7ae2b2ea52100bae0db4424f9107e9c0 + // Blobscan: https://sepolia.blobscan.com/tx/0x9a22ccb0029bc8b0ddd073be1a1d923b7ae2b2ea52100bae0db4424f9107e9c0 + fn test_live_tx_4844_fill() { + let raw_tx = alloy_primitives::hex::decode("0x03f9011d83aa36a7820fa28477359400852e90edd0008252089411e9ca82a3a762b4b5bd264d4173a242e7a770648080c08504a817c800f8a5a0012ec3d6f66766bedb002a190126b3549fce0047de0d4c25cffce0dc1c57921aa00152d8e24762ff22b1cfd9f8c0683786a7ca63ba49973818b3d1e9512cd2cec4a0013b98c6c83e066d5b14af2b85199e3d4fc7d1e778dd53130d180f5077e2d1c7a001148b495d6e859114e670ca54fb6e2657f0cbae5b08063605093a4b3dc9f8f1a0011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e654901a0c8de4cced43169f9aa3d36506363b2d2c44f6c49fc1fd91ea114c86f3757077ea01e11fdd0d1934eda0492606ee0bb80a7bf8f35cc5f86ec60fe5031ba48bfd544").unwrap(); + let tx = TxEnvelope::decode(&mut raw_tx.as_slice()).unwrap(); + + let _ = Evm::builder() + .with_db(InMemoryDB::default()) + .build_trevm() + .fill_cfg(&NoopCfg) + .fill_block(&NoopBlock) + .fill_tx(&tx); + } + + #[test] + fn test_header_fill() { + let raw = r#"{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","withdrawalsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x0","gasUsed":"0x0","timestamp":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1","extraData":"0x"}"#; + let header = Header { + base_fee_per_gas: Some(1), + withdrawals_root: Some(EMPTY_ROOT_HASH), + ..Default::default() + }; + + let json = serde_json::to_string(&header).unwrap(); + assert_eq!(json, raw); + + // Fill using the constructed header + let _ = Evm::builder() + .with_db(InMemoryDB::default()) + .build_trevm() + .fill_cfg(&NoopCfg) + .fill_block(&header); + } +} diff --git a/src/fill/mod.rs b/src/fill/mod.rs new file mode 100644 index 0000000..6c33032 --- /dev/null +++ b/src/fill/mod.rs @@ -0,0 +1,9 @@ +mod alloy; + +mod traits; +pub use traits::{Block, Cfg, Tx}; + +mod noop; +pub use noop::{NoopBlock, NoopCfg}; + +mod zenith; diff --git a/src/fill/noop.rs b/src/fill/noop.rs new file mode 100644 index 0000000..8494275 --- /dev/null +++ b/src/fill/noop.rs @@ -0,0 +1,19 @@ +use revm::primitives::{BlockEnv, CfgEnv}; + +use crate::{Block, Cfg}; + +/// A no-op block filler. +#[derive(Debug)] +pub struct NoopBlock; + +impl Block for NoopBlock { + fn fill_block_env(&self, _: &mut BlockEnv) {} +} + +/// A no-op configuration filler. +#[derive(Debug)] +pub struct NoopCfg; + +impl Cfg for NoopCfg { + fn fill_cfg_env(&self, _: &mut CfgEnv) {} +} diff --git a/src/fill/traits.rs b/src/fill/traits.rs new file mode 100644 index 0000000..eedcf9e --- /dev/null +++ b/src/fill/traits.rs @@ -0,0 +1,121 @@ +use revm::{ + primitives::{BlockEnv, CfgEnv, TxEnv}, + Database, Evm, +}; + +/// Types that can fill the EVM transaction environment [`TxEnv`]. +pub trait Tx { + /// Fill the transaction environment. + /// + /// ## Note: + /// + /// It is generally expected that the filler will fill (or at least + /// inspect) ALL fields of the transaction environment. This is because + /// the EVM will NOT clear the transaction environment between + /// transactions. If the filler does not fill a field, it will be left + /// unchanged from the previous transaction. + fn fill_tx_env(&self, tx_env: &mut TxEnv); + + /// Fill the transaction environment on the EVM. + fn fill_tx(&self, evm: &mut Evm<'_, Ext, Db>) { + let tx_env: &mut TxEnv = evm.tx_mut(); + self.fill_tx_env(tx_env); + } +} +/// Types that can fill the EVM block environment [`BlockEnv`]. +pub trait Block { + /// Fill the block environment. + /// + /// ## Note: + /// + /// It is generally expected that the filler will fill (or at least + /// inspect) ALL fields of the block environment. This is because the EVM + /// will NOT clear the block environment between blocks. If the filler does + /// not fill a field, it will be left unchanged from the previous block. + fn fill_block_env(&self, block_env: &mut BlockEnv); + + /// Fill the block environment on the EVM. + fn fill_block(&self, evm: &mut Evm<'_, Ext, Db>) { + let block_env: &mut BlockEnv = evm.block_mut(); + self.fill_block_env(block_env); + } + + /// Get the transaction count hint from the filler. This can be used for + /// memory pre-allocation during block execution. + fn tx_count_hint(&self) -> Option { + None + } +} + +/// Types that can fill the EVM configuration environment [`CfgEnv`]. +/// +/// Because the CFG env has quite a few conditionally compiled properties, it +/// is recommended to use the default implementation of `fill_cfg_env` to ensure +/// that fields are filled only when appropriate. +/// +/// Note that the following properties on [`CfgEnv`] are feature-gated: +/// - `kzg_settings` - gated by `c-kzg` +/// - `memory_limit` - gated by `memory_limit` +/// - `disable_balance_check` - gated by `optional_balance_check` +/// - `disable_block_gas_limit` - gated by `optional_block_gas_limit` +/// - `disable_eip3607` - gated by `optional_eip3607` +/// - `disable_gas_refund` - gated by `optional_gas_refund` +/// - `disable_base_fee` - gated by `optional_no_base_fee` +/// - `disable_beneficiary_reward` - gated by `optional_beneficiary_reward` +/// +/// Cfg fillers should consider these feature gates when implementing the trait. +pub trait Cfg { + /// Fill the configuration environment. + fn fill_cfg_env(&self, cfg_env: &mut CfgEnv); + + /// Fill the configuration environment on the EVM. + fn fill_cfg(&self, evm: &mut Evm<'_, Ext, Db>) { + let cfg_env: &mut CfgEnv = evm.cfg_mut(); + self.fill_cfg_env(cfg_env); + } +} + +#[cfg(test)] +mod test { + use alloy_consensus::constants::GWEI_TO_WEI; + use alloy_primitives::{B256, U256}; + use revm::primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv}; + + use super::*; + + impl Block for () { + fn fill_block_env(&self, block_env: &mut BlockEnv) { + let BlockEnv { + number, + coinbase, + timestamp, + gas_limit, + basefee, + difficulty, + prevrandao, + blob_excess_gas_and_price, + } = block_env; + *number = U256::from(1); + *coinbase = Default::default(); + *timestamp = U256::from(1720450148); // Time when I was writing the test code + *gas_limit = U256::from(30_000_000); + *basefee = U256::from(5 * GWEI_TO_WEI); + + let diff = B256::repeat_byte(0xab); + *prevrandao = Some(diff); + *difficulty = U256::from_be_bytes(diff.into()); + *blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(1_000_000)); + } + + fn tx_count_hint(&self) -> Option { + None + } + } + + impl Cfg for () { + fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) { + let CfgEnv { chain_id, .. } = cfg_env; + *chain_id = 1; + } + } +} diff --git a/src/fill/zenith.rs b/src/fill/zenith.rs new file mode 100644 index 0000000..8c697cd --- /dev/null +++ b/src/fill/zenith.rs @@ -0,0 +1,43 @@ +use crate::Tx; +use alloy_primitives::U256; +use revm::primitives::{TransactTo, TxEnv}; +use zenith_types::Transactor; + +impl Tx for Transactor::Transact { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + // destructuring here means that any changes to the fields will result + // in breaking changes here, ensuring that they never silently add new + // fields + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + + *caller = self.sender; + *gas_limit = self.gas.as_limbs()[0]; + *gas_price = self.maxFeePerGas; + *gas_priority_fee = Some(U256::ZERO); + *transact_to = TransactTo::Call(self.to); + *value = self.value; + *data = self.data.clone(); + *chain_id = Some(self.rollup_chain_id()); + // This causes nonce validation to be skipped. i.e. the Transact event + // will always use the next available nonce + *nonce = None; + *access_list = vec![]; + blob_hashes.clear(); + max_fee_per_blob_gas.take(); + authorization_list.take(); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a8262fc --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,443 @@ +//! [`Trevm`] - a typestate interface to [`revm`]. +//! +//! Tevm provides a safe and low-overhead way to interact with the EVM. It is +//! based on the [typestate pattern], which allows the compiler to enforce +//! correct usage of the EVM. +//! +//! Tevm is NOT an EVM implementation. It is a thin wrapper around the EVM +//! provided by [`revm`]. +//! +//! [`Trevm`] models the EVM as a state machine with the following states: +//! +//! - [`EvmNeedsCfg`]: The EVM needs to be configured. +//! - [`EvmNeedsFirstBlock`]: The EVM is configured and needs a block +//! environment. +//! - [`EvmNeedsTx`]: The EVM is configured and has a block environment, and +//! now needs a transaction to execute. +//! - [`EvmReady`]: The EVM has a transaction loaded and is ready to execute it. +//! - [`EvmErrored`]: The EVM has executed a transaction and encountered an +//! error. +//! - [`EvmTransacted`]: The EVM has executed a transaction successfully. +//! - [`EvmBlockComplete`]: The EVM has executed and closed a block and contains +//! some a populated [`BlockContext`] object +//! - [`EvmNeedsNextBlock`]: The EVM has executed a transaction (or several +//! transactions) successfully and the block has been closed. The EVM is now +//! ready to open the next block, or to yield its outputs. +//! +//! ## Quickstart +//! +//! To get started, use a [`revm::EvmBuilder`] to configure the EVM, then call +//! [`TrevmBuilder::build_trevm`] to construct the [`Trevm`] instance. From +//! there, you should do the following: +//! +//! - Fill a Cfg by calling [`Trevm::fill_cfg`] with a [`Cfg`]. +//! - Open a block by calling [`Trevm::open_block`] with a [`Block`]. +//! - Fill a Tx by calling [`Trevm::fill_tx`] with a [`Tx`]. +//! - Run the transaction by calling [`Trevm::run_tx`]. +//! - Handle the result by calling [`EvmTransacted::accept`] or +//! [`EvmTransacted::reject`]. +//! - Call [`Trevm::close_block`] to close the block. +//! - Call[ [`Trevm::take_context`] to get the context object or +//! [`Trevm::discard_context`] to drop it. +//! - Then call [`Trevm::finish`] to get the outputs. +//! +//! +//! ### Running a transaction +//! +//! Running transactions is simple with Trevm. Here's a basic example: +//! +//! ``` +//! use revm::{EvmBuilder, db::InMemoryDB}; +//! use trevm::{TrevmBuilder, EvmErrored, Cfg, Block, Tx, }; +//! +//! # fn t(cfg: &C, block: &B, tx: &T) +//! # -> Result<(), Box> { +//! EvmBuilder::default() +//! .with_db(InMemoryDB::default()) +//! .build_trevm() +//! .fill_cfg(cfg) +//! .fill_block(block) +//! .run_tx(tx); +//! # Ok(()) +//! # } +//! ``` +//! If you get stuck, don't worry! You _cannot_ invoke the wrong function or +//! mess up the inner state unless you access a method marked `_unchecked`. +//! While the states and generics may seem intimidating at first, they fade +//! into the background when you start writing your application. +//! +//! ## Writing an application +//! +//! When writing your code, we strongly recommend using the `Evm____` type +//! aliases to simplify your code. +//! +//! We also recommend defining concrete types for `Ext` and `Db` whenever +//! possible, to simplify your code and remove bounds. Most users will want +//! `()` for `Ext`, unless specifically using an inspector or a customized EVM. +//! +//! To help you use concrete types, we provide the [`trevm_aliases`] macro. This +//! macro generates type aliases for the Trevm states with a concrete `Ext` and +//! +//! ``` +//! use trevm::trevm_aliases; +//! use revm::db::InMemoryDB; +//! +//! // produces types that look like this: +//! // type EvmNeedsCfg = trevm::EvmNeedsCfg<'static, (), InMemoryDB>; +//! trevm_aliases!(revm::db::InMemoryDB); +//! ``` +//! +//! ### [`BlockContext`] +//! +//! Trevm handles transaction application, receipts, and pre- and post-block +//! logic through the [`BlockContext`] trait. The [`BlockContext`] trait is +//! invoked by [`Trevm`] to manage the lifecycle of a single block. At the start +//! of a block, the context is opened with [`BlockContext::open_block`], and at +//! the end of the block, the context is closed with +//! [`BlockContext::close_block`]. After each transaction, the context's +//! [`BlockContext::after_tx`] logic controls how and whether the execution +//! result is applied to the EVM state, and handles per-transaction logic like +//! generating receipts and tracking senders. +//! +//! Trevm provides a few block context implementations: +//! +//! - [`Shanghai`]: Shanghai context applies the post-block system +//! action (withdrawals) introduced by [EIP-4895]. +//! - [`Cancun`]: Cancun context applies the [`Shanghai`] +//! as well as the post-block logic introduced by [EIP-4788]. +//! - [`Prague`]: Prague context applies [`Shanghai`] and +//! [`Cancun`] as well as the pre-block logic of [EIP-2935], the +//! post-block logic introduced by [EIP-7002] and [EIP-7251], and the +//! withdrawal request accumulation logic introduced in [EIP-6110]. +//! - [`BasicContext`]: Basic context applies no pre- or post-block logic, and +//! is useful for testing or for applications that do not require the +//! real system state. +//! +//! Contexts before Shanghai are not currently implemented. In particular, +//! block and ommer rewards for pre-merge blocks are not implemented. +//! +//! The [`BlockContext`] trait methods take a mutable reference to allow the +//! context to accumulate information about the execution. This is useful for +//! accumulating receipts, senders, or other information that is more readily +//! available during execution. It is also useful for pre-block logic, where +//! the lifecycle may need to accumulate information about the block before the +//! first transaction is executed, and re-use that information to close the +//! block. It may also be used to compute statistics or indices that are only +//! available after the block is closed. +//! +//! ``` +//! # use revm::{EvmBuilder, db::InMemoryDB}; +//! # use trevm::{TrevmBuilder, EvmErrored, Cfg, Block, Tx, +//! # Shanghai, Cancun}; +//! # use alloy_primitives::B256; +//! # fn t(cfg: &C, block: &B, tx: &T) +//! # -> Result<(), Box> { +//! // Contexts manage the lifecycle of a single block +//! let mut context = Cancun::<'static> { +//! parent_beacon_root: B256::repeat_byte(0x42), +//! shanghai: Shanghai::default(), +//! }; +//! +//! let (context, trevm) = EvmBuilder::default() +//! .with_db(InMemoryDB::default()) +//! .build_trevm() +//! .fill_cfg(cfg) +//! // The pre-block logic is applied here +//! .open_block(block, context) +//! // Note that the logic is fallible, so we have to handle errors +//! .map_err(EvmErrored::into_error)? +//! .run_tx(tx) +//! .map_err(EvmErrored::into_error)? +//! .accept() +//! // Closing the block applies the post-block logic, and is also fallible +//! .close_block() +//! .map_err(EvmErrored::into_error)? +//! // This splits the context, and puts trevm into `EvmNeedsNextBlock` +//! .take_context(); +//! # Ok(()) +//! # } +//! ``` +//! +//! ### Handling execution errors +//! +//! Trevm uses the [`EvmErrored`] state to handle errors during transaction +//! execution. This type is a wrapper around the error that occurred, and +//! provides a method to discard the error and continue execution. This is +//! useful when you want to continue executing transactions even if one fails. +//! +//! Usually, errors will be [`EVMError`], but [`BlockContext`] +//! implementations may return other errors. The [`EvmErrored`] type is +//! generic over the error type, so you can use it with any error type. +//! +//! ``` +//! # use revm::{EvmBuilder, db::InMemoryDB}; +//! # use trevm::{TrevmBuilder, EvmErrored, Cfg, Block, Tx, +//! # Shanghai, Cancun}; +//! # use alloy_primitives::B256; +//! # fn t(cfg: &C, block: &B, tx: &T) +//! # -> Result<(), Box> { +//! // Contexts manage the lifecycle of a single block +//! let mut context = Cancun::<'static> { +//! parent_beacon_root: B256::repeat_byte(0x42), +//! shanghai: Shanghai::default(), +//! }; +//! +//! match EvmBuilder::default() +//! .with_db(InMemoryDB::default()) +//! .build_trevm() +//! .fill_cfg(cfg) +//! // The pre-block logic is applied here +//! .open_block(block, context) { +//! Ok(trevm) => { +//! trevm +//! } +//! Err(transacted_error) => { +//! let (trevm, error) = transacted_error.take_error(); +//! // Handle the error here, and return the EVM if you want +//! // to keep going +//! trevm +//! } +//! }; +//! # Ok(()) +//! # } +//! ``` +//! +//! ### Extending Trevm +//! +//! Trevm has a few extension points: +//! +//! - Build the [`revm::Evm`] with a [`revm::Inspector`] and use it in trevm. +//! - Implement the [`PostTx`] trait to apply post-transaction logic/changes. +//! - Implement your own [`Cfg`], [`Block`], and +//! [`Tx`] to fill the EVM from your own data structures. +//! - Implement your own [`BlockContext`] to apply pre- and post-block logic, +//! use custom receipt types, or more. +//! +//! ``` +//! # use trevm::Tx; +//! # use alloy_primitives::Address; +//! // You can implement your own Tx to fill the EVM environment with your own +//! // data. +//! pub struct MyTx; +//! +//! impl Tx for MyTx { +//! fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { +//! // fill the tx_env with your data +//! // we recommend destructuring here to safeguard against future changes +//! // to the TxEnv struct +//! let revm::primitives::TxEnv { +//! caller, +//! .. +//! } = tx_env; +//! *caller = Address::repeat_byte(0xde); +//! } +//! } +//! ``` +//! +//! ### Trevm feature flags +//! +//! Trevm passes through most feature flags from revm, the following are on by +//! default: +//! +//! - `c-kzg` - Enable KZG precompiles as specced for [EIP-4844]. +//! - `blst` - Enable BLST precompiles as speced for [EIP-2537]. +//! - `portable` - Compiles BLST in portable mode. +//! - `secp256k1` - Use libsecp256k1 for ecrecover (default is k256). +//! +//! Cfg features: +//! - `memory_limit` - Allow users to limit callframe memory usage. +//! - `optional_balance_check` - Allow transacting with insufficient balance. +//! - `optional_block_gas_limit` - Allow transactions that exceed the block gas +//! limit. +//! - `optional_eip3607` - Allow transactions whose sender account has contract +//! code. +//! - `optional_gas_refund` - Allow disabling gas refunds, as in Avalanche. +//! - `optional_no_base_fee` - Allow disabling basefee checks. +//! - `optional_beneficiary_reward` - Allow disabling fees and rewards paid to +//! the block beneficiary. +//! +//! - `dev` - Enable all Cfg features. +//! +//! Trevm also provides the following: +//! +//! - `test-utils` - activates revm's `test-utils` feature, and provides +//! convenience functions for instantiating [`Trevm`] with an in-memory DB. +//! +//! ### Testing using Trevm +//! +//! Trevm provides a `test-utils` module for easy testing. The test-utils gives +//! you access to an in-memory clean-slate [`Trevm`] instance, as well as tools +//! for directly modifying the state of the EVM. +//! +//! During testing you can use +//! - set balance, nonce, codehash for any account +//! - a single-function setup for a blank EVM +//! - pre-funding for any number of accounts +//! ## Understanding the state machine +//! +//! Here's an example, with states written out: +//! +//! ``` +//! # use revm::{EvmBuilder, db::{InMemoryDB, BundleState}, State, +//! # StateBuilder}; +//! # use trevm::{TrevmBuilder, EvmErrored, Cfg, Block, Tx, BlockOutput, +//! # EvmNeedsCfg, EvmNeedsFirstBlock, EvmNeedsTx, EvmReady, EvmNeedsNextBlock, +//! # EvmBlockComplete, Shanghai, EvmTransacted}; +//! # fn t(cfg: &C, block: &B, tx: &T) +//! # -> Result<(), Box> { +//! let state = StateBuilder::new_with_database(InMemoryDB::default()).build(); +//! +//! // Trevm starts in `EvmNeedsCfg`. +//! let trevm: EvmNeedsCfg<'_, _, _> = EvmBuilder::default() +//! .with_db(state) +//! .build_trevm(); +//! +//! // Once the cfg is filled, we move to `EvmNeedsFirstBlock`. +//! let trevm: EvmNeedsFirstBlock<'_, _, _> = trevm.fill_cfg(cfg); +//! +//! // Filling the block gets us to `EvmNeedsTx`. `open_block` takes a +//! // context object that will apply pre- and post-block logic, accumulate +//! // receipts, and perform other lifecycle tasks. +//! let trevm: EvmNeedsTx<'_, _, _, _> = trevm.open_block( +//! block, +//! Shanghai::default() +//! ).map_err(EvmErrored::into_error)?; +//! // Filling the tx gets us to `EvmReady`. +//! let trevm: EvmReady<'_, _, _, _> = trevm.fill_tx(tx); +//! +//! let res: Result< +//! EvmTransacted<'_, _, _, _>, +//! EvmErrored<'_, _, _, _>, +//! > = trevm.run(); +//! +//! +//! // Applying the tx or ignoring the error gets us back to `EvmNeedsTx`. +//! // You could also make additional checks and discard the success result here +//! let trevm: EvmNeedsTx<'_, _, _, _> = match res { +//! Ok(trevm) => trevm.accept(), +//! Err(e) => e.discard_error(), +//! }; +//! +//! // Clearing or closing a block gets us to `EvmNeedsNextBlock`, ready for the +//! // next block. +//! let trevm: EvmBlockComplete<'_, _, _, _> = trevm +//! .close_block() +//! .map_err(EvmErrored::into_error)?;; +//! +//! // During block execution, a context object +//! let (context, trevm): (Shanghai<'_>, EvmNeedsNextBlock<'_, _, _>) = trevm +//! .take_context(); +//! +//! // Finishing the EVM gets us the final changes and a list of block outputs +//! // that includes the transaction receipts. +//! let bundle: BundleState = trevm.finish(); +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Happy Path Loop +//! +//! The most simple, straightforward application of Tevm is applying a +//! set of transaction to the EVM. This is done by following : +//! +//! ```none +//! +-----+ +-----------+ +//! |Start| ---> |EvmNeedsCfg| +//! +-----+ +-----------+ +//! | +--------------------+ +//! +-- fill_cfg() -------> | EvmNeedsFirstBlock | +//! +--------------------+ +//! | +//! +----------------+ | +//! +-- |EvmBlockComplete|--take_context()-+ | +//! | +----------------+ or discard | | +//! | ^ V | +//! | | +-----------------+ | +//! finish() | |EvmNeedsNextBlock|------+ +//! | close_block() +-----------------+ | +//! V | | +//! +------+ +----------+ | +//! |Finish| |EvmNeedsTx| <------ open_block() -----------+ +//! +------+ +----------+ +//! ^ | +--------+ +//! | +------- fill_tx() -------> |EvmReady|--+ +//! | +--------+ | +//! | +-------------+ | +//! +- accept() --|EvmTransacted| <-- run_tx() -----+ +//! or reject() +-------------+ +//! ``` +//! +//! A basic block loop should look like this: +//! +//! ```no_compile +//! let mut evm = evm +//! .fill_cfg(cfg); +//! .open_block(block, pre_block_logic); +//! +//! for tx in txs { +//! // apply the transaction, discard the error if any +//! evm = match evm.run_tx(tx); +//! } +//! +//! // close out the EVM, getting the final state +//! let (bundle, outputs) = evm.close_block(block, post_block_logic).finish(); +//! ``` +//! +//! [`EVMError`]: revm::primitives::EVMError +//! [typestate pattern]: https://cliffle.com/blog/rust-typestate/ +//! [crate readme]: https://github.com/init4tt/trevm +//! [EIP-2537]: https://eips.ethereum.org/EIPS/eip-2537 +//! [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 +//! [EIP-4895]: https://eips.ethereum.org/EIPS/eip-4895 +//! [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 +//! [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg", + html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +mod evm; +pub use evm::Trevm; + +mod fill; +pub use fill::{Block, Cfg, NoopBlock, NoopCfg, Tx}; + +mod lifecycle; +pub use lifecycle::{ + BasicContext, BlockContext, BlockOutput, Cancun, PostTx, PostflightResult, Prague, Shanghai, +}; + +mod states; +pub(crate) use states::sealed::*; +pub use states::{ + EvmBlockComplete, EvmErrored, EvmNeedsCfg, EvmNeedsFirstBlock, EvmNeedsNextBlock, EvmNeedsTx, + EvmReady, EvmTransacted, +}; + +pub mod syscall; + +pub use revm; + +/// Utilities for testing Trevm or testing with Trevm. +#[cfg(feature = "test-utils")] +pub mod test_utils; + +use revm::{Database, DatabaseCommit, EvmBuilder}; + +/// Ext trait for [`EvmBuilder`] that builds a [`Trevm`]. +pub trait TrevmBuilder<'a, Ext, Db: Database + DatabaseCommit> { + /// Builds the [`Trevm`]. + fn build_trevm(self) -> EvmNeedsCfg<'a, Ext, Db>; +} + +impl<'a, Stage, Ext, Db: Database + DatabaseCommit> TrevmBuilder<'a, Ext, Db> + for EvmBuilder<'a, Stage, Ext, Db> +{ + /// Builds the [`Trevm`]. + fn build_trevm(self) -> EvmNeedsCfg<'a, Ext, Db> { + Trevm::from(self.build()) + } +} diff --git a/src/lifecycle/contexts.rs b/src/lifecycle/contexts.rs new file mode 100644 index 0000000..b6514dc --- /dev/null +++ b/src/lifecycle/contexts.rs @@ -0,0 +1,790 @@ +use crate::{ + syscall::{ + eip6110, eip7002::WITHDRAWAL_REQUEST_BYTES, eip7251::CONSOLIDATION_REQUEST_BYTES, + execute_system_tx, SystemTx, + }, + Block, BlockContext, BlockOutput, +}; +use alloy_consensus::{Receipt, ReceiptEnvelope, Request, TxReceipt}; +use alloy_eips::{ + eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}, + eip4895::Withdrawal, + eip7002::WithdrawalRequest, + eip7251::ConsolidationRequest, +}; +use alloy_primitives::{Bloom, Log, B256, U256}; +use alloy_sol_types::SolEvent; +use revm::{ + primitives::{ + Account, AccountInfo, AccountStatus, Bytecode, EVMError, EvmStorageSlot, ExecutionResult, + ResultAndState, SpecId, BLOCKHASH_SERVE_WINDOW, + }, + Database, DatabaseCommit, Evm, +}; +use std::{collections::HashMap, sync::OnceLock}; + +/// A context that performs the fewest meaingful actions. Specifically, it +/// fills the block, and applies transactions to the EVM db. It does not apply +/// any pre- or post-block actions. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +pub struct BasicContext; + +impl BlockContext for BasicContext { + type Error = EVMError; + + fn open_block( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + b: &B, + ) -> Result<(), Self::Error> { + b.fill_block(evm); + Ok(()) + } + + fn after_tx(&mut self, evm: &mut Evm<'_, Ext, Db>, result: revm::primitives::ResultAndState) { + evm.db_mut().commit(result.state); + } + + fn close_block(&mut self, _evm: &mut Evm<'_, Ext, Db>) -> Result<(), Self::Error> { + Ok(()) + } +} + +/// Shanghai lifecycle. This applies the [EIP-4895] post-block system action. +/// +/// [EIP-4895]: https://eips.ethereum.org/EIPS/eip-4895 +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct Shanghai<'a> { + /// The withdrawals to be processed. + pub withdrawals: &'a [Withdrawal], + + /// The block outputs. + outputs: BlockOutput, +} + +impl<'a> From<&'a [Withdrawal]> for Shanghai<'a> { + fn from(withdrawals: &'a [Withdrawal]) -> Self { + Self { withdrawals, outputs: Default::default() } + } +} + +impl BlockContext for Shanghai<'_> { + type Error = EVMError; + + fn open_block( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + b: &B, + ) -> Result<(), Self::Error> { + if let Some(hint) = b.tx_count_hint() { + self.outputs.reserve(hint); + } + b.fill_block(evm); + Ok(()) + } + + fn after_tx(&mut self, evm: &mut Evm<'_, Ext, Db>, result: ResultAndState) { + let sender = evm.tx().caller; + + let receipt = self.make_receipt(result.result).into(); + + let tx_env = evm.tx(); + + // Determine the receipt envelope type based on the transaction type. + let receipt = if !tx_env.blob_hashes.is_empty() { + ReceiptEnvelope::Eip4844(receipt) + } else if tx_env.gas_priority_fee.is_some() { + ReceiptEnvelope::Eip1559(receipt) + } else if !tx_env.access_list.is_empty() { + ReceiptEnvelope::Eip2930(receipt) + } else { + ReceiptEnvelope::Legacy(receipt) + }; + + evm.db_mut().commit(result.state); + self.outputs.push_result(receipt, sender); + } + + fn close_block(&mut self, evm: &mut Evm<'_, Ext, Db>) -> Result<(), Self::Error> { + self.apply_withdrawals(evm)?; + Ok(()) + } +} + +impl<'a> Shanghai<'a> { + /// Instantiate a new Shanghai context. + pub fn new(withdrawals: &'a [Withdrawal]) -> Self { + Self { withdrawals, outputs: Default::default() } + } + + /// Destroy the Shanghai context and return the withdrawals and block + /// outputs. + pub fn into_parts(self) -> (&'a [Withdrawal], BlockOutput) { + (self.withdrawals, self.outputs) + } +} + +impl Shanghai<'_> { + /// Cumulative gas used in the block so far. + pub fn cumulative_gas_used(&self) -> u128 { + self.outputs.cumulative_gas_used() + } + + /// Make a receipt from the execution result. + pub fn make_receipt(&self, result: ExecutionResult) -> Receipt { + let cumulative_gas_used = + self.cumulative_gas_used().saturating_add(result.gas_used() as u128); + Receipt { + status: result.is_success().into(), + cumulative_gas_used, + logs: result.into_logs(), + } + } + + /// Apply the withdrawals to the EVM state. + pub fn apply_withdrawals( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + ) -> Result<(), >::Error> + where + Db: Database + DatabaseCommit, + { + // We need to apply the withdrawals by incrementing the balances of the + // respective accounts, then committing the changes to the database. + let mut changes = HashMap::new(); + + let increments = self + .withdrawals + .iter() + .map(|withdrawal| (withdrawal.address, withdrawal.amount as u128)) + .filter(|(_, amount)| *amount != 0); + + for (address, amount) in increments { + let mut info = match evm.db_mut().basic(address) { + Ok(account) => account.unwrap_or_default(), + Err(error) => return Err(EVMError::Database(error)), + }; + info.balance = info.balance.saturating_add(U256::from(amount)); + changes.insert( + address, + Account { info, status: AccountStatus::Touched, ..Default::default() }, + ); + } + evm.db_mut().commit(changes); + + Ok(()) + } + + /// Get the block outputs. This contains receipts and senders. + pub const fn outputs(&self) -> &BlockOutput { + &self.outputs + } + + /// Get the receipts produced in the block. + pub fn receipts(&self) -> &[ReceiptEnvelope] { + self.outputs.receipts() + } + + /// Get the logs produced in the block. + pub fn logs(&self) -> impl Iterator { + self.outputs.logs() + } + + /// Calculate the bloom filter for the block. + pub fn bloom(&self) -> &Bloom { + static BLOOM: OnceLock = OnceLock::new(); + + BLOOM.get_or_init(|| { + let mut bloom: Bloom = Bloom::default(); + self.outputs.receipts().iter().for_each(|r| bloom.accrue_bloom(&r.bloom())); + bloom + }) + } +} + +/// Cancun lifecycle. This applies the [EIP-4788] pre-block beacon root update +/// system transact action, as well withdrawals via the [`Shanghai`] context. +/// +/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Cancun<'a> { + /// The parent beacon root, for the [EIP-4788] pre-block system action. + /// + /// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 + pub parent_beacon_root: B256, + + /// The Cancun lifecycle is a superset of the Shanghai lifecycle. + pub shanghai: Shanghai<'a>, +} + +impl<'a> std::ops::Deref for Cancun<'a> { + type Target = Shanghai<'a>; + + fn deref(&self) -> &Self::Target { + &self.shanghai + } +} + +impl<'a> std::ops::DerefMut for Cancun<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.shanghai + } +} + +impl BlockContext for Cancun<'_> { + type Error = EVMError; + + fn open_block( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + b: &B, + ) -> Result<(), Self::Error> { + self.shanghai.open_block(evm, b)?; + self.apply_eip4788(evm) + } + + fn after_tx(&mut self, evm: &mut Evm<'_, Ext, Db>, result: ResultAndState) { + self.shanghai.after_tx(evm, result) + } + + fn close_block(&mut self, evm: &mut Evm<'_, Ext, Db>) -> Result<(), Self::Error> { + self.shanghai.close_block(evm) + } +} + +impl<'a> Cancun<'a> { + /// Create a new Cancun context. + pub const fn new(parent_beacon_root: B256, shanghai: Shanghai<'a>) -> Self { + Self { parent_beacon_root, shanghai } + } +} + +impl Cancun<'_> { + /// Apply a system transaction as specified in [EIP-4788]. The EIP-4788 + /// pre-block action was introduced in Cancun, and calls the beacon root + /// contract to update the historical beacon root. + /// + /// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 + pub fn apply_eip4788( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + ) -> Result<(), >::Error> + where + Db: Database + DatabaseCommit, + { + if evm.spec_id() < SpecId::CANCUN { + return Ok(()); + } + execute_system_tx(evm, &SystemTx::eip4788(self.parent_beacon_root))?; + Ok(()) + } +} + +/// Prague block context. This applies withdrawals via the [Shanghai], +/// beacon root updates via the [`Cancun`] context, the [EIP-7002] post-block +/// withdrawal requests, and the [EIP-7251] post-block consolidation requests. +/// +/// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 +/// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Prague<'a> { + /// The Prague context is a superset of the [`Cancun`] context. + pub cancun: Cancun<'a>, + + /// Requests produced in the block. These include Deposit, Withdrawal, and + /// Consolidation requests. + requests: Vec, +} + +impl<'a> std::ops::Deref for Prague<'a> { + type Target = Cancun<'a>; + + fn deref(&self) -> &Self::Target { + &self.cancun + } +} + +impl<'a> std::ops::DerefMut for Prague<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cancun + } +} + +impl<'a> From> for Prague<'a> { + fn from(cancun: Cancun<'a>) -> Self { + Self { cancun, requests: Vec::new() } + } +} + +impl BlockContext for Prague<'_> +where + Db: Database + DatabaseCommit, +{ + type Error = EVMError; + + fn open_block<'a, B: Block>( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + b: &B, + ) -> Result<(), Self::Error> { + self.cancun.open_block(evm, b)?; + Self::apply_eip2935(evm) + } + + fn after_tx<'a>(&mut self, evm: &mut Evm<'_, Ext, Db>, result: ResultAndState) { + // ordering is important here as the `find_deposit_logs` method relies + // on the receipt produced by the inner `after_tx` call. + self.cancun.after_tx(evm, result); + self.find_deposit_logs(); + } + + fn close_block<'a>(&mut self, evm: &mut Evm<'_, Ext, Db>) -> Result<(), Self::Error> { + self.apply_eip7002(evm)?; + self.apply_eip7251(evm)?; + self.cancun.close_block(evm) + } +} + +impl<'a> Prague<'a> { + /// Create a new Prague context. + pub fn new(cancun: Cancun<'a>) -> Self { + Self { cancun, requests: Vec::new() } + } + + /// Get the requests produced in the block. + pub fn requests(&self) -> &[Request] { + &self.requests + } + + /// Destructure the Prague context and return the Cancun context and the + /// requests produced during the block. + pub fn into_parts(self) -> (Cancun<'a>, Vec) { + (self.cancun, self.requests) + } +} + +impl Prague<'_> { + /// Finds deposit logs for the most recent receipt. + fn find_deposit_logs(&mut self) { + let receipt = + self.cancun.shanghai.outputs.receipts().last().expect("produced in shanghai lifecycle"); + + for log in receipt + .logs() + .iter() + .filter(|log| log.address == eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS) + { + // We assume that the log is valid because it was emitted by the + // deposit contract. + let decoded_log = eip6110::DepositEvent::decode_log(log, false).expect("invalid log"); + let deposit = eip6110::parse_deposit_from_log(&decoded_log); + self.requests.push(Request::DepositRequest(deposit)); + } + } + + /// Apply the pre-block logic for [EIP-2935]. This logic was introduced in + /// Prague and updates historical block hashes in a special system + /// contract. Unlike other system actions, this is NOT modeled as a + /// transaction. + /// + /// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935 + pub fn apply_eip2935( + evm: &mut Evm<'_, Ext, Db>, + ) -> Result<(), >::Error> + where + Db: Database + DatabaseCommit, + { + if evm.spec_id() < SpecId::PRAGUE || evm.block().number.is_zero() { + return Ok(()); + } + + let mut account: Account = match evm.db_mut().basic(HISTORY_STORAGE_ADDRESS) { + Ok(Some(account)) => account, + Ok(None) => AccountInfo { + nonce: 1, + code: Some(Bytecode::new_raw(HISTORY_STORAGE_CODE.clone())), + ..Default::default() + }, + Err(error) => return Err(EVMError::Database(error)), + } + .into(); + + let block_num = evm.block().number.as_limbs()[0]; + let prev_block = block_num.saturating_sub(1); + + // Update the EVM state with the new value. + { + let slot = U256::from(block_num % BLOCKHASH_SERVE_WINDOW as u64); + let current_hash = match evm.db_mut().storage(HISTORY_STORAGE_ADDRESS, slot) { + Ok(current_hash) => current_hash, + Err(error) => return Err(EVMError::Database(error)), + }; + let parent_block_hash = match evm.db_mut().block_hash(prev_block) { + Ok(parent_block_hash) => parent_block_hash, + Err(error) => return Err(EVMError::Database(error)), + }; + + // Insert the state change for the slot + let value = EvmStorageSlot::new_changed(current_hash, parent_block_hash.into()); + + account.storage.insert(slot, value); + } + + // Mark the account as touched and commit the state change + account.mark_touch(); + evm.db_mut().commit(HashMap::from([(HISTORY_STORAGE_ADDRESS, account)])); + + Ok(()) + } + + /// Apply a system transaction as specified in [EIP-7002]. The EIP-7002 + /// post-block action was introduced in Prague, and calls the withdrawal + /// request contract to process withdrawal requests. + /// + /// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 + pub fn apply_eip7002( + &mut self, + + evm: &mut Evm<'_, Ext, Db>, + ) -> Result<(), >::Error> + where + Db: Database + DatabaseCommit, + { + if evm.spec_id() < SpecId::PRAGUE { + return Ok(()); + } + let res = execute_system_tx(evm, &SystemTx::eip7002())?; + + // We make assumptions here: + // - The system transaction never reverts. + // - The system transaction always has an output. + // - The system contract produces correct output. + // - The output is a list of withdrawal requests. + // - The output does not contain incomplete requests. + + let Some(output) = res.output() else { + panic!("execution halted during withdrawal request system contract execution") + }; + self.requests.extend(output.chunks_exact(WITHDRAWAL_REQUEST_BYTES).map(|chunk| { + let mut req: WithdrawalRequest = Default::default(); + + req.source_address.copy_from_slice(&chunk[0..20]); + req.validator_pubkey.copy_from_slice(&chunk[20..68]); + req.amount = u64::from_be_bytes(chunk[68..76].try_into().unwrap()); + + Request::WithdrawalRequest(req) + })); + + Ok(()) + } + + /// Apply a system transaction as specified in [EIP-7251]. The EIP-7251 + /// post-block action calls the consolidation request contract to process + /// consolidation requests. + /// + /// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 + pub fn apply_eip7251( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + ) -> Result<(), >::Error> + where + Db: Database + DatabaseCommit, + { + if evm.spec_id() < SpecId::PRAGUE { + return Ok(()); + } + let res = execute_system_tx(evm, &SystemTx::eip7251())?; + + // We make assumptions here: + // - The system transaction never reverts. + // - The system transaction always has an output. + // - The system contract produces correct output. + // - The output is a list of consolidation requests. + // - The output does not contain incomplete requests. + + let Some(output) = res.output() else { panic!("no output") }; + self.requests.extend(output.chunks_exact(CONSOLIDATION_REQUEST_BYTES).map(|chunk| { + let mut req: ConsolidationRequest = Default::default(); + + req.source_address.copy_from_slice(&chunk[0..20]); + req.source_pubkey.copy_from_slice(&chunk[20..68]); + req.target_pubkey.copy_from_slice(&chunk[68..116]); + + Request::ConsolidationRequest(req) + })); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{syscall::eip4788::BEACON_ROOTS_ADDRESS, NoopBlock, NoopCfg, TrevmBuilder, Tx}; + use alloy_consensus::constants::{ETH_TO_WEI, GWEI_TO_WEI}; + use alloy_eips::{ + eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, + eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS, + }; + use alloy_primitives::{fixed_bytes, Address, Bytes, FixedBytes, TxKind, U256}; + + use revm::{Evm, InMemoryDB}; + + const WITHDRAWALS: &[Withdrawal] = &[Withdrawal { + validator_index: 1, + index: 1, + address: Address::with_last_byte(0x69), + amount: 100 * GWEI_TO_WEI, + }]; + + // Withdrawal tx + const WITHDRAWAL_ADDR: Address = Address::with_last_byte(0x42); + const WITHDRAWAL_AMOUNT: FixedBytes<8> = fixed_bytes!("2222222222222222"); + const VALIDATOR_PUBKEY: FixedBytes<48> = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); + const TARGET_VALIDATOR_PUBKEY: FixedBytes<48> = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); + + // TODO: Remove once https://github.com/alloy-rs/alloy/issues/1103 is resolved. + const CONSOLIDATION_REQUEST_PREDEPLOY_CODE: &str = "3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd"; + + struct WithdrawalTx; + + impl Tx for WithdrawalTx { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + // https://github.com/lightclient/7002asm/blob/e0d68e04d15f25057af7b6d180423d94b6b3bdb3/test/Contract.t.sol.in#L49-L64 + let input: Bytes = [&VALIDATOR_PUBKEY[..], &WITHDRAWAL_AMOUNT[..]].concat().into(); + + tx_env.caller = WITHDRAWAL_ADDR; + tx_env.data = input; + tx_env.transact_to = TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS); + // `MIN_WITHDRAWAL_REQUEST_FEE` + tx_env.value = U256::from(1); + } + } + + struct ConsolidationTx; + + impl Tx for ConsolidationTx { + fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + let input: Bytes = + [&VALIDATOR_PUBKEY[..], &TARGET_VALIDATOR_PUBKEY[..]].concat().into(); + + tx_env.caller = WITHDRAWAL_ADDR; + tx_env.data = input; + tx_env.transact_to = TxKind::Call(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS); + // `MIN_CONSOLIDATION_REQUEST_FEE` + tx_env.value = U256::from(1); + } + } + + fn get_shanghai_context<'a>() -> Shanghai<'a> { + let outputs = BlockOutput::default(); + let mut withdrawals = Vec::new(); + + let withdrawal = Withdrawal { + validator_index: 1, + index: 1, + address: Address::with_last_byte(0x69), + amount: 100 * GWEI_TO_WEI, + }; + + withdrawals.push(withdrawal); + + Shanghai { withdrawals: WITHDRAWALS, outputs } + } + + #[test] + fn test_shanghai_syscall() { + let mut db = InMemoryDB::default(); + + db.insert_account_info( + Address::with_last_byte(0x69), + AccountInfo { + balance: U256::ZERO, + nonce: 1, + code: None, + code_hash: Default::default(), + }, + ); + + let shanghai = get_shanghai_context(); + + let balance = Evm::builder() + .with_db(db) + .build_trevm() + .fill_cfg(&NoopCfg) + .open_block(&NoopBlock, shanghai) + .unwrap() + .close_block() + .unwrap() + .read_balance(Address::with_last_byte(0x69)); + + assert_eq!(balance, U256::from(100 * GWEI_TO_WEI)); + } + + #[test] + fn test_cancun_syscall() { + // Pre-cancun setup (Shanghai) + let mut db = InMemoryDB::default(); + + db.insert_account_info( + Address::with_last_byte(0x69), + AccountInfo { + balance: U256::ZERO, + nonce: 1, + code: None, + code_hash: Default::default(), + }, + ); + + let shanghai = get_shanghai_context(); + + // Set up cancun + // 1. Insert the beacon root contract into the EVM + let bytecode = Bytecode::new_raw(alloy_eips::eip4788::BEACON_ROOTS_CODE.clone()); + let mut beacon_roots_info = AccountInfo { + nonce: 1, + code_hash: bytecode.hash_slow(), + code: Some(bytecode), + ..Default::default() + }; + + db.insert_contract(&mut beacon_roots_info); + db.insert_account_info(BEACON_ROOTS_ADDRESS, beacon_roots_info); + + // 2. Set up the Cancun context, by loading the parent beacon root, + // which we expect to be 0x21 (33). + let expected_beacon_root = B256::with_last_byte(0x21); + let cancun = Cancun { parent_beacon_root: expected_beacon_root, shanghai }; + + // We expect the root to be stored at timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH. + // In this case, 0 % 8192 + 8192 = 8192. quick maffs + let expected_beacon_root_slot = U256::from(8192); + + let stored_beacon_root = Evm::builder() + .with_db(db) + .build_trevm() + .fill_cfg(&NoopCfg) + .open_block(&NoopBlock, cancun) + .unwrap() + .close_block() + .unwrap() + .read_storage(BEACON_ROOTS_ADDRESS, expected_beacon_root_slot); + + assert_eq!(stored_beacon_root, expected_beacon_root.into()); + } + + #[test] + fn test_prague_syscalls() { + // Pre-prague setup (Shanghai) + let mut db = InMemoryDB::default(); + + db.insert_account_info( + Address::with_last_byte(0x69), + AccountInfo { + balance: U256::ZERO, + nonce: 1, + code: None, + code_hash: Default::default(), + }, + ); + + let shanghai = get_shanghai_context(); + + // Pre-prague setup (Cancun) + // 1. Insert the beacon root contract into the EVM + let bytecode = Bytecode::new_raw(alloy_eips::eip4788::BEACON_ROOTS_CODE.clone()); + let mut beacon_roots_info = AccountInfo { + nonce: 1, + code_hash: bytecode.hash_slow(), + code: Some(bytecode), + ..Default::default() + }; + + db.insert_contract(&mut beacon_roots_info); + db.insert_account_info(BEACON_ROOTS_ADDRESS, beacon_roots_info); + + // 2. Set up the Cancun context, by loading the parent beacon root, + // which we expect to be 0x21 (33). + let expected_beacon_root = B256::with_last_byte(0x21); + let cancun = Cancun { parent_beacon_root: expected_beacon_root, shanghai }; + + // Prague setup + // 1. Set up EIP-7002 by inserting the withdrawals contract into the EVM + let bytecode = + Bytecode::new_raw(alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_CODE.clone()); + let mut withdrawal_request_info = AccountInfo { + nonce: 1, + code_hash: bytecode.hash_slow(), + code: Some(bytecode), + ..Default::default() + }; + + db.insert_contract(&mut withdrawal_request_info); + db.insert_account_info( + alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, + withdrawal_request_info, + ); + + // 2. Insert the consolidation requests contract into the EVM + let bytecode = Bytecode::new_raw( + alloy_primitives::hex::decode(CONSOLIDATION_REQUEST_PREDEPLOY_CODE).unwrap().into(), + ); + let mut consolidation_request_info = AccountInfo { + nonce: 1, + code_hash: bytecode.hash_slow(), + code: Some(bytecode), + ..Default::default() + }; + + db.insert_contract(&mut consolidation_request_info); + db.insert_account_info(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS, consolidation_request_info); + + // 3. Insert an user account, which will send a withdrawal and consolidation request. + let user_account_info = AccountInfo { + balance: U256::from(100 * ETH_TO_WEI), + nonce: 1, + code: None, + code_hash: Default::default(), + }; + + db.insert_account_info(WITHDRAWAL_ADDR, user_account_info); + + // 4. Set up the Prague context, by loading the parent beacon root, + let prague = Prague { cancun, requests: Vec::new() }; + + // 5. Set up the EVM along with the Prague context and transactions. + let evm = Evm::builder() + .with_db(db) + .with_spec_id(SpecId::PRAGUE) + .build_trevm() + .fill_cfg(&NoopCfg) + .open_block(&NoopBlock, prague) + .unwrap() + .fill_tx(&WithdrawalTx) + .run() + .unwrap() + .accept() + .fill_tx(&ConsolidationTx) + .run() + .unwrap() + .accept() + .close_block() + .unwrap(); + + let (prague, _) = evm.take_context(); + + // We should have 1 withdrawal request processed by 7002 and one consolidation request processed by 7251. + assert_eq!(2, prague.requests.len()); + + let withdrawal_request = prague.requests[0].as_withdrawal_request().unwrap(); + + assert_eq!(withdrawal_request.validator_pubkey, VALIDATOR_PUBKEY); + assert_eq!(withdrawal_request.source_address, WITHDRAWAL_ADDR); + + let consolidation_request = prague.requests[1].as_consolidation_request().unwrap(); + + assert_eq!(consolidation_request.source_address, WITHDRAWAL_ADDR); + assert_eq!(consolidation_request.source_pubkey, VALIDATOR_PUBKEY); + assert_eq!(consolidation_request.target_pubkey, TARGET_VALIDATOR_PUBKEY); + } +} diff --git a/src/lifecycle/mod.rs b/src/lifecycle/mod.rs new file mode 100644 index 0000000..37c05aa --- /dev/null +++ b/src/lifecycle/mod.rs @@ -0,0 +1,11 @@ +mod contexts; +pub use contexts::{BasicContext, Cancun, Prague, Shanghai}; + +mod output; +pub use output::BlockOutput; + +mod postflight; +pub use postflight::{PostTx, PostflightResult}; + +mod r#trait; +pub use r#trait::BlockContext; diff --git a/src/lifecycle/output.rs b/src/lifecycle/output.rs new file mode 100644 index 0000000..847b97d --- /dev/null +++ b/src/lifecycle/output.rs @@ -0,0 +1,75 @@ +use alloy_consensus::{ReceiptEnvelope, TxReceipt}; +use alloy_primitives::{Address, Log}; + +/// Information externalized during block execution. +/// +/// This struct is used to collect the results of executing a block of +/// transactions. It accumulates the receipts and senders of the transactions. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BlockOutput { + /// The receipts of the transactions in the block, in order. + receipts: Vec, + + /// The senders of the transactions in the block, in order. + senders: Vec
, +} + +impl Default for BlockOutput { + fn default() -> Self { + Self::with_capacity(0) + } +} + +impl BlockOutput { + /// Create a new block output with memory allocated to hold `capacity` + /// transaction outcomes. + pub fn with_capacity(capacity: usize) -> Self { + Self { receipts: Vec::with_capacity(capacity), senders: Vec::with_capacity(capacity) } + } + + /// Reserve memory for `capacity` transaction outcomes. + pub fn reserve(&mut self, capacity: usize) { + self.receipts.reserve(capacity); + self.senders.reserve(capacity); + } + + /// Get a reference to the receipts of the transactions in the block. + pub fn receipts(&self) -> &[T] { + &self.receipts + } + + /// Get an iterator over the logs of the transactions in the block. + pub fn logs(&self) -> impl Iterator { + self.receipts.iter().flat_map(|r| r.logs()) + } + + /// Get a reference the senders of the transactions in the block. + pub fn senders(&self) -> &[Address] { + &self.senders + } + + /// Get the cumulative gas used in the block. + pub fn cumulative_gas_used(&self) -> u128 { + self.receipts().last().map(TxReceipt::cumulative_gas_used).unwrap_or_default() + } + + /// Accumulate the result of a transaction execution. If `parse_deposits` is + /// true, the logs of the transaction will be scanned for deposit events + /// according to the [EIP-6110] specification. + /// + /// [EIP-6110]: https://eips.ethereum.org/EIPS/eip-6110 + pub fn push_result(&mut self, receipt: T, sender: Address) { + self.push_receipt(receipt); + self.push_sender(sender); + } + + /// Push a receipt onto the list of receipts. + fn push_receipt(&mut self, receipt: T) { + self.receipts.push(receipt); + } + + /// Push a sender onto the list of senders. + fn push_sender(&mut self, sender: Address) { + self.senders.push(sender); + } +} diff --git a/src/lifecycle/postflight.rs b/src/lifecycle/postflight.rs new file mode 100644 index 0000000..c5d804e --- /dev/null +++ b/src/lifecycle/postflight.rs @@ -0,0 +1,84 @@ +use revm::primitives::ResultAndState; + +/// Control flow for transaction execution. +/// +/// This enum is used to determine whether to apply or discard the state +/// changes after a transaction is executed. +#[derive(Debug, Clone, Copy)] +pub enum PostflightResult { + /// Discard the state changes + Discard(&'static str), + /// Apply the state changes + Apply, +} + +impl From for PostflightResult { + fn from(b: bool) -> Self { + if b { + Self::Apply + } else { + Self::Discard("") + } + } +} + +impl From<&'static str> for PostflightResult { + fn from(s: &'static str) -> Self { + Self::Discard(s) + } +} + +impl From> for PostflightResult { + fn from(s: Option<&'static str>) -> Self { + s.map(Self::Discard).unwrap_or(Self::Apply) + } +} + +impl PostflightResult { + /// Returns `true` if the result is `Discard`. + pub const fn is_discard(&self) -> bool { + matches!(self, Self::Discard(_)) + } + + /// Returns the discard reason if the result is `Discard`. + pub const fn as_discard_reason(&self) -> Option<&'static str> { + match self { + Self::Discard(reason) => Some(reason), + _ => None, + } + } + + /// Returns `true` if the result is `Apply`. + pub const fn is_apply(&self) -> bool { + matches!(self, Self::Apply) + } +} + +/// Discard the transaction if the condition is true, providing a discard +/// reason. +#[macro_export] +macro_rules! discard_if { + ($a:expr, $reason:literal) => { + if $a { + tracing::debug!(reason = $reason, "Discarding transaction"); + return $crate::PostflightResult::Discard($reason); + } + }; +} + +/// Inspect the outcome of a transaction execution, and determine whether to +/// apply or discard the state changes. +pub trait PostTx { + /// Check the result of the EVM execution, potentially mutating self. + fn run_post_tx(&mut self, result: &ResultAndState) -> PostflightResult; +} + +impl PostTx for T +where + T: for<'a> FnMut(&'a ResultAndState) -> O, + O: Into, +{ + fn run_post_tx(&mut self, result: &ResultAndState) -> PostflightResult { + self(result).into() + } +} diff --git a/src/lifecycle/trait.rs b/src/lifecycle/trait.rs new file mode 100644 index 0000000..9cee4f8 --- /dev/null +++ b/src/lifecycle/trait.rs @@ -0,0 +1,110 @@ +use crate::Block; +use revm::{ + primitives::{EVMError, ResultAndState}, + Database, DatabaseCommit, Evm, +}; + +/// Block contexts apply pre-block and post-block logic to the EVM, as well as +/// post-tx logic like receipt generation. +/// +/// This trait encapsulates special pre-block and post-block logic that needs to +/// be applied to the EVM. This is useful for implementing EIPs that require +/// special system actions to be taken before and after the block is processed. +/// +/// ### Mutability and the EVM +/// +/// The [`BlockContext`] trait has mutable access to the EVM, allowing it to +/// modify the EVM state as needed. This is useful for implementing EIPs that +/// require special system actions to be taken before and after the block is +/// processed. +/// +/// Because the EVM is passed as a mutable reference, the [`BlockContext`] trait +/// can make ANY modificatiopn to the EVM state. This includes potentially +/// changing the [`BlockEnv`] and [`CfgEnv`] objects, the [`SpecId`], or any +/// other property. As such, block contexts are allowed to violate [`Trevm`] +/// state guarantees. Please be careful. +/// +/// ### Provided contexts +/// +/// Contexts are provided for [Shanghai], [Cancun], and [Prague]. While most +/// Contexts do not modify previous behavior, older context modify things like +/// the block reward in place. The [Prague] lifecycle is a superset of the +/// [Cancun] lifecycle, and the [Cancun] lifecycle is a superset of the +/// [Shanghai] lifecycle. This means that the [Prague] lifecycle includes all +/// the logic of the [Cancun] and [Shanghai] Contexts. +/// +/// [Shanghai]: crate::Shanghai +/// [Cancun]: crate::Cancun +/// [Prague]: crate::Prague +/// [`BlockEnv`]: revm::primitives::BlockEnv +/// [`CfgEnv`]: revm::primitives::CfgEnv +/// [`SpecId`]: revm::primitives::SpecId +/// [`Trevm`]: crate::Trevm +pub trait BlockContext { + /// The error type for the context. This captures logic errors that occur + /// during the lifecycle. + type Error: From>; + + /// Apply pre-block logic, and prep the EVM for the first user transaction. + fn open_block( + &mut self, + evm: &mut Evm<'_, Ext, Db>, + b: &B, + ) -> Result<(), Self::Error>; + + /// Apply post-transaction logic and then commit the transaction to the evm + /// state. This will be called by [`Trevm`] for each transaction in a block. + /// + /// This is the hook to produce receipts, update cumulative gas used, + /// inspect logs, etc etc. You can read transaction details from `evm.tx()` + /// and the result of the transaction from `result`. + /// + /// Generally this should end by calling `evm.db_mut().commit(result.state)` + /// however, it is allowed to discard the transaction instead of committing + /// it. + /// + /// ``` + /// # use revm::{ + /// # primitives::{EVMError, ResultAndState}, + /// # Database, DatabaseCommit, Evm, + /// # }; + /// # use trevm::BlockContext; + /// # struct MyContext; + /// # + /// # impl MyContext { fn make_receipt(&self, result: &ResultAndState) {} } + /// # + /// impl BlockContext for MyContext + /// where + /// Db: Database + DatabaseCommit + /// { + /// # type Error = EVMError; + /// # fn open_block( + /// # &mut self, + /// # _evm: &mut Evm<'_, Ext, Db>, + /// # _b: &B + /// # ) -> Result<(), Self::Error> { Ok(()) } + /// fn after_tx( + /// &mut self, + /// evm: &mut Evm<'_, Ext, Db>, + /// result: ResultAndState + /// ) { + /// // Do something with the result + /// self.make_receipt(&result); + /// evm.db_mut().commit(result.state); + /// } + /// # + /// # fn close_block( + /// # &mut self, + /// # _evm: &mut Evm<'_, Ext, Db> + /// # ) -> Result<(), Self::Error> { + /// # Ok(()) + /// # } + /// } + /// ``` + /// + /// [`Trevm`]: crate::Trevm + fn after_tx(&mut self, evm: &mut Evm<'_, Ext, Db>, result: ResultAndState); + + /// Apply post-block logic and close the block. + fn close_block(&mut self, evm: &mut Evm<'_, Ext, Db>) -> Result<(), Self::Error>; +} diff --git a/src/states.rs b/src/states.rs new file mode 100644 index 0000000..e2068e0 --- /dev/null +++ b/src/states.rs @@ -0,0 +1,378 @@ +use crate::{BlockContext, Trevm}; +use sealed::*; + +/// A [`Trevm`] that requires a [`Cfg`]. +/// +/// Expected continuations include: +/// - [`EvmNeedsCfg::fill_cfg`] +/// +/// [`Cfg`]: crate::Cfg +pub type EvmNeedsCfg<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsCfg>; + +/// A [`Trevm`] that requires a [`Block`] and contains no +/// outputs. This EVM has not yet executed any transactions or state changes. +/// +/// Expected continuations include: +/// - [`EvmNeedsFirstBlock::open_block`] +/// +/// [`Block`]: crate::Block +pub type EvmNeedsFirstBlock<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsFirstBlock>; + +/// A [`Trevm`] that has completed a block and contains the block's populated +/// lifecycle object. +/// +/// Expected continuations include: +/// - [`EvmBlockComplete::take_context`] +/// - [`EvmBlockComplete::discard_context`] +pub type EvmBlockComplete<'a, Ext, Db, T> = Trevm<'a, Ext, Db, BlockComplete>; + +/// A [`Trevm`] that requires a [`Block`]. +/// +/// Expected continuations include: +/// - [`EvmNeedsFirstBlock::open_block`] +/// +/// [`Block`]: crate::Block +pub type EvmNeedsNextBlock<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsNextBlock>; + +/// A [`Trevm`] that requires a [`Tx`]. +/// +/// Expected continuations include: +/// - [`EvmNeedsTx::fill_tx`] +/// - [`EvmNeedsTx::run_tx`] +/// - [`EvmNeedsTx::finish`] +/// +/// [`Tx`]: crate::Tx +pub type EvmNeedsTx<'a, Ext, Db, C> = Trevm<'a, Ext, Db, NeedsTx>; + +/// A [`Trevm`] that is ready to execute a transaction. +/// +/// The transaction may be executed with [`EvmReady::run`] or cleared +/// with [`EvmReady::clear_tx`] +pub type EvmReady<'a, Ext, Db, C> = Trevm<'a, Ext, Db, Ready>; + +/// A [`Trevm`] that encountered an error during transaction execution. +/// +/// Expected continuations include: +/// - [`EvmTransacted::reject`] +/// - [`EvmTransacted::accept`] +pub type EvmTransacted<'a, Ext, Db, C> = Trevm<'a, Ext, Db, TransactedState>; + +/// A [`Trevm`] that encountered an error during transaction execution. +/// +/// Expected continuations include: +/// - [`EvmErrored::discard_error`] +/// - [`EvmErrored::into_error`] +pub type EvmErrored<'a, Ext, Db, C, E = >::Error> = + Trevm<'a, Ext, Db, ErroredState>; + +#[allow(dead_code)] +#[allow(unnameable_types)] +pub(crate) mod sealed { + use revm::primitives::ResultAndState; + + macro_rules! states { + ($($name:ident),+) => { + $( + + /// A state for the [`Trevm`]. + /// + /// [`Trevm`]: crate::Trevm + #[derive(Debug)] + pub struct $name { _private: () } + + impl $name { + /// Create a new state. + pub(crate) const fn new() -> Self { + Self { _private: () } + } + } + + )* + }; + } + + states!(NeedsCfg, NeedsFirstBlock, NeedsNextBlock); + + /// A state for the [`Trevm`]. + /// + /// [`Trevm`]: crate::Trevm + #[derive(Debug)] + pub struct NeedsTx(pub T); + + /// A state for the [`Trevm`]. + /// + /// [`Trevm`]: crate::Trevm + #[derive(Debug)] + pub struct Ready(pub T); + + /// A state for the [`Trevm`]. + /// + /// [`Trevm`]: crate::Trevm + #[derive(Debug)] + pub struct BlockComplete(pub T); + + /// A state for the [`Trevm`]. + /// + /// [`Trevm`]: crate::Trevm + #[derive(Debug)] + pub struct TransactedState { + /// The context for the block. + pub context: T, + /// The transaction result. + pub result: ResultAndState, + } + + /// A state for the [`Trevm`]. + /// + /// [`Trevm`]: crate::Trevm + #[derive(Debug)] + pub struct ErroredState { + /// The context for the block. + pub context: T, + /// The transaction error. + pub error: E, + } + + /// Trait for states where block execution can be started. + #[allow(unnameable_types)] + pub trait NeedsBlock {} + impl NeedsBlock for NeedsFirstBlock {} + impl NeedsBlock for NeedsNextBlock {} + + /// Trait for states where thcare outputs vec is non-empty. + #[allow(unnameable_types)] + pub trait HasOutputs {} + impl HasOutputs for NeedsNextBlock {} + impl HasOutputs for NeedsTx {} + impl HasOutputs for TransactedState {} + impl HasOutputs for ErroredState {} + impl HasOutputs for Ready {} + + #[allow(unnameable_types)] + pub trait HasCfg {} + #[allow(unnameable_types)] + impl HasCfg for NeedsFirstBlock {} + impl HasCfg for NeedsNextBlock {} + impl HasCfg for NeedsTx {} + impl HasCfg for TransactedState {} + impl HasCfg for ErroredState {} + impl HasCfg for Ready {} +} + +#[macro_export] +/// Declare type aliases for trevm with a concrete `Ext` and `Db` type. +/// +/// This will create aliases with your concrete types for the following types: +/// - [`EvmNeedsCfg`] +/// - [`EvmNeedsFirstBlock`] +/// - [`EvmBlockComplete`] +/// - [`EvmNeedsNextBlock`] +/// - [`EvmNeedsTx`] +/// - [`EvmReady`] +/// +/// ## Basic usage: +/// +/// Invoking with just a DB type will use [`()`] for the ext +/// +/// ``` +/// use trevm::trevm_aliases; +/// use revm::db::InMemoryDB; +/// +/// // produces types that look like this: +/// // type EvmNeedsCfg = trevm::EvmNeedsCfg<'static, (), InMemoryDB>; +/// trevm_aliases!(revm::db::InMemoryDB); +/// ``` +/// +/// Invoking with an ext and DB type will use the provided ext type and the +/// static lifetime: +/// +/// ``` +/// # mod t { +/// # use trevm::trevm_aliases; +/// # use revm::db::InMemoryDB; +/// # pub struct SomeExtType; +/// // produces types that look like this: +/// // type EvmNeedsCfg = trevm::EvmNeedsCfg<'static, SomeExtType, InMemoryDB>; +/// trevm_aliases!(SomeExtType, InMemoryDB); +/// # } +/// ``` +/// +/// To add a lifetime to the ext type, add the word lifetime: +/// +/// ``` +/// # mod t { +/// # use trevm::trevm_aliases; +/// # use revm::db::InMemoryDB; +/// # pub struct SomeExtType; +/// // produces types that look like this: +/// // type EvmNeedsCfg<'a> = trevm::EvmNeedsCfg<'a, SomeExtType, InMemoryDB>; +/// trevm_aliases!(lifetime: SomeExtType, InMemoryDB); +/// # } +/// ``` +macro_rules! trevm_aliases { + ($db:ty) => { + trevm_aliases!((), $db); + }; + + (lifetime: $ext:ty, $db:ty) => { + #[allow(unused_imports, unreachable_pub, dead_code)] + pub use __aliases::*; + + #[allow(unused_imports, unreachable_pub, dead_code)] + mod __aliases { + use super::*; + // bring these in scope so that doclinks work in generated docs + use $crate::Block; + use $crate::Cfg; + use $crate::Trevm; + use $crate::Tx; + + /// A [`Trevm`] that requires a [`Cfg`]. + /// + /// Expected continuations include: + /// - [`Trevm::fill_cfg`] + /// + /// [`Cfg`]: crate::Cfg + /// [`Trevm`]: crate::Trevm + pub type EvmNeedsCfg<'a> = $crate::EvmNeedsCfg<'a, $ext, $db>; + + /// A [`Trevm`] that requires a [`Block`] and contains no + /// outputs. This EVM has not yet executed any transactions or state changes. + /// + /// Expected continuations include: + /// - [`EvmNeedsFirstBlock::open_block`] + /// + /// [`Block`]: crate::Block + pub type EvmNeedsFirstBlock<'a> = $crate::EvmNeedsFirstBlock<'a, $ext, $db>; + + /// A [`Trevm`] that has completed a block and contains the block's populated + /// lifecycle object. + /// + /// Expected continuations include: + /// - [`EvmBlockComplete::into_parts`] + /// - [`EvmBlockComplete::discard_context`] + pub type EvmBlockComplete<'a, C> = $crate::EvmBlockComplete<'a, $ext, $db, C>; + + /// A [`Trevm`] that requires a [`Block`]. + /// + /// Expected continuations include: + /// - [`EvmNeedsFirstBlock::open_block`] + /// + /// [`Block`]: crate::Block + pub type EvmNeedsNextBlock<'a> = $crate::EvmNeedsNextBlock<'a, $ext, $db>; + + /// A [`Trevm`] that requires a [`Tx`]. + /// + /// Expected continuations include: + /// - [`EvmNeedsTx::fill_tx`] + /// - [`EvmNeedsTx::execute_tx`] + /// - [`EvmNeedsTx::apply_tx`] + /// - [`EvmNeedsTx::finish`] + /// + /// [`Tx`]: crate::Tx + pub type EvmNeedsTx<'a, C> = $crate::EvmNeedsTx<'a, $ext, $db, C>; + + /// A [`Trevm`] that is ready to execute a transaction. + /// + /// The transaction may be executed with [`Trevm::execute_tx`] or + /// cleared with [`Trevm::clear_tx`] + pub type EvmReady<'a, C> = $crate::EvmReady<'a, $ext, $db, C>; + + /// A [`Trevm`] that encountered an error during transaction execution. + /// + /// Expected continuations include: + /// - [`EvmTransacted::reject`] + /// - [`EvmTransacted::accept`] + pub type EvmTransacted<'a, C> = $crate::EvmTransacted<'a, $ext, $db, C>; + + /// A [`Trevm`] that encountered an error during transaction execution. + /// + /// Expected continuations include: + /// - [`EvmErrored::discard_error`] + /// - [`EvmErrored::into_error`] + pub type EvmErrored<'a, C, E = >::Error> = + $crate::EvmErrored<'a, $ext, $db, C, E>; + } + }; + + ($ext:ty, $db:ty) => { + #[allow(unused_imports, unreachable_pub, dead_code)] + pub use __aliases::*; + + #[allow(unused_imports, unreachable_pub, dead_code)] + mod __aliases { + use super::*; + // bring these in scope so that doclinks work in generated docs + use $crate::Block; + use $crate::Cfg; + use $crate::Trevm; + use $crate::Tx; + + /// A [`Trevm`] that requires a [`Cfg`]. + /// + /// Expected continuations include: + /// - [`Trevm::fill_cfg`] + /// + /// [`Cfg`]: crate::Cfg + /// [`Trevm`]: crate::Trevm + pub type EvmNeedsCfg = $crate::EvmNeedsCfg<'static, $ext, $db>; + + /// A [`Trevm`] that requires a [`Block`] and contains no + /// outputs. This EVM has not yet executed any transactions or state changes. + /// + /// Expected continuations include: + /// - [`EvmNeedsFirstBlock::open_block`] + /// + /// [`Block`]: crate::Block + pub type EvmNeedsFirstBlock = $crate::EvmNeedsFirstBlock<'static, $ext, $db>; + + /// A [`Trevm`] that has completed a block and contains the block's populated + /// lifecycle object. + /// + /// Expected continuations include: + /// - [`EvmBlockComplete::into_parts`] + /// - [`EvmBlockComplete::discard_context`] + pub type EvmBlockComplete = $crate::EvmBlockComplete<'static, $ext, $db, C>; + + /// A [`Trevm`] that requires a [`Block`]. + /// + /// Expected continuations include: + /// - [`EvmNeedsFirstBlock::open_block`] + /// + /// [`Block`]: crate::Block + pub type EvmNeedsNextBlock = $crate::EvmNeedsNextBlock<'static, $ext, $db>; + + /// A [`Trevm`] that requires a [`Tx`]. + // + /// Expected continuations include: + /// - [`EvmNeedsTx::fill_tx`] + /// - [`EvmNeedsTx::execute_tx`] + /// - [`EvmNeedsTx::apply_tx`] + /// - [`EvmNeedsTx::finish`] + /// + /// [`Tx`]: crate::Tx + pub type EvmNeedsTx = $crate::EvmNeedsTx<'static, $ext, $db, C>; + + /// A [`Trevm`] that is ready to execute a transaction. + /// + /// The transaction may be executed with [`Trevm::execute_tx`] or + /// cleared with [`Trevm::clear_tx`] + pub type EvmReady = $crate::EvmReady<'static, $ext, $db, C>; + + /// A [`Trevm`] that encountered an error during transaction execution. + /// + /// Expected continuations include: + /// - [`EvmTransacted::reject`] + /// - [`EvmTransacted::accept`] + pub type EvmTransacted = $crate::EvmTransacted<'static, $ext, $db, C>; + + /// A [`Trevm`] that encountered an error during transaction execution. + /// + /// Expected continuations include: + /// - [`EvmErrored::discard_error`] + /// - [`EvmErrored::into_error`] + pub type EvmErrored>::Error> = + $crate::EvmErrored<'static, $ext, $db, C, E>; + } + }; +} diff --git a/src/syscall/eip4788.rs b/src/syscall/eip4788.rs new file mode 100644 index 0000000..275df4f --- /dev/null +++ b/src/syscall/eip4788.rs @@ -0,0 +1,37 @@ +use crate::syscall::SystemTx; +use alloy_primitives::{Address, Bytes, B256}; + +/// The address for the [EIP-4788] beacon roots contract. +/// +/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 +pub use alloy_eips::eip4788::BEACON_ROOTS_ADDRESS; + +impl SystemTx { + /// Instantiate a system call for the pre-block beacon roots as specified in + /// [EIP-4788]. + /// + /// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 + pub fn eip4788(parent_beacon_root: B256) -> Self { + Self::eip4788_with_target(parent_beacon_root, BEACON_ROOTS_ADDRESS) + } + + /// Instantiate a system call for the pre-block beacon roots as specified in + /// [EIP-4788], with a custom target address. + /// + /// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 + pub fn eip4788_with_target(parent_beacon_root: B256, target: Address) -> Self { + Self::new(target, Bytes::from(parent_beacon_root)) + } + + /// Instantiate a system call for the pre-block beacon roots as specified in + /// [EIP-4788], with a custom target address and caller address. + /// + /// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 + pub fn eip4788_with_target_and_caller( + parent_beacon_root: B256, + target: Address, + caller: Address, + ) -> Self { + Self::new_with_caller(target, Bytes::from(parent_beacon_root), caller) + } +} diff --git a/src/syscall/eip6110.rs b/src/syscall/eip6110.rs new file mode 100644 index 0000000..c9243f9 --- /dev/null +++ b/src/syscall/eip6110.rs @@ -0,0 +1,83 @@ +use alloy_eips::eip6110::DepositRequest; +use alloy_primitives::Log; +use alloy_sol_types::sol; + +/// The address for the Ethereum 2.0 deposit contract on the mainnet. +pub use alloy_eips::eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS; + +sol! { + #[allow(missing_docs)] + event DepositEvent( + bytes pubkey, + bytes withdrawal_credentials, + bytes amount, + bytes signature, + bytes index + ); +} + +/// Parse deposit requests from logs. +/// +/// When parsing logs, the following assumptions are made +/// +/// - The `DepositEvent` is the only event in the deposit contract. +/// - The deposit contract enforces the length of the fields. +pub fn parse_deposit_from_log(log: &Log) -> DepositRequest { + // SAFETY: These `expect` https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/solidity_deposit_contract/deposit_contract.sol#L107-L110 + // are safe because the `DepositEvent` is the only event in the deposit contract and the length + // checks are done there. + DepositRequest { + pubkey: log + .pubkey + .as_ref() + .try_into() + .expect("pubkey length should be enforced in deposit contract"), + withdrawal_credentials: log + .withdrawal_credentials + .as_ref() + .try_into() + .expect("withdrawal_credentials length should be enforced in deposit contract"), + amount: u64::from_le_bytes( + log.amount + .as_ref() + .try_into() + .expect("amount length should be enforced in deposit contract"), + ), + signature: log + .signature + .as_ref() + .try_into() + .expect("signature length should be enforced in deposit contract"), + index: u64::from_le_bytes( + log.index + .as_ref() + .try_into() + .expect("deposit index length should be enforced in deposit contract"), + ), + } +} + +// Some code above is reproduced from `reth`. It is reused here under the MIT +// license. +// +// The MIT License (MIT) +// +// Copyright (c) 2022-2024 Reth Contributors +// +// 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. diff --git a/src/syscall/eip7002.rs b/src/syscall/eip7002.rs new file mode 100644 index 0000000..a503f1c --- /dev/null +++ b/src/syscall/eip7002.rs @@ -0,0 +1,37 @@ +use crate::syscall::SystemTx; +use alloy_primitives::{Address, Bytes}; + +/// The address for the [EIP-7002] withdrawal requests contract. +/// +/// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 +pub use alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS; + +/// The size of a withdrawal request in bytes. +pub const WITHDRAWAL_REQUEST_BYTES: usize = 20 + 48 + 8; + +impl SystemTx { + /// Instantiate a system call for the post-block withdrawal requests as + /// specified in [EIP-7002]. + /// + /// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 + pub const fn eip7002() -> Self { + Self::eip7002_with_target(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS) + } + + /// Instantiate a system call for the post-block withdrawal requests as + /// specified in [EIP-7002], with a custom target address. + /// + /// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 + pub const fn eip7002_with_target(target: Address) -> Self { + Self::new(target, Bytes::new()) + } + + /// Instantiate a system call for the post-block withdrawal requests as + /// specified in [EIP-7002], with a custom target address and caller + /// address. + /// + /// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 + pub const fn eip7002_with_target_and_caller(target: Address, caller: Address) -> Self { + Self::new_with_caller(target, Bytes::new(), caller) + } +} diff --git a/src/syscall/eip7251.rs b/src/syscall/eip7251.rs new file mode 100644 index 0000000..f7fff10 --- /dev/null +++ b/src/syscall/eip7251.rs @@ -0,0 +1,37 @@ +use crate::syscall::SystemTx; +use alloy_primitives::{Address, Bytes}; + +/// The address for the [EIP-7251] consolidation requests contract +/// +/// [`EIP-7251`]: https://eips.ethereum.org/EIPS/eip-7251 +pub use alloy_eips::eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS; + +/// The size of a consolidation request in bytes. +pub const CONSOLIDATION_REQUEST_BYTES: usize = 20 + 48 + 48; + +impl SystemTx { + /// Instantiate a system call for the post-block consolidation requests as + /// specified in [EIP-7251]. + /// + /// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 + pub const fn eip7251() -> Self { + Self::eip7251_with_target(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS) + } + + /// Instantiate a system call for the post-block consolidation requests as + /// specified in [EIP-7251], with a custom target address. + /// + /// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 + pub const fn eip7251_with_target(target: Address) -> Self { + Self::new(target, Bytes::new()) + } + + /// Instantiate a system call for the post-block consolidation requests as + /// specified in [EIP-7251], with a custom target address and caller + /// address. + /// + /// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 + pub const fn eip7251_with_target_and_caller(target: Address, caller: Address) -> Self { + Self::new_with_caller(target, Bytes::new(), caller) + } +} diff --git a/src/syscall/fill.rs b/src/syscall/fill.rs new file mode 100644 index 0000000..31ad13c --- /dev/null +++ b/src/syscall/fill.rs @@ -0,0 +1,83 @@ +use crate::Tx; +use alloy_primitives::{address, Address, Bytes, U256}; +use revm::primitives::TxEnv; + +/// System smart contract calls as specified in [EIP-4788], [EIP-7002], +/// and [EIP-7251]. +/// +/// By default, these calls are sent from a special system caller address +/// specified in the EIPs, but this can be overridden using the +/// [`SystemTx::new_with_caller`] method. +/// +/// +/// [`EIP-4788`]: https://eips.ethereum.org/EIPS/eip-4788 +/// [`EIP-7002`]: https://eips.ethereum.org/EIPS/eip-7002 +/// [`EIP-7251`]: https://eips.ethereum.org/EIPS/eip-7251 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SystemTx { + /// The target address of the system call. + pub target: Address, + /// The input data of the system call. + pub input: Bytes, + /// The caller address of the system call. + pub caller: Address, +} + +/// The system caller as specified in [EIP-4788], [EIP-7002], and [EIP-7251]. +/// +/// [`EIP-4788`]: https://eips.ethereum.org/EIPS/eip-4788 +/// [`EIP-7002`]: https://eips.ethereum.org/EIPS/eip-7002 +/// [`EIP-7251`]: https://eips.ethereum.org/EIPS/eip-7251 +pub const DEFAULT_SYSTEM_CALLER: Address = address!("fffffffffffffffffffffffffffffffffffffffe"); + +impl SystemTx { + /// Instantiate a new [`SystemTx`]. + pub const fn new(target: Address, input: Bytes) -> Self { + Self { caller: DEFAULT_SYSTEM_CALLER, target, input } + } + + /// Instantiate a new [`SystemTx`] with a custom caller address. + pub const fn new_with_caller(target: Address, input: Bytes, caller: Address) -> Self { + Self { caller, target, input } + } +} + +impl Tx for SystemTx { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { + let TxEnv { + caller, + gas_limit, + gas_price, + transact_to, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = tx_env; + *caller = self.caller; + *gas_limit = 30_000_000; + // 0 gas price + *gas_price = U256::ZERO; + *transact_to = self.target.into(); + *value = U256::ZERO; + *data = self.input.clone(); + // disable revm nonce checks + nonce.take(); + // disable chain id checks + chain_id.take(); + // set priority fee to 0 + gas_priority_fee.take(); + // disable eip-2930 + access_list.clear(); + // disable eip-4844 + blob_hashes.clear(); + max_fee_per_blob_gas.take(); + // disable eip-7702 + authorization_list.take(); + } +} diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs new file mode 100644 index 0000000..fc49257 --- /dev/null +++ b/src/syscall/mod.rs @@ -0,0 +1,102 @@ +//! Helpers for system actions including [EIP-4788], [EIP-6110], [EIP-7002] and +//! [EIP-7251]. +//! +//! System actions are special state changes or smart contract calls made +//! before or after transaction exection. These actions are introduced via +//! hardfork. System actions are sometimes modeled as transactions with special +//! properties (as in [EIP-4788], [EIP-7002] and [EIP-7251]) or as special state +//! changes outside of the transaction lifecycle (as in [EIP-6110]). +//! +//! System transactions are modeled by the [`SystemTx`] struct, which implements +//! the [`Tx`] trait. The system transactions are sent from a special system +//! caller address: [`DEFAULT_SYSTEM_CALLER`]. Note that the system caller is +//! specified independently in each EIP, which allows introduction off +//! different system callers in future EIPs +//! +//! [`Tx`]: crate::Tx +//! +//! [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 +//! [EIP-6110]: https://eips.ethereum.org/EIPS/eip-6110 +//! [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 +//! [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 + +mod fill; +pub use fill::{SystemTx, DEFAULT_SYSTEM_CALLER}; + +/// Helpers for Cancun beacon root [EIP-4788] system actions. +/// +/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 +pub mod eip4788; + +/// Helpers for Shanghai withdrawal [EIP-6110] system actions. +/// +/// [EIP-6110]: https://eips.ethereum.org/EIPS/eip-6110 +pub mod eip6110; + +/// Helpers for Prague withdrawal request [EIP-7002] system actions. +/// +/// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 +pub mod eip7002; + +/// Helpers for Prague consolidation request [EIP-7251] system actions. +/// +/// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 +pub mod eip7251; + +use crate::Tx; +use alloy_primitives::U256; +use revm::{ + primitives::{EVMError, ExecutionResult, ResultAndState}, + Database, DatabaseCommit, Evm, +}; + +/// Clean up the system call, restoring the block env. +fn cleanup_syscall( + evm: &mut Evm<'_, Ext, Db>, + result: &mut ResultAndState, + syscall: &SystemTx, + old_gas_limit: U256, + old_base_fee: U256, +) where + Db: Database + DatabaseCommit, +{ + evm.block_mut().gas_limit = old_gas_limit; + evm.block_mut().basefee = old_base_fee; + + // Remove the system caller and fees from the state + let coinbase = evm.block().coinbase; + let state = &mut result.state; + state.remove(&syscall.caller); + state.remove(&coinbase); +} + +/// Apply a system transaction as specified in [EIP-4788], [EIP-7002], or +/// [EIP-7251]. This function will execute the system transaction and apply +/// the result if non-error, cleaning up any extraneous state changes, and +/// restoring the block environment. +/// +/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 +/// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 +/// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 +pub fn execute_system_tx( + evm: &mut Evm<'_, Ext, Db>, + syscall: &SystemTx, +) -> Result> +where + Db: Database + DatabaseCommit, +{ + let limit = U256::from(evm.tx().gas_limit); + let old_gas_limit = std::mem::replace(&mut evm.block_mut().gas_limit, limit); + let old_base_fee = std::mem::replace(&mut evm.block_mut().basefee, U256::ZERO); + + syscall.fill_tx(evm); + let mut result = evm.transact()?; + + // Cleanup the syscall. + cleanup_syscall(evm, &mut result, syscall, old_gas_limit, old_base_fee); + + evm.db_mut().commit(result.state); + + // apply result, remove receipt from block outputs. + Ok(result.result) +} diff --git a/src/test_utils.rs b/src/test_utils.rs new file mode 100644 index 0000000..08682d8 --- /dev/null +++ b/src/test_utils.rs @@ -0,0 +1,113 @@ +use crate::{EvmNeedsCfg, Trevm, TrevmBuilder}; +use alloy_primitives::{Address, U256}; +use revm::{ + db::{CacheDB, EmptyDB, InMemoryDB}, + inspector_handle_register, + primitives::{AccountInfo, Bytecode}, + Database, DatabaseCommit, EvmBuilder, GetInspector, +}; + +pub use revm::test_utils as revm_test_utils; + +impl<'a, Ext, Db: Database + DatabaseCommit, State> Trevm<'a, Ext, Db, State> { + /// Make a new [`Trevm`] with a [`InMemoryDB`]. + pub fn test_trevm() -> EvmNeedsCfg<'static, (), InMemoryDB> { + test_trevm() + } + + /// Make a new [`Trevm`], funding the provided accounts with the given + /// amounts. + pub fn test_trevm_with_funds<'b, I>(i: I) -> EvmNeedsCfg<'static, (), InMemoryDB> + where + I: IntoIterator, + { + let mut trevm = test_trevm(); + + for (address, amount) in i { + trevm.test_set_balance(*address, *amount); + } + + trevm + } +} + +impl<'a, Ext, State> Trevm<'a, Ext, InMemoryDB, State> { + /// Modify an account with the provide closure. Returns the original + /// account info + pub fn test_modify_account(&mut self, address: Address, f: F) -> AccountInfo + where + F: FnOnce(&mut AccountInfo), + { + self.modify_account_unchecked(address, f) + } + + /// Set the nonce of an account, returning the previous nonce. + pub fn test_set_nonce(&mut self, address: Address, nonce: u64) -> u64 { + self.set_nonce_unchecked(address, nonce) + } + + /// Increment the nonce of an account, returning the previous nonce. + /// + /// If this would cause the nonce to overflow, the nonce will be set to the + /// maximum value. + pub fn test_increment_nonce(&mut self, address: Address) -> u64 { + self.increment_nonce_unchecked(address) + } + + /// Decrement the nonce of an account, returning the previous nonce. + /// + /// If this would cause the nonce to underflow, the nonce will be set to + /// 0. + pub fn test_decrement_nonce(&mut self, address: Address) -> u64 { + self.decrement_nonce_unchecked(address) + } + + /// Set the EVM storage at a slot. + pub fn test_set_storage(&mut self, address: Address, slot: U256, value: U256) -> U256 { + self.set_storage_unchecked(address, slot, value) + } + + /// Set the bytecode at a specific address, returning the previous bytecode + /// at that address. + pub fn test_set_bytecode(&mut self, address: Address, bytecode: Bytecode) -> Option { + self.set_bytecode_unchecked(address, bytecode) + } + + /// Increase the balance of an account. Returns the previous balance. + /// + /// If this would cause the balance to overflow, the balance will be set + /// to `U256::MAX`. + pub fn test_increase_balance(&mut self, address: Address, amount: U256) -> U256 { + self.increase_balance_unchecked(address, amount) + } + + /// Decrease the balance of an account. Returns the previous balance. + /// + /// If this would cause the balance to underflow, the balance will be set + /// to `U256::ZERO`. + pub fn test_decrease_balance(&mut self, address: Address, amount: U256) -> U256 { + self.decrease_balance_unchecked(address, amount) + } + + /// Set the balance of an account. Returns the previous balance. + pub fn test_set_balance(&mut self, address: Address, amount: U256) -> U256 { + self.set_balance_unchecked(address, amount) + } +} + +/// Make a new [`Trevm`] with the given inspector and an in-memory database. +pub fn test_trevm_with_inspector(inspector: I) -> EvmNeedsCfg<'static, I, CacheDB> +where + I: GetInspector, +{ + EvmBuilder::default() + .with_db(CacheDB::new(EmptyDB::default())) + .with_external_context(inspector) + .append_handler_register(inspector_handle_register) + .build_trevm() +} + +/// Make a new [`Trevm`] with an in-memory database. +pub fn test_trevm() -> EvmNeedsCfg<'static, (), CacheDB> { + EvmBuilder::default().with_db(CacheDB::new(EmptyDB::default())).build_trevm() +}