diff --git a/.github/workflows/client_host.yaml b/.github/workflows/client_host.yaml index 0a067c9902..37bfe20ed7 100644 --- a/.github/workflows/client_host.yaml +++ b/.github/workflows/client_host.yaml @@ -12,7 +12,7 @@ jobs: strategy: matrix: target: ["native", "asterisc"] - name: ["OP Sepolia (Holocene) - Block #22012816"] + name: ["OP Sepolia (Holocene) - Block #26215604"] runs-on: ubuntu-latest timeout-minutes: 20 steps: @@ -53,13 +53,13 @@ jobs: mv ./rvgo/bin/asterisc /usr/local/bin/ - name: Set run environment run: | - if [[ ${{ contains(matrix.name, 22012816) }} == true ]]; then - BLOCK_NUMBER=22012816 + if [[ ${{ contains(matrix.name, 26215604) }} == true ]]; then + BLOCK_NUMBER=26215604 echo "BLOCK_NUMBER=$BLOCK_NUMBER" >> $GITHUB_ENV - echo "L2_CLAIM=0x42ff78e504c207c3786cb30ecb74fe915984b48649165f95bbf6f9248584be69" >> $GITHUB_ENV - echo "L2_OUTPUT_ROOT=0x9084f101b85cd1c7c624946feca169768896d88b3ecf4eea3a7760bfceb9cd73" >> $GITHUB_ENV - echo "L2_HEAD=0x6a34183664b9ad39de024a8d4077c78abf05198148b6dbfc6e39fbe4a70de299" >> $GITHUB_ENV - echo "L1_HEAD=0x02a50d0b5a3226758a6e9b2bdeb5deb5f0779ab55b2b34a52331d0eac48c9389" >> $GITHUB_ENV + echo "L2_CLAIM=0x7415d942f80a34f77d344e4bccb7050f14e593f5ea33669d27ea01dce273d72d" >> $GITHUB_ENV + echo "L2_OUTPUT_ROOT=0xaa34b62993bd888d7a2ad8541935374e39948576fce12aa8179a0aa5b5bc787b" >> $GITHUB_ENV + echo "L2_HEAD=0xf4adf5790bad1ffc9eee315dc163df9102473c5726a2743da27a8a10dc16b473" >> $GITHUB_ENV + echo "L1_HEAD=0x010cfdb22eaa13e8cdfbf66403f8de2a026475e96a6635d53c31f853a0e3ae25" >> $GITHUB_ENV echo "L2_CHAIN_ID=11155420" >> $GITHUB_ENV echo "WITNESS_TAR_NAME=holocene-op-sepolia-$BLOCK_NUMBER-witness.tar.zst" >> $GITHUB_ENV fi diff --git a/Cargo.lock b/Cargo.lock index 04bf23541b..df26ea801a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,9 +106,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.1.69" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e2652684758b0d9b389d248b209ed9fd9989ef489a550265fe4bb8454fe7eb" +checksum = "7734aecfc58a597dde036e4c5cace2ae43e2f8bf3d406b022a1ef34da178dd49" dependencies = [ "alloy-primitives", "num_enum", @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fbf458101ed6c389e9bb70a34ebc56039868ad10472540614816cdedc8f5265" +checksum = "c2179ba839ac532f50279f5da2a6c5047f791f03f6f808b4dfab11327b97902f" dependencies = [ "alloy-eips", "alloy-primitives", @@ -130,7 +130,7 @@ dependencies = [ "arbitrary", "auto_impl", "c-kzg", - "derive_more 2.0.1", + "derive_more", "either", "k256", "once_cell", @@ -142,23 +142,24 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc982af629e511292310fe85b433427fd38cb3105147632b574abc997db44c91" +checksum = "aec6f67bdc62aa277e0ec13c1b1fb396c8a62b65c8e9bd8c1d3583cc6d1a8dd3" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", + "arbitrary", "serde", ] [[package]] name = "alloy-eip2124" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675264c957689f0fd75f5993a73123c2cc3b5c235a38f5b9037fe6c826bfb2c0" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -171,9 +172,9 @@ dependencies = [ [[package]] name = "alloy-eip2930" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +checksum = "dbe3e16484669964c26ac48390245d84c410b1a5f968976076c17184725ef235" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -184,9 +185,9 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b15b13d38b366d01e818fe8e710d4d702ef7499eacd44926a06171dd9585d0c" +checksum = "804cefe429015b4244966c006d25bda5545fa9db5990e9c9079faf255052f50a" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -199,9 +200,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e86967eb559920e4b9102e4cb825fe30f2e9467988353ce4809f0d3f2c90cd4" +checksum = "609515c1955b33af3d78d26357540f68c5551a90ef58fd53def04f2aa074ec43" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -212,20 +213,51 @@ dependencies = [ "arbitrary", "auto_impl", "c-kzg", - "derive_more 2.0.1", + "derive_more", "either", "ethereum_ssz", "ethereum_ssz_derive", - "once_cell", "serde", "sha2 0.10.8", ] +[[package]] +name = "alloy-evm" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1ae7de7526aed0484be50c4cc4c01122b94d0f70fd34fcca79e2caa987e434" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-hardforks", + "alloy-primitives", + "alloy-sol-types", + "auto_impl", + "derive_more", + "op-alloy-consensus", + "op-revm", + "revm", + "thiserror 2.0.12", +] + +[[package]] +name = "alloy-hardforks" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d3b2243e2adfaea41da41982f91ecab8083fa51b240d0427955d709f65b1b4" +dependencies = [ + "alloy-chains", + "alloy-eip2124", + "alloy-primitives", + "auto_impl", + "dyn-clone", +] + [[package]] name = "alloy-json-abi" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6beff64ad0aa6ad1019a3db26fef565aefeb011736150ab73ed3366c3cfd1b" +checksum = "5189fa9a8797e92396bc4b4454c5f2073a4945f7c2b366af9af60f9536558f7a" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -235,9 +267,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27434beae2514d4a2aa90f53832cbdf6f23e4b5e2656d95eaf15f9276e2418b6" +checksum = "3994ab6ff6bdeb5aebe65381a8f6a47534789817570111555e8ac413e242ce06" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -249,9 +281,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a33a38c7486b1945f8d093ff027add2f3a8f83c7300dbad6165cc49150085e" +checksum = "0be3aa020a6d3aa7601185b4c1a7d6f3a5228cb5424352db63064b29a455c891" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -266,7 +298,7 @@ dependencies = [ "alloy-sol-types", "async-trait", "auto_impl", - "derive_more 2.0.1", + "derive_more", "futures-utils-wasm", "serde", "serde_json", @@ -275,9 +307,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db973a7a23cbe96f2958e5687c51ce2d304b5c6d0dc5ccb3de8667ad8476f50b" +checksum = "498f2ee2eef38a6db0fc810c7bf7daebdf5f2fa8d04adb8bd53e54e91ddbdea3" dependencies = [ "alloy-consensus", "alloy-eips", @@ -286,11 +318,38 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-op-evm" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427bfde7779a82607cc97df6c6e634dc8b25a1412d03d0e26a2ef27b83c3856a" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-op-hardforks", + "alloy-primitives", + "auto_impl", + "op-alloy-consensus", + "op-revm", + "revm", +] + +[[package]] +name = "alloy-op-hardforks" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04a45f2af91a348e5d22dbb3589d821d2e83d2e65b54c14c3f9e8e9c6903fc09" +dependencies = [ + "alloy-hardforks", + "auto_impl", +] + [[package]] name = "alloy-primitives" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e" +checksum = "70b98b99c1dcfbe74d7f0b31433ff215e7d1555e367d90e62db904f3c9d4ff53" dependencies = [ "alloy-rlp", "arbitrary", @@ -298,9 +357,9 @@ dependencies = [ "cfg-if", "const-hex", "derive_arbitrary", - "derive_more 2.0.1", + "derive_more", "foldhash", - "getrandom 0.2.15", + "getrandom 0.3.2", "hashbrown 0.15.2", "indexmap 2.9.0", "itoa", @@ -309,7 +368,7 @@ dependencies = [ "paste", "proptest", "proptest-derive", - "rand 0.8.5", + "rand 0.9.0", "ruint", "rustc-hash 2.1.1", "serde", @@ -319,9 +378,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b03bde77ad73feae14aa593bcabb932c8098c0f0750ead973331cfc0003a4e1" +checksum = "3d6ba76d476f475668925f858cc4db51781f12abdaa4e0274eb57a09f574e869" dependencies = [ "alloy-chains", "alloy-consensus", @@ -334,6 +393,7 @@ dependencies = [ "alloy-rpc-client", "alloy-rpc-types-engine", "alloy-rpc-types-eth", + "alloy-signer", "alloy-sol-types", "alloy-transport", "alloy-transport-http", @@ -343,6 +403,7 @@ dependencies = [ "async-trait", "auto_impl", "dashmap", + "either", "futures", "futures-utils-wasm", "lru 0.13.0", @@ -360,21 +421,23 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721aca709a9231815ad5903a2d284042cc77e7d9d382696451b30c9ee0950001" +checksum = "04135d2fd7fa1fba3afe9f79ec2967259dbc0948e02fa0cd0e33a4a812e2cb0a" dependencies = [ "alloy-json-rpc", "alloy-primitives", "alloy-transport", "bimap", "futures", + "parking_lot", "serde", "serde_json", "tokio", "tokio-stream", "tower 0.5.2", "tracing", + "wasmtimer", ] [[package]] @@ -401,9 +464,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445a3298c14fae7afb5b9f2f735dead989f3dd83020c2ab8e48ed95d7b6d1acb" +checksum = "1d6a6985b48a536b47aa0aece56e6a0f49240ce5d33a7f0c94f1b312eda79aa1" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -429,9 +492,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157deaec6ba2ad7854f16146e4cd60280e76593eed79fdcb06e0fa8b6c60f77" +checksum = "3bf27873220877cb15125eb6eec2f86c6e9b41473aca85844bd3d9d755bfc0a0" dependencies = [ "alloy-primitives", "alloy-rpc-types-debug", @@ -442,9 +505,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604dea1f00fd646debe8033abe8e767c732868bf8a5ae9df6321909ccbc99c56" +checksum = "d1a40595b927dfb07218459037837dbc8de8500a26024bb6ff0548dd2ccc13e0" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -453,9 +516,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645455186916281e0b3f063fd07d007711257cf90c3499ff3569a39ffdfc9d2f" +checksum = "77c08a6f2593a8b6401e579996a887b22794543e0ff5976c5c21ddd361755dec" dependencies = [ "alloy-eips", "alloy-primitives", @@ -467,9 +530,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08b113a0087d226291b9768ed331818fa0b0744cc1207ae7c150687cf3fde1bd" +checksum = "05525519bd7f37f98875354f0b3693d3ad3c7a7f067e3b8946777920be15cb5b" dependencies = [ "alloy-primitives", "serde", @@ -477,16 +540,16 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874ac9d1249ece0453e262d9ba72da9dbb3b7a2866220ded5940c2e47f1aa04d" +checksum = "4235d79af20fe5583ca26096258fe9307571a345745c433cfd8c91b41aa2611e" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", - "derive_more 2.0.1", + "derive_more", "ethereum_ssz", "ethereum_ssz_derive", "jsonwebtoken", @@ -497,9 +560,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e13d71eac04513a71af4b3df580f52f2b4dcbff9d971cc9a52519acf55514cb" +checksum = "f2a9f64e0f69cfb6029e2a044519a1bdd44ce9fc334d5315a7b9837f7a6748e5" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -518,9 +581,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1cd73fc054de6353c7f22ff9b846b0f0f145cd0112da07d4119e41e9959207" +checksum = "d4dba6ff08916bc0a9cbba121ce21f67c0b554c39cf174bc7b9df6c651bd3c3b" dependencies = [ "alloy-primitives", "arbitrary", @@ -530,9 +593,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96fbde54bee943cd94ebacc8a62c50b38c7dfd2552dcd79ff61aea778b1bfcc" +checksum = "0c580da7f00f3999e44e327223044d6732358627f93043e22d92c583f6583556" dependencies = [ "alloy-primitives", "async-trait", @@ -545,9 +608,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" +checksum = "60fcfa26956bcb22f66ab13407115197f26ef23abca5b48d39a1946897382d74" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -559,9 +622,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ad5da86c127751bc607c174d6c9fe9b85ef0889a9ca0c641735d77d4f98f26" +checksum = "72a9b402f0013f1ff8c24066eeafc2207a8e52810a2b18b77776ce7fead5af41" dependencies = [ "alloy-sol-macro-input", "const-hex", @@ -577,9 +640,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3d30f0d3f9ba3b7686f3ff1de9ee312647aac705604417a2f40c604f409a9e" +checksum = "d02d61741337bb6b3f4899c2e3173fe17ffa2810e143d3b28acd953197c8dd79" dependencies = [ "const-hex", "dunce", @@ -593,9 +656,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" +checksum = "d2b5f5f9f561c29f78ea521ebe2e5ac1633f1b1442dae582f68ecd57c6350042" dependencies = [ "serde", "winnow", @@ -603,9 +666,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43d5e60466a440230c07761aa67671d4719d46f43be8ea6e7ed334d8db4a9ab" +checksum = "c02635bce18205ff8149fb752c753b0a91ea3f3c8ee04c58846448be4811a640" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -616,13 +679,13 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec325c2af8562ef355c02aeb527c755a07e9d8cf6a1e65dda8d0bf23e29b2c" +checksum = "6e1f1a55f9ff9a48aa0b4a8c616803754620010fbb266edae2f4548f4304373b" dependencies = [ "alloy-json-rpc", "base64", - "derive_more 2.0.1", + "derive_more", "futures", "futures-utils-wasm", "parking_lot", @@ -638,9 +701,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a082c9473c6642cce8b02405a979496126a03b096997888e86229afad05db06c" +checksum = "171b3d8824b6697d6c8325373ec410d230b6c59ce552edfbfabe4e7b8a26aac3" dependencies = [ "alloy-json-rpc", "alloy-rpc-types-engine", @@ -658,9 +721,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a78cfda2cac16fa83f6b5dd8b4643caec6161433b25b67e484ce05d2194513" +checksum = "f8a71043836f2144e1fe30f874eb2e9d71d2632d530e35b09fadbf787232f3f4" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -678,9 +741,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.12.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae865917bdabaae21f418010fe7e8837c6daa6611fde25f8d78a1778d6ecb523" +checksum = "fdde5b241745076bcbf2fcad818f2c42203bd2c5f4b50ea43b628ccbd2147ad6" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -696,15 +759,19 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.7.9" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a94854e420f07e962f7807485856cde359ab99ab6413883e15235ad996e8b" +checksum = "983d99aa81f586cef9dae38443245e585840fcf0fc58b09aee0b1f27aed1d500" dependencies = [ "alloy-primitives", "alloy-rlp", + "arbitrary", "arrayvec", - "derive_more 1.0.0", + "derive_arbitrary", + "derive_more", "nybbles", + "proptest", + "proptest-derive", "serde", "smallvec", "tracing", @@ -783,9 +850,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -805,6 +872,51 @@ dependencies = [ "arbitrary", ] +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -843,6 +955,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -863,6 +995,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.100", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -888,6 +1030,63 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber 0.2.25", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -909,6 +1108,30 @@ dependencies = [ "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -929,6 +1152,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -1223,6 +1456,22 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1390,10 +1639,11 @@ dependencies = [ [[package]] name = "c-kzg" -version = "1.0.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +checksum = "4e7e3c397401eb76228c89561cf22f85f41c95aa799ee9d860de3ea1cbc728fc" dependencies = [ + "arbitrary", "blst", "cc", "glob", @@ -1637,6 +1887,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1901,15 +2160,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "data-encoding-macro" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9724adfcf41f45bf652b3995837669d73c4d49a1b5ac1ff82905ac7d9b5558" +checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -1917,9 +2176,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4fdb82bd54a12e42fb58a800dcae6b9e13982238ce2296dc3570b92148e1f" +checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" dependencies = [ "data-encoding", "syn 2.0.100", @@ -1991,10 +2250,10 @@ dependencies = [ ] [[package]] -name = "derive_arbitrary" -version = "1.4.1" +name = "derive-where" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", @@ -2002,12 +2261,14 @@ dependencies = [ ] [[package]] -name = "derive_more" -version = "1.0.0" +name = "derive_arbitrary" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ - "derive_more-impl 1.0.0", + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] @@ -2016,18 +2277,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ - "derive_more-impl 2.0.1", -] - -[[package]] -name = "derive_more-impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "derive_more-impl", ] [[package]] @@ -2036,6 +2286,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ + "convert_case", "proc-macro2", "quote", "syn 2.0.100", @@ -2192,6 +2443,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "either" version = "1.15.0" @@ -2261,6 +2524,26 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "enumn" version = "0.1.14" @@ -2310,9 +2593,9 @@ dependencies = [ [[package]] name = "ethereum_serde_utils" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70cbccfccf81d67bff0ab36e591fa536c8a935b078a7b0e58c1d00d418332fc9" +checksum = "3dc1355dbb41fbbd34ec28d4fb2a57d9a70c67ac3c19f6a5ca4d4a176b9e997a" dependencies = [ "alloy-primitives", "hex", @@ -2323,9 +2606,9 @@ dependencies = [ [[package]] name = "ethereum_ssz" -version = "0.8.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86da3096d1304f5f28476ce383005385459afeaf0eea08592b65ddbc9b258d16" +checksum = "9ca8ba45b63c389c6e115b095ca16381534fdcc03cf58176a3f8554db2dbe19b" dependencies = [ "alloy-primitives", "ethereum_serde_utils", @@ -2338,9 +2621,9 @@ dependencies = [ [[package]] name = "ethereum_ssz_derive" -version = "0.8.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d832a5c38eba0e7ad92592f7a22d693954637fbb332b4f669590d66a5c3183e5" +checksum = "0dd55d08012b4e0dfcc92b8d6081234df65f2986ad34cc76eeed69c5e2ce7506" dependencies = [ "darling", "proc-macro2", @@ -2379,7 +2662,7 @@ dependencies = [ "kona-p2p", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -2394,7 +2677,7 @@ dependencies = [ "libp2p", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -2766,9 +3049,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" dependencies = [ "atomic-waker", "bytes", @@ -2862,6 +3145,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hex_fmt" version = "0.3.0" @@ -3752,7 +4044,7 @@ dependencies = [ "libc", "metrics-exporter-prometheus", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -3761,6 +4053,8 @@ version = "0.1.0" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-evm", + "alloy-op-evm", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", @@ -3782,11 +4076,14 @@ dependencies = [ "lru 0.13.0", "op-alloy-consensus", "op-alloy-rpc-types-engine", + "op-revm", "revm", "serde", "serde_json", + "sha2 0.10.8", "spin 0.10.0", "thiserror 2.0.12", + "tokio", "tracing", ] @@ -3811,13 +4108,12 @@ dependencies = [ "op-alloy-consensus", "proptest", "rand 0.9.0", - "revm", "serde", "serde_json", "spin 0.10.0", "thiserror 2.0.12", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "unsigned-varint 0.8.0", ] @@ -3844,7 +4140,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -3852,6 +4148,7 @@ name = "kona-driver" version = "0.3.0" dependencies = [ "alloy-consensus", + "alloy-evm", "alloy-primitives", "alloy-rlp", "async-trait", @@ -3884,7 +4181,7 @@ dependencies = [ "alloy-transport-http", "arbitrary", "async-trait", - "derive_more 2.0.1", + "derive_more", "http-body-util", "kona-genesis", "kona-protocol", @@ -3911,6 +4208,9 @@ version = "0.3.0" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-evm", + "alloy-op-evm", + "alloy-op-hardforks", "alloy-primitives", "alloy-provider", "alloy-rlp", @@ -3919,13 +4219,12 @@ dependencies = [ "alloy-transport", "alloy-transport-http", "alloy-trie", - "criterion", "kona-genesis", "kona-mpt", "kona-registry", "op-alloy-consensus", "op-alloy-rpc-types-engine", - "pprof", + "op-revm", "rand 0.9.0", "revm", "rocksdb", @@ -3944,13 +4243,15 @@ version = "0.3.0" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-hardforks", + "alloy-op-hardforks", "alloy-primitives", "alloy-sol-types", "arbitrary", - "derive_more 2.0.1", + "derive_more", "kona-serde", + "op-revm", "rand 0.9.0", - "revm", "serde", "serde_json", "serde_repr", @@ -3973,6 +4274,7 @@ version = "0.1.1" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-op-evm", "alloy-primitives", "alloy-provider", "alloy-rlp", @@ -4011,7 +4313,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -4025,7 +4327,7 @@ dependencies = [ "alloy-sol-types", "arbitrary", "async-trait", - "derive_more 2.0.1", + "derive_more", "kona-genesis", "kona-registry", "op-alloy-consensus", @@ -4081,7 +4383,7 @@ dependencies = [ "tabled", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "url", ] @@ -4096,7 +4398,7 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-transport", "async-trait", - "derive_more 2.0.1", + "derive_more", "futures", "jsonrpsee", "kona-derive", @@ -4126,7 +4428,7 @@ dependencies = [ "arbitrary", "arbtest", "async-trait", - "derive_more 2.0.1", + "derive_more", "dirs", "discv5", "futures", @@ -4138,7 +4440,7 @@ dependencies = [ "multihash", "op-alloy-rpc-types-engine", "openssl", - "secp256k1 0.30.0", + "secp256k1", "serde", "serde_json", "snap", @@ -4170,6 +4472,8 @@ version = "0.3.0" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-evm", + "alloy-op-evm", "alloy-primitives", "alloy-rlp", "alloy-trie", @@ -4186,6 +4490,7 @@ dependencies = [ "lru 0.13.0", "op-alloy-consensus", "op-alloy-rpc-types-engine", + "op-revm", "rstest", "serde", "serde_json", @@ -4201,6 +4506,7 @@ version = "0.2.0" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-op-evm", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", @@ -4239,14 +4545,13 @@ dependencies = [ "arbitrary", "async-trait", "brotli", - "derive_more 2.0.1", + "derive_more", "kona-genesis", "miniz_oxide", "op-alloy-consensus", "op-alloy-rpc-types", "proptest", "rand 0.9.0", - "revm", "rstest", "serde", "serde_json", @@ -4254,7 +4559,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "unsigned-varint 0.8.0", ] @@ -4306,7 +4611,7 @@ dependencies = [ "alloy-primitives", "alloy-rpc-client", "async-trait", - "derive_more 2.0.1", + "derive_more", "getrandom 0.3.2", "jsonrpsee", "kona-genesis", @@ -4371,9 +4676,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" @@ -4871,7 +5176,7 @@ dependencies = [ "generator", "scoped-tls", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -5349,6 +5654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" dependencies = [ "alloy-rlp", + "arbitrary", "const-hex", "proptest", "serde", @@ -5387,9 +5693,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "op-alloy-consensus" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "889facbf449b2d9c8de591cd467a6c7217936f3c1c07a281759c01c49d08d66d" +checksum = "1a09198717ebb22b201442c12a306a62de4a5d9535993b975c6bc0e5a919e2b1" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5397,16 +5703,16 @@ dependencies = [ "alloy-rlp", "alloy-serde", "arbitrary", - "derive_more 2.0.1", + "derive_more", "serde", "thiserror 2.0.12", ] [[package]] name = "op-alloy-network" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248ee57676f8e249cf250a72c887d3376d256c58fe3d73d06cff2170daee244" +checksum = "a244918cb04caafab5d53f1d78ec684295cac83e1966b4ae874220d7f070d6fe" dependencies = [ "alloy-consensus", "alloy-network", @@ -5419,9 +5725,9 @@ dependencies = [ [[package]] name = "op-alloy-provider" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c63517ff704ab5993f2bfeedb881099e44493f3b8b0441d2b7a5bbbce6cb2e" +checksum = "eef175021386c4fc7324ead2a2704ef5e6f9f0b9931e045c121a2596cf64b073" dependencies = [ "alloy-network", "alloy-primitives", @@ -5434,9 +5740,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-jsonrpsee" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bf4be90d70d847c0d41c39364dec96bd1e6bb9212826bfba0cf0aab85a81da" +checksum = "9de601488af140dc7c981480284211262f15eb2f34a36c9d2540bc042dd26dcd" dependencies = [ "alloy-primitives", "jsonrpsee", @@ -5444,9 +5750,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba7bfcc5d0b08c7a8bbdfaffa81e47edbb00185f0bf08e9f008216057700e50" +checksum = "f410c4bd213df7c4963828b45a1e201d119b5c223d12468ad8e393e655167eee" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5455,7 +5761,7 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-serde", "arbitrary", - "derive_more 2.0.1", + "derive_more", "op-alloy-consensus", "serde", "serde_json", @@ -5463,16 +5769,16 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d639498a499be4370d9b0c4542acd04f181ae991104d9965a5a65ba976f04888" +checksum = "b8ec35c34f8b74f329b0a43ab462c65943cf894406126b613e65e0e4313eaadb" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", "alloy-serde", - "derive_more 2.0.1", + "derive_more", "ethereum_ssz", "op-alloy-consensus", "serde", @@ -5480,6 +5786,18 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "op-revm" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8646cb935063087579f44da58fe1dea329c280c3b35898d6fd01a928de91f" +dependencies = [ + "auto_impl", + "once_cell", + "revm", + "serde", +] + [[package]] name = "opaque-debug" version = "0.3.1" @@ -5675,6 +5993,48 @@ dependencies = [ "rustc_version 0.4.1", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -6124,6 +6484,7 @@ checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", + "serde", "zerocopy 0.8.24", ] @@ -6163,6 +6524,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.2", + "serde", ] [[package]] @@ -6365,67 +6727,184 @@ dependencies = [ [[package]] name = "revm" -version = "19.7.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c175ecec83bba464aa8406502fe5bf670491c2ace81a153264891d43bc7fa332" +checksum = "f5378e95ffe5c8377002dafeb6f7d370a55517cef7d6d6c16fc552253af3b123" +dependencies = [ + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", +] + +[[package]] +name = "revm-bytecode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63e138d520c5c5bc25ecc82506e9e4e6e85a811809fc5251c594378dccabfc6" +dependencies = [ + "bitvec", + "phf", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-context" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9765628dfea4f3686aa8f2a72471c52801e6b38b601939ac16965f49bac66580" dependencies = [ - "auto_impl", "cfg-if", - "dyn-clone", - "once_cell", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-context-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d74335aa1f14222cc4d3be1f62a029cc7dc03819cc8d080ff17b7e1d76375f" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5c80c5a2fd605f2119ee32a63fb3be941fb6a81ced8cdb3397abca28317224" +dependencies = [ + "alloy-eips", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e4dfbc734b1ea67b5e8f8b3c7dc4283e2210d978cdaf6c7a45e97be5ea53b3" +dependencies = [ + "auto_impl", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-handler" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8676379521c7bf179c31b685c5126ce7800eab5844122aef3231b97026d41a10" +dependencies = [ + "auto_impl", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database-interface", "revm-interpreter", "revm-precompile", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-inspector" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfed4ecf999a3f6ae776ae2d160478c5dca986a8c2d02168e04066b1e34c789e" +dependencies = [ + "auto_impl", + "revm-context", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives", + "revm-state", "serde", "serde_json", ] [[package]] name = "revm-interpreter" -version = "15.2.0" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcab7ef2064057acfc84731205f4bc77f4ec1b35630800b26ff6a185731c5ab" +checksum = "feb20260342003cfb791536e678ef5bbea1bfd1f8178b170e8885ff821985473" dependencies = [ + "revm-bytecode", + "revm-context-interface", "revm-primitives", "serde", ] [[package]] name = "revm-precompile" -version = "16.2.0" +version = "19.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99743c3a2cac341084cc15ac74286c4bf34a0941ebf60aa420cfdb9f81f72f9f" +checksum = "418e95eba68c9806c74f3e36cd5d2259170b61e90ac608b17ff8c435038ddace" dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", "aurora-engine-modexp", "blst", "c-kzg", "cfg-if", "k256", + "libsecp256k1", "once_cell", "p256", "revm-primitives", "ripemd", - "secp256k1 0.29.1", + "secp256k1", "sha2 0.10.8", - "substrate-bn", ] [[package]] name = "revm-primitives" -version = "15.2.0" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f987564210317706def498421dfba2ae1af64a8edce82c6102758b48133fcb" +checksum = "1fc2283ff87358ec7501956c5dd8724a6c2be959c619c4861395ae5e0054575f" dependencies = [ - "alloy-eip2930", - "alloy-eip7702", "alloy-primitives", - "auto_impl", - "bitflags 2.9.0", - "bitvec", - "c-kzg", - "cfg-if", - "dyn-clone", "enumn", - "hex", + "serde", +] + +[[package]] +name = "revm-state" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09dd121f6e66d75ab111fb51b4712f129511569bc3e41e6067ae760861418bd8" +dependencies = [ + "bitflags 2.9.0", + "revm-bytecode", + "revm-primitives", "serde", ] @@ -6862,22 +7341,14 @@ dependencies = [ "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" -dependencies = [ - "rand 0.8.5", - "secp256k1-sys", -] - [[package]] name = "secp256k1" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", "secp256k1-sys", ] @@ -7174,6 +7645,12 @@ dependencies = [ "time", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "sketches-ddsketch" version = "0.3.0" @@ -7195,6 +7672,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" dependencies = [ + "arbitrary", "serde", ] @@ -7327,19 +7805,6 @@ dependencies = [ "syn 2.0.100", ] -[[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 0.8.5", - "rustc-hex", -] - [[package]] name = "subtle" version = "2.6.1" @@ -7393,9 +7858,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.25" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560533fbd6914b94a8fb5cc803ed6801c3455668db3b810702c57612bac9412" +checksum = "34c9c96de1f835488c1501092847b522be88c9ac6fb0d4c0fbea92992324c8f4" dependencies = [ "paste", "proc-macro2", @@ -7850,6 +8315,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -7942,6 +8416,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index b1fa4be6b0..683f277e3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,35 +103,40 @@ kona-serde = { path = "crates/utilities/serde", version = "0.2.0", default-featu # Alloy alloy-rlp = { version = "0.3.11", default-features = false } -alloy-trie = { version = "0.7.9", default-features = false } -alloy-chains = { version = "0.1", default-features = false } -alloy-eips = { version = "0.12.6", default-features = false } -alloy-serde = { version = "0.12.6", default-features = false } -alloy-network = { version = "0.12.6", default-features = false } -alloy-provider = { version = "0.12.6", default-features = false } -alloy-sol-types = { version = "0.8.24", default-features = false } -alloy-consensus = { version = "0.12.6", default-features = false } -alloy-transport = { version = "0.12.6", default-features = false } -alloy-rpc-types = { version = "0.12.6", default-features = false } -alloy-rpc-client = { version = "0.12.6", default-features = false } -alloy-primitives = { version = "0.8.24", default-features = false } -alloy-node-bindings = { version = "0.12.6", default-features = false } -alloy-rpc-types-eth = { version = "0.12.6", default-features = false } -alloy-transport-http = { version = "0.12.6", default-features = false } -alloy-rpc-types-engine = { version = "0.12.6", default-features = false } -alloy-rpc-types-beacon = { version = "0.12.6", default-features = false } -alloy-network-primitives = { version = "0.12.6", default-features = false } +alloy-trie = { version = "0.8.0", default-features = false } +alloy-chains = { version = "0.2", default-features = false } +alloy-eips = { version = "0.14.0", default-features = false } +alloy-serde = { version = "0.14.0", default-features = false } +alloy-network = { version = "0.14.0", default-features = false } +alloy-provider = { version = "0.14.0", default-features = false } +alloy-sol-types = { version = "1.0.0", default-features = false } +alloy-consensus = { version = "0.14.0", default-features = false } +alloy-transport = { version = "0.14.0", default-features = false } +alloy-rpc-types = { version = "0.14.0", default-features = false } +alloy-rpc-client = { version = "0.14.0", default-features = false } +alloy-primitives = { version = "1.0.0", default-features = false } +alloy-node-bindings = { version = "0.14.0", default-features = false } +alloy-rpc-types-eth = { version = "0.14.0", default-features = false } +alloy-transport-http = { version = "0.14.0", default-features = false } +alloy-rpc-types-engine = { version = "0.14.0", default-features = false } +alloy-rpc-types-beacon = { version = "0.14.0", default-features = false } +alloy-network-primitives = { version = "0.14.0", default-features = false } +alloy-hardforks = { version = "0.2.0", default-features = false } # OP Alloy -op-alloy-network = { version = "0.11.4", default-features = false } -op-alloy-provider = { version = "0.11.4", default-features = false } -op-alloy-consensus = { version = "0.11.4", default-features = false } -op-alloy-rpc-types = { version = "0.11.4", default-features = false } -op-alloy-rpc-jsonrpsee = { version = "0.11.4", default-features = false } -op-alloy-rpc-types-engine = { version = "0.11.4", default-features = false } +op-alloy-network = { version = "0.13.0", default-features = false } +op-alloy-provider = { version = "0.13.0", default-features = false } +op-alloy-consensus = { version = "0.13.0", default-features = false } +op-alloy-rpc-types = { version = "0.13.0", default-features = false } +op-alloy-rpc-jsonrpsee = { version = "0.13.0", default-features = false } +op-alloy-rpc-types-engine = { version = "0.13.0", default-features = false } +alloy-op-hardforks = { version = "0.2.0", default-features = false } # Execution -revm = { version = "19.7.0", default-features = false } +revm = { version = "22.0.0", default-features = false } +op-revm = { version = "3.0.1", default-features = false } +alloy-evm = { version = "0.4.0", default-features = false, features = ["op"] } +alloy-op-evm = { version = "0.4.0", default-features = false } # General url = "2.5.4" diff --git a/bin/client/Cargo.toml b/bin/client/Cargo.toml index 80a8baa0b1..427e642b67 100644 --- a/bin/client/Cargo.toml +++ b/bin/client/Cargo.toml @@ -37,8 +37,11 @@ alloy-rpc-types-engine.workspace = true op-alloy-consensus.workspace = true op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] } -# Revm +# Execution revm.workspace = true +op-revm.workspace = true +alloy-evm.workspace = true +alloy-op-evm.workspace = true # General lru.workspace = true @@ -50,6 +53,11 @@ serde_json.workspace = true async-trait.workspace = true thiserror.workspace = true +[dev-dependencies] +tokio = { workspace = true, features = ["full"] } +kona-preimage = { workspace = true, features = ["std"] } +sha2.workspace = true + [features] default = ["client-tracing"] client-tracing = ["kona-std-fpvm/tracing"] diff --git a/bin/client/src/fpvm_evm/factory.rs b/bin/client/src/fpvm_evm/factory.rs new file mode 100644 index 0000000000..21ebafe12f --- /dev/null +++ b/bin/client/src/fpvm_evm/factory.rs @@ -0,0 +1,99 @@ +//! [`EvmFactory`] implementation for the EVM in the FPVM environment. + +use super::precompiles::OpFpvmPrecompiles; +use alloy_evm::{Database, EvmEnv, EvmFactory}; +use alloy_op_evm::OpEvm; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use op_revm::{ + DefaultOp, OpContext, OpEvm as RevmOpEvm, OpHaltReason, OpSpecId, OpTransaction, + OpTransactionError, +}; +use revm::{ + Context, Inspector, + context::{Evm as RevmEvm, EvmData, TxEnv, result::EVMError}, + handler::instructions::EthInstructions, + inspector::NoOpInspector, +}; + +/// Factory producing [`OpEvm`]s with FPVM-accelerated precompile overrides enabled. +#[derive(Debug, Clone)] +pub struct FpvmOpEvmFactory { + /// The hint writer. + hint_writer: HintWriter, + /// The oracle reader. + oracle_reader: OracleReader, +} + +impl FpvmOpEvmFactory +where + C: Channel + Clone + Send + Sync + 'static, +{ + /// Creates a new [`FpvmOpEvmFactory`]. + pub fn new(hint_writer: HintWriter, oracle_reader: OracleReader) -> Self { + Self { hint_writer, oracle_reader } + } + + /// Returns a reference to the inner [`HintWriter`]. + pub fn hint_writer(&self) -> &HintWriter { + &self.hint_writer + } + + /// Returns a reference to the inner [`OracleReader`]. + pub fn oracle_reader(&self) -> &OracleReader { + &self.oracle_reader + } +} + +impl EvmFactory for FpvmOpEvmFactory +where + C: Channel + Clone + Send + Sync + 'static, +{ + type Evm>> = OpEvm>; + type Context = OpContext; + type Tx = OpTransaction; + type Error = + EVMError; + type HaltReason = OpHaltReason; + type Spec = OpSpecId; + + fn create_evm( + &self, + db: DB, + input: EvmEnv, + ) -> Self::Evm { + let spec_id = *input.spec_id(); + let ctx = Context::op().with_db(db).with_block(input.block_env).with_cfg(input.cfg_env); + let revm_evm = RevmOpEvm(RevmEvm { + data: EvmData { ctx, inspector: NoOpInspector {} }, + instruction: EthInstructions::new_mainnet(), + precompiles: OpFpvmPrecompiles::new_with_spec( + spec_id, + self.hint_writer.clone(), + self.oracle_reader.clone(), + ), + }); + + OpEvm::new(revm_evm, false) + } + + fn create_evm_with_inspector>>( + &self, + db: DB, + input: EvmEnv, + inspector: I, + ) -> Self::Evm { + let spec_id = *input.spec_id(); + let ctx = Context::op().with_db(db).with_block(input.block_env).with_cfg(input.cfg_env); + let revm_evm = RevmOpEvm(RevmEvm { + data: EvmData { ctx, inspector }, + instruction: EthInstructions::new_mainnet(), + precompiles: OpFpvmPrecompiles::new_with_spec( + spec_id, + self.hint_writer.clone(), + self.oracle_reader.clone(), + ), + }); + + OpEvm::new(revm_evm, true) + } +} diff --git a/bin/client/src/fpvm_evm/mod.rs b/bin/client/src/fpvm_evm/mod.rs new file mode 100644 index 0000000000..12e30bb820 --- /dev/null +++ b/bin/client/src/fpvm_evm/mod.rs @@ -0,0 +1,8 @@ +//! Custom [`EvmFactory`] for the fault proof virtual machine's EVM. +//! +//! [`EvmFactory`]: alloy_evm::EvmFactory + +mod precompiles; + +mod factory; +pub use factory::FpvmOpEvmFactory; diff --git a/bin/client/src/fpvm_evm/precompiles/bls12_g1_add.rs b/bin/client/src/fpvm_evm/precompiles/bls12_g1_add.rs new file mode 100644 index 0000000000..7573aa1dd6 --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bls12_g1_add.rs @@ -0,0 +1,94 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G1 Point Addition. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g1_add.rs + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, bls12_381, + bls12_381_const::{G1_ADD_BASE_GAS_FEE, G1_ADD_INPUT_LENGTH}, +}; + +/// Performs an FPVM-accelerated BLS12-381 G1 addition check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +pub(crate) fn fpvm_bls12_g1_add( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + if G1_ADD_BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let input_len = input.len(); + if input_len != G1_ADD_INPUT_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "G1 addition input length should be {G1_ADD_INPUT_LENGTH} bytes, was {input_len}" + ))); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[bls12_381::g1_add::PRECOMPILE.address().as_slice(), &G1_ADD_BASE_GAS_FEE.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(G1_ADD_BASE_GAS_FEE, result_data.into())) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g1_add() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + // G1.INF + G1.INF = G1.INF + let input = [0u8; G1_ADD_INPUT_LENGTH]; + let accelerated_result = + fpvm_bls12_g1_add(&input, u64::MAX, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile( + *bls12_381::g1_add::PRECOMPILE.address(), + input, + u64::MAX, + ) + .unwrap(); + + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g1_add_bad_input_len() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g1_add(&[], u64::MAX, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g1_add_bad_gas_limit() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g1_add(&[], 0, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/bls12_g1_msm.rs b/bin/client/src/fpvm_evm/precompiles/bls12_g1_msm.rs new file mode 100644 index 0000000000..5443073068 --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bls12_g1_msm.rs @@ -0,0 +1,122 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G1 MSM. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g1_msm.rs + +use crate::fpvm_evm::precompiles::utils::{msm_required_gas, precompile_run}; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, bls12_381, + bls12_381_const::{DISCOUNT_TABLE_G1_MSM, G1_MSM_BASE_GAS_FEE, G1_MSM_INPUT_LENGTH}, +}; + +/// The maximum input size for the BLS12-381 g1 msm operation after the Isthmus Hardfork. +/// +/// See: +const BLS12_MAX_G1_MSM_SIZE_ISTHMUS: usize = 513760; + +/// Performs an FPVM-accelerated `bls12` g1 msm check precompile call after the Isthmus Hardfork. +pub(crate) fn fpvm_bls12_g1_msm( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + if input.len() > BLS12_MAX_G1_MSM_SIZE_ISTHMUS { + return Err(PrecompileError::Other(alloc::format!( + "G1MSM input length must be at most {}", + BLS12_MAX_G1_MSM_SIZE_ISTHMUS + ))); + } + + let input_len = input.len(); + if input_len == 0 || input_len % G1_MSM_INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(alloc::format!( + "G1MSM input length should be multiple of {}, was {}", + G1_MSM_INPUT_LENGTH, + input_len + ))); + } + + let k = input_len / G1_MSM_INPUT_LENGTH; + let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G1_MSM, G1_MSM_BASE_GAS_FEE); + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[bls12_381::g1_msm::PRECOMPILE.address().as_slice(), &required_gas.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(required_gas, result_data.into())) +} + +#[cfg(test)] +mod test { + use alloy_primitives::hex; + + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g1_msm() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + // https://raw.githubusercontent.com/ethereum/execution-spec-tests/a1c4eeff347a64ad6c5aedd51314d4ffc067346b/tests/prague/eip2537_bls_12_381_precompiles/vectors/msm_G1_bls.json + let input = hex!("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000002"); + let expected = hex!("000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28"); + + let accelerated_result = fpvm_bls12_g1_msm(&input, 12000, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(*bls12_381::g1_msm::PRECOMPILE.address(), input, 12000).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), expected.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g1_msm_bad_input_len_isthmus() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = fpvm_bls12_g1_msm( + &[0u8; BLS12_MAX_G1_MSM_SIZE_ISTHMUS + 1], + u64::MAX, + hint_writer, + oracle_reader, + ) + .unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g1_msm_bad_input_len() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g1_msm(&[], u64::MAX, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g1_msm_bad_gas_limit() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g1_msm(&[0u8; G1_MSM_INPUT_LENGTH], 0, hint_writer, oracle_reader) + .unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/bls12_g2_add.rs b/bin/client/src/fpvm_evm/precompiles/bls12_g2_add.rs new file mode 100644 index 0000000000..02a2b371c5 --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bls12_g2_add.rs @@ -0,0 +1,94 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G2 Point Addition. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g2_add.rs + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, bls12_381, + bls12_381_const::{G2_ADD_BASE_GAS_FEE, G2_ADD_INPUT_LENGTH}, +}; + +/// Performs an FPVM-accelerated BLS12-381 G2 addition check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +pub(crate) fn fpvm_bls12_g2_add( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + if G2_ADD_BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let input_len = input.len(); + if input_len != G2_ADD_INPUT_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "G2 addition input length should be {G2_ADD_INPUT_LENGTH} bytes, was {input_len}" + ))); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[bls12_381::g2_add::PRECOMPILE.address().as_slice(), &G2_ADD_BASE_GAS_FEE.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(G2_ADD_BASE_GAS_FEE, result_data.into())) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g2_add() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + // G2.INF + G2.INF = G2.INF + let input = [0u8; G2_ADD_INPUT_LENGTH]; + let accelerated_result = + fpvm_bls12_g2_add(&input, u64::MAX, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile( + *bls12_381::g2_add::PRECOMPILE.address(), + input, + u64::MAX, + ) + .unwrap(); + + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g2_add_bad_input_len() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g2_add(&[], u64::MAX, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g2_add_bad_gas_limit() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g2_add(&[], 0, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/bls12_g2_msm.rs b/bin/client/src/fpvm_evm/precompiles/bls12_g2_msm.rs new file mode 100644 index 0000000000..dc55283efe --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bls12_g2_msm.rs @@ -0,0 +1,123 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G2 MSM. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g2_msm.rs + +use crate::fpvm_evm::precompiles::utils::{msm_required_gas, precompile_run}; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, bls12_381, + bls12_381_const::{DISCOUNT_TABLE_G2_MSM, G2_MSM_BASE_GAS_FEE, G2_MSM_INPUT_LENGTH}, +}; + +/// The maximum input size for the BLS12-381 g2 msm operation after the Isthmus Hardfork. +/// +/// See: +const BLS12_MAX_G2_MSM_SIZE_ISTHMUS: usize = 488448; + +/// Performs an FPVM-accelerated BLS12-381 G2 msm check. +pub(crate) fn fpvm_bls12_g2_msm( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + let input_len = input.len(); + + if input_len > BLS12_MAX_G2_MSM_SIZE_ISTHMUS { + return Err(PrecompileError::Other(alloc::format!( + "G2MSM input length must be at most {}", + BLS12_MAX_G2_MSM_SIZE_ISTHMUS + ))); + } + + if input_len == 0 || input_len % G2_MSM_INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(alloc::format!( + "G2MSM input length should be multiple of {}, was {}", + G2_MSM_INPUT_LENGTH, + input_len + ))); + } + + let k = input_len / G2_MSM_INPUT_LENGTH; + let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G2_MSM, G2_MSM_BASE_GAS_FEE); + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[bls12_381::g2_msm::PRECOMPILE.address().as_slice(), &required_gas.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(required_gas, result_data.into())) +} + +#[cfg(test)] +mod test { + use alloy_primitives::hex; + + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g2_msm() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + // https://raw.githubusercontent.com/ethereum/execution-spec-tests/a1c4eeff347a64ad6c5aedd51314d4ffc067346b/tests/prague/eip2537_bls_12_381_precompiles/vectors/msm_G2_bls.json + let input = hex!("00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002"); + let expected = hex!("000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3"); + + let accelerated_result = fpvm_bls12_g2_msm(&input, 22500, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(*bls12_381::g2_msm::PRECOMPILE.address(), input, 22500).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), expected.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g2_msm_bad_input_len_isthmus() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = fpvm_bls12_g2_msm( + &[0u8; BLS12_MAX_G2_MSM_SIZE_ISTHMUS + 1], + u64::MAX, + hint_writer, + oracle_reader, + ) + .unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g2_msm_bad_input_len() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g2_msm(&[], u64::MAX, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_g2_msm_bad_gas_limit() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_g2_msm(&[0u8; G2_MSM_INPUT_LENGTH], 0, hint_writer, oracle_reader) + .unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/bls12_map_fp.rs b/bin/client/src/fpvm_evm/precompiles/bls12_map_fp.rs new file mode 100644 index 0000000000..4cc4a287cd --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bls12_map_fp.rs @@ -0,0 +1,93 @@ +//! Contains the accelerated precompile for the BLS12-381 curve FP to G1 Mapping. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/map_fp_to_g1.rs + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, bls12_381, + bls12_381_const::{MAP_FP_TO_G1_BASE_GAS_FEE, PADDED_FP_LENGTH}, +}; + +/// Performs an FPVM-accelerated BLS12-381 map fp check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +pub(crate) fn fpvm_bls12_map_fp( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + if MAP_FP_TO_G1_BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + if input.len() != PADDED_FP_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "MAP_FP_TO_G1 input should be {PADDED_FP_LENGTH} bytes, was {}", + input.len() + ))); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[bls12_381::map_fp_to_g1::PRECOMPILE.address().as_slice(), &MAP_FP_TO_G1_BASE_GAS_FEE.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(MAP_FP_TO_G1_BASE_GAS_FEE, result_data.into())) +} + +#[cfg(test)] +mod test { + use alloy_primitives::hex; + + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_map_fp_g1() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + // https://github.com/ethereum/execution-spec-tests/blob/a1c4eeff347a64ad6c5aedd51314d4ffc067346b/tests/prague/eip2537_bls_12_381_precompiles/vectors/map_fp_to_G1_bls.json + let input = hex!("00000000000000000000000000000000156c8a6a2c184569d69a76be144b5cdc5141d2d2ca4fe341f011e25e3969c55ad9e9b9ce2eb833c81a908e5fa4ac5f03"); + let expected = hex!("00000000000000000000000000000000184bb665c37ff561a89ec2122dd343f20e0f4cbcaec84e3c3052ea81d1834e192c426074b02ed3dca4e7676ce4ce48ba0000000000000000000000000000000004407b8d35af4dacc809927071fc0405218f1401a6d15af775810e4e460064bcc9468beeba82fdc751be70476c888bf3"); + + let accelerated_result = fpvm_bls12_map_fp(&input, 5500, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(*bls12_381::map_fp_to_g1::PRECOMPILE.address(), input, 5500).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), expected.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_map_fp_g1_bad_gas_limit() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_map_fp(&[], 0, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_map_fp_g1_bad_input_size() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_map_fp(&[], u64::MAX, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/bls12_map_fp2.rs b/bin/client/src/fpvm_evm/precompiles/bls12_map_fp2.rs new file mode 100644 index 0000000000..861df22ceb --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bls12_map_fp2.rs @@ -0,0 +1,93 @@ +//! Contains the accelerated precompile for the BLS12-381 curve FP2 to G2 Mapping. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/map_fp_to_g1.rs + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, bls12_381, + bls12_381_const::{MAP_FP2_TO_G2_BASE_GAS_FEE, PADDED_FP2_LENGTH}, +}; + +/// Performs an FPVM-accelerated BLS12-381 map fp2 check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +pub(crate) fn fpvm_bls12_map_fp2( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + if MAP_FP2_TO_G2_BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + if input.len() != PADDED_FP2_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "MAP_FP2_TO_G2 input should be {PADDED_FP2_LENGTH} bytes, was {}", + input.len() + ))); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[bls12_381::map_fp2_to_g2::PRECOMPILE.address().as_slice(), &MAP_FP2_TO_G2_BASE_GAS_FEE.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(MAP_FP2_TO_G2_BASE_GAS_FEE, result_data.into())) +} + +#[cfg(test)] +mod test { + use alloy_primitives::hex; + + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_map_fp_g2() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + // https://github.com/ethereum/execution-spec-tests/blob/a1c4eeff347a64ad6c5aedd51314d4ffc067346b/tests/prague/eip2537_bls_12_381_precompiles/vectors/map_fp2_to_G2_bls.json + let input = hex!("0000000000000000000000000000000007355d25caf6e7f2f0cb2812ca0e513bd026ed09dda65b177500fa31714e09ea0ded3a078b526bed3307f804d4b93b040000000000000000000000000000000002829ce3c021339ccb5caf3e187f6370e1e2a311dec9b75363117063ab2015603ff52c3d3b98f19c2f65575e99e8b78c"); + let expected = hex!("0000000000000000000000000000000000e7f4568a82b4b7dc1f14c6aaa055edf51502319c723c4dc2688c7fe5944c213f510328082396515734b6612c4e7bb700000000000000000000000000000000126b855e9e69b1f691f816e48ac6977664d24d99f8724868a184186469ddfd4617367e94527d4b74fc86413483afb35b000000000000000000000000000000000caead0fd7b6176c01436833c79d305c78be307da5f6af6c133c47311def6ff1e0babf57a0fb5539fce7ee12407b0a42000000000000000000000000000000001498aadcf7ae2b345243e281ae076df6de84455d766ab6fcdaad71fab60abb2e8b980a440043cd305db09d283c895e3d"); + + let accelerated_result = fpvm_bls12_map_fp2(&input, 23800, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(*bls12_381::map_fp2_to_g2::PRECOMPILE.address(), input, 23800).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), expected.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_map_fp_g2_bad_gas_limit() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_map_fp2(&[], 0, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_map_fp_g2_bad_input_size() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_map_fp2(&[], u64::MAX, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/bls12_pair.rs b/bin/client/src/fpvm_evm/precompiles/bls12_pair.rs new file mode 100644 index 0000000000..d2b495172c --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bls12_pair.rs @@ -0,0 +1,119 @@ +//! Contains the accelerated precompile for the BLS12-381 curve. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/pairing.rs + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, bls12_381, + bls12_381_const::{PAIRING_INPUT_LENGTH, PAIRING_MULTIPLIER_BASE, PAIRING_OFFSET_BASE}, +}; + +/// The max pairing size for BLS12-381 input given a 20M gas limit. +const BLS12_MAX_PAIRING_SIZE_ISTHMUS: usize = 235_008; + +/// Performs an FPVM-accelerated BLS12-381 pairing check. +pub(crate) fn fpvm_bls12_pairing( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + let input_len = input.len(); + + if input_len > BLS12_MAX_PAIRING_SIZE_ISTHMUS { + return Err(PrecompileError::Other(alloc::format!( + "Pairing input length must be at most {}", + BLS12_MAX_PAIRING_SIZE_ISTHMUS + ))); + } + + if input_len % PAIRING_INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(alloc::format!( + "Pairing input length should be multiple of {PAIRING_INPUT_LENGTH}, was {input_len}" + ))); + } + + let k = input_len / PAIRING_INPUT_LENGTH; + let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE; + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[bls12_381::pairing::PRECOMPILE.address().as_slice(), &required_gas.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(required_gas, result_data.into())) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + use alloy_primitives::hex; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_pairing() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + // https://github.com/ethereum/execution-spec-tests/blob/a1c4eeff347a64ad6c5aedd51314d4ffc067346b/tests/prague/eip2537_bls_12_381_precompiles/vectors/pairing_check_bls.json + let input = hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + let expected = hex!("0000000000000000000000000000000000000000000000000000000000000001"); + + let accelerated_result = fpvm_bls12_pairing(&input, 70300, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(*bls12_381::pairing::PRECOMPILE.address(), input, 70300).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), expected.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_pairing_bad_input_len_isthmus() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = fpvm_bls12_pairing( + &[0u8; BLS12_MAX_PAIRING_SIZE_ISTHMUS + 1], + 0, + hint_writer, + oracle_reader, + ) + .unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_pairing_bad_input_len() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_pairing(&[0u8; PAIRING_INPUT_LENGTH - 1], 0, hint_writer, oracle_reader) + .unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::Other(_))); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bls12_381_pairing_bad_gas_limit() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_bls12_pairing(&[0u8; PAIRING_INPUT_LENGTH], 0, hint_writer, oracle_reader) + .unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/bn128_pair.rs b/bin/client/src/fpvm_evm/precompiles/bn128_pair.rs new file mode 100644 index 0000000000..fe73f91bd5 --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/bn128_pair.rs @@ -0,0 +1,138 @@ +//! Contains the accelerated version of the `ecPairing` precompile. + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{ + PrecompileError, PrecompileOutput, PrecompileResult, + bn128::{ + PAIR_ELEMENT_LEN, + pair::{self, ISTANBUL_PAIR_BASE, ISTANBUL_PAIR_PER_POINT}, + }, +}; + +const BN256_MAX_PAIRING_SIZE_GRANITE: usize = 112_687; + +/// Runs the FPVM-accelerated `ecpairing` precompile call. +pub(crate) fn fpvm_bn128_pair( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + let gas_used = + (input.len() / PAIR_ELEMENT_LEN) as u64 * ISTANBUL_PAIR_PER_POINT + ISTANBUL_PAIR_BASE; + + if gas_used > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + if input.len() % PAIR_ELEMENT_LEN != 0 { + return Err(PrecompileError::Bn128PairLength); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[pair::ISTANBUL.address().as_slice(), &gas_used.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(gas_used, result_data.into())) +} + +/// Runs the FPVM-accelerated `ecpairing` precompile call, with the input size limited by the +/// Granite hardfork. +pub(crate) fn fpvm_bn128_pair_granite( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + if input.len() > BN256_MAX_PAIRING_SIZE_GRANITE { + return Err(PrecompileError::Bn128PairLength); + } + + fpvm_bn128_pair(input, gas_limit, hint_writer, oracle_reader) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + use alloy_primitives::hex; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bn128_pairing() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + const EXPECTED_RESULT: [u8; 32] = hex!("0000000000000000000000000000000000000000000000000000000000000001"); + + let input = hex!( + "2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f61fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d92bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f902fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd451971ff0471b09fa93caaf13cbf443c1aede09cc4328f5a62aad45f40ec133eb4091058a3141822985733cbdddfed0fd8d6c104e9e9eff40bf5abfef9ab163bc72a23af9a5ce2ba2796c1f4e453a370eb0af8c212d9dc9acd8fc02c2e907baea223a8eb0b0996252cb548a4487da97b02422ebc0e834613f954de6c7e0afdc1fc" + ); + let accelerated_result = fpvm_bn128_pair(&input, u64::MAX, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(*pair::ISTANBUL.address(), input, u64::MAX).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), EXPECTED_RESULT.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bn128_pairing_granite() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + const EXPECTED_RESULT: [u8; 32] = hex!("0000000000000000000000000000000000000000000000000000000000000001"); + + let input = hex!( + "2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f61fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d92bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f902fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd451971ff0471b09fa93caaf13cbf443c1aede09cc4328f5a62aad45f40ec133eb4091058a3141822985733cbdddfed0fd8d6c104e9e9eff40bf5abfef9ab163bc72a23af9a5ce2ba2796c1f4e453a370eb0af8c212d9dc9acd8fc02c2e907baea223a8eb0b0996252cb548a4487da97b02422ebc0e834613f954de6c7e0afdc1fc" + ); + let accelerated_result = fpvm_bn128_pair_granite(&input, u64::MAX, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(*pair::ISTANBUL.address(), input, u64::MAX).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), EXPECTED_RESULT.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bn128_pairing_not_enough_gas() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let input = hex!("0badc0de"); + let accelerated_result = + fpvm_bn128_pair(&input, 0, hint_writer, oracle_reader).unwrap_err(); + + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bn128_pairing_bad_input_len() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let input = hex!("0badc0de"); + let accelerated_result = + fpvm_bn128_pair(&input, u64::MAX, hint_writer, oracle_reader).unwrap_err(); + + assert!(matches!(accelerated_result, PrecompileError::Bn128PairLength)); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_bn128_pairing_bad_input_len_granite() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let input = [0u8; BN256_MAX_PAIRING_SIZE_GRANITE + 1]; + let accelerated_result = + fpvm_bn128_pair(&input, u64::MAX, hint_writer, oracle_reader).unwrap_err(); + + assert!(matches!(accelerated_result, PrecompileError::Bn128PairLength)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/ecrecover.rs b/bin/client/src/fpvm_evm/precompiles/ecrecover.rs new file mode 100644 index 0000000000..14ba412f3e --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/ecrecover.rs @@ -0,0 +1,72 @@ +//! Contains the accelerated version of the `ecrecover` precompile. + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use alloy_primitives::Address; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{PrecompileError, PrecompileOutput, PrecompileResult}; + +/// Address of the `ecrecover` precompile. +pub(crate) const ECRECOVER_ADDR: Address = revm::precompile::u64_to_address(1); + +/// Runs the FPVM-accelerated `ecrecover` precompile call. +pub(crate) fn fpvm_ec_recover( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + const ECRECOVER_BASE: u64 = 3_000; + + if ECRECOVER_BASE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[ECRECOVER_ADDR.as_slice(), &ECRECOVER_BASE.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string())) + .unwrap_or_default(); + + Ok(PrecompileOutput::new(ECRECOVER_BASE, result_data.into())) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + use alloy_primitives::hex; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_ecrecover() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + const EXPECTED_RESULT: [u8; 32] = hex!("0000000000000000000000007156526fbd7a3c72969b54f64e42c10fbb768c8a"); + + let input = hex!( + "456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3000000000000000000000000000000000000000000000000000000000000001c9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac80388256084f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada" + ); + let accelerated_result = fpvm_ec_recover(&input, u64::MAX, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(ECRECOVER_ADDR, input, u64::MAX).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), EXPECTED_RESULT.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_ecrecover_out_of_gas() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_ec_recover(&[], 0, hint_writer, oracle_reader).unwrap_err(); + + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/kzg_point_eval.rs b/bin/client/src/fpvm_evm/precompiles/kzg_point_eval.rs new file mode 100644 index 0000000000..1453bb7e73 --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/kzg_point_eval.rs @@ -0,0 +1,92 @@ +//! Contains the accelerated version of the KZG point evaluation precompile. + +use crate::fpvm_evm::precompiles::utils::precompile_run; +use alloc::string::ToString; +use alloy_primitives::Address; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use revm::precompile::{PrecompileError, PrecompileOutput, PrecompileResult}; + +/// Address of the KZG point evaluation precompile. +pub(crate) const KZG_POINT_EVAL_ADDR: Address = revm::precompile::u64_to_address(0x0A); + +/// Runs the FPVM-accelerated `kzgPointEval` precompile call. +pub(crate) fn fpvm_kzg_point_eval( + input: &[u8], + gas_limit: u64, + hint_writer: &HintWriter, + oracle_reader: &OracleReader, +) -> PrecompileResult { + const GAS_COST: u64 = 50_000; + + if gas_limit < GAS_COST { + return Err(PrecompileError::OutOfGas); + } + + if input.len() != 192 { + return Err(PrecompileError::BlobInvalidInputLength); + } + + let result_data = kona_proof::block_on(precompile_run! { + hint_writer, + oracle_reader, + &[KZG_POINT_EVAL_ADDR.as_slice(), &GAS_COST.to_be_bytes(), input] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(GAS_COST, result_data.into())) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::fpvm_evm::precompiles::test_utils::{ + execute_native_precompile, test_accelerated_precompile, + }; + use alloy_eips::eip4844::VERSIONED_HASH_VERSION_KZG; + use alloy_primitives::hex; + use sha2::{Digest, Sha256}; + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_kzg_point_eval() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let commitment = hex!("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").to_vec(); + let mut versioned_hash = Sha256::digest(&commitment).to_vec(); + versioned_hash[0] = VERSIONED_HASH_VERSION_KZG; + let z = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000").to_vec(); + let y = hex!("1522a4a7f34e1ea350ae07c29c96c7e79655aa926122e95fe69fcbd932ca49e9").to_vec(); + let proof = hex!("a62ad71d14c5719385c0686f1871430475bf3a00f0aa3f7b8dd99a9abc2160744faf0070725e00b60ad9a026a15b1a8c").to_vec(); + + let input = [versioned_hash, z, y, commitment, proof].concat(); + + let expected_result = hex!("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); + + let accelerated_result = fpvm_kzg_point_eval(&input, u64::MAX, hint_writer, oracle_reader).unwrap(); + let native_result = execute_native_precompile(KZG_POINT_EVAL_ADDR, input, u64::MAX).unwrap(); + + assert_eq!(accelerated_result.bytes.as_ref(), expected_result.as_ref()); + assert_eq!(accelerated_result.bytes, native_result.bytes); + assert_eq!(accelerated_result.gas_used, native_result.gas_used); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_kzg_point_eval_out_of_gas() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_kzg_point_eval(&[], 0, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::OutOfGas)); + }) + .await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_accelerated_kzg_point_eval_bad_input_size() { + test_accelerated_precompile(|hint_writer, oracle_reader| { + let accelerated_result = + fpvm_kzg_point_eval(&[], u64::MAX, hint_writer, oracle_reader).unwrap_err(); + assert!(matches!(accelerated_result, PrecompileError::BlobInvalidInputLength)); + }) + .await; + } +} diff --git a/bin/client/src/fpvm_evm/precompiles/mod.rs b/bin/client/src/fpvm_evm/precompiles/mod.rs new file mode 100644 index 0000000000..402a552aab --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/mod.rs @@ -0,0 +1,22 @@ +//! Contains the [`PrecompileProvider`] implementation that serves FPVM-accelerated OP Stack +//! precompiles. +//! +//! [`PrecompileProvider`]: revm::handler::PrecompileProvider + +mod provider; +pub(crate) use provider::OpFpvmPrecompiles; + +mod bls12_g1_add; +mod bls12_g1_msm; +mod bls12_g2_add; +mod bls12_g2_msm; +mod bls12_map_fp; +mod bls12_map_fp2; +mod bls12_pair; +mod bn128_pair; +mod ecrecover; +mod kzg_point_eval; +mod utils; + +#[cfg(test)] +mod test_utils; diff --git a/bin/client/src/fpvm_evm/precompiles/provider.rs b/bin/client/src/fpvm_evm/precompiles/provider.rs new file mode 100644 index 0000000000..bc55ff4d00 --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/provider.rs @@ -0,0 +1,227 @@ +//! [`PrecompileProvider`] for FPVM-accelerated OP Stack precompiles. + +use crate::fpvm_evm::precompiles::{ + ecrecover::ECRECOVER_ADDR, kzg_point_eval::KZG_POINT_EVAL_ADDR, +}; +use alloc::{boxed::Box, string::String, vec, vec::Vec}; +use alloy_primitives::{Address, Bytes}; +use kona_preimage::{Channel, HintWriter, OracleReader}; +use op_revm::{ + OpSpecId, + precompiles::{fjord, granite, isthmus}, +}; +use revm::{ + context::{Cfg, ContextTr}, + handler::{EthPrecompiles, PrecompileProvider}, + interpreter::{Gas, InputsImpl, InstructionResult, InterpreterResult}, + precompile::{PrecompileError, PrecompileResult, Precompiles, bls12_381_const, bn128}, + primitives::{hardfork::SpecId, hash_map::HashMap}, +}; + +/// The FPVM-accelerated precompiles. +#[derive(Debug)] +pub struct OpFpvmPrecompiles { + /// The default [`EthPrecompiles`] provider. + inner: EthPrecompiles, + /// The accelerated precompiles for the current [`OpSpecId`]. + accelerated_precompiles: HashMap>, + /// The [`OpSpecId`] of the precompiles. + spec: OpSpecId, + /// The inner [`HintWriter`]. + hint_writer: HintWriter, + /// The inner [`OracleReader`]. + oracle_reader: OracleReader, +} + +impl OpFpvmPrecompiles { + /// Create a new precompile provider with the given [`OpSpecId`]. + #[inline] + pub fn new_with_spec( + spec: OpSpecId, + hint_writer: HintWriter, + oracle_reader: OracleReader, + ) -> Self { + let precompiles = match spec { + spec @ (OpSpecId::BEDROCK | + OpSpecId::REGOLITH | + OpSpecId::CANYON | + OpSpecId::ECOTONE) => Precompiles::new(spec.into_eth_spec().into()), + OpSpecId::FJORD => fjord(), + OpSpecId::GRANITE | OpSpecId::HOLOCENE => granite(), + OpSpecId::ISTHMUS | OpSpecId::INTEROP | OpSpecId::OSAKA => isthmus(), + }; + + let accelerated_precompiles = match spec { + OpSpecId::BEDROCK | OpSpecId::REGOLITH | OpSpecId::CANYON => accelerated_bedrock::(), + OpSpecId::ECOTONE | OpSpecId::FJORD => accelerated_ecotone::(), + OpSpecId::GRANITE | OpSpecId::HOLOCENE => accelerated_granite::(), + OpSpecId::ISTHMUS | OpSpecId::INTEROP | OpSpecId::OSAKA => accelerated_isthmus::(), + }; + + Self { + inner: EthPrecompiles { precompiles, spec: SpecId::default() }, + accelerated_precompiles: accelerated_precompiles + .into_iter() + .map(|p| (p.address, p.precompile)) + .collect(), + spec, + hint_writer, + oracle_reader, + } + } +} + +impl PrecompileProvider for OpFpvmPrecompiles +where + C: Channel + Clone + Send + Sync, + CTX: ContextTr>, +{ + type Output = InterpreterResult; + + #[inline] + fn set_spec(&mut self, spec: ::Spec) -> bool { + if spec == self.spec { + return false; + } + *self = Self::new_with_spec(spec, self.hint_writer.clone(), self.oracle_reader.clone()); + true + } + + #[inline] + fn run( + &mut self, + _context: &mut CTX, + address: &Address, + inputs: &InputsImpl, + _is_static: bool, + gas_limit: u64, + ) -> Result, String> { + let mut result = InterpreterResult { + result: InstructionResult::Return, + gas: Gas::new(gas_limit), + output: Bytes::new(), + }; + + // Priority: + // 1. If the precompile has an accelerated version, use that. + // 2. If the precompile is not accelerated, use the default version. + // 3. If the precompile is not found, return None. + let output = if let Some(accelerated) = self.accelerated_precompiles.get(address) { + (accelerated)(&inputs.input, gas_limit, &self.hint_writer, &self.oracle_reader) + } else if let Some(precompile) = self.inner.precompiles.get(address) { + (*precompile)(&inputs.input, gas_limit) + } else { + return Ok(None); + }; + + match output { + Ok(output) => { + let underflow = result.gas.record_cost(output.gas_used); + assert!(underflow, "Gas underflow is not possible"); + result.result = InstructionResult::Return; + result.output = output.bytes; + } + Err(PrecompileError::Fatal(e)) => return Err(e), + Err(e) => { + result.result = if e.is_oog() { + InstructionResult::PrecompileOOG + } else { + InstructionResult::PrecompileError + }; + } + } + + Ok(Some(result)) + } + + #[inline] + fn warm_addresses(&self) -> Box> { + self.inner.warm_addresses() + } + + #[inline] + fn contains(&self, address: &Address) -> bool { + self.inner.contains(address) + } +} + +/// A precompile function that can be accelerated by the FPVM. +type AcceleratedPrecompileFn = + fn(&[u8], u64, &HintWriter, &OracleReader) -> PrecompileResult; + +/// A tuple type for accelerated precompiles with an associated [`Address`]. +struct AcceleratedPrecompile { + /// The address of the precompile. + address: Address, + /// The precompile function. + precompile: AcceleratedPrecompileFn, +} + +impl AcceleratedPrecompile { + /// Create a new accelerated precompile. + fn new(address: Address, precompile: AcceleratedPrecompileFn) -> Self { + Self { address, precompile } + } +} + +/// The accelerated precompiles for the bedrock spec. +fn accelerated_bedrock() -> Vec> { + vec![ + AcceleratedPrecompile::new(ECRECOVER_ADDR, super::ecrecover::fpvm_ec_recover::), + AcceleratedPrecompile::new(bn128::pair::ADDRESS, super::bn128_pair::fpvm_bn128_pair::), + ] +} + +/// The accelerated precompiles for the ecotone spec. +fn accelerated_ecotone() -> Vec> { + let mut base = accelerated_bedrock::(); + base.push(AcceleratedPrecompile::new( + KZG_POINT_EVAL_ADDR, + super::kzg_point_eval::fpvm_kzg_point_eval::, + )); + base +} + +/// The accelerated precompiles for the granite spec. +fn accelerated_granite() -> Vec> { + let mut base = accelerated_ecotone::(); + base.push(AcceleratedPrecompile::new( + bn128::pair::ADDRESS, + super::bn128_pair::fpvm_bn128_pair_granite::, + )); + base +} + +/// The accelerated precompiles for the isthmus spec. +fn accelerated_isthmus() -> Vec> { + let mut base = accelerated_granite::(); + base.push(AcceleratedPrecompile::new( + bls12_381_const::G1_ADD_ADDRESS, + super::bls12_g1_add::fpvm_bls12_g1_add::, + )); + base.push(AcceleratedPrecompile::new( + bls12_381_const::G1_MSM_ADDRESS, + super::bls12_g1_msm::fpvm_bls12_g1_msm::, + )); + base.push(AcceleratedPrecompile::new( + bls12_381_const::G2_ADD_ADDRESS, + super::bls12_g2_add::fpvm_bls12_g2_add::, + )); + base.push(AcceleratedPrecompile::new( + bls12_381_const::G2_MSM_ADDRESS, + super::bls12_g2_msm::fpvm_bls12_g2_msm::, + )); + base.push(AcceleratedPrecompile::new( + bls12_381_const::MAP_FP_TO_G1_ADDRESS, + super::bls12_map_fp::fpvm_bls12_map_fp::, + )); + base.push(AcceleratedPrecompile::new( + bls12_381_const::MAP_FP2_TO_G2_ADDRESS, + super::bls12_map_fp2::fpvm_bls12_map_fp2::, + )); + base.push(AcceleratedPrecompile::new( + bls12_381_const::PAIRING_ADDRESS, + super::bls12_pair::fpvm_bls12_pairing::, + )); + base +} diff --git a/bin/client/src/fpvm_evm/precompiles/test_utils.rs b/bin/client/src/fpvm_evm/precompiles/test_utils.rs new file mode 100644 index 0000000000..fb68bab6a7 --- /dev/null +++ b/bin/client/src/fpvm_evm/precompiles/test_utils.rs @@ -0,0 +1,148 @@ +//! Test utilities for accelerated precompiles. + +use alloy_primitives::{Address, Bytes, keccak256}; +use async_trait::async_trait; +use kona_preimage::{ + BidirectionalChannel, HintReader, HintReaderServer, HintRouter, HintWriter, NativeChannel, + OracleReader, OracleServer, PreimageFetcher, PreimageKey, PreimageKeyType, + PreimageOracleServer, + errors::{PreimageOracleError, PreimageOracleResult}, +}; +use kona_proof::{Hint, HintType}; +use revm::precompile::PrecompileResult; +use std::{collections::HashMap, sync::Arc}; +use tokio::sync::{Mutex, RwLock}; + +/// Runs a test with a mock host that serves [`HintType::L1Precompile`] hints and preimages. The +/// closure accepts the client's [`HintWriter`] and [`OracleReader`] as arguments. +pub(crate) async fn test_accelerated_precompile( + f: impl Fn(&HintWriter, &OracleReader) + Send + Sync + 'static, +) { + let (hint_chan, preimage_chan) = + (BidirectionalChannel::new().unwrap(), BidirectionalChannel::new().unwrap()); + + let host = tokio::task::spawn(precompile_host( + OracleServer::new(preimage_chan.host), + HintReader::new(hint_chan.host), + )); + let client = tokio::task::spawn(async move { + let oracle_reader = OracleReader::new(preimage_chan.client); + let hint_writer = HintWriter::new(hint_chan.client); + + (f)(&hint_writer, &oracle_reader) + }); + + tokio::try_join!(host, client).unwrap_or_else(|e| { + panic!("Failed to join client/host: {e:?}"); + }); +} + +/// Executes a precompile on [`revm`]. +pub(crate) fn execute_native_precompile>( + address: Address, + input: T, + gas: u64, +) -> PrecompileResult { + let precompiles = revm::handler::EthPrecompiles::default(); + let Some(precompile) = precompiles.precompiles.get(&address) else { + panic!("Precompile not found"); + }; + precompile(&input.into(), gas) +} + +/// Starts a mock host thread that serves [`HintType::L1Precompile`] hints and preimages. +async fn precompile_host( + oracle_server: OracleServer, + hint_reader: HintReader, +) { + let last_hint = Arc::new(RwLock::new(None)); + let preimage_fetcher = + PrecompilePreimageFetcher { map: Default::default(), last_hint: last_hint.clone() }; + let hint_router = PrecompileHintRouter { last_hint: last_hint.clone() }; + + let server = tokio::task::spawn(async move { + loop { + match oracle_server.next_preimage_request(&preimage_fetcher).await { + Ok(_) => continue, + Err(PreimageOracleError::IOError(_)) => return, + Err(e) => { + panic!("Critical: Failed to serve preimage: {e:?}"); + } + } + } + }); + let hint_reader = tokio::task::spawn(async move { + loop { + match hint_reader.next_hint(&hint_router).await { + Ok(_) => continue, + Err(PreimageOracleError::IOError(_)) => return, + Err(e) => { + panic!("Critical: Failed to serve hint: {e:?}"); + } + } + } + }); + + tokio::try_join!(server, hint_reader).unwrap_or_else(|e| { + panic!("Failed to join server/hint reader: {e:?}"); + }); +} + +#[derive(Default, Debug, Clone)] +struct PrecompilePreimageFetcher { + /// Inner map of preimages. + map: Arc>>>, + /// The previous hint received. + last_hint: Arc>>, +} + +#[async_trait] +impl PreimageFetcher for PrecompilePreimageFetcher { + async fn get_preimage(&self, key: PreimageKey) -> PreimageOracleResult> { + let mut map_lock = self.map.lock().await; + if let Some(preimage) = map_lock.get(&key) { + return Ok(preimage.clone()); + } + + let last_hint = self.last_hint.read().await; + let Some(last_hint) = last_hint.as_ref() else { unreachable!("Hint not queued") }; + + let parsed_hint = last_hint.parse::>().unwrap(); + if matches!(parsed_hint.ty, HintType::L1Precompile) { + let address = Address::from_slice(&parsed_hint.data.as_ref()[..20]); + let gas = u64::from_be_bytes(parsed_hint.data.as_ref()[20..28].try_into().unwrap()); + let input = parsed_hint.data[28..].to_vec(); + let input_hash = keccak256(parsed_hint.data.as_ref()); + + let result = execute_native_precompile(address, input, gas).map_or_else( + |_| vec![0u8; 1], + |raw_res| { + let mut res = Vec::with_capacity(1 + raw_res.bytes.len()); + res.push(0x01); + res.extend_from_slice(&raw_res.bytes); + res + }, + ); + + map_lock + .insert(PreimageKey::new(*input_hash, PreimageKeyType::Precompile), result.clone()); + return Ok(result); + } else { + panic!("Unexpected hint type: {:?}", parsed_hint.ty); + } + } +} + +#[derive(Default, Debug, Clone)] +struct PrecompileHintRouter { + /// The latest hint received. + last_hint: Arc>>, +} + +#[async_trait] +impl HintRouter for PrecompileHintRouter { + async fn route_hint(&self, hint: String) -> PreimageOracleResult<()> { + self.last_hint.write().await.replace(hint); + Ok(()) + } +} diff --git a/bin/client/src/precompiles/utils.rs b/bin/client/src/fpvm_evm/precompiles/utils.rs similarity index 89% rename from bin/client/src/precompiles/utils.rs rename to bin/client/src/fpvm_evm/precompiles/utils.rs index 0ed66e8b6c..4fcf1b0e6c 100644 --- a/bin/client/src/precompiles/utils.rs +++ b/bin/client/src/fpvm_evm/precompiles/utils.rs @@ -27,24 +27,24 @@ pub(crate) fn msm_required_gas(k: usize, discount_table: &[u16], multiplication_ /// - `hint_data`: The hint data to send to the host. #[macro_export] macro_rules! precompile_run { - ($hint_data:expr) => { + ($hint_writer:expr, $oracle_reader:expr, $hint_data:expr) => { async move { + use alloc::{string::ToString, vec::Vec}; use kona_preimage::{ PreimageKey, PreimageKeyType, PreimageOracleClient, errors::PreimageOracleError, }; use kona_proof::{HintType, errors::OracleProviderError}; - use $crate::{HINT_WRITER, ORACLE_READER}; // Write the hint for the precompile run. let hint_data = $hint_data; - HintType::L1Precompile.with_data(hint_data).send(&HINT_WRITER).await?; + HintType::L1Precompile.with_data(hint_data).send($hint_writer).await?; // Construct the key hash for the precompile run. let raw_key_data = hint_data.iter().copied().flatten().copied().collect::>(); - let key_hash = keccak256(&raw_key_data); + let key_hash = alloy_primitives::keccak256(&raw_key_data); // Fetch the result of the precompile run from the host. - let result_data = ORACLE_READER + let result_data = $oracle_reader .get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile)) .await .map_err(OracleProviderError::Preimage)?; diff --git a/bin/client/src/interop/mod.rs b/bin/client/src/interop/mod.rs index 5ae57b2f6d..6e35fe87d5 100644 --- a/bin/client/src/interop/mod.rs +++ b/bin/client/src/interop/mod.rs @@ -6,9 +6,9 @@ use consolidate::consolidate_dependencies; use core::fmt::Debug; use kona_derive::errors::PipelineErrorKind; use kona_driver::DriverError; -use kona_executor::{ExecutorError, KonaHandleRegister}; +use kona_executor::ExecutorError; use kona_preimage::{HintWriterClient, PreimageOracleClient}; -use kona_proof::{CachingOracle, errors::OracleProviderError, l2::OracleL2ChainProvider}; +use kona_proof::{CachingOracle, errors::OracleProviderError}; use kona_proof_interop::{ BootInfo, ConsolidationError, PreState, TRANSITION_STATE_MAX_STEPS, boot::BootstrapError, }; @@ -52,16 +52,7 @@ pub enum FaultProofProgramError { /// Executes the interop fault proof program with the given [PreimageOracleClient] and /// [HintWriterClient]. #[inline] -pub async fn run( - oracle_client: P, - hint_client: H, - handle_register: Option< - KonaHandleRegister< - OracleL2ChainProvider>, - OracleL2ChainProvider>, - >, - >, -) -> Result<(), FaultProofProgramError> +pub async fn run(oracle_client: P, hint_client: H) -> Result<(), FaultProofProgramError> where P: PreimageOracleClient + Send + Sync + Debug + Clone, H: HintWriterClient + Send + Sync + Debug + Clone, @@ -100,7 +91,7 @@ where } // If the pre-state is a super root, the first sub-problem is always selected. - sub_transition(oracle, handle_register, boot).await + sub_transition(oracle, boot).await } PreState::TransitionState(ref transition_state) => { // If the claimed L2 block timestamp is less than the prestate timestamp, the @@ -115,7 +106,7 @@ where // If the pre-state is a transition state, the sub-problem is selected based on the // current step. if transition_state.step < TRANSITION_STATE_MAX_STEPS { - sub_transition(oracle, handle_register, boot).await + sub_transition(oracle, boot).await } else { consolidate_dependencies(oracle, boot).await } diff --git a/bin/client/src/interop/transition.rs b/bin/client/src/interop/transition.rs index a0a0e74373..70036330bb 100644 --- a/bin/client/src/interop/transition.rs +++ b/bin/client/src/interop/transition.rs @@ -4,11 +4,12 @@ use super::FaultProofProgramError; use crate::interop::util::fetch_l2_safe_head_hash; use alloc::sync::Arc; use alloy_consensus::Sealed; +use alloy_op_evm::OpEvmFactory; use alloy_primitives::B256; use core::fmt::Debug; use kona_derive::errors::{PipelineError, PipelineErrorKind}; use kona_driver::{Driver, DriverError}; -use kona_executor::{KonaHandleRegister, TrieDBProvider}; +use kona_executor::TrieDBProvider; use kona_preimage::{HintWriterClient, PreimageOracleClient}; use kona_proof::{ CachingOracle, @@ -24,12 +25,6 @@ use tracing::{error, info, warn}; /// [HintWriterClient]. pub(crate) async fn sub_transition( oracle: Arc>, - handle_register: Option< - KonaHandleRegister< - OracleL2ChainProvider>, - OracleL2ChainProvider>, - >, - >, boot: BootInfo, ) -> Result<(), FaultProofProgramError> where @@ -111,7 +106,7 @@ where rollup_config.as_ref(), l2_provider.clone(), l2_provider, - handle_register, + OpEvmFactory::default(), None, ); let mut driver = Driver::new(cursor, executor, pipeline); diff --git a/bin/client/src/kona.rs b/bin/client/src/kona.rs index a3189ff731..8fc8098eae 100644 --- a/bin/client/src/kona.rs +++ b/bin/client/src/kona.rs @@ -8,12 +8,11 @@ extern crate alloc; use alloc::string::String; +use kona_client::fpvm_evm::FpvmOpEvmFactory; use kona_preimage::{HintWriter, OracleReader}; use kona_std_fpvm::{FileChannel, FileDescriptor}; use kona_std_fpvm_proc::client_entry; -mod precompiles; - /// The global preimage oracle reader pipe. static ORACLE_READER_PIPE: FileChannel = FileChannel::new(FileDescriptor::PreimageRead, FileDescriptor::PreimageWrite); @@ -42,6 +41,6 @@ fn main() -> Result<(), String> { kona_proof::block_on(kona_client::single::run( ORACLE_READER, HINT_WRITER, - Some(precompiles::fpvm_handle_register), + FpvmOpEvmFactory::new(HINT_WRITER, ORACLE_READER), )) } diff --git a/bin/client/src/kona_interop.rs b/bin/client/src/kona_interop.rs index 34f89d5921..f23a72fddc 100644 --- a/bin/client/src/kona_interop.rs +++ b/bin/client/src/kona_interop.rs @@ -12,8 +12,6 @@ use kona_preimage::{HintWriter, OracleReader}; use kona_std_fpvm::{FileChannel, FileDescriptor}; use kona_std_fpvm_proc::client_entry; -mod precompiles; - /// The global preimage oracle reader pipe. static ORACLE_READER_PIPE: FileChannel = FileChannel::new(FileDescriptor::PreimageRead, FileDescriptor::PreimageWrite); @@ -39,9 +37,5 @@ fn main() -> Result<(), String> { .expect("Failed to set tracing subscriber"); } - kona_proof::block_on(kona_client::interop::run( - ORACLE_READER, - HINT_WRITER, - Some(precompiles::fpvm_handle_register), - )) + kona_proof::block_on(kona_client::interop::run(ORACLE_READER, HINT_WRITER)) } diff --git a/bin/client/src/lib.rs b/bin/client/src/lib.rs index ae62ca0686..58128dd352 100644 --- a/bin/client/src/lib.rs +++ b/bin/client/src/lib.rs @@ -3,9 +3,10 @@ #![deny(unused_must_use, rust_2018_idioms)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![allow(clippy::type_complexity)] -#![no_std] +#![cfg_attr(not(test), no_std)] extern crate alloc; +pub mod fpvm_evm; pub mod interop; pub mod single; diff --git a/bin/client/src/precompiles/bls12_g1_add.rs b/bin/client/src/precompiles/bls12_g1_add.rs deleted file mode 100644 index 6f193e16ed..0000000000 --- a/bin/client/src/precompiles/bls12_g1_add.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Contains the accelerated precompile for the BLS12-381 curve G1 Point Addition. -//! -//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). -//! -//! For constants and logic, see the [revm implementation]. -//! -//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g1_add.rs - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, address, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, - primitives::PrecompileOutput, -}; - -/// The address of the BLS12-381 g1 addition check precompile. -/// -/// See: -const BLS12_G1_ADD_CHECK: Address = address!("0x000000000000000000000000000000000000000b"); - -/// Input length of G1 Addition operation. -const INPUT_LENGTH: usize = 256; - -/// Base gas fee for the BLS12-381 g1 addition operation. -const G1_ADD_BASE_FEE: u64 = 375; - -/// The address of the BLS12-381 g1 addition precompile. -pub(crate) const FPVM_BLS12_G1_ADD_ISTHMUS: PrecompileWithAddress = - PrecompileWithAddress(BLS12_G1_ADD_CHECK, Precompile::Standard(fpvm_bls12_g1_add)); - -/// Performs an FPVM-accelerated BLS12-381 G1 addition check. -/// -/// Notice, there is no input size limit for this precompile. -/// See: -fn fpvm_bls12_g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if G1_ADD_BASE_FEE > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - let input_len = input.len(); - if input_len != INPUT_LENGTH { - return Err(PrecompileError::Other(alloc::format!( - "G1 addition input length should be multiple of {INPUT_LENGTH}, was {input_len}" - )) - .into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[BLS12_G1_ADD_CHECK.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(G1_ADD_BASE_FEE, result_data.into())) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn test_fpvm_bls12_g1_add_input_len() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); - let err = PrecompileError::Other(alloc::format!( - "G1 addition input length should be multiple of {}, was {}", - INPUT_LENGTH, - INPUT_LENGTH + 1 - )); - assert_eq!(fpvm_bls12_g1_add(&input, G1_ADD_BASE_FEE), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_g1_add_out_of_gas() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); - assert_eq!( - fpvm_bls12_g1_add(&input, G1_ADD_BASE_FEE - 1), - Err(PrecompileError::OutOfGas.into()) - ); - } -} diff --git a/bin/client/src/precompiles/bls12_g1_msm.rs b/bin/client/src/precompiles/bls12_g1_msm.rs deleted file mode 100644 index b3635195c9..0000000000 --- a/bin/client/src/precompiles/bls12_g1_msm.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! Contains the accelerated precompile for the BLS12-381 curve G1 MSM. -//! -//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). -//! -//! For constants and logic, see the [revm implementation]. -//! -//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g1_msm.rs - -use crate::precompiles::utils::{msm_required_gas, precompile_run}; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, address, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, - primitives::PrecompileOutput, -}; - -/// The maximum input size for the BLS12-381 g1 msm operation after the Isthmus Hardfork. -/// -/// See: -const BLS12_MAX_G1_MSM_SIZE_ISTHMUS: usize = 513760; - -/// The address of the BLS12-381 g1 msm check precompile. -/// -/// See: -const BLS12_G1_MSM_CHECK: Address = address!("0x000000000000000000000000000000000000000c"); - -/// Input length of g1 msm operation. -const INPUT_LENGTH: usize = 160; - -/// Base gas fee for the BLS12-381 g1 msm operation. -const G1_MSM_BASE_FEE: u64 = 12000; - -/// The address of the BLS12-381 g1 msm precompile. -pub(crate) const FPVM_BLS12_G1_MSM_ISTHMUS: PrecompileWithAddress = - PrecompileWithAddress(BLS12_G1_MSM_CHECK, Precompile::Standard(fpvm_bls12_g1_msm_isthmus)); - -/// Discounts table for G1 MSM as a vector of pairs `[k, discount]`. -static DISCOUNT_TABLE: [u16; 128] = [ - 1000, 949, 848, 797, 764, 750, 738, 728, 719, 712, 705, 698, 692, 687, 682, 677, 673, 669, 665, - 661, 658, 654, 651, 648, 645, 642, 640, 637, 635, 632, 630, 627, 625, 623, 621, 619, 617, 615, - 613, 611, 609, 608, 606, 604, 603, 601, 599, 598, 596, 595, 593, 592, 591, 589, 588, 586, 585, - 584, 582, 581, 580, 579, 577, 576, 575, 574, 573, 572, 570, 569, 568, 567, 566, 565, 564, 563, - 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 547, 546, 545, - 544, 543, 542, 541, 540, 540, 539, 538, 537, 536, 536, 535, 534, 533, 532, 532, 531, 530, 529, - 528, 528, 527, 526, 525, 525, 524, 523, 522, 522, 521, 520, 520, 519, -]; - -/// Performs an FPVM-accelerated BLS12-381 G1 msm check. -fn fpvm_bls12_g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { - let input_len = input.len(); - if input_len == 0 || input_len % INPUT_LENGTH != 0 { - return Err(PrecompileError::Other(alloc::format!( - "G1MSM input length should be multiple of {}, was {}", - INPUT_LENGTH, - input_len - )) - .into()); - } - - let k = input_len / INPUT_LENGTH; - let required_gas = msm_required_gas(k, &DISCOUNT_TABLE, G1_MSM_BASE_FEE); - if required_gas > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[BLS12_G1_MSM_CHECK.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(G1_MSM_BASE_FEE, result_data.into())) -} - -/// Performs an FPVM-accelerated `bls12` g1 msm check precompile call -/// after the Isthmus Hardfork. -fn fpvm_bls12_g1_msm_isthmus(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if input.len() > BLS12_MAX_G1_MSM_SIZE_ISTHMUS { - return Err(PrecompileError::Other(alloc::format!( - "G1MSM input length must be at most {}", - BLS12_MAX_G1_MSM_SIZE_ISTHMUS - )) - .into()); - } - - fpvm_bls12_g1_msm(input, gas_limit) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn test_fpvm_bls12_g1_msm_isthmus_max_bytes() { - let input = Bytes::from(vec![0u8; BLS12_MAX_G1_MSM_SIZE_ISTHMUS + 1]); - let gas_limit = G1_MSM_BASE_FEE; - let err = PrecompileError::Other(alloc::format!( - "G1MSM input length must be at most {}", - BLS12_MAX_G1_MSM_SIZE_ISTHMUS - )); - assert_eq!(fpvm_bls12_g1_msm_isthmus(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_g1_msm_offset() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); - let gas_limit = G1_MSM_BASE_FEE; - let err = PrecompileError::Other(alloc::format!( - "G1MSM input length should be multiple of {}, was {}", - INPUT_LENGTH, - input.len(), - )); - assert_eq!(fpvm_bls12_g1_msm(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_g1_msm_out_of_gas() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); - let gas_limit = G1_MSM_BASE_FEE - 1; - assert_eq!(fpvm_bls12_g1_msm(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); - } -} diff --git a/bin/client/src/precompiles/bls12_g2_add.rs b/bin/client/src/precompiles/bls12_g2_add.rs deleted file mode 100644 index 9239759ccf..0000000000 --- a/bin/client/src/precompiles/bls12_g2_add.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Contains the accelerated precompile for the BLS12-381 curve G2 Point Addition. -//! -//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). -//! -//! For constants and logic, see the [revm implementation]. -//! -//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g2_add.rs - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, address, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, - primitives::PrecompileOutput, -}; - -/// The address of the BLS12-381 g2 addition check precompile. -/// -/// See: -const BLS12_G2_ADD_CHECK: Address = address!("0x000000000000000000000000000000000000000d"); - -/// Input length of g2 addition operation. -const INPUT_LENGTH: usize = 512; - -/// Base gas fee for the BLS12-381 g2 addition operation. -const G2_ADD_BASE_FEE: u64 = 600; - -/// The address of the BLS12-381 g2 addition precompile. -pub(crate) const FPVM_BLS12_G2_ADD_ISTHMUS: PrecompileWithAddress = - PrecompileWithAddress(BLS12_G2_ADD_CHECK, Precompile::Standard(fpvm_bls12_g2_add)); - -/// Performs an FPVM-accelerated BLS12-381 G2 addition check. -/// -/// Notice, there is no input size limit for this precompile. -/// See: -fn fpvm_bls12_g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if G2_ADD_BASE_FEE > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - let input_len = input.len(); - if input_len != INPUT_LENGTH { - return Err(PrecompileError::Other(alloc::format!( - "G2 addition input length should be multiple of {INPUT_LENGTH}, was {input_len}" - )) - .into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[BLS12_G2_ADD_CHECK.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(G2_ADD_BASE_FEE, result_data.into())) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn test_fpvm_bls12_g2_add_input_len() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); - let err = PrecompileError::Other(alloc::format!( - "G2 addition input length should be multiple of {}, was {}", - INPUT_LENGTH, - INPUT_LENGTH + 1 - )); - assert_eq!(fpvm_bls12_g2_add(&input, G2_ADD_BASE_FEE), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_g2_add_out_of_gas() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); - assert_eq!( - fpvm_bls12_g2_add(&input, G2_ADD_BASE_FEE - 1), - Err(PrecompileError::OutOfGas.into()) - ); - } -} diff --git a/bin/client/src/precompiles/bls12_g2_msm.rs b/bin/client/src/precompiles/bls12_g2_msm.rs deleted file mode 100644 index 2bb67b6ffa..0000000000 --- a/bin/client/src/precompiles/bls12_g2_msm.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! Contains the accelerated precompile for the BLS12-381 curve G2 MSM. -//! -//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). -//! -//! For constants and logic, see the [revm implementation]. -//! -//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g2_msm.rs - -use crate::precompiles::utils::{msm_required_gas, precompile_run}; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, address, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, - primitives::PrecompileOutput, -}; - -/// The maximum input size for the BLS12-381 g2 msm operation after the Isthmus Hardfork. -/// -/// See: -const BLS12_MAX_G2_MSM_SIZE_ISTHMUS: usize = 488448; - -/// The address of the BLS12-381 g2 msm check precompile. -/// -/// See: -const BLS12_G2_MSM_CHECK: Address = address!("0x000000000000000000000000000000000000000e"); - -/// Input length of g2 msm operation. -const INPUT_LENGTH: usize = 288; - -/// Base gas fee for the BLS12-381 g2 msm operation. -const G2_MSM_BASE_FEE: u64 = 22500; - -/// The address of the BLS12-381 g2 msm precompile. -pub(crate) const FPVM_BLS12_G2_MSM_ISTHMUS: PrecompileWithAddress = - PrecompileWithAddress(BLS12_G2_MSM_CHECK, Precompile::Standard(fpvm_bls12_g2_msm_isthmus)); - -// Discounts table for G2 MSM as a vector of pairs `[k, discount]`: -static DISCOUNT_TABLE: [u16; 128] = [ - 1000, 1000, 923, 884, 855, 832, 812, 796, 782, 770, 759, 749, 740, 732, 724, 717, 711, 704, - 699, 693, 688, 683, 679, 674, 670, 666, 663, 659, 655, 652, 649, 646, 643, 640, 637, 634, 632, - 629, 627, 624, 622, 620, 618, 615, 613, 611, 609, 607, 606, 604, 602, 600, 598, 597, 595, 593, - 592, 590, 589, 587, 586, 584, 583, 582, 580, 579, 578, 576, 575, 574, 573, 571, 570, 569, 568, - 567, 566, 565, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 552, 551, 550, 549, - 548, 547, 546, 545, 545, 544, 543, 542, 541, 541, 540, 539, 538, 537, 537, 536, 535, 535, 534, - 533, 532, 532, 531, 530, 530, 529, 528, 528, 527, 526, 526, 525, 524, 524, -]; - -/// Performs an FPVM-accelerated BLS12-381 G2 msm check. -fn fpvm_bls12_g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { - let input_len = input.len(); - if input_len == 0 || input_len % INPUT_LENGTH != 0 { - return Err(PrecompileError::Other(alloc::format!( - "G2MSM input length should be multiple of {}, was {}", - INPUT_LENGTH, - input_len - )) - .into()); - } - - let k = input_len / INPUT_LENGTH; - let required_gas = msm_required_gas(k, &DISCOUNT_TABLE, G2_MSM_BASE_FEE); - if required_gas > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[BLS12_G2_MSM_CHECK.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(G2_MSM_BASE_FEE, result_data.into())) -} - -/// Performs an FPVM-accelerated `bls12` g2 msm check precompile call -/// after the Isthmus Hardfork. -fn fpvm_bls12_g2_msm_isthmus(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if input.len() > BLS12_MAX_G2_MSM_SIZE_ISTHMUS { - return Err(PrecompileError::Other(alloc::format!( - "G2MSM input length must be at most {}", - BLS12_MAX_G2_MSM_SIZE_ISTHMUS - )) - .into()); - } - - fpvm_bls12_g2_msm(input, gas_limit) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn test_fpvm_bls12_g2_msm_isthmus_max_bytes() { - let input = Bytes::from(vec![0u8; BLS12_MAX_G2_MSM_SIZE_ISTHMUS + 1]); - let gas_limit = G2_MSM_BASE_FEE; - let err = PrecompileError::Other(alloc::format!( - "G2MSM input length must be at most {}", - BLS12_MAX_G2_MSM_SIZE_ISTHMUS - )); - assert_eq!(fpvm_bls12_g2_msm_isthmus(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_g2_msm_offset() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); - let gas_limit = G2_MSM_BASE_FEE; - let err = PrecompileError::Other(alloc::format!( - "G2MSM input length should be multiple of {}, was {}", - INPUT_LENGTH, - input.len(), - )); - assert_eq!(fpvm_bls12_g2_msm(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_g2_msm_out_of_gas() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); - let gas_limit = G2_MSM_BASE_FEE - 1; - assert_eq!(fpvm_bls12_g2_msm(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); - } -} diff --git a/bin/client/src/precompiles/bls12_map_fp.rs b/bin/client/src/precompiles/bls12_map_fp.rs deleted file mode 100644 index 96312672bc..0000000000 --- a/bin/client/src/precompiles/bls12_map_fp.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Contains the accelerated precompile for the BLS12-381 curve FP to G1 Mapping. -//! -//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). -//! -//! For constants and logic, see the [revm implementation]. -//! -//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/map_fp_to_g1.rs - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, address, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, - primitives::PrecompileOutput, -}; - -/// The address of the BLS12-381 map fp to g1 check precompile. -/// -/// See: -const BLS12_MAP_FP_CHECK: Address = address!("0x0000000000000000000000000000000000000010"); - -/// Base gas fee for the BLS12-381 map fp to g1 operation. -const MAP_FP_BASE_FEE: u64 = 5500; - -/// The padded FP length. -const PADDED_FP_LENGTH: usize = 64; - -/// The address of the BLS12-381 map fp to g1 precompile. -pub(crate) const FPVM_BLS12_MAP_FP_ISTHMUS: PrecompileWithAddress = - PrecompileWithAddress(BLS12_MAP_FP_CHECK, Precompile::Standard(fpvm_bls12_map_fp)); - -/// Performs an FPVM-accelerated BLS12-381 map fp check. -/// -/// Notice, there is no input size limit for this precompile. -/// See: -fn fpvm_bls12_map_fp(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if MAP_FP_BASE_FEE > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - if input.len() != PADDED_FP_LENGTH { - return Err(PrecompileError::Other(alloc::format!( - "MAP_FP_TO_G1 input should be {PADDED_FP_LENGTH} bytes, was {}", - input.len() - )) - .into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[BLS12_MAP_FP_CHECK.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(MAP_FP_BASE_FEE, result_data.into())) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn test_fpvm_bls12_map_fp_offset() { - let input = Bytes::from(vec![0u8; PADDED_FP_LENGTH + 1]); - let gas_limit = MAP_FP_BASE_FEE; - let err = PrecompileError::Other(alloc::format!( - "MAP_FP_TO_G1 input should be {} bytes, was {}", - PADDED_FP_LENGTH, - input.len(), - )); - assert_eq!(fpvm_bls12_map_fp(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_map_fp_out_of_gas() { - let input = Bytes::from(vec![0u8; PADDED_FP_LENGTH]); - let gas_limit = MAP_FP_BASE_FEE - 1; - assert_eq!(fpvm_bls12_map_fp(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); - } -} diff --git a/bin/client/src/precompiles/bls12_map_fp2.rs b/bin/client/src/precompiles/bls12_map_fp2.rs deleted file mode 100644 index 494a4b540b..0000000000 --- a/bin/client/src/precompiles/bls12_map_fp2.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Contains the accelerated precompile for the BLS12-381 curve FP2 to G2 Mapping. -//! -//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). -//! -//! For constants and logic, see the [revm implementation]. -//! -//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/map_fp_to_g1.rs - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, address, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, - primitives::PrecompileOutput, -}; - -/// The address of the BLS12-381 map fp2 to g2 check precompile. -/// -/// See: -const BLS12_MAP_FP2_CHECK: Address = address!("0x0000000000000000000000000000000000000011"); - -/// Base gas fee for the BLS12-381 map fp2 to g2 operation. -const MAP_FP2_BASE_FEE: u64 = 23800; - -/// The padded FP2 length. -const PADDED_FP2_LENGTH: usize = 128; - -/// The address of the BLS12-381 map fp2 to g2 precompile. -pub(crate) const FPVM_BLS12_MAP_FP2_ISTHMUS: PrecompileWithAddress = - PrecompileWithAddress(BLS12_MAP_FP2_CHECK, Precompile::Standard(fpvm_bls12_map_fp2)); - -/// Performs an FPVM-accelerated BLS12-381 map fp2 check. -/// -/// Notice, there is no input size limit for this precompile. -/// See: -fn fpvm_bls12_map_fp2(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if MAP_FP2_BASE_FEE > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - if input.len() != PADDED_FP2_LENGTH { - return Err(PrecompileError::Other(alloc::format!( - "MAP_FP2_TO_G2 input should be {PADDED_FP2_LENGTH} bytes, was {}", - input.len() - )) - .into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[BLS12_MAP_FP2_CHECK.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(MAP_FP2_BASE_FEE, result_data.into())) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn test_fpvm_bls12_map_fp2_offset() { - let input = Bytes::from(vec![0u8; PADDED_FP2_LENGTH + 1]); - let gas_limit = MAP_FP2_BASE_FEE; - let err = PrecompileError::Other(alloc::format!( - "MAP_FP2_TO_G2 input should be {} bytes, was {}", - PADDED_FP2_LENGTH, - input.len(), - )); - assert_eq!(fpvm_bls12_map_fp2(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_map_fp_out_of_gas() { - let input = Bytes::from(vec![0u8; PADDED_FP2_LENGTH]); - let gas_limit = MAP_FP2_BASE_FEE - 1; - assert_eq!(fpvm_bls12_map_fp2(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); - } -} diff --git a/bin/client/src/precompiles/bls12_pairing.rs b/bin/client/src/precompiles/bls12_pairing.rs deleted file mode 100644 index c4e73a2b4f..0000000000 --- a/bin/client/src/precompiles/bls12_pairing.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Contains the accelerated precompile for the BLS12-381 curve. -//! -//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). -//! -//! For constants and logic, see the [revm implementation]. -//! -//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/pairing.rs - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, address, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, - primitives::PrecompileOutput, -}; - -/// The max pairing size for BLS12-381 input given a 20M gas limit. -const BLS12_MAX_PAIRING_SIZE_ISTHMUS: usize = 235_008; - -/// The address of the BLS12-381 pairing check precompile. -const BLS12_PAIRING_CHECK: Address = address!("0x000000000000000000000000000000000000000f"); - -/// Input length of pairing operation. -const INPUT_LENGTH: usize = 384; - -/// Multiplier gas fee for BLS12-381 pairing operation. -const PAIRING_MULTIPLIER_BASE: u64 = 32600; - -/// Offset gas fee for BLS12-381 pairing operation. -const PAIRING_OFFSET_BASE: u64 = 37700; - -/// The address of the BLS12-381 pairing precompile. -pub(crate) const FPVM_BLS12_PAIRING_ISTHMUS: PrecompileWithAddress = - PrecompileWithAddress(BLS12_PAIRING_CHECK, Precompile::Standard(fpvm_bls12_pairing_isthmus)); - -/// Performs an FPVM-accelerated BLS12-381 pairing check. -fn fpvm_bls12_pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { - let input_len = input.len(); - if input_len % INPUT_LENGTH != 0 { - return Err(PrecompileError::Other(alloc::format!( - "Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}" - )) - .into()); - } - - let k = input_len / INPUT_LENGTH; - let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE; - if required_gas > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[BLS12_PAIRING_CHECK.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(required_gas, result_data.into())) -} - -/// Performs an FPVM-accelerated `bls12` pairing check precompile call -/// after the Isthmus Hardfork. -fn fpvm_bls12_pairing_isthmus(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if input.len() > BLS12_MAX_PAIRING_SIZE_ISTHMUS { - return Err(PrecompileError::Other(alloc::format!( - "Pairing input length must be at most {}", - BLS12_MAX_PAIRING_SIZE_ISTHMUS - )) - .into()); - } - - fpvm_bls12_pairing(input, gas_limit) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn test_fpvm_bls12_pairing_isthmus_max_bytes() { - let input = Bytes::from(vec![0u8; BLS12_MAX_PAIRING_SIZE_ISTHMUS + 1]); - let gas_limit = PAIRING_MULTIPLIER_BASE; - let err = PrecompileError::Other("Pairing input length must be at most 235008".to_string()); - assert_eq!(fpvm_bls12_pairing_isthmus(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_offset() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); - let gas_limit = PAIRING_OFFSET_BASE; - let err = PrecompileError::Other( - "Pairing input length should be multiple of 384, was 385".to_string(), - ); - assert_eq!(fpvm_bls12_pairing(&input, gas_limit), Err(err.into())); - } - - #[test] - fn test_fpvm_bls12_out_of_gas() { - let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); - let gas_limit = PAIRING_MULTIPLIER_BASE - 1; - assert_eq!(fpvm_bls12_pairing(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); - } -} diff --git a/bin/client/src/precompiles/bn128_pair.rs b/bin/client/src/precompiles/bn128_pair.rs deleted file mode 100644 index 9cb55b51f7..0000000000 --- a/bin/client/src/precompiles/bn128_pair.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Contains the accelerated version of the `ecPairing` precompile. - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, keccak256}; -use revm::{ - precompile::{ - Error as PrecompileError, PrecompileWithAddress, - bn128::pair::{ISTANBUL_PAIR_BASE, ISTANBUL_PAIR_PER_POINT}, - u64_to_address, - }, - primitives::{Precompile, PrecompileOutput, PrecompileResult}, -}; - -const ECPAIRING_ADDRESS: Address = u64_to_address(8); -const PAIR_ELEMENT_LEN: usize = 64 + 128; - -pub(crate) const FPVM_ECPAIRING: PrecompileWithAddress = - PrecompileWithAddress(ECPAIRING_ADDRESS, Precompile::Standard(fpvm_ecpairing)); - -pub(crate) const FPVM_ECPAIRING_GRANITE: PrecompileWithAddress = - PrecompileWithAddress(ECPAIRING_ADDRESS, Precompile::Standard(fpvm_ecpairing_granite)); - -/// Performs an FPVM-accelerated `ecpairing` precompile call. -fn fpvm_ecpairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { - let gas_used = - (input.len() / PAIR_ELEMENT_LEN) as u64 * ISTANBUL_PAIR_PER_POINT + ISTANBUL_PAIR_BASE; - - if gas_used > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - if input.len() % PAIR_ELEMENT_LEN != 0 { - return Err(PrecompileError::Bn128PairLength.into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[ECPAIRING_ADDRESS.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(gas_used, result_data.into())) -} - -/// Performs an FPVM-accelerated `ecpairing` precompile call after the Granite hardfork. -fn fpvm_ecpairing_granite(input: &Bytes, gas_limit: u64) -> PrecompileResult { - const BN256_MAX_PAIRING_SIZE_GRANITE: usize = 112_687; - if input.len() > BN256_MAX_PAIRING_SIZE_GRANITE { - return Err(PrecompileError::Bn128PairLength.into()); - } - - fpvm_ecpairing(input, gas_limit) -} diff --git a/bin/client/src/precompiles/ecrecover.rs b/bin/client/src/precompiles/ecrecover.rs deleted file mode 100644 index fffd6bb680..0000000000 --- a/bin/client/src/precompiles/ecrecover.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Contains the accelerated version of the `ecrecover` precompile. - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, PrecompileWithAddress, u64_to_address}, - primitives::{Precompile, PrecompileOutput, PrecompileResult}, -}; - -const ECRECOVER_ADDRESS: Address = u64_to_address(1); - -pub(crate) const FPVM_ECRECOVER: PrecompileWithAddress = - PrecompileWithAddress(ECRECOVER_ADDRESS, Precompile::Standard(fpvm_ecrecover)); - -/// Performs an FPVM-accelerated `ecrecover` precompile call. -fn fpvm_ecrecover(input: &Bytes, gas_limit: u64) -> PrecompileResult { - const ECRECOVER_BASE: u64 = 3_000; - - if ECRECOVER_BASE > gas_limit { - return Err(PrecompileError::OutOfGas.into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[ECRECOVER_ADDRESS.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(ECRECOVER_BASE, result_data.into())) -} diff --git a/bin/client/src/precompiles/kzg_point_eval.rs b/bin/client/src/precompiles/kzg_point_eval.rs deleted file mode 100644 index bfb65e05a2..0000000000 --- a/bin/client/src/precompiles/kzg_point_eval.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Contains the accelerated version of the KZG point evaluation precompile. - -use crate::precompiles::utils::precompile_run; -use alloc::{string::ToString, vec::Vec}; -use alloy_primitives::{Address, Bytes, keccak256}; -use revm::{ - precompile::{Error as PrecompileError, PrecompileWithAddress, u64_to_address}, - primitives::{Precompile, PrecompileOutput, PrecompileResult}, -}; - -const POINT_EVAL_ADDRESS: Address = u64_to_address(0x0A); - -pub(crate) const FPVM_KZG_POINT_EVAL: PrecompileWithAddress = - PrecompileWithAddress(POINT_EVAL_ADDRESS, Precompile::Standard(fpvm_kzg_point_eval)); - -/// Performs an FPVM-accelerated KZG point evaluation precompile call. -fn fpvm_kzg_point_eval(input: &Bytes, gas_limit: u64) -> PrecompileResult { - const GAS_COST: u64 = 50_000; - - if gas_limit < GAS_COST { - return Err(PrecompileError::OutOfGas.into()); - } - - if input.len() != 192 { - return Err(PrecompileError::BlobInvalidInputLength.into()); - } - - let result_data = kona_proof::block_on(precompile_run! { - &[POINT_EVAL_ADDRESS.as_ref(), input.as_ref()] - }) - .map_err(|e| PrecompileError::Other(e.to_string()))?; - - Ok(PrecompileOutput::new(GAS_COST, result_data.into())) -} diff --git a/bin/client/src/precompiles/mod.rs b/bin/client/src/precompiles/mod.rs deleted file mode 100644 index 72afe764bb..0000000000 --- a/bin/client/src/precompiles/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Contains the [KonaHandleRegister] function for registering the FPVM-accelerated precompiles. -//! -//! [KonaHandleRegister]: kona_executor::KonaHandleRegister - -use alloc::sync::Arc; -use kona_executor::{TrieDB, TrieDBProvider}; -use kona_mpt::TrieHinter; -use revm::{ - State, - handler::register::EvmHandler, - primitives::{SpecId, spec_to_generic}, -}; - -mod bn128_pair; -mod ecrecover; -mod kzg_point_eval; -pub(crate) mod utils; - -mod bls12_g1_add; -mod bls12_g1_msm; -mod bls12_g2_add; -mod bls12_g2_msm; -mod bls12_map_fp; -mod bls12_map_fp2; -mod bls12_pairing; - -/// The [KonaHandleRegister] function for registering the FPVM-accelerated precompiles. -/// -/// [KonaHandleRegister]: kona_executor::KonaHandleRegister -pub(crate) fn fpvm_handle_register( - handler: &mut EvmHandler<'_, (), &mut State<&mut TrieDB>>, -) where - F: TrieDBProvider, - H: TrieHinter, -{ - let spec_id = handler.cfg.spec_id; - - handler.pre_execution.load_precompiles = Arc::new(move || { - let mut ctx_precompiles = spec_to_generic!(spec_id, { - revm::optimism::load_precompiles::>>() - }); - - // Extend with FPVM-accelerated precompiles - let override_precompiles = [ - ecrecover::FPVM_ECRECOVER, - bn128_pair::FPVM_ECPAIRING, - kzg_point_eval::FPVM_KZG_POINT_EVAL, - ]; - ctx_precompiles.extend(override_precompiles); - - if spec_id.is_enabled_in(SpecId::GRANITE) { - ctx_precompiles.extend([bn128_pair::FPVM_ECPAIRING_GRANITE]); - } - - if spec_id.is_enabled_in(SpecId::ISTHMUS) { - ctx_precompiles.extend([bls12_g1_add::FPVM_BLS12_G1_ADD_ISTHMUS]); - ctx_precompiles.extend([bls12_g1_msm::FPVM_BLS12_G1_MSM_ISTHMUS]); - ctx_precompiles.extend([bls12_g2_add::FPVM_BLS12_G2_ADD_ISTHMUS]); - ctx_precompiles.extend([bls12_g2_msm::FPVM_BLS12_G2_MSM_ISTHMUS]); - ctx_precompiles.extend([bls12_map_fp::FPVM_BLS12_MAP_FP_ISTHMUS]); - ctx_precompiles.extend([bls12_map_fp2::FPVM_BLS12_MAP_FP2_ISTHMUS]); - ctx_precompiles.extend([bls12_pairing::FPVM_BLS12_PAIRING_ISTHMUS]); - } - - ctx_precompiles - }); -} diff --git a/bin/client/src/single.rs b/bin/client/src/single.rs index eab57ec9f8..402205f4f1 100644 --- a/bin/client/src/single.rs +++ b/bin/client/src/single.rs @@ -2,11 +2,12 @@ use alloc::sync::Arc; use alloy_consensus::Sealed; +use alloy_evm::{EvmFactory, FromRecoveredTx, FromTxWithEncoded}; use alloy_primitives::B256; use core::fmt::Debug; use kona_derive::errors::PipelineErrorKind; use kona_driver::{Driver, DriverError}; -use kona_executor::{ExecutorError, KonaHandleRegister, TrieDBProvider}; +use kona_executor::{ExecutorError, TrieDBProvider}; use kona_preimage::{CommsClient, HintWriterClient, PreimageKey, PreimageOracleClient}; use kona_proof::{ BootInfo, CachingOracle, HintType, @@ -16,6 +17,8 @@ use kona_proof::{ l2::OracleL2ChainProvider, sync::new_pipeline_cursor, }; +use op_alloy_consensus::OpTxEnvelope; +use op_revm::OpSpecId; use thiserror::Error; use tracing::{error, info}; @@ -38,19 +41,16 @@ pub enum FaultProofProgramError { /// Executes the fault proof program with the given [PreimageOracleClient] and [HintWriterClient]. #[inline] -pub async fn run( +pub async fn run( oracle_client: P, hint_client: H, - handle_register: Option< - KonaHandleRegister< - OracleL2ChainProvider>, - OracleL2ChainProvider>, - >, - >, + evm_factory: Evm, ) -> Result<(), FaultProofProgramError> where P: PreimageOracleClient + Send + Sync + Debug + Clone, H: HintWriterClient + Send + Sync + Debug + Clone, + Evm: EvmFactory + Send + Sync + Debug + Clone + 'static, + ::Tx: FromTxWithEncoded + FromRecoveredTx, { const ORACLE_LRU_SIZE: usize = 1024; @@ -121,7 +121,7 @@ where rollup_config.as_ref(), l2_provider.clone(), l2_provider, - handle_register, + evm_factory, None, ); let mut driver = Driver::new(cursor, executor, pipeline); diff --git a/bin/client/testdata/holocene-op-sepolia-22012816-witness.tar.zst b/bin/client/testdata/holocene-op-sepolia-22012816-witness.tar.zst deleted file mode 100644 index 7489fa5ba0..0000000000 Binary files a/bin/client/testdata/holocene-op-sepolia-22012816-witness.tar.zst and /dev/null differ diff --git a/bin/client/testdata/holocene-op-sepolia-26215604-witness.tar.zst b/bin/client/testdata/holocene-op-sepolia-26215604-witness.tar.zst new file mode 100644 index 0000000000..2dc467d4e2 Binary files /dev/null and b/bin/client/testdata/holocene-op-sepolia-26215604-witness.tar.zst differ diff --git a/bin/host/Cargo.toml b/bin/host/Cargo.toml index 8e1e5135e3..507c61c2b6 100644 --- a/bin/host/Cargo.toml +++ b/bin/host/Cargo.toml @@ -49,6 +49,7 @@ alloy-rpc-types-beacon.workspace = true # Op Alloy op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] } op-alloy-network.workspace = true +alloy-op-evm = { workspace = true, features = ["std"] } # Revm revm = { workspace = true, features = ["std", "c-kzg", "secp256k1", "portable", "blst"] } diff --git a/bin/host/src/eth/precompiles.rs b/bin/host/src/eth/precompiles.rs index 4bfb47857b..6d195e8ad7 100644 --- a/bin/host/src/eth/precompiles.rs +++ b/bin/host/src/eth/precompiles.rs @@ -2,10 +2,7 @@ use alloy_primitives::{Address, Bytes}; use anyhow::{Result, anyhow}; -use revm::{ - precompile::{self, PrecompileWithAddress}, - primitives::{Env, Precompile}, -}; +use revm::precompile::{self, PrecompileWithAddress}; /// List of precompiles that are accelerated by the host program. pub(crate) const ACCELERATED_PRECOMPILES: &[PrecompileWithAddress] = &[ @@ -23,27 +20,14 @@ pub(crate) const ACCELERATED_PRECOMPILES: &[PrecompileWithAddress] = &[ ]; /// Executes an accelerated precompile on [revm]. -pub(crate) fn execute>(address: Address, input: T) -> Result> { +pub(crate) fn execute>(address: Address, input: T, gas: u64) -> Result> { if let Some(precompile) = ACCELERATED_PRECOMPILES.iter().find(|precompile| precompile.0 == address) { - match precompile.1 { - Precompile::Standard(std_precompile) => { - // Standard precompile execution - no access to environment required. - let output = std_precompile(&input.into(), u64::MAX) - .map_err(|e| anyhow!("Failed precompile execution: {e}"))?; + let output = precompile.precompile()(&input.into(), gas) + .map_err(|e| anyhow!("Failed precompile execution: {e}"))?; - Ok(output.bytes.into()) - } - Precompile::Env(env_precompile) => { - // Use default environment for KZG point evaluation. - let output = env_precompile(&input.into(), u64::MAX, &Env::default()) - .map_err(|e| anyhow!("Failed precompile execution: {e}"))?; - - Ok(output.bytes.into()) - } - _ => anyhow::bail!("Precompile not accelerated"), - } + Ok(output.bytes.into()) } else { anyhow::bail!("Precompile not accelerated"); } diff --git a/bin/host/src/interop/cfg.rs b/bin/host/src/interop/cfg.rs index 8a7015326a..7b39d87041 100644 --- a/bin/host/src/interop/cfg.rs +++ b/bin/host/src/interop/cfg.rs @@ -191,7 +191,6 @@ impl InteropHost { let client_task = task::spawn(kona_client::interop::run( OracleReader::new(preimage.client), HintWriter::new(hint.client), - None, )); let (_, client_result) = tokio::try_join!(server_task, client_task)?; diff --git a/bin/host/src/interop/handler.rs b/bin/host/src/interop/handler.rs index b498eac203..eca23f3203 100644 --- a/bin/host/src/interop/handler.rs +++ b/bin/host/src/interop/handler.rs @@ -10,6 +10,7 @@ use alloy_eips::{ eip2718::Encodable2718, eip4844::{FIELD_ELEMENTS_PER_BLOB, IndexedBlobHash}, }; +use alloy_op_evm::OpEvmFactory; use alloy_primitives::{Address, B256, Bytes, address, keccak256}; use alloy_provider::Provider; use alloy_rlp::{Decodable, Encodable}; @@ -149,13 +150,14 @@ impl HintHandler for InteropHintHandler { )?; } HintType::L1Precompile => { - ensure!(hint.data.len() >= 20, "Invalid hint data length"); + ensure!(hint.data.len() >= 28, "Invalid hint data length"); let address = Address::from_slice(&hint.data.as_ref()[..20]); - let input = hint.data[20..].to_vec(); + let gas = u64::from_be_bytes(hint.data.as_ref()[20..28].try_into()?); + let input = hint.data[28..].to_vec(); let input_hash = keccak256(hint.data.as_ref()); - let result = crate::eth::execute(address, input).map_or_else( + let result = crate::eth::execute(address, input, gas).map_or_else( |_| vec![0u8; 1], |raw_res| { let mut res = Vec::with_capacity(1 + raw_res.len()); @@ -488,7 +490,7 @@ impl HintHandler for InteropHintHandler { rollup_config.as_ref(), l2_provider.clone(), l2_provider, - None, + OpEvmFactory::default(), None, ); let mut driver = Driver::new(cursor, executor, pipeline); @@ -497,24 +499,23 @@ impl HintHandler for InteropHintHandler { .advance_to_target(rollup_config.as_ref(), Some(target_block)) .await?; - Ok::<_, anyhow::Error>(driver.safe_head_artifacts.unwrap_or_default()) + driver + .safe_head_artifacts + .ok_or_else(|| anyhow!("No artifacts found for the safe head")) } }); // Wait on both the server and client tasks to complete. let (_, client_result) = tokio::try_join!(server_task, client_task)?; - let (execution_artifacts, raw_transactions) = client_result?; + let (build_outcome, raw_transactions) = client_result?; // Store optimistic block hash preimage. let mut kv_lock = kv.write().await; - let mut rlp_buf = Vec::with_capacity(execution_artifacts.block_header.length()); - execution_artifacts.block_header.encode(&mut rlp_buf); + let mut rlp_buf = Vec::with_capacity(build_outcome.header.length()); + build_outcome.header.encode(&mut rlp_buf); kv_lock.set( - PreimageKey::new( - *execution_artifacts.block_header.hash(), - PreimageKeyType::Keccak256, - ) - .into(), + PreimageKey::new(*build_outcome.header.hash(), PreimageKeyType::Keccak256) + .into(), rlp_buf, )?; @@ -522,7 +523,8 @@ impl HintHandler for InteropHintHandler { drop(kv_lock); // Store receipts root preimages. - let raw_receipts = execution_artifacts + let raw_receipts = build_outcome + .execution_result .receipts .into_iter() .map(|receipt| Ok::<_, anyhow::Error>(receipt.encoded_2718())) diff --git a/bin/host/src/single/cfg.rs b/bin/host/src/single/cfg.rs index bc3335bf72..5f8c613cde 100644 --- a/bin/host/src/single/cfg.rs +++ b/bin/host/src/single/cfg.rs @@ -10,6 +10,7 @@ use alloy_primitives::B256; use alloy_provider::RootProvider; use clap::Parser; use kona_cli::cli_styles; +use kona_client::fpvm_evm::FpvmOpEvmFactory; use kona_genesis::RollupConfig; use kona_preimage::{ BidirectionalChannel, Channel, HintReader, HintWriter, OracleReader, OracleServer, @@ -197,9 +198,9 @@ impl SingleChainHost { let server_task = self.start_server(hint.host, preimage.host).await?; let client_task = task::spawn(kona_client::single::run( - OracleReader::new(preimage.client), - HintWriter::new(hint.client), - None, + OracleReader::new(preimage.client.clone()), + HintWriter::new(hint.client.clone()), + FpvmOpEvmFactory::new(HintWriter::new(hint.client), OracleReader::new(preimage.client)), )); let (_, client_result) = tokio::try_join!(server_task, client_task)?; diff --git a/bin/host/src/single/handler.rs b/bin/host/src/single/handler.rs index 30642303b4..a988197e6e 100644 --- a/bin/host/src/single/handler.rs +++ b/bin/host/src/single/handler.rs @@ -134,13 +134,14 @@ impl HintHandler for SingleChainHintHandler { )?; } HintType::L1Precompile => { - ensure!(hint.data.len() >= 20, "Invalid hint data length"); + ensure!(hint.data.len() >= 28, "Invalid hint data length"); let address = Address::from_slice(&hint.data.as_ref()[..20]); - let input = hint.data[20..].to_vec(); + let gas = u64::from_be_bytes(hint.data.as_ref()[20..28].try_into()?); + let input = hint.data[28..].to_vec(); let input_hash = keccak256(hint.data.as_ref()); - let result = crate::eth::execute(address, input).map_or_else( + let result = crate::eth::execute(address, input, gas).map_or_else( |_| vec![0u8; 1], |raw_res| { let mut res = Vec::with_capacity(1 + raw_res.len()); diff --git a/crates/node/p2p/src/gossip/handler.rs b/crates/node/p2p/src/gossip/handler.rs index a0a49b69bf..0b9ba2bddd 100644 --- a/crates/node/p2p/src/gossip/handler.rs +++ b/crates/node/p2p/src/gossip/handler.rs @@ -162,7 +162,7 @@ impl BlockHandler { #[cfg(test)] mod tests { use super::*; - use alloy_primitives::{Address, B256, Bloom, Bytes, PrimitiveSignature, U256}; + use alloy_primitives::{Address, B256, Bloom, Bytes, Signature, U256}; use alloy_rpc_types_engine::ExecutionPayloadV1; use op_alloy_rpc_types_engine::{OpExecutionPayload, PayloadHash}; @@ -190,7 +190,7 @@ mod tests { let payload = OpExecutionPayload::V1(v1); let envelope = OpNetworkPayloadEnvelope { payload, - signature: PrimitiveSignature::test_signature(), + signature: Signature::test_signature(), payload_hash: PayloadHash(B256::ZERO), parent_beacon_block_root: None, }; diff --git a/crates/proof/executor/Cargo.toml b/crates/proof/executor/Cargo.toml index 9c9450fbeb..69ac8e049a 100644 --- a/crates/proof/executor/Cargo.toml +++ b/crates/proof/executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kona-executor" -description = "An no_std implementation of a stateless L2 block executor for the OP Stack." +description = "A no_std stateless block builder for the OP Stack" version = "0.3.0" edition.workspace = true authors.workspace = true @@ -26,9 +26,15 @@ alloy-trie.workspace = true # Op Alloy op-alloy-consensus.workspace = true op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] } +alloy-op-hardforks.workspace = true -# Revm -revm = { workspace = true, features = ["optimism"] } +# revm +op-revm.workspace = true +revm.workspace = true + +# alloy-evm +alloy-evm.workspace = true +alloy-op-evm.workspace = true # General thiserror.workspace = true @@ -36,18 +42,16 @@ tracing.workspace = true [dev-dependencies] rand.workspace = true -alloy-rlp.workspace = true serde_json.workspace = true -alloy-rpc-types-engine.workspace = true serde = { workspace = true, features = ["derive"] } -criterion = { workspace = true, features = ["html_reports"] } -pprof = { workspace = true, features = ["criterion", "flamegraph", "frame-pointer"] } tokio = { workspace = true, features = ["full"] } rstest.workspace = true kona-registry.workspace = true +rocksdb = { workspace = true, features = ["snappy"] } +tempfile.workspace = true +alloy-rpc-types-engine.workspace = true +alloy-rlp.workspace = true alloy-provider = { workspace = true, features = ["reqwest"] } alloy-rpc-client.workspace = true alloy-transport.workspace = true alloy-transport-http.workspace = true -rocksdb.workspace = true -tempfile.workspace = true diff --git a/crates/proof/executor/benches/execution.rs b/crates/proof/executor/benches/execution.rs deleted file mode 100644 index ddcb490d79..0000000000 --- a/crates/proof/executor/benches/execution.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! Benches for the [StatelessL2BlockExecutor] implementation. - -#![allow(missing_docs)] - -use alloy_consensus::{Header, Sealable}; -use alloy_primitives::{B256, Bytes, address, b256, hex}; -use alloy_rlp::Decodable; -use alloy_rpc_types_engine::PayloadAttributes; -use criterion::{Bencher, Criterion, criterion_group, criterion_main}; -use kona_executor::{StatelessL2BlockExecutor, TrieDBProvider}; -use kona_genesis::{HardForkConfig, OP_MAINNET_BASE_FEE_CONFIG, RollupConfig}; -use kona_mpt::{NoopTrieHinter, TrieNode, TrieProvider}; -use op_alloy_rpc_types_engine::OpPayloadAttributes; -use pprof::criterion::{Output, PProfProfiler}; -use serde::Deserialize; -use std::collections::HashMap; - -/// A [TrieProvider] implementation that fetches trie nodes and bytecode from the local -/// testdata folder. -#[derive(Deserialize)] -struct TestdataTrieProvider { - preimages: HashMap, -} - -#[derive(Debug, thiserror::Error)] -enum TestdataTrieProviderError { - #[error("RLP error: {0}")] - Rlp(alloy_rlp::Error), - #[error("Preimage not found for key: {0}")] - PreimageNotFound(B256), -} - -impl TestdataTrieProvider { - /// Constructs a new [TestdataTrieProvider] with the given testdata folder. - pub(crate) fn new(testdata_folder: &str) -> Self { - let file_name = format!("testdata/{}/output.json", testdata_folder); - let preimages = serde_json::from_str::>( - &std::fs::read_to_string(&file_name).unwrap(), - ) - .unwrap(); - Self { preimages } - } -} - -impl TrieProvider for TestdataTrieProvider { - type Error = TestdataTrieProviderError; - - fn trie_node_by_hash(&self, key: B256) -> Result { - TrieNode::decode( - &mut self - .preimages - .get(&key) - .cloned() - .ok_or(TestdataTrieProviderError::PreimageNotFound(key))? - .as_ref(), - ) - .map_err(TestdataTrieProviderError::Rlp) - } -} - -impl TrieDBProvider for TestdataTrieProvider { - fn bytecode_by_hash(&self, code_hash: B256) -> Result { - self.preimages - .get(&code_hash) - .cloned() - .ok_or(TestdataTrieProviderError::PreimageNotFound(code_hash)) - } - - fn header_by_hash(&self, hash: B256) -> Result { - let encoded_header = - self.preimages.get(&hash).ok_or(TestdataTrieProviderError::PreimageNotFound(hash))?; - Header::decode(&mut encoded_header.as_ref()).map_err(TestdataTrieProviderError::Rlp) - } -} - -fn op_mainnet_exec_bench( - data_folder: &str, - pre_state_header: Header, - payload_attrs: OpPayloadAttributes, - bencher: &mut Bencher<'_>, -) { - // Make a mock rollup config for OP mainnet, with Ecotone activated at timestamp = 0. - let rollup_config = RollupConfig { - l2_chain_id: 10, - hardforks: HardForkConfig { - regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - ..Default::default() - }, - chain_op_config: OP_MAINNET_BASE_FEE_CONFIG, - ..Default::default() - }; - - // Bench the block execution. - bencher.iter(|| { - let mut l2_block_executor = StatelessL2BlockExecutor::builder( - &rollup_config, - TestdataTrieProvider::new(data_folder), - NoopTrieHinter, - ) - .with_parent_header(pre_state_header.clone().seal_slow()) - .build(); - l2_block_executor.execute_payload(payload_attrs.clone()).unwrap(); - }); -} - -fn execution(c: &mut Criterion) { - let mut g = c.benchmark_group("execution"); - g.sample_size(10); - - g.bench_function("Execution - OP Mainnet block 121065789", |b| { - let raw_parent_header = hex!("f90245a00047e5d14e74fa24a08654b49795e57114475fd455689c71c5002f22a39e1be4a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a03a2d37a5619f9cbcb1828a0201e9185b67005131ed6236eac338cf759f0b9ad2a0fcaea4dfdc9c2ab4f0100b5c2fe33fba45c3ebb6a8beb0c156ccbbc901403040a0cde372a52b7bbd47e6fed509c5e43b74bd12a3119bc6a63c311bd00a80d524f5b90100000491006000000040040280000804040000000002010140000400000400004000020000880000200040001000400100000000500200200000102040040000000000000000000008110000080000000000008000004002001000000010004000040500020000000000200000010802000000000000020c010022201004484000000000040000000804800600020000004000000080200008400010010000000000000000000800040000001000000400000000408000000002000020020000007000000200000000000480020036000060002000000000180008008204000080000002082000880000080004000100000004000000080840020000400041040080840737513c8401c9c380830a11a98466627c3180a0c7acc30c856d749a81902d811e879e8dae5de2e022091aaa7eb4b586dcd3d052880000000000000000840395611ba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0a4414c4984ce7285b82bd9b21c642af30f0f648fb6f4929b67753e7345a06bab"); - let parent_header = Header::decode(&mut &raw_parent_header[..]).unwrap(); - let raw_txs = vec![ - hex!("7ef8f8a0dd829082801fa06ba178080ec514ae92ae90b5fd6799fcedc5a582a54f1358c094deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc500000000000000050000000066627b9f000000000131be5400000000000000000000000000000000000000000000000000000001e05d6a160000000000000000000000000000000000000000000000000000000000000001dc97827f5090fcc3425f1f8a22ac4603b0b176a11997a423006eb61cf64d817a0000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985").into(), - hex!("f8ac8301a40e841dcd6500830186a09494b008aa00579c1307b0ef2c499ad98a8ce58e5880b844a9059cbb0000000000000000000000004d2c13fb1201add53b822969231de6d1b0235f1e00000000000000000000000000000000000000000000000000000000049ac5a037a0c66b4526837e93e8d20bf5d378f060c5d4bbf5f6aee41be55598255083c1ff71a02fe196d9fcbd0980017d7d77c2c882c0851c0b06b59753bff54f8726e74870b9").into(), - hex!("02f901720a8203a0839896808407270e00830213d394e592427a0aece92de3edee1f18e0157c0586156480b90104db3e219800000000000000000000000094b008aa00579c1307b0ef2c499ad98a8ce58e580000000000000000000000004b03afc91295ed778320c2824bad5eb5a1d852dd0000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000fcd04b8f8e8ad520e3c494b6b573f49ad4c9853d0000000000000000000000000000000000000000000000000000000066628a400000000000000000000000000000000000000000000067aa2de076064cbc00000000000000000000000000000000000000000000000000000000000003b20b800000000000000000000000000000000000000000000000000000000000000000c001a04c85fb7e9c041376918b4b3c2e520f0973a564cace5e49929f829236bcf45dcfa01a7d82fe70bf54633ffe3e69f238641695914c4e400c62de8f023b788b29bda0").into(), - hex!("02f9016f0a018312dbe2840ab59b9c826fe99464812f1212f6276068a0726f4695a6637da3e4f880b901045b7d7482000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000004061653166346133333163313166333033623161626232376237393434633435616564326533653137333033366638626237633439353036613135333934393436000000000000000000000000000000000000000000000000000000000000004036616438623264376631333764363166393864613961313830316133353564383237303137666238663263656461343739333062613833353739616636646436c001a068b105ac4576560ec0e938d20b5b4cf001d161729597e7db17205238f4277629a059199bac24b6a7dfc08a3b3ab471d2052a64d367190b078fce60622fed4507b1").into(), - hex!("02f91eb30a83039c68830d59468407381b7c830961bd94087000a300de7200382b55d40045000000e5d60e80b91e4482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000cc00000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001b20000000000000000000000000f7bd944cd6d51a8b7dab54785608d8bda08f91550000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000000ed78ae2a0800d6395cf9e311659323bf2822c5600000000000000000000000000000000000000000000000029a74ba63dbfdb780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411506c3fea23c087ecd0605c103b3dc00eb380f2d4fa9a0d93c983074f53398ed1e558cd371b8704be8a1ddfd012027853bb1d2fb0599242ea4bd92ebe1b1d3c41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000314c9258a47fcaf9a59a0eb2e02d8b503dab09840000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a7612020000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000090768aea66779f77f8e11f33ce35f3c0d0814617000000000000000000000000000000000000000000000000000000000366f270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041ff3a97fcb63be58074d66c191d1a808ea49a1ec6a10f82fdfee5039f8c79425822362696b8a2792140275cd76e4df87c51b84e255390449fb00ac885706d3e4f1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c7271b6dafb7adfccebc04a1c05160c11cc37860000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a7612020000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000023d640c90786e477226915473fe6fe354ecd24e30000000000000000000000000000000000000000000000000000000000d9a926000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041b555110518c88b56869792d167288b73f0b7a2789f0acc257208973d6f365d84266d67c697245198d433bf8802d56f9147264f8769b5f82f00e66fbb0bf55e701c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b3c6afc0a5cff7c98db387d3b9bea85fb2209660000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000bfde6228d74d163a4bd135395249348719d55b1300000000000000000000000000000000000000000000000029a2241af62c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041dc55a561f8ea7fab8b964c186e44b4d3c71fcfdda44cb37cc8c457ab53e081aa40a10c51841c5e8959525d82f08b115135763d3f2d51f9d6f928f040cec64dcb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036db1e5d1a94acd2349a21db1c3c5699995f1110000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000005dff975994c962195f0d909be53a9c5d13c398c500000000000000000000000000000000000000000000000029a1814e46c1d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041dbc3b402f947cad5e317951d6ba00ef6d1007f8617ee304dd251262dd949018b64b794f00c0a21af7eb3d769b4fbf6655057105b1a5c157dcaca92596808197c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f764262a8d96239275b6955f1b0c2e490e78dfd0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000008f0ac647326c6deb5b355fdd49dae8bdd496708e00000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004168c74803581ceeee1233a6aa181da3ef1a015d7518333a9f50fd2d16ca2f1b30192406e7d61899c2533779b472d74cd686a3ff6fb903e60daf1abd7018f68b151b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cbf74b5e15404cdc8d8391ffdbf2cd48971a20bd0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000a89182e4e2aacf3de24dc8c2b571714dab6508fd0000000000000000000000000000000000000000000000000001c7a82708500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004151574458788fe9f96885b496f5621ff074a16b6c5e3de9f306ee2f88cbf163a95eea1bf4f79caf0771120d77b43093166e064edf80aec596909541aabf34cb551b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005fa18acc756d83ce08e0dd8db44b62b904190e30000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000000ed78ae2a0800d6395cf9e311659323bf2822c5600000000000000000000000000000000000000000000000029a2241af62c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041704047cfdb2bfe65bf969675594f0d2da7eaf951b4d57144af5351f17f8e9b81442eb2d58ac78c29331a1857cb270b5736ac65c7f450c2500ab423fc00d47f5e1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090a32be26009dfb0a36b3be2ec9f50a9fa0bf2230000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000055d8fd11958a4bfb4ea341142eb002f66c6ac6e80000000000000000000000000000000000000000000000000b7d5107b20f30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419fa97b385e50a1044ed62550e1e3f4960ca1e5f953c3c07458cef234151f7ec7191bcca4a46ac285fea9cbad1be1d86b4d11ac44584c292b2dfafc4e68d512301b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dea125ffc58cbfc448654b9a7697aca7501e5a2d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000001a466a1a1195d9496f5cff39b881225525769a3300000000000000000000000000000000000000000000000051766de63f8b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004106404715a55eb449609a6b0f8720a68996a0072d894ed6fcfff3ff9d9590bb9561b43c3b1384619d46cbac842dae9309a91e636d03e67e8c6c9046dc00791a351c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a001cddc6970b581a8ddde9a548e83b23071bd2a59c3004d14fa513ce9d8b8860ba016e1c19a70c6f988873b62d499e9f4b827cee51874e1b8538be2bedd0b81215d").into(), - hex!("02f8f20a8222468307a12085012a05f20083011170948c7c2c3362a42308bb5c368677ad321d11693b8180b88497998611000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006168adf58e1ad446bad45c6275bef60ef4ffbab8be412ce3e5a692d0670703e8e56d648a33e80a6d4920166ba42d14ccd4eecda2c001a00e5583d7ac97afd3232bd3deed40c2c3c085b06d73e3ab0d5ceb77892219acc3a0491b2927fcbc3b82165428a5a3d532611792e19506db542d00c90b994782ae8f").into(), - hex!("02f8f20a8215a28307a12085012a05f20083011170948c7c2c3362a42308bb5c368677ad321d11693b8180b88497998611000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006168adf58e1ad446bad45c6275bef60ef4ffbab8be412ce3e5a692d0670703e8e56d648a33e80a6d4920166ba42d14ccd4eecda2c080a0be21db9df84d991bbc0d0b062553ab76be037059aff7fade639d536dfb0c03f1a04585c3272bbdce40e55637cddf1ef8797f07b875bdf7364f23526cbd87bf0872").into(), - hex!("02f920340a83026c9d84039387008403938700834a420894087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a9aa45a7df41841e834bd0b1204989d7350aee2b2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7019c6b6fe6e4e18ffc69958a529c2b591dc978f1f1fac89108ebb460dd64903007706afa5c18f7e101f5757aa975a0bd584a75abf25c55721448a13a1d7280590e308fb0b2029032f838d15d12c0bc116f5f911f3c8a6fb992fa93e45fad91bf19a99eb9cacb5c76526d20f47ed7c6db5e32dd92c0b745ccb9bbc60f268a9ff82c53a0fb1ccb463a855fc6cf2fd322ce37f6aaf65096796b8a29540cf36d478d0e3baba70eac1d51f5518851a537a13978bb25a201790912e54a984562bed7151e6431b5623237b5f5c32cc6b1ed693ae159add9d421339d5db513b70e75d1861fb904a42b34762f03e4a515c63d0c25354f00a0cc89c9ab0d985aa4cf37069424604a41736425729dc3f234370a2ea89d701ec1f76934f566f7d479732e69a1000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e115109f26205ceb8e28e227bc58a3cf500f8c312c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc71e7d290b46718f2eb8d8e47226b21529466aaa10cd18a76484854a78f735141d1e8111cab1c7cd5eb38dfc4aef92dfdb93a64426ddc0222fd5e4a30f989ffaeb0b5217bcb6d582638442705a158d57df4fe0dd4cae0fef3d7ad656d7c8f64aca10c16864fa9cbe4a423afaef0621a00c178e4b4e690472ffe82b76448ff2735d2a255341036d70a0df129fdbae5667947d4807b7e8128c1ce8344f71bb21510a2f63ece569a0d9aa4e77689965b08130141ba88f79e4770db8e6348e8fe03a3210ecced6257dee3d31fbfdde243940ab556f4740a9b5c20edc4125b2b843062f2a1bfe066ac56f7b6de17fb5816deb8c4345ddedf1260b6146d4104d8f3f8f200e9c26ca19f5ac327559d8a3c3ad2366014cd76432b74af62011c00bf564462a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000999bba23dac348a9a7169664b1149abc0783d67c2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7177c60556fef8e41a8b3329838e6aba09df2f82fdb1eca33052df7e38516d68d256db0c7796da2b2fc508bcbc5f135afea7588df794a545eaed6e2a8c791b70b04df92e213d8956be5a9164606119114680a471eb091a3f8ba21b997d2b967bf2477689decfc4e8af5a2002725f656e731460120fa9795ec4a01517eb3dc5f8d138d5b1205eb28403be5c2ec1dae214c33b7e9837119da90ff45b858b23971b023148beaff65b4da6384a9354c3462896f10721015e66c28fc14ebb06d21d4af0dc09412a48d63ef25c92e7747d8142f2fa3e5368bee92360baeccfacbb49c9918f8266ca3596d83c00c23ea40db624ab0ee8e1b17e4d4744f5e45f19f18f45e0ce91a2f8105d523c35d89c4be394b0a64fec4a3ea0c5eafcee89e5b10fc9a5f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000005f10f62a0d4bd4bb7c229aab031ae51c6ac31d542c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7278fe9a6b6739901d9f2b36a9f4d9208744200ee37eae1905510be82e4d810a5098b7a0ae27ff42906e48d329011e42fa8f1640a183b6e0cf7467d7e429916c71ac1420326dac3098492a3e0244f381e68abedb76655a76d09f38ccc7bdae56c1bbf7de4b909aa89d6a4e5cb93cc5a201e287364d4d42d183dc278aa73f0e6201344ccaf60ba33412c9267ba2374741fa07d9438f6a30a87a551d71de792269816de70f0e23d5fc7e6f6561d813573ba8500990cadd54665619eb6f115ee1dbc1f9630be6dac5e1b5c37ea14f8082ae57f43fa3b2afbedd445134f15d62320782cbeed48f54ceda94c43de4f0e90e3ad9b37342e7b0a54105b65a045d00841ce2fabb7d092bba29ca228ae95f8ce51af403a152c4871d4dfc27166eb8f35269f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a30aa37128a2119ab89652914a30a956eae35f9a2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc70b299790ba04716ba16479689195094d269b626c97827cbeedcbbb8c516efbd40e5c1120d26b239abf8d1db317c8ccf6d99ff9fda34bfab8d077bfbd6497e1fa2e2d657dd11880e5ff8e2fb7bfd3ce3a33b341fc3de41f32c05c87d0e7bab105139becd8882b7d141e1c84c3496287792d7613a544e08d32cd87c8dbd36272c426846de45ccb93788060a164a0cc2a91cfaa73d596b68633a7c8e885c47cd10e1e7c6a9d390f1d2b353e4cd439c464d05c4783d046777db2c35f122e1e1c028d20b9e2a27f1a4a23ac6688c1d31703d25ee805fe5d0df9d201cab8f87868deef149dae6283ba14246b2606dec37d0b6c16cd7bcaca1fed9d9613da85aec75f312a9834a01c99568f050a78c45097ecfb76145cf125cf0d2103f27634786891ca000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007fa4b114d2d14b89dc6515399ae09fe2d7441b762c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc72a508522071abf0a3f074ed3ca628e4bcef7a1efe3db7ce2ea732c4f25a9f235293fcd7e88604cac4348079c347a4ec2cb0345660c2c3a7e79729450bb93483c185a64e9bcca1daec006367472d8b8ed5d429afb7c47d0a8d1252c7ea00809e329d02d5c8e4db2911db0693cb4c36a51d7e79f746d7582ba3cb27603c5394ba52e728b48ad38d788966430d1a62addb3faf3613b5e547ed4b71a1da0631b7e102cfaa1b8d91ecd1fab6eb138dd96b16b29b5b45d0a6208e1a9f2197c69f83be92558be565b70dcd0dac3eda3e02431e3a6c03bfd23a5b79efbd2cbd144cdcde129fd53821de617048263ca17984db238f09c0486f092214f10911e00b7a85c2205fff76cb75d2a35ed30daa89384c8b208d486f47ce93fe45f62c594e23971c3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a2f059c5e329560a7f4ae4472ee4097f015df1d42c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc715cfd4d9061fda04a7ff4c66cec0d2d482201b9f4a1117548d313ef0bf3e189300aec46572ae69d07eaf083cbde723b162622e228bfbbd8eed01d3c791650d3d1feed6991f37c930677e9838458b9ef5e9738a836bffa3c7a86ec6bf9e6f67772741d5cb21d1c97faf6e102f9c0bb15e32db77e82bc51b760c70a1f32979ce8a23f841593456260fa50974347c4d80710157b7577d02e16e771664a0ea8bc19512c5898cc28345b1822234a99f2145b1980e9ccfce18329a494fc596d1697aa7116cc2a22f1bf3db13f0039a69a1d0415671a6140ea4753473ef2c4429e6f39d1ba1bbad2945740fcd828cb427ce598127fe4a740e4a76c090a14b7a86341c4b0e812956c081103d37c667d654b881f1abe74f167c6bdfa656b388d7990ac25b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000074c5d8389e56fc119ebc9e013cc1f7684d5a6b072c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc714a09e53d385d673c05228ddb26d7bc3be74f7a103f196567e2968287dab7a8b19aa753e75a75af73cce0bc21eaa8caae77d61af896d0159f6bd9d6c42d1a1251452e4f3b8058a3fe140472133d79b9bfffac66782355a9429255ea98c7a66b62c70a2a680fdce54eafba7e09739dc906327abcfb0199237dbfc28e9499b846216e3242c42fbb9848519d25efd11e8b30e873250186e0b2321d4af000f6e5e372c58d70a568f0d3e034e4aa5c1c8538c5ff07c1deccf3b779f371fde322d468c21d3295fdcadd60fe4ea1267c0792f7276b9f56429776e63c4f38b1ba75cd9c826c9904b4b750cd0a0d133969617fbda3046108e543d227a43d4f11d7662a0cd097a462190a390f639bb3c7df415150a25e7de70a8f58ee40650aa974cf16e3e000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000003a1917ef1b997b9ecaadea9fc836c40fc5a158612c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc71c711c12d07372deb6db123d4824f3ca1cccc452a89efa11b3fed5058d46263a28bb748862ad7b526192f76868aa2656248114f1fee8fc90b75fbbb0e399c131001f9c1d61b55c1479debc9cc5db22c2eb10a4141b952bf0e8ac51bf348fa0261fd0e8307a84500bf3a3511fcf55a04ad6bbf02e84c1602d1c8eab8269f5ca711819dd95e0eedb673fad82e15193673bd88573e883738c6384d6d7661dc2b3461407f83a9c96a0e61577c5f150ba93cb2309b88c77313db9580dababaf158a45085b16d533ad5b2d9d3f30b40eb653873f5f76e4d951c5a2dffb07b5b1831b22105c3325d94010e6a83488b7593452d8ab85f604b0d5c9349700b869215d4d922a84ffb448ddb0617857497f7a791fffbd68a0ca6536c5e6fe8e9df64e90f651000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000b319c3d1ef0f60c6e03085ce397aea2f2bbed99d2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7210c111ef03da72d83a899c671cf0d97a47205c0a462f206a5f8012870d75358247af48699c9c38cc36f280beef3e6b877a4ff3ddbb32881bded52bb7108a0df06f4fae4d32d4273f2beee224f1948dfc1730cea292baaa5391fe74f2a9cea702c013d1895ec1e8351f858074bfd57cd5c2bf13333d83df8d984ea144ae1650c2a8172d6f6523db18f407bbde01c23a218dc6280569b50b7b1ecd1ead768f82416bc1eda96770b4542e34e1dcf955ab3433af90036b78dfaf3d4513347301947026626c780884600afe5203fa9e8b15f6e3a72afcd4ebb9c068e57497e64c2920efef1c8b2187d434511572a803a2b8aaa35edd9658f0f10f681a10d251398dc149c1620acf0e50c8479680a199a24e0db6055e5c5227e780b60073eaefcb95c000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f5da1b574a7675327d1b7339ad9570363c5c34ef2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc728efef1c7cf6964407aa9cd0a21a2618b0b55d4e32e9713d47845be6a155712f164b5b65121455d7f647d5bc8314800fe4ce5179f1d1dfad006418f047020b36007b623ad50378124af98fab6274e64b1312650613ca19eac7eb89376971ec80280faca31d2fe889ae7a9ec4ae12f4fb8e7bc3b6e52110cc696397a4c289de6206bce497ce7b5fb9f23365ebebda365848486ad94136bce4c3e46810622c75b51cc40fc25555def1b8fda690461906dd3659a3e2450335b0af27a30c808158272934cb5d306306fb6b9e35677dacdd71fff28e8cbb85459d2a299b1eef4653ee176c207195dfe7c2660a74cebcbfe901bb9411c60fc50b78ccfb92c8036759851b136cd186aaa78f6f4c21a82f5445660f5175347a26b8a4523d4efb5f5f7fbd000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000009b0f286627130086f85f63177421ea1b2cd9f0112c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc715c82da09b1c96f513aae1a7f168c2f9fc77553cc19b4e0ec50f315d2f216c5d1fbcc5b43a01f2e4b53f4b6e7634599e9e516cde0f4b2d502893f7d66c843e2b2500e467e437a3265e203c19d92abbfcf1a9609c1b5b736cf249424afdf3f4d71f5d87add3acf628b1b8068b188277bf2d2aa87ddf10c8408079e40fb11468e011ec157bba5ecb886d5e05b05f225a5bc39f09e1e0a0bdbbd758c04ea304d02103ceddb427310d24f2f4e9f416f962e2c3efc58177fb7441150bd292896769b506a99097e337947e5a5019ffabbf2483d2867167111b3570088c1f4f5ba6b77b0798fca770007a70dada02aa9e6eb42d8c547faf5b53e75a8183bca5a40449a2209a2b54939c9ac7fcb528565001890ccf1c8f0d4fe7fe8c513eca3989a75b31000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000b5950dc266f30702248335d8f6bf4f8950b77ca22c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc72e937b4950068a3aacffe5a9841739e89c7f72706107b62109da41fc5e6a034113e6495faa3c3c637292220714a0ae733f54257ecaabe7bfa3658cfd10d33353089879446d6f6940e41786eae92d9862537549f1849a0ea652a3245f1e3c16080dfc882056e6e363bb516d39891fd50c297dcbdf20119721f80a77a57d15d51b29e4b31981b4bbeb71619bdd77eb7c74000573d6458a1ef3078ddd174138456e29bdd12d6b0531ee54f8c28d36fa55a17f818deee78441bdf5d2b1224687100a1221687757fe803d8ec441e2eec6a84abace83df3a8751f8b3456587182ac83b21c4730a474697036174b1277d3a1e8f68d424f46f72286c3871b4ed98a283a117d60c47aacd44384fd49ef3cc22d3d076d332783f8fe111f19ca5e5b92f4996000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000920c45b408f6a0c08c4a0481541acc5336e4beca2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc70cfb4bd66c6dc2d7cd7c104893f0a9bf073fb3144f672bb9ed1eb2dee72e39d20bbb1ba1a071f453a92bc1524762e9f7a6d4ffb918d56a059165bc2df45364212fb7c74a2cd0a4acc230c9875eb343747844b8abf20d0e6d5ba61351d73fa7b41de3d6d85f4ca9e199bffec3360f89955df46dd9ba41e23b7c7478cf3d31fe0707dbd1c40a18e480905899ff851dd2a38405c8374b362f64012192a6b2caa3db07611d351c33da2e7b9d5dbc9880a8ed60eaced742390f5d97a1dcd4b87b6ad02d1b929053e54ba0a221038c7ecada4afb36205305a7750fdf978b0ba49904fa0ee6e8fe3627a001814f99e01c80549a424ec106187ac0bf6331065bee11b7641b6f8570d85a3f531205dc5fb5336a1c8bfc708a2cf6b9378e7cc6f8e075e76100000000000000000000000000000000000000000000000000000000c001a0537050b3611333491c79373e0026e1ecf8582a6cf5d82a9318b4ba9b1c82a5b5a053127290f0a4f4a3dcf8cfcbf1a874471b0eefa1ac8cf0e3b4ac97f58f5069bf").into(), - hex!("02f920340a830269c2840393870084039387008349cf0194087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000ff5b81c06a347cb8268210e970cfb650fa76137528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae629a1fe61acc415f47fb1df4678c0aafb8977b62aef6325be11f3c26eb36ed5a825acd8d663439a51e60752dd4511d9af15c89ef116130f74c7f10eca596ecbec245b30414b0c4b95e72d6094ce22cfd7ff21ab7de7ec918182b0c1c91ae715fd007ccc9e09775420c6e7f1bc73aa8c88520e37d1428b9f792e546395c853f6d5090e477ddedbe861b0841ae47c1edd5619cc919f03fb26cbe2e09183dfaafa7d24b2318f73d8f1426223e5a1380042f598b2ad19caad855685f696c40bc269df1e7de6b1c189beb2603b86d58392a12e4891b3fe197f318da04453bd335049450f38465dc2a05ea81d5032e670331822eeb3d92960885367ea5c913eab351f7710fb70c8c532d5b2257f13dca19e0eac3d506133738244e5db782a73e22b09c9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000242ab389dea6b46da7fcfba55d6318c1e2fe7d0628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae624427bf3c4fb33035faa23446dde42edf4b00f2c76d2284e2d589694ca6896961a078f3488fe8ba820e217d4477912fd96b0ceae34a0608b5db519e302f53c712625caca9ac53703531f7ec7572b9b5f80de7160a5df81029bb29f834de0c3740b15818ff91d30b341b30ec6eed99e4e5bc4aed0101c72e092babbe7ca1aabfb0df5294675220069521b1ea0315edc860450086ea1fab8aeae7bbaa84189b84b21af835d67bbd00b61e7c2fc9b3cddd79f927801d369c275b6be3112583457b42056e57c9f86eaf48c30534ee59bbbff72c77368ed4d3be941f5be3bf9f474df07ebcc794c92f409a4bf625adc56b6076100e4c8a04a98e7b7f8d0ed3e04f13f0e9ba6c313ee27196f25ead7314f56d063e7344e9bcbb69cec65d8c5be59b426000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000056c9aee5056ef57250fb974ff9bcab45b121dbdb28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6284b84661b3e7d8247b71e03458b1560b0590094f5e7c7d6b0c340a7a73d950126b8d6826406705cca25312888531e3595769bcb60c783d4699c2c94fbfb88451d9d8daffa3707389dc7b6d951a9e7a3cd0fca4754b570a834634bede4401c3a1858e38e1a0174d26a4134dd4a9ade06b393269fb96421ed6377282a86e3d25601204f8680e2e112771469071db800cff8738193077cf8f5606402056a8d701d116fd6ce2be79eec293fd6aaee23f7b7ad1b500f01025a5439e0caeec5a4c1941b84a0801f23cb5690a38495a4810d6fadaf2ae74525bb9ee60110ccabe1470816b5b742d4b9757a21846410f848aa6acd2ba7b8ffaafcc459f3f465c9a5e5991f03daf0ef1a0bbf2bb8fa6af00517e4e4ffb0883e51531d25a7a5fbe74797f0000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e426cebd1060d4bdd9051feec88be9403486cd8028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61bc3b3a4f2d260a159b623c703b914ea585c4ed2c73484dc1fb362fe5ca8918a0f2b415093c671280a1a9666a4171305736ba04b4c59979668de99eb6207c1aa0ab3e2931eb4d8128bf58ca6b305adb61b8296f15415d1edec109f8757f8644b09bed0a4184379b56cf64300dbf1b79070e76b62cf6f30f3aafdfd2980abcc1a0830d97b570b40c69d246f6690be9a1636350e4da7de3976ca6db1bf61006beb11e407e1049d700a15a3e10cf0e7e12c374c872b7f8a0772d9b528905fd49f2e08cb7dff6b3c7615409135fea859c455400f2471eef275bdedd852ce81f74be9013d4d176587f44cb22e142cfba09332748617bd8df8512e88c9e67b90b2f1fe154f456dc600560a0b214c09e28e7f7848eca56b40269de0e8b4721249a221c0000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007c86c46c5cdb785dc78ba1837e0225e59450b18128942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae602565c1759ddd04a0819a7aa7a96edc3cd222f119d4e6f550d4bda9997ca45c118468ce7b1c6616208a9f0c5857e2bbb96ac51c73a58e0e1d60e1e2adc9ebaf1160ade7456bc61891c670b5b2b6d40ecabcccb3086f4d79e2147b8d4fe889e56169db8287264aed78a3bcc7f14c97501cefeb5ee0fdd6f199a32daa028b8df8b2b982a923d639cec85d15255ed9b91bd19e26dec3da5fe220677f0ad66bc71a30bd2fe84c4ff72057115eeb8fd51c847682b147d429739025cfdf6e26b7ae86a1d48d009ad19300f056540fdfe08de659ac2f6d4f192e3b1bdf6ffb41576cd2b0753ba92215508561aad8c79aa9c34fa5a3506e7ec7fe7645c810c410c471fd12526160d102ff8a08611cfcfa6dadef243c0513f6739550b9ffc9ce99fdb7297000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000641bed5addd2a358468adf163e6c6ebb80b675da28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60ae86a5c0f75cec4ec7b453be4fdfc134090e99d66bb9390b908782ad550f426039fde3482e025803dcef8fbe6923b6b6af7a046ec975515430d24443aa15c5c2dd3e8093f9cb080600349e51d7e56b5fc6f0ac083da6d63e03e46003a3a379812c6e738e5d34d372a656dd19e8410b8a00aef4cf3a26bb7076f709953bfbdd202ce2b1ffedeba392f9df3b208b6ed2becc3e6d4b3c5593dc93c5a9d8681d1c42fa7327bc880d13029a9213f88529f089da75c30ca2dd52d0370132a03e378f3006a83b97ed66aa961836459b7d4f6544f1550419d493fd534bfe21266a60bae178d3a497e3e9b0d285015e918a625658ca52d21d6a2aa62667fc4d47039a1900e76a537453b72f8adfaf853e04e68c4f27e34eb84623bdc0b3e1be3648eea2f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000dbea52199557b8fa35a0fd208d7ca2b964c8955e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62600f9363c032d201bd8616f84cabc6010919aecce646109b2f807733be53ba8142a9e34992574b9a4a7ece6de4e9ec8fe60b42fa48cb216c242d9ccb49ed4851704c306d9570788730c05ce290d6b5603d3e51c332a9f60c90fdb8cee47076e1ba1bb35ef430c23f2e6100a541864a83e63e3ca07b054a1ffa1283550fca44700e5456abfa56f15552481280c5239d2f3d3822d1a83abe0a973ac3ea2c9647f25b22b68aefc0243277645d2dbb062595c5b0c26aa18a1449a4d25b5d0e1fcfd26dd9c789797d0941377dc1516dd7d4d1912b74636d7a8ec5fbb183ac34d841f0ccb72ffa06c254085208b3554bacf41f623c7d051bd72d814968379f9f53a982292f9b8a2ec73d2b4f33d009b871003c205d71063ef6bc2b810d0e58906322b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000339cac126a7b5d6807780f9ebc3b5f0a7cb2626b28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62f3d9e4e7ca68fbe0889f086d9e238b256d57d515ffbd3cd40bf0aca6b0492ec2dc950c2b7d6c026158d109af1da9c32a47380fc0c7bdcd79d61c43bde7ec5fa099f3b2158ef7935587d1428124be6d2777e283e2dc385eb21c037efc7504d550b98049a7454f9b5d51b96179d8b08d74c65ee27e6efa169f96539abcd448d74150f3d44585790d7af41c0f47025c38f93b3df962d53aba203b2977e0b03a86e13fb21ca28b90c530ff14213e64dbc26c64f4fec89ff0f5e8e70bf32563fd5a1213824e8073aea4908b30f0f2897305725b00fece62de3fc86ae10fcb5158cf42fc550c1d59f63ae72212609bb35db10080ccf9bf4298d993b3fc4da9481d8c12aa75eca7e4c8744599f89ebff87dcc5b6c92786c4831cdb01731ad7492eb2bc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000898cdb69ab8946814b6b53481d2eeb5dfae589e928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae628df4363d09f14cc0b180122fb355e58aae4f248a95537baaece2b465bc4b39424d6d520537eafb05785e691f7c8e3a68b00f3e1a71059f763649b0fa1666ca5250cd5c227f0a746063f3dc00fddf2e508f4f005ef02cf0f740addc832f6b71e281b74883a14686f41b30c315c0a7ae5c61ad87c6bcd4c8c2b629878383bbd00278c74f9c3fb9829720af7dc49292b1b74ccb19e4200478551d10de8bf5353ed1dfdbeebfc985888567badf136b727684bceeb41f72138ffd953f9159506f64d0af450ab1db15d160f2907b0c6beef8cb85eed914b58747be81f7ce5267f14f005987b9b30e3a076a21edc79868c2a54075f918b7660435773140c42100b383114ab9a984050afc9dabbd36989204903a234ef647f51501d202267511bc64db3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000089bf43f6d3014039263b05bb7a01c8646350e6328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61b5099c5aaa2aa4fe3ea537c82fc999c56d5e1a0504d48316162fb007247a9351deea520dac62b7a7ad005b3abfd18dcbdf30ee5f9783c58f0ec80cbf67aa526172f62057d065d382ea631782dca3668a56139d25322e8d3128b8ba8989e5e8807e95e4c13049d69ebd673a9b277fea16879eaf3916c0eb384ecb6882f3bfed32a056a0673318cb2dd91fa8cced0076fab50f1a48c9f0cc85564ab58f4280e091018d09d4176019296ec1bead6fe3ec0ae4f653ecd1fc79fa5e76c6444b57a4f114d78fa109f07db217968af2f14c34de42809f4200c7009896107a01edb36ed008d052f0f106b6f446ef5fbe229ad7274519f6bc3208d2c1742d448595061f40f8e73042ce05d9cd4dcc4e753a38b497914719f634abff53e5105b768f6a968000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006c0ba81f432a713774283f812bef31d90d20135328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6188e2c1a9a4653e70d1ae03b2750f721a28414019aaa3ca024ca734b2e2d51a7089a71e0d1ca62857286e070825a63ff61c2a5e19b12e62b7c7353ec13c2c8a60d7f667f6bf650bffb6548aacfc54a3c76b2291a2167176c306c5b9933192ad02e9a48800575f56460b02e120de938f514ef627d8b3a6f52e757b3fbc9c7e20f1960c8fc64330e626936c22ad350096fdfd0347652428b8f8815471d3354e31f2ff82e557609b86e761ec1efc4a25dc82961a29400cb728a6d6877394439f7e42fc90e0e1f03b0b56cef81dc69800ca3ae06209cd4340d069234af11e012b28a2dfe3dcc6612173df72ccfdeb30e65b16cd72d9d93abd804f177ec37c0a225321a27158c9162a130048d54fb3ac8a09e9eed1c943f5b030cd7e225a0ef43d436000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000093e8b4942d760c8131989a31ddabe994224fc7328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62aa72c25afdc2c65ccac73fa14504c772f86671d5d24ffda4c29c80049b10be603efe26951efc3e66b1cada240b46ba47c193fde7a505eb5f7b90ee821c492871a21e84f29903b895ba690af55a5c6e4eec9c4993f2d6fcb3bdce49c2272cc7d0dd2a2208ec72027f259c47be09ef2a5f91c5f88c8f1004d2f473ab5d591d86308f27e6a91d1a5f4c22d91e5626aac68f4ae8fc70627fa608b37e6008b3ef4362745e5efcfc745c520d13870f9b3ddf41372c76e05c8f8bb818b9fe0b4e7e30e1c8b1ccdec4317ec340fcc5ffe195d2e7adbc6d518d0418159c277887f87ef7512daf179dcba4ebd96b8e46c74c975fb1f74fd2371f13abdeecb82d95397c7d214f6fa20a20fd820e80f89df05fd6eb28bc38af199f97da922116b1b81d5992b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000005694d5bca63987fafbc506499abf1d3df7542f3d28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62197da3e2e450b7e4295785aa9b2141cbfefa00bd32d01e38bd3ad66cbb4f9bd2ba627efc5a62548611a3b206fecf82937d0681a957bc4b05b69ebeb4b1aad14068983c83a07b558cf74cb7ad93f1e08a10bc1d31938e43948f50478ec0d5adf1c61551b324e6af3d9d04329c7d7150e59099f59c02260243e3ba7fe9bf7a9670ab1bffa724e9e9e13e378c12da3102adce093be3cff880e62c56ba3c2082e4111f51f6ddf705a68987e1d52ef54285e1cc405a3f9e1757a0bacafbb11a13fe90d0e40768ba2e30f81a9b67154c47e0c1724f63bd199962a46c566165abc73c729b6a6181730a69348c8ad17c511756cdbd60a2c9f86f2392282f87fe5b37ae60b252be50c7c03d11da135928a6eeb34feb8c52f23d54994783bb1521a94dc1c000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000d433b30092565fee0f5571c7b4b219808cbd525028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60b645f78e9ef37499005d2361154b0ccbbf8ba935d20fa8d90025125262881782c209330e318f86aeb8bec2351bb0d803c445030eca84323234e2cff7c2e30bb12f4886b1789a434d736a17ed9d51f56848ebf962dd0c3c517d68a7eb110fe8111dd1723aa0567a2c1f5fa1cbe681bd82733fc402554d09c55ec7eb1f17ce93117a196deeb54728ef1aeae66250dc819df5e101b22527bed75aadeb3dedc6e0b03473037f988a0498c180c24f03eacd75c83a2ed0f18ea79855d46695e6ea15519ac138f865c649909fafc068e7b3ca65c06af530e3c38b521a2ee2a19e43b121b12033ce74d820c048886b14391417046e03f3686acde01ff8b76cc33d818711dd6811711439bb2bcc43e0a5e43682a1f8870254bb24735bd658d99e4cdbbca00000000000000000000000000000000000000000000000000000000c001a00d851236f0e494fca892608f43aeffee730c92b0c1a9871838a18cd14f80cd47a00f6027f2445ee8452f573d074a0f0879b275eba8c0dcf2c77b0f874c68a1d01e").into(), - hex!("02f920340a830269c3840393870084039387008349cf4394087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000002fc452d648f7e3043f6f3c7e05f79824f07e126528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60d070771ea1782f53e75601ec9fdcbfa8165dd10e78facc01734960b460e8bc002d540e4fc9470713a92a102ba6efb53f5195ec39df5fa7c39ded840cac2665e150caf268538195cc7155c61877d76b96f4500268a5b291d0fbec018782434231b0b1b2421890453a77b437398b581794d0e9fcb7665677c1baa6bb4fd32027e1eeed729491ebfacb2d025e3b6fa9a4e9ec09fbfa76eda164907561e7658678115a3cd07f44dc2b38d4a56cefb1b203a78d69c07e4b793aaba302815e282b4550bbb96dae434f7e75c0e9ec7e3c13a7c275a63774c9a1afcf71b5d601d33d0fd150484555347b520362d8ad08e0196ba5ec3a86867e1045fef7c06cd764dab050e2af04a61253746c3b43cb0fb746624ed90bfa5681bd43f461dba788b679367000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000004ff1a4ad03dcf3e228712b54a499b6fecb56116528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61cb78c9bf2c47a0e409d66d6e535bf475722669c70b0b38b8e6101af2722ee2e02cdeb14b93671e5cf75d02fe89b3581ae8a6754b0b654661181011545a7f8422b5edf9d0e6b47e7024f39de0eaeae3dbf929c8331b7e355a33ccba47abe2f9701dd64e2acf93cea4139b852b2f5705045b4f8dd5048bf6773b07c06cb999b8221680a8796febfc0521bb58645c71e60f51be506241a3245363ac506b023c4fc2847dd48ed1b0e15f9a15c94a96bfa332a39da0199f1ac0ac9608f82bf01ba9628b1af262d218d7e836641ef05c35d09411785f61d9b1fc4ab6f7e673802742813e27335a6e6332a36864ec19142c577acb77e3843cae4c3a753b324227884d81c9260ae6dc694e4176e913c26fc558763cad7f60bf123006d3d72736fcf3ffc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000012d2142a7cbebdcc7ff6cd5b95469abbe4cbf24928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae615880e10593596d4cb658f00c5562bc58c5a6afc0eb2201f862350792f1edb7512169e7be24ecfce258ae13fb0a4c8de4c8fda790563f7f3ce774220cfe972e1268cc85bf6345d455dd833eb8fe1c980326cea7ed702049d4c86accfe458012b1a0053fbf513220999498d04bc78ae54fce71139e54d9d5746713eeecfe3cba305882c63745df15d918b36cafd8f50cf7216e90b1aa8bc9dc2e3e5429a3bba641b17ac760debdb5700c4c9bad98ee427f265aabf94f2622f90be0ab8fb849ba716477b7071a7d42828716a27e9f6207c49e37bec930d029611c2b98fbd78ec62247bc890c170f59ec6dd157e7975901ed9142563c3d331af055f49a7afd3adca0f8413abe7a9d392410e6ec6193dff28dcde681477d34ea9def60978cd57c7dc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e6da5018bd56d59ed86c34bd37e4d3c6eec61c4528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62cb04ba4e26d335daf21194aef490805e7c3e3e0410b593f7d7459533908346917b5c793a295e007de396925820eee2c04d47d4027546318716fe4b2b6f323702cf3eb9676205471b0c77116b85d9c5974036a46290df0a80bf86d609287f4a123339d2f5621ccdbed149c2302dd01a3760920a61e8b6bf96f0986b20ef8865224b2c8d18e6d7d92b199564612d8cb33b22423af4c67fc793e2fd504504d51382fff82ab032b15d672bd52ce82c75558fbb1efa9ba7bdd84b295a781a00b04541e312bc1d73e8635d297c7f09448862f568ff6062b5fbe6f48bfb0f4bf3d488f1ef3ade38a1c0f9e21d011193e16f57211ff291da3cb0ce20ef75bb1b426e676267fa0f47ced1401e91a26abf637b88447b2794df9b56fa60a62f51ba414e9af000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000dc5bfc07d7ab9392b706b0ea472bd659dbed8f8f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6217cb74019121e68260c8908a6df82d1d728fe3287602b826397b023fc5e43302f245a4ac4b7c1afd8f1fa9deb074b8535cd4e3bd2d275f28a3a66100810b4890ed44be420c6b1409e0e33cacd54bcb47911839f76905b0c6101d9b2b1286b6723fe89341298544f07b77c3b23c16b51114b8f438f9cab043f06122202d2801227cc6e2ac7598adfca6426dcdff07e8c09ef8299cc6d40a7edbad876ba25b4af1eb1ebd3f7cb41dcb78d8972fe5c81bad17a9e98bc27e2f2ea9a6a183002fd362d28cfb0bf8ae7c4536c4e22623f8ed88861561379138247db9d18bb3d683c272962c3f94f3d2c6a4206975d1fb3bf9eb5ce122ec5024fe2f97ef03274350a0e1bdaee3a1550eb966610d56ab224fac4fa3a8d8a2608cda75d2e02c57e2ccb21000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000005b4d0d491e04171fa86465244e305591b539af8628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60ee7bebe2389775c6f21811d85d1e3debfe450264c80ee39b9d17cf7a7964d73198cd9411360e7d18ba9766bad00b081e874286654ffce04106cd07ab39a80f31fbab5aee54c5f0a51f72b785e8d8be68f4c3ff9b72b7ee06f06fae8257ea005167bff7a7352371616ce294502328d16cb4669bc35f8a6cd3445de9db7beb3fb1a59b7744a0d611e6048e085144682db83231fe279b77ae157193c4f341e1bc32b4be703dd580cb27c297a8682553f9edfba9fde365ad5c5cdabc024b5bb1d6a2845eebf6142cd01024f1dfcc061f25cd668693f0ff709b802c5863363ec08ab1b95f0c7daff4283c94e7629c22514e02442ef02efe22ff99548924f28071ad60379102d4becf6362773c6159a4c3a93a4400d21e1ec39099e6ee9c86fff66ca000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000667c943726579c6b8b3ff2cbb47126e52f59f80f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62c940a714aae7708e5a0513ae7fc00273f221598ccdf6a9125a131ab9d8478850047378127753b3cb5fee3a06630428036b23cb039525fecb0de048f6a2eff1e2bb4d3dccafe9dea03935572b49c75342c8f2f4227eb764a76c5eba46da3e08d261edbdea002fbbaae124dfb642481bd3f9c38367c5366d46b860e2dadb3a08103410883fdc095c9866e8a0991556813f661fa4a2c381ce33e17c7e817f0a87d17831194f810d395ba0cf19dc742f1cc37e80348d8450660c00133a6af1703900ad346eb5f46d2b8aa146eb19ccb875a7b1cdcec1718e7111e1343868908bcf003bd5a001b9a8acf992d4aff869e306241ad07f0834dff041cd80e5ad5f842c41a2753564b701f03089b903befd41840d5f3cff2e9c7975bfab8249fd20cab46000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000098d88afdfb242127432c715189a775f12bb3390f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60efea4f327aefa5e9ead161dd6611ab61df4c9dab9c5988d97612cc479a9f123016930525c1781976da3a14df82768f937f7f70bf96e3cc26bb5dc21dd6cd74f0a47c7bdcc19947fd3ec249b699347c0d78cb35ed6ee393354289f75b924b388227dce1983515cb1368327275a37996e7de1ce67991f773077fb86c352b7695f1d4cae6a343eda07d8b2897b6ba428ee50208001947d75c0d3f6f4730361878a164af0f33cae3197eeb8a07523557a9391a05a0698ad5ac0a50d65dce5caf9ff2bb1c4d9461350a8bc0f778b1a009f42949b7baa3bb2ac472ca3e0f47a541ede14f6abf64d02842c87ad07403aa75bc400b93f94659a6a3e7d5cb45894c0b5662bdb9b7cacf927aa1d2ccbf2307359dfe2dd9853858fbc2309cbd84222ee1c5a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000082fb30bc5c250e9d57cb16e112a7c15a984f94f728942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae613503f6c7ddd1ade21af1b97a7ddb381910c4ccd550bad7eb9d4c773c0d1f41328becb7e3fea7c0af3e8c3bbdb39e2ea67650c0fe58804bb439a70917517e5ff27dba88c9e32b65474be306bdd1ea2b20b4b30d1cf2afd1b63cce6ccdd36aea8089ce6f5703c70ece7ffc1991e6ee367df5b1357d1dd9589ce9838d41972d5f816a37135c21e77f563b25b36932bcb690a61e8d19558b52872e0f2b6de93b686211c9a2aa97c567fd45b927bf3cd9445592d7b0383c16d2d34639556b23e59d5151f0bebe67a27cd7b0aafca46bc5c5dbff099374004d90679a52535a5e2ca7d27fe43171a04b24a499318fe7c030f7985931c7800b5fa5b59687cc52301a7bf2e707160a3e4325baf87bf59e2d8e833668bca2ec7ebf3353b36a0e26ae4587f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000fc3d84fe66f8f6ce3496fa925f067884c1d11bca28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae620e7d1baa83df3ff39ace24a671d6b3f69bfd8f8e38f9d4c76394e6127113ef61f12276b126303fc35cfc4ea0c935c8d1dee00d9cb654e86b2a2ddbd8b84ebc91169a19887203f9066caecb932178461017d06f66a4ca97dc7919838228fdd080de03a06d07484f6f0840471305fe63e3f60c5682a778b3f180643bc661eff5f15aa8796a3d83ad29685a5743838adc982403daf3bd40c06b7bd525d60c641e30b56e652955d1bc7645537d3b4fd83a780210236ec879b2a5595033c28b5b8ab260deb20e2d5741eab2b68caf50f1192825cba2d2a23ff349b266b5a3cbb93ae1d3b6acfef2820bcd768afb6624ae3a6638b757f447fe0ac3b3a44f060cb92cf2ff522eda5f60551b816e746404aabdadc902cdb01f9c496b7c145c6fcebaecc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000003911c90a4fec5fb6ff39ae0d502dda70c032143228942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae614d76f34519b08809f7d882290658a65b920507b47a4f1931ab4ed831deaac542823eaf1391da29dc538f8ce3fbd4c67f4bfb7b124d8feab2a2ef58d37fb5d72172bbad25a35eaad915bcbc4d9ef1c8caa54694d61524640fff87406f056d890255cbe5c7c56332c1ada63328614d7831c79dfd56784563280da99982420d63301abe49846092d86265d808a363307466e3e15a2aef7e2168e1df212f5b4b7ce27ba044096f19795deb46c94c116327e72e88999aab61150ea629d14bbaa75d922efa2a4ae3c8dd9b7b2306be9f3f04cd660a13c2631d321cdd0098fc88fc6d8070fd6df8a8e2b4cfa9f1a7af64893f2a9759c62498b592d72e36b60b70cd7d21a6c3c5dd10dbb80507845d384e2a0a72c47d82dd9a0eeb7ad8968623c61b40d000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000033687810343cee7bdea2cacca78ea6c540c7c3d628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61166c0d2307a5ac1c2c7fd55e2263089047b5621a3ea51a6a0a3a861ea096fff1e8085f3ac492c9b35a72ee206e5edb6b1eee04f97198759ea72a902cb1429d1261265b59197fdb6442ad18783cde7daffd682166a58ff620802a244dc224ee619b566dfddcd48572a8eba16b2b0bddf00c812c88dbee6dae0d133004cb757360d94bfba6eed1593868ebe4784ecc3e38808d8771dcb061234fe503ccbae4a1c1dfa73cebcce6e299c431902dea0fecab696c7f2bc74e9b693f724e61c6c68e72c5b6d36705d519d7bdf166e45bfdfdc55728bd7a1e273cb9b7e445e0d6eb7f802b136c3ec82d9e2c31b62669d60dfed1dcb953ea9c53012a2554281dd3a882704e627b208bd0c06874eea409ac1bfe30bb5a3afca1209e4d4d0d9fcba61c864000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000224a08c35cc1ebbfca7d4b4f4c3210b1768c48fb28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae616b0b9916fbd613c79327220b58a6ed1601eb6190ad9984011779d4f26ed0e0b02b9cdf0a697390b1dba01fbf8839aedac9c1d1bed91c2f62790feba4bae20a7227f582865c4e244144caa2de39629356aa3b727db714fa23fa8eef1a0851eaa097aef2ef723bdc57770ef7ba686ebcd49afaad4af272f5b56936ba2f324f5f3143d38c2b9b3d1ca2cb6b2fafad02c3568bef51d41f74056f61698e25ee1dce7048d71b1afbb73453538b6880c65d6a3035c90725491cae13aadf6f7a4c3389c0f8607ffbcbe8681ecfdd75aafab65e190a96fc7084eda9f76a9b824659f60ad0654a033acf4d47c021824138c94d55043f6c062ec30dec32d8392c9fbb7d9110ac815952d896e580ea58c0d1255e9abe5e21c4af2417992eec652ff131bc93a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000412bd8f25473f2fd93c05013980d2a82d3ecb1a028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60792158ffb93c36ee6385bde89e6278d9c81d0695cf7fdb4c161be1d14b9879c00d67c1adbefbfc9cce1eb8a76db8cc0431266d9de688841b796a893cfdf604f1717df5e42292c9036dee88cce2e1f72f123cb38a5087cc69dd3082f72c2b10f278a96ba70aa94dddf347c1147f0746db1e19c2ade2ec6ba03471eabb7569ae62c96515427237b01d7269324b02adc857a7d2a39f25d1210430b7e00b07f05e024c43f76223a90b001631a2c3ed5a904b9106f97374bc39addfc5fec805546b3049966a90b90356e0b949176e1bd76493af2d5646374b9c8864fd1da3c0c8b0008d3e477c6bd287ceef5497bffa552531f6914362ff000409ac01b3125e07f312d035a245808afcee7785031f40587cf25de1dadf7c7255709df7636c7f1f76600000000000000000000000000000000000000000000000000000000c080a0b51e7f43ced124a0110c23d55d5eb2a4b094af4f5d366d955076ef471110ca3aa06c7f8df564f4090b81e8bcaf17637b00ddc6ac0513e8b71522abe47999827380").into(), - hex!("02f920340a8306969a84039387008403938700834af50394087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000091bf80d5452bd35a48d6f8c86c16973b9fc839528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae615fd0bcc6b78ca0d068409c82bd6a0560422aa4e76a39747cb3527779b3d10b1109e5e3b7e07ac635de04e45b49baa610d7d58dbb5334a17034fa72e42cf97951dd1f25cdd214841af8c9cd3d7fc7cb6f0a63f896196d8593e0f950b652474c912a16a926ddf0fef1ece209525ebd672fbf331eeac58362355a6929bac7aef89020264f4a382f15cf0e86d637ef7b6525d039c5a26c25217a65144a8fc0e8be91237a63ece99d760b22c098fc06ae96b8221683bf9bd8738e532602c457b0f8206dda8bc97efe551ce4dba6a7bbc3cd0615ea954656fbfaf134aeba1adc149fa2c3415a732bf747cc8b4efe1b7aaa2c9c17d3a6e0d0b8a2732716648bae7b98d2c03d6480453e3234429df386a14b0a5538ee41c2cfe083bf4716516c4d36e77000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a88c2b0fd676117d9825602c10a26874eb53462728942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae621597357b85ebd21923a956cdadfac2e29949d8445536cb2357a98ce389c9dd00613458c19d646984ad2b63f2e6bc587943f2fda4f96d23391e0d375e6c3cd1b1e08f47cd690bf6bd78aa1098765393f523b55f133faa2e74a39007b761fbcbb07cd568b56e13d97f48d6d05ac6ebd28c387faa09003b931ea11a4a81682a09b2faf9222d7eb5c46b7e268674df2500212ae2fd9882ca73b95ad151cb9edaeeb022bcc9ed786c242f2174c023f027338e70d8da48af8b5ec3118ad7c6044360d1c9e25999717ed8862278f6719c74d64703888cf41248978217bb897f29ccba02259238a185a76990b8e2bce0af5135e7fa53bd18efe3753d5834bb241f81e5b028989a1ca9dfd2cdb1c0161a6c3c360008cc5ec806e04048a222f047508e460000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000039bbebaa990e926f859e5bfed1357558c2124a0028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae607bfc1dbb7cb8f1b249a8e884eda1ebc000a28cf62e95b0df40c7269a2e31c791ef0a7da327c4d71cb5450ea1f3543b6e8da8506e05284440f9959b52a792efb1796d4d1d6909d1c709e4ab5fc06e32f97b0ba3f034ffd11826e009679df5f1e037a93feb52babef495dbc27c7d5b7318075a53b00172545d1e1c27b36ea62a7021b66a1992b26c5c499c31513bc4867f52133f5af31194ccfd4523b2970a05d1697197d982c7d4e95c0c0f6e5616d70c351583909f9b77f10a1bbded80b1aeb1b1adace4e62472954e171bfa434d0adfcadfaf55c3fc416e9063465f2574cf31ad044497a6e3daf933033c136a027751ecf92974038fe19fa95cecc467313ea239ba876a0622d1bb13e885cd9ff2e88bc7c77681801abc32c075b87fd981fea000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000081e08338d5231e5b879e2b3fa560efd11026845228942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6284c21d93a655024f8afd34edc66f6d8d470a1f98a00b4922eb32d1e1b72aa7e0b27c333641719a86364a96c4d9ea44cb2fb35880828694eff5fad4efa64bbd62fdaa0d5996e556f76c0c444c305d3d632e920980968be6d90d819f49534df6e1213ce620eefe0592a99fb3f177ecc4e44fedb71d8273606e6910a765cd68ddb1d7d7942531eee25421628d3df18b6a99d6642a67adc17a837ea6f0377a817a70da666466dda5715aa8ebb905cff09ac31de68829f753dfb6ceaf07c604bc41e076e77c244e2683378c7999b298143e70e02fcce5f2702fa0c3f4ab0c9124ee905f3b92e7b9faf2439eb3b13dcc61f42f94573b26908753cd5e70dbfdce133bb12994979a1f5421f22debf7eb86384b3ea67eb028e5e914f0039f00a8dc8e49e000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000d22666a4ea994185639b9d49e08ff9c181973eba28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61c0055bc27c4c3824df4fee8de1a033fbc485da86d7dc60a9ff3e28f1af3d27b1e0c1e33bdce9a4506332df34b4a9ccf64a8d77b6a044541a73806ee2d5faad52331294b3992aebe6c164334ed7492afaa15629bcadb9ed6cf8174d12cce52560f5969705fafedc2e3cbd28a597a4e38f3ec9f6b53e98d841ecff6c3cab304c5106d67e8e4bb5256118639b83f9aee7efc605dfaa27f72f73310cdd8fcd7c6e304d834e86b013b3459218b0d8d5cfc9be53c4abe73f90faec9d3495f48a4a54c166a4cb2da9c3c82b5bb54504fb6742522c05038bd766037772b4ba54f14bdaa06dc0477627fe55db05d2be748ecec74752c54e0846a0733e54fc9ed8befdac12725f70d26f43b2059a186b4a801175432478ab9824c37d9c8ac62b28a6b0df9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006c7a88a3fffc0e32a65efe9dbca7ebef781ff3ac28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61f8c0ae0efac374c124895a71f82dbe39b17666162ed12523625cc781fce898b050aca11bb96a1c15a8c2c79fdb3d457ee992a0b8f9876dea6a747c052ee6e92104be0981bb2e19f7b49cff94ee4e96276150f5781f23857d6a3c2a328890a7c1022fec3967c9b22a33e6138319057985a9bc1bcb7dc7b52887071343222f0a3205239a8578dca33f4f0ff44605b669eae0f496e7f9532672504ec5b2764e89a163c6fa3d1a339df863a80e4b824e616491d736685b4b68fe008037ae9a0adb914ce67e76aca57400179a7f1a431d55477aa80ca9ce9dc2f1d68a1d5a938a85a2d22933370ea288614c7d3c13960a32240fd76652b8f6bcfb0190941ae8fae86034cacd834618c533e5546a772f9c9f660520c201788b2dd7e3c071c4bb41951000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007e6a5fae2523fa310c0713f7c8cd34f1ee38470d28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae616d4c04c49348fc7844cc251d87fedfd8e810b1e0c2bd61c602a725a861f6910180ccedf030d7678cd567472eabe05e8cbb08ed34163e769644e69e757b2c7f92f2f0109fee8cae60cb587bf3b488903a61e1ca5225359c441fa749166129d6b2afa338de2ef2147f0ca5466679f03bfdef8da5db37b25d29a7ec2fc2648c0611675425fb9a9391caa9b8d7d3f540f02432ef65fbddb3e192a7dec2277bae81225e234f7b0e3364e71db446fec381e09df79ab6dffbfeb8259de6af1ebef1c740a68c98ed119b9e51aa27040fca58f7a00f30972bd21568879ddf0c246f560b822ff7c1650628b584e3a96c61be54b7ecd51bd779b2d4fd6a12a86999ab23515175649c71641fa898fed23379878fbfdccc932e0f4a478bf88af3e79c7653a90000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000dd75e013b66cbb2aa418cb4b2692dcfc9849f40e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60d5da2b68f5d410c28aa577cceaf7b894664b06a96a97bc1d2753b53d23377531630c200b3d7643d136e6e9256aaea23676c20b94ef1c7f4888553674ea895941ea660085887d5b65bca0da94260fc4929d259e8f496e938fb276f0bfd055e3a19890b120f10c79a0615e1fb42da8e6deecd079eb31f20bbc50fde260e57cc4918fff935aec59948cd60f431d7aef81d2c5b5a59b046f52f6e2fe6748222c86c2e1135cf95e23fa167432e8b915db34e2efab40d3427dab386b85315981b28bd207751003741525798cc7234a8497890e6b163ee0ac99249eb8b5d43abd2087c2387c914d92d42aca318b7006115d4cfd6529b524ced840a95afc22a953659cf06d7ed44ae5a016eaa41b12a631ba51e8df6c0f4c7e1ce9e5c6902dd4ea6a785000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000000f05d6887b0233c339feb5ad2ff23f87bf41be6828942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61a8fe7eecded8555ec402387be0b88a0c5adc189fd8b71bbf871378a6941218f29da8ad7d1016ee49b9c6288f17277c24b61cdc0355438c73a641141d022605b025a62c611cf353712911d3f61b1fcec2c91ee2ab6192be544e49efb2a4a50510410b0e377e6f059612023201056e36d06b44096ff3c3e147c3c3ab28bf2c3e5281face614b7007cf82c485a522642582f67c08397a37350c3b38b5582af478f0013f1dee2866bd8e1d876135589e29f72aca4080e4a26e6bddacfb3e2fa50fa2ab1d6e70622cb9fae9e6fafcf80f5e0d93635cdf5f7483d6b9df0c34969d00911c0953b7fa85184ad0c2f24121cd8728dd6acf4ea0349ee6364e2e678ebb42627a13d8a8082907ea78ad804f951ca004c8b2573602283ad9fc6f15ff6b9d4f1000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000011a7587346dfa931b806ff5f9977109db91efddf28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae625be9d8bcb36aeff220e762650578f29ecd4e99d5210cbfd2498880c6bfdb5e92012a3eb720fd028528bcc103345ae1c4e877db28fff10c435c9cbbe421a0c0f282d3743a3cb2389fe9ef23dd8af75ab5b706c3cf506b77ff6c186ca9d3a63c70a94cce50ec196601cac07e33a5a566a2622eeccb46243930eaf6e0b1e482a651c51057ce621b43e9e2948a352968c612a62765f97b5c4027e81accecc0d028a0771d0572bd4d505c8560513cbccd42f4a255e9f0fdb5023d61014bd1130ed72007102fcd9a1a4eb0f4ea8a1ab4384b02125a84f7a2b1e0115c1d8a8db7ea8061c664ee452f5d5149348f4c2ebc23eccb626ab3b275ea17ae227f440eb7d00f91316b1fae327bf9dd48d422141c56322cf4b0253d249469658e0bae0a31583ed000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007527959b2127f440ad9ab50968fa31acb221f8b428942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae621671e114dfdc998962474a624de9dc385015c89fba8c28bb62396a86fb3df0e17bf2ae07a798b9db4c5d1e73b49ebad41764cc4625f6bd67c30ee38e37a12fe1f84d347a39c94b27189de9a159247542fccd336eee271e696152b7e4197ab3218b64f72ed18a5685d5076610645fda0974379b025fc5b12f5e9ed852ae34bfc01361aa569e6aad7924edb221adb5b3983bb8d9b82bb3b4b742efda83a25c4512c67b28eeefc8dcab34d802c005d1baf023e2068e0500ee1288e41d95ced1b1518bb868523fe25efbb9ebc5928e762e993ba580ddc71f2b6645ce93b0e1ba66b02b33fb53b179483ce8a57f3c0d5903619b76834899295afb4a2e6d9a241d43a14211e2ba038fc5a42893eae0c785a2a02902ff8ac4206e6d8095540fa668191000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f693bd3ca91bf811367096068c7f23175218a01e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62cc2e17e4379c7c2d340a496320adff1a90cb195a9eb89f749cbe61cc301ed0716a7ad4fbf31b32e4d4db65789252bd299b23326b222bf197c94cffbfc97f75b26a7334cb7ee68ab9d8598f72eddb6922e685d77893724e8f13602f7ef539a752eefcbfd427dd9e64e0b53cba20f3c1686956359322cbe24f9343190dccfd7c628c4a19347913eb202533e53d7b3a86b9bcb188f922c8ac4e355d1352e67f7571f9c7c65bb2fbce018f4b9b6eb90f2453d2147d9ce48c153b665b11d2d4a891b0758c29655e377dde22872379459363e6d803dc1448d65506a97bc1c5b221b5a098aa4f9d28cd371668a1dae0bd62ff0700916596830a0580b203fcbffa5d3a119a87b6069429455c0b98105c7dc7666e5851a4d2a5179ab766e6581b912453b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e0e0504d9fcf343852a560834c1ccaf8b51f682728942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6072da586fed751ae8d3effd56ea2a96172b970f2b318c8471b3b2a8a56af968d10219530b160e8541a91a591ccd6ff5b396eafe24c322b9f991ed186c86288e120e49597383d85897069ffb2faa9ab3aea39c8e2bee30632a9d95fe4c632da02111f0096faaaf3572a5ed85b7c400e6e6c3f5f9a7906ec050f1e81184c9105aa292b1da0bd15c6de94f8ea3fa62b07d12f68c516ab0f68457acb6c583f3393651a4cf81688403773aef482427f22089cdf1ccb5df70a588ade26cc603578b50e1c2e473a5c11edd234697a81335a1a3468984728b8a1893a0d5f1f7226fd95a60fbfa60cdaa44d2ba9e1c50eac4026e1695e7c1c8cd9b05a6e67b2823355d3a72478b24e2564d9ada30f91edb4349ca84029a79237442bacb7508eee50ab3c1a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000bf604969202162d64c0b3fd72c0e550aff8c9f9028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61762942ae25b62df89794a14f0547240b5176a501a72f41434c51bd321b2ddd60601d70f80affb5ffd214152f77c69f6948ad44e0032056dcba35063bc336112116efa5196a6ca895df75fabed5706ec3e0822668e3f09c39c5415ee158a3f312c424a82ab819300183f392e946ccf5874cbde3d37bc6a07123e3a0dcba3a4ea14676b893285b2dc382ffbf64c876e9326f936791b36fe03c5e24a688e24379922458260dc9a934304b92642af551f7143973a291b7319c1d3137d253dfcf7df0d63b707edfdad155dae7387bdcbc5b48776c61db44ed51ecb723d25927a37cc2309a9f7a46582666701c40e2dd8c53dd058f0412376c3d4c9bcfb3acf83dc6a05275166c41c2c99a994b2b27686a27f86aac5a08b3a802a4717f6f7ac25709700000000000000000000000000000000000000000000000000000000c001a0d7070e7cd041624764220631f8a65be0e918d2c90107af534b57091c824b9389a02480f4c936f0ef4e9507b208e82baba87021525ee98b5941d08cfc0d7d146547").into(), - hex!("02f920340a8306969b84032a47f984039387008349857a94087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000cbf61a54ebe5e9152e1f6b81cbffd3027062642928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61d460bd138ee32c939dfd8e49c57a95ef4dcef2f88b92e5a1d5e2905f86d787328bb4c7a1e4eb3b8db4d59a38321cd444d510a700551beb6fdfcdc88068c02f70506c41903052ed62b6913f66c9595a218d5726ea3128be80d62f7c69887816a22f613c865b39a6e228b0d90313dad896d11000afe422c2412aa8eef93fb1a1e0cd8be0d3226796e106d56c9f3d6ea5f189f88353aecab6565a256034ee48fd00bafdf7b018aa742f06a35f8ac0442c02d1a4f75186798a33cb57b53f3b2a09507ca58f2e94f1bc503faaabb19812e52adc5446d0d3a2eaa3c37c96cd6b3937014ef84689357e91ccced5dbfda2cbcff66f237923aa145326a831953620b7fc711e8faedc7ef58112a00cf6e13cbc0f005606720fb034d7a57f591ebcf33a66c000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007cdb62cd44f27416d3d80060887b79edbc66eed428942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae627cd53af047b648a62ebbc6b7022738934e337451e6934e285bcb17ed151e9a2156cee556c24689d42cf8d19d308cdaf32215270100cb7de2300b61d6f3805e61fad747173364b42a1fbc54501d3fe6689204bb44e095ca5aca1652d4ce018070bbbad2a1406c2ed33020899c296fb67957c0dafa5e7630c6f15eed2d85ca3921f78322e092ee4289f1f00dbc46793221e1b2439129fb05b1f185cfa857baf812e9ba7fecd26f0671e1fbc3796ab226a8484095d31360f45222167cd7dab33f11a13d59918ab5dbcbd350d47b8d48d3b52e275887e0663b63b9cba34e97377af15def44fb6d6227bc92d17b372a4779d53d4117357d4e372f15ead01502b0cc3006542ebe7436861a0a015643024b8eb364ecc758dc76e38f5cbbf461c18a73b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000060de5ca48792914e8ed36f8294c571cb64cbc86228942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61c2f5918a5841520443a45ccf49a742a50bcd4548fd8ad248a1b8742aa75b46417c1fc6a32babcf3b5960b1cfb35d98a261641322b811053ace79049d236019205960ca817a496c09847350c58899c0008ab73f124204dacff678139ae80c95c1d7877bf7f5c4b37f570321a76e604b5a140229e1564216e722102a0131c6f442933d8de999cee105ba504babd60abf0d97ff47ccf6395159a8c2a24d24ed918029a1cde683c17c594cad199facdf9928066a73025189be71671e2df5314c0cd00c501e761df7d4b8a0cc152d6870bdf5a3f5f7ad8bdbc2d0f11ce6cdcc829bc1acb667ba2d8c86243659458f23b0c5c46fef1761cc7013ce20c5a55bf9f28481c42002db11bd87e9f501a27ffa16297536ff3bd04d44cf8385c66913b259f94000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000004427395e8d53ec91fe009b9f9f7d108a6d046fa328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60e8eb84cafb9b1049f380e248ee56e410da056b3ac4fae01e640bf76dfa9b32c089f372414a1aa9c722f3af366ab7f4dbf700d8cfd8376f90c5125df5211c0240c1b68b374253a99342db518fff6ecc0605c35d0abc5cb9fd58d13b554ca1204306006c533a0d4e84cbdc3d1a219f562df9e5afc90dd541b8b2332ba63eba2062b9aeaa5722b7ae0e7d60a977dfc2cc05bf7064b1ed2aa897c306236b1adea8528a850bbec99f23a3c0b9a747c2f285474f266424bf6d336d0c4ec119877f5a9109eafdf5d0f879f6907ecdc9cbd20f41d43dff8d94caf9c4486f017f7d10c511da1f9629b4d2e0232c0bf208a0f9408134b1f6fcf77b33ca549ea32536e43b900f4fbb5c755d3221871fdd7c7118c1fec5559871922b1b462a5f0502b9e14e9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000ff7fa1fcf8df81ea158cfebdad80d00d49790c1b28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6142c5c102e9eb810eec6a0fe8cb214c224de98a8ae9e73f46897df36bffe668f15c5b544e21b5c7495900a1bcba9a3b9ff362e192a88c24be1834cecbbebcb172be37dcbd251b8ad00f6a589bf6a296eadba57dbebca0ec879f7c0b101c5a2d12849f2cb39082e9a68623d3793562d40de78acc164ece4ba819b9cd41c60ddb0155ce47cccdd81c62bd4850644937385e494c711b794ea61c3f876cfae88e05805ef8c12ea3890fb78f382fd4757b43fb31e9b711d5eb6179b302bc187b621e806dcecbe346e981b671c871b81d963a58c674ba7b5aaf83203e8b6480104b02006491322421291c323149a72e34c1c9c793b6797eb2a83408faba857a60d810f0f64bf23f7d507c895edfb71d617ccdc2f1f819e16bd07cb467ee77794bfc9b6000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f34c1f7627c21d08affe689360b68e3b86bddd8e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae603f4f9d9e44ecdfa78b3f822a00aac0a80fbde1675bed218b4e9daf3018c75c2274fc133f9df6704f4926e8201f000cdb3f5288f5bab86b24f4501734b001faa06b1f228701b430c5f77357668d11abb9aa246ec200026b8835fc8ea038dbc3721978e874ed6e196d0ee6ef1baed881ec1a8fdc818fca586e49adf1a01014d630b247457164a28f47dbef855ff71f85bc3d2d114f450bc209463a532cff56aa9183a29e8599a51c0a5a46435d21e0421a5ee0b31590e2670431f59948523a3840a6914dfcdaa1d8f4acc0999bff181168bc97f59d2e76914b8fe40da7cfd767510fcf9dce7c0aa00f582fcb232b250941dc3acdfb71328c97fb21804ad1abb181f04e30fe89e260a50e3ecff6b402e0796a12625cbb28e218565ca449bfc5d54000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000b6816921690bbb13022ce4279c741e9f10f6d25028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60c7d7a2327da7193adb6e7da1a0011071990b12213c823686963a0fba1a43683034744575541f9edc32e3ce969ca106604b4a989340584ddc55b9728c7e2e735074515993dfc63a646b2d8f748414d5dbcd64394118e0f89d165c746caf2434209bb608dd08ab880aad6440c7340c1c684403cb97e2276590bd18963940d98eb1e1a272569a949e07dfe4a665893154eceb132e728555b80e40a51b6134c6a1e0a6fba21519df338be4c257b4a5300e8b8f22fd006f2e9fa8e2d72b60f3818e72de6b2584eda4a90fc2d78b98dc1b5ccbdf1f3c20e733bbff817158df22fbdba1d8e56cd2b62522af6b23891f4f2494e565ded4983941326df46f8895df90b261eddd0dbf8d65704970292fd40ea3c440b4f7004f8a988eaa0124ca04acc2f80000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000046cd855658bcbb261645dac5de9bcf3e86338ca528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61a678665a7ae5d9945c98f2448bf68e73e80475cbba2f1601c5be074171c21082ad67f4b03530e704fb1b232b3cddf83ed3cc000fcc0cc5137b6f4c3e89d59fe0f02287c98f5c39229b9ea0ecb3b2e927f66c5bd814bcf032c28d3b9227d3cb91154886e38171ac9cb09ad8f8a7898fe624c216c1f2753fdf2126f1e06adbecc0647e62c17a2c83ba39b269533b35a377b069f0b4ef684142f7f38360feb6e832ac89f308bf01ac0fe322a4d106b404f192b2c279299e97be3a5344516ca21ea105a99ffa98dca692c8c3f52addc90eda18cb19336aaa6d085e40463d74d3b8e0f317e0047e3c6f7f9ea5e99a7adf0afc1acffad89ac728808bb2ac3cd57c5aa2b0ccbc0976152d5b67b89e939da3ba4e0490d962b8035782ff36db7f05a23a3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000004ef8a049f19848666c00d958723dda15310a88aa28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae629342c1f6c1e951de321ada9f9dd51886c7da9f435a971f21dcce3e8067d80b20edc4b5a3a2982f4bb2825f7e82dba0143325323491b7810c291cbcbd76e35242f9e523c196e71f608c01dc6fdda1f5a6fa0f60ee6422f0363313332b7f6c4ed2d2daaa8ded8a06a27765e33668632033a783e6a452d32f2d327f629e25106560c6251b41c8d03f2fd7617f7f3c745c899f32353223f8ab32b56f813e430391d0686a6604ba4f73d140c25c0d30a8f7aacc24696207d256f14a2d5f3e217f8a70a9254141d4351a6cfda264150d89b2a35140530990449b767f05689709488f00e227ac767806f1c3dfc1173d3886189057e5a55d147166005840d7ca50f17861700af52ea29cab029a6808d6dc6f82acaf942f9254adea7ac455916f0da4452000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000944618cd80dae4191c7f7f21c58ab13bdf81738a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61b7951b069b65c12393920364d045f8d76add6c1d9f29245188781b12600d6be0d5d127d6bd399a6ef83d157093e1f5a7f3e9a1edf67993b678a7f6b2be9b65129827246aee4b32f7d33af5d8363c7edd2b8fa882103655c0e57999d5127aee113a7fe6d4e694ec0e96cca8218f2cac3ea45a958cdb8e7a77e5b0a7f65834f12178510f9a90038299b02ca079f79890aa550ecd77b0b88e6ada0b411255a560c0e214079f6191a523d2f8dac0a1426ddb1b7aaa51f4ab184341392492f727cad29d9439d19f56f626ff8a8482bd148134d5cad497b01d310680537b8e3dbad9705cc9230d48983aee1839334e024c271ea9560ced93bfa54b880901249fc647713b1931335356f6f2c35ac21de1c2a6c3302763a0eea4461c757fb18bf8bdad3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f2a05e7c62af3f2f02a24b43c2ae13b08890fd4628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae622cde3d420dbb6ff32a2b0cae2a9e25945c539ad843317103de9e09595f424b328dada7a73b9e990c662830d82148ef6c90879c37ded18d7f24f9dea6c6cf01504184ca216206879d98b04f4e0eb97f6a6128a309e699e7d160201ed34f76d070c5377a5dc4baa602431b5034dce504c8e8fcb3033e605a7f9d43f5e9e4738c30c9021ba9dde79e0338b9843fbdfa7507174fbf43a28fa11b90f39bd4d0c697c0bc0c8292d6d79489b492324735a57da87a52f3fc56c83706711c86188e4734317b57e8482be2fbddd7b8999c6c403b1649ca77cae53ccb33a7466c0ba2e43670717bb2502de19dd83165e63ac0bdf45f628e77f314131766965730a44a947ab2d37be9216c866637b04e5ee682cb7fc17f92ce5c77cf9113abb1030a1997ab2000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000cbd0a779c26eb779769cc9d3a42f61c97c99602928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60396cdbbacab4ca173328793d82669df272d72cbd5f355277324d1cf707995f82b320ecd46b4bc60e11394a891aa160cc8e87ac44ae214a23cddf356c8ef90990d7c8f0c9da0e89ce98f30d4b468df256397afae21430e552c0ab9a4fac037710c7ac7c8858a6d26323a0ef3e40bd3c62fccf473eaa83aebcf6b545a7bc6fd9105811a4341bdab25b827b79253700ac63f5df83cf602db53efa3c93aef66c99d0a5b385aa594eaa55cc8eba9fc5bb179bc1745e4fa1b988e58bd438c1b6a23be0a19671d950886a2c5d8adeb93b36d55c2a6a3fd577fa1f1645edd71a36c37581a5ff14720ee29643e09096dd01785828380c42c9dbe38d2fb89ea391af5deff2ebbaf11c9e1370f4786ae7deb76760ea476ebbbb2bdfce20159706bc2e18fd5000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000377a5093c2531aeaf4f72b4d0b2c48d3d6c8684a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62375d5b21debe1c780d2dcf962266b2df4937663d6b6e93bcf22f1d64af660b51760dd6af28c91232ef017518ba734b91d159c4146074d8f8bdf5d0ca47f220f2d03765f35c93d02340b24d19aec48cbdc3f1fc9788ac2aad187ef5b9bc6bca6038a078c76db57cc594712c5c73c31afd34a7a441743799e3543968c33f76634138cd4cb56addade4da332152eee582c4bb8e416e45d3fc7f3f8ed0b7073337e2bcaf837d7d01edb32e38abf2439fa2aa55b077c1c7b60640d4dab03bf59c7f305c8ca9cd7a20b79807a5180f921a14acd7f30aa74882bc531c0b42c6e08d66904d07970d54795b0c30c383228090d4ed088af846c318e4de7c25ae9dc01e5352ed242f8f39a28c8dd178f364beed17820829d319729f3b3fbc85908339f1220000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000083b664be1badd9f38133826ed0d1051c473e474e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61b96cb848a7076d907b26de483e289c97c2d7a37b74db23961df4cf3b7a77618019266266d91c62ff228e6016a2f9cb3635b8d7431b80a2284ea13e8692a049f0e81c6a92b69cf67abe95986bf1fd34f17bd458cf13668f47e11edc991a4aac313e246126ed023db3b6d19112f7acf890b77efb0300868a91e09d52a966e6d0315c21f20fe7630e06a0e648cd21e430e9cc12c920bb2df8ff89966830faae7243018fe0cb624573d66479c635f8d7ce04fa45292d39aafd96caeea287e08ca6210ee7e000e89bfbc77617a1f1c2c92bc25f4ca5bc4cb9fa8cff4039e27345baa09b9db170f8e1e9655ced30f72be9edefa5257ce44ad8cd3855cc9fcbaaa443923c51df11ed2f8b830c7bf83c18a77600b170ed08e7a0545c690e1357bc9cf4200000000000000000000000000000000000000000000000000000000c080a0b2ba45b0c4cabc8981799c254b90d90c019b757833e05c2742c13f52e82c7bcfa0296885d0ea2c68aa6020ac3881d89a110471efeef6327af2eb295481571c4386").into(), - hex!("02f920340a8306969c84016c2d0e84039387008349cef494087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000050a76afb1154d01d6eba284069708d356d9969928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6204472fcf9520f9fb2076ff97de783931cff4485b9028f260839f5a3518c0b7c2dedb9ba79cbf3ce5e0eca92a12da266d66f21c58bc107fb961e7fdce9538d4c195256b732f3eae1f49cde40c25294963146d06212e318cfba43ec8ec274d1bf22c8f77a99a5797161aad10de1fb3f3754df5fc20ccede01674a7c7284f7bd690484bc65d8c32f6a062c6e886f8563ce28e02d2e58485273eca71a27aeb19dc70860db898acf6d32b0140c8b90355e8b4b4bcc0d01f2761d44a573421bf4af1c0e6bcc3f1b2cd42af6830438342270b83e244cb2d680021a46c6a0416683e1e10fcb9e36c27546a590b8bfdaab06385ae9c72b22160622aa8acaf404bfafa50c2fd454af5d6f6d7dc38a9fd1dc115b8f1a55b7f9a2fac0e080cc6e7acf472955000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000fd176b56e03a2a4d400c61cade47630196614e6a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61f480e5d05a2821f7b6a0da7912130ca375498b472fe02cdd1635bf57e3fc79d0e99986102ae4e27760a6d33cab28b4b77c5fc177b0030d8021b67017f7b4c931a69139b25a75a2023160dd6d6f02a21e95d3005308ce63c45c423de987d8e4b1dbec338be731bba82354b115902c3f4d702178bedea57978eb5b174459fc1b1270ea499e3a908cbda58d2c091f5616d9c2b18687adda6c24017833ce90acec200e87b2cc129df7a4f39d8f6e2c3b2a8d3f3e0905c3d4bff8ede401310ae1d9f276d6239c4c32dc9e627a1dbe6a60ea37e4f7de95512de72696e37de529686d0212ee16598faeb5445f37c581fd9a60bd3d22b1fd965a9cea3dd677df95c9fb3151ba48ffa3b5e7454aa32c6850bbed3457f6cccaac2f5cc9e399a68196b29e4000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000897e11089a878542836ec8e77b825a51ef8829b528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae600164253f8e62ae2671abad4b06d54a890f9abc01afec02287a15cf1115068951c9bdbc96cb8adaafae3aa83c4110616113c066688bb00fecc39bdeb64a1390a2917725d914fcc89e3c18a87a8ed00d9540700ec7320ab345baafb920b0441ad07c4a7e6b2dc434e9934277572be6f581fff0eb7be0857f48ddfa68c2e66cfce21fe5a394f6fcc4844335bae1029ebb014c6c08c2403aa11fbbf18cf6bffc425060e00ed6a571e020461981b6429019c35ef9f1be8bcbde05745a1c537b9472d03cba89ce21b3cb28eb03f08d7c97f1d94e8c0b55d3fd2586b74da048726ddbc1c8eb5ff64d606c6bacc97d6428a1ff83517a46b8f3d5194714a98957d2f1cd905a46fdce4364f2512312c238f9dc59ee6faffe30ee2d7f5887ab0eecd596b40000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006bc063c2b6c1c94490329f632725e22237456b3f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62ad99a00f80269a3a77de4fc3bd9976e9ef2a94954860a99c785b2bf1b63accc26de5151dac27c1c3d92571dfba7a67ca017482bee0be2188fa571875c660e5d221a475b95129123030032cf5243f78a2e6cf478c6c3c549d46fe6811a59c3900578aa1407face18fc14174b56571888ef0c471fd66aa52a53206215429d0f8405511b5377d2e625d010030d49045e1828e2366e8d5df27068e8eb9b89891b170a61b2f39e61d48c97c6117b1f04e5ac104311785063e3acc3cbe7358b13082204a43390431779d8fad127b39c5853f9926e94e6985a0fba609e7453db8a9e7c26d930a97127bc0cb549e5723f4b92f8cc7e5f800368ef108411f31e8c2476b80eac922344044afde8e958a3af9422dda01d35584d76526fc1a2a13ae59dbd0f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000033200fe170f61ed4ac8a09b43e3798e4ac8f195b28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62d3092e1316ce6abb3acc796d98205e786e22c1345c132b0e61070095b83993b136fae2ec9bb03d161cef5cad8bff5335812f32cea2191dfd42df867f64981542b7fc99748f6833af03f2d7c93ad8d3cfe6b5103a510deebbb029e4005dec5a201326eee2a5598f72b7500f0aedebc83563faef710c75cf0a8f69ee75645ecf0053f00c5847f869a0b27d58d6ca7314f590766b4e4eb305c3c31e64b206df10d02ae3cf650459570d00f74f002fdfa92e68bf056c8b974c07b189a33442281c51748d8cfeb75803b470f289144f38d5648bc6d2def5caf65d0cab9583dc0220f17c983c93039ed5fff9d82b233a207a1069f00bfee072c1ce04211e6571df5c825dc3cacbeb084a77f015460798ebf9a2a5e546013bbd245b57ccb3a3a60579b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f1ba6cef8ccb2990ce7de325b7fa407906125bf328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae620c0644be433481651df7035bc5cc1247d8eb024f08f06646a9f1a81e475902711574aa82220fd71bc6cd5f1e7a2f1c66f6cdec680e04c449fd5f65f0606f84207dac5ae5563747e3e74aca6b92fe8be94a591ba654763f2c376a984ab6bac5a07cf890ae88d46cebfabe94398e2d8aef0a277caa1de32e3a81377e564286b1e02161e7871b40c0a388af9e732df270970cd74b6bb71ec71479a1144789da3ab279ba62160fbc729e5ce188fe5925e3ec9d04988f62adfbb9c8cef7246cd0d5720705aafd2bd6f4735dc9b19b03d606a70aabb86c38e2c3fdf2f53ef92e7eb64207335417ad2b241b88d9ae80418ca07eb457f2c557a5bd4c1eb2ef3c3fcbe3120e195a0a41d0dc2aec8703992711bc3ca34432f04012e6b771841b9862a7447000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000785cb80c25d8d3618ca7962b2dd85e7513b0fda528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6291ca2fbeb9e08a732b6937ff647309d7152fb770052fe37d3c7ca22911a6bec11b0f463565e65e5c255bb13afa8fb025bf41cc4aee8f4b8d00d1826c6ab90f813e024024e4c916186ca0ec32ab1688a6a09a156462027b218f39a1f4dd4b964243e8898fc270f9621c0a45380bcb5bc9b14a236680180a042258fac8aae0c9e1dd0ec39787afd536b51527426964ccbc2ddc1ae16b0d6f11d9241d1cb53b94e0e989e1624568bb59dea3cce55fd0b21696e6153034d29e5144b91afaebbc1ca28e9eacaa694821f267617c5cc3b5812f914315097b210e50c31cccc33dcc3310166b0c3a00a800e11be916b0e02875105e99127e4b458784594de119c5be391096f4f245bd3e19ce16a035f8f784a255e4b91bf5af58e6c8b25b0ea151a74c9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000033090fc05f8e16cae75f332ebd31bb92135ee43028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61293b778ea3a0add86d973685193aac98de614c89ed36878548b7e2a4abb37bf244289929b41c2ca77197403e44de06d465b59e36f189cbff475f4507f7676d0080338e4831274e7ebb54e58c60ad99e45273c61a7e8928f22a52784987e49d61d915117aeeeeeb6619849969af3e29831e98e5fef5b7ee074710aa86a76bd1c27b1e5fb6cd2e22786fce1f03564cdc8c1ed37a9a7d8f036351132437c16c2bf1edf147d96e5946d37803b5b60606971186736514563b075e15c871aa8072f552659fc082dc7dde5907057306ea98d5c1d82a96fc92a5ccd31fed314579e5ce92e1c0ef05de09ea78c2b62c8b4b51b33235fbea7ec6cd6fb6678ba6a81ecfb0b09b380a270901fe8ecf3b5c8875cfafcefc3ac58e44d7233756d97e0844234f5000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006a63428000c4d1f428c3a7546dbc2b897336304a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae612cd2880f852b8d726ec68101fa2ee3011c46c3e3c111a39db1356bba256244c2b88c6ff827347a3a00d18c54feff6f30519ac8f95a4851f05c148b15072f8b20aa1e91b77afa9bbd05aef46c2b90b138a1e6117c9d87a73f682e5db6ae890232a5a58a0063bd20022baba8317a33105e3f9ed5ff9786fe114c8bcf9c93d8d092bcda239c922faf406ae57773acab2fadebcf4fde5763153fabdbf198c36146010a39e592415cd62fc4eefe6e6f00c24aee3c626c1d8e4efe0ff664324d172441e993b5f28bb82d89c318f23c0c8b34b8d3d22fa692be9918ecc1e813144be9b014021eb71ccc2649f3a3c0cb7b56eccc633b41daee6f51fc3acca801201a69620784e86e0894942c024878b4b0040040851c2bf0ca42b34381e95fc28e28a28000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e38fb18ff3738c39b1d9f9352f2468c4426ce4ae28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61c4102b911ae374a542f5c3c2629332d107f87c9d7f084e58ad6686b8ca032d02e4945598231c20938d0af0ce8567fb69936139c2ba3d6e8e1d9c7d986367a9f29a32ba151998a6732af0747596e22828161d91a3a92ed6664a99b7a0d988c2302b6f9af088ccf5d117a451d93d5b97a4555853aae24178279175905606d3af91c3f6e575377a0504d03e34de54894bc2caec9be3dac382a8d39be54a37069442f58d5cedd52832dddece59733cd2b4a6d370681b5a48b52bc76667902f20c0d1011a2c4396ef44f6003ae3bfb73948a1ecfa6f1855984b0d211ac0f4870a7682cd9ba5ecf6858e550b4fdc10893a899d9bc5327885047c271380499c3c0a7f51be5923b17ea743f23538d8b463fd7d142301174b8b9253f11b7e74310b4c17d000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006d012fe8cdfd1b3db63e95c8d7a06dc9e0b66aef28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61f92267a1575d60651f0ca0a74d2ab67989f3ccc976b18246b504fca3df8cef31db8c4f95b1afeb35f826a69dca4995c5d2efcf3e9e459bbf99cca255ca1e8ea08c230b042609463c274ed7e6439e545d730c770ff035643c98c03bc419ef0c82eb48d9897932b8f919dc0684164b261d640c0a25e7064de8413beeb515d95121b47662c8e2fc34190f77919fa05e41226a1fa236d464cdd0c46e5d0822fdb4226ab9297b1ac2763b87897e4001bb5fd117ba894621c4f19291b31e074f4614523259e4884d735dbd2f0be3a5e687ccd4824a0a501cc311578f49a13b82beb0e18f3a1aca9688d95856c04b6a6c453397b08301bbb222c83e0a5ef28a116dce41c8ee0133596865178948427ffbfacf1856dbf317bc0d10ecb2ca1aa33dee293000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000049c0d6a9e6f273c4494f3568e55d0a313c2edcfc28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae612c4c6415c49c164f8c81c76939fde44b1e6619d1946eb673ac203903dc36a00001c8c09a245beacc76f69f41def1da2219a0cd1ea328134e3aba603e29770fc1ef007c81d6fec56f2f1633d4a5f0b185fad2f719a8b92c624c1441eb2a2f9633020b4b1a0c2a6b16dea1fe908f0d5ab7c2d6f9d7ab50abd9135c25936c317a200f31f339962c0bba6bf3878088ee151d5163df24097350d02cc00f3d5f3a2e316554592f12df06777fc2eeb343641083f6299f66bd6f6f4ae3c125da8cc15680d35cfdfc71d15f59e6e37bae016dfc96da646aea2fbdba7be6fd334c53490ee008c2f1d877ed983a8afe7f98529da6e8186cb1874695070aeb5dc126d4235ad1fd76af0b23372d37b7f5181db3da8d2a46848cf4a473d55ccd23def6db02d46000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000485d8a98bb5dc09f1735aecbc8144ab2db7b545428942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60543198b027d09bba2e1a841d4d3abd89256be8b84db977f5f651fbadf879efa05b9205ea53264deb3985cd04a071d90646a7f7f598d2caf2d2d005ad498943e15e5e0bbe91d868a0ee665e0651f8ffb6c6d2ac509c43d5bb53d805bc6c15f6d06909f64060d8c1a9519cf2b2c06a4542594ef2c3f03628ab85816700d9e6d4115ae7319fb08e0d7cc7755a766fe2be37a6f41332c900b23330c78cfb42e965b0fb6968782b33ec1dc44e79704c6eab3264b4a1a95caa47f3c1eeba76ab83dea260c18ce79fef579dacdc214b521666a9cb9c5ecd0ef82199e2b045ab073bd0926ccbdd591bacf2f04ce8b13437ec5ee71061c37a3bbd68879e0917ddf157ff5082b9767119e087ee6979a6ba346d99a2f6755aab877b680bd1973b7e6c96563000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000231a2f44fde5788ee99c2ea163be421714ee47fc28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae624bd26434331113463b0801bad03295369f09b001551e3039be9a5c86f7c463d0fdd76dae5e472d7738264ac9db2ef6179e1d90a2e2f7931de1b862d24e4cacc171d8f1057095e652a2276423f70ec952dc43abb32bc72ca8080ae10451098b40aca120d5b8822848412087d67b40498eeab7246254d95db1b49b2b77838bee02597c0796b870fe29d3e0fcb8cd2d3148cc5d29ac0e0fe3cc1b42310b6f06cc90f771c1c8425d1e6ee1929cbc01986def1ea012780d606b41cf378682c9a0a2a13e44d09eac7239b532e1c5d99fc76a5b0c0e184edc31aea2b1ded286a8b7b8b1b8c744c3b5b68a413b7710a4106993e0e3aa97c148bbc46e7bd475e4a4a0bf71a64ba3b34be6656b6760ccd4b3c080019735cbf852cd50a5608d56ead05ffe900000000000000000000000000000000000000000000000000000000c080a0f613146bcf55b47f690f88aa4d95f8e188b28065b0ddbd49f689c7776a4049b3a00b4d55033092f80ca9df1123c6437f52372e2548cb8fbeca54722d9fe760e3c2").into() - ]; - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 1717730355, - prev_randao: b256!("c7acc30c856d749a81902d811e879e8dae5de2e022091aaa7eb4b586dcd3d052"), - withdrawals: Default::default(), - suggested_fee_recipient: address!("4200000000000000000000000000000000000011"), - parent_beacon_block_root: Some(b256!( - "a4414c4984ce7285b82bd9b21c642af30f0f648fb6f4929b67753e7345a06bab" - )), - }, - gas_limit: Some(30_000_000), - transactions: Some(raw_txs), - no_tx_pool: Some(false), - eip_1559_params: None, - }; - - op_mainnet_exec_bench("block_121065789_exec", parent_header, payload_attrs, b) - }); - - g.bench_function("Execution - OP Mainnet block 121135704", |b| { - let raw_parent_header = hex!("f90245a0e5d5cf15815d34d1f52079c2eade50abb5a4fb076f63276f8040e81116d87e72a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a05605664e786f79b2312e293136d1aa6d5624181a59ad30bd11c91047100d2365a0cab880357793e1e6207e913de30eeaed08f7678c6d7822e8d5d44eec9b0ccd3ba073d6669bdb07a8d3fd21c24289e7176bd2890404acfd1978004c0da9f7ba4a48b90100008000000100200000c01080000000000000080000000020000c08000000000000001000030000010000003000800040000900c000000000040100400024000001000000000080000100000800000004000000000005200008001800800000100001000002000002000010000000082000004000090000000000685000a802000a00000008000000000004000000400000010001002080002000000820000802021000000004280200084200000001000080000000200000200080000000000040020082000000000000080000080000000000000000000000040000000060200090020800000080101000400000021000008400030008c000008000000108408084073862578401c9c3808312003c8466649e6780a023b3d2cb1b7216ef94837fdf94767b6235ce735a19de4f3feee7c1d603f2d10b880000000000000000840393d0c8a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a08ab0d68c0fc4fe40d31baf01bcf73de45ddf15ab58e66738ca6c60648676f9af"); - let parent_header = Header::decode(&mut &raw_parent_header[..]).unwrap(); - let raw_txs = vec![ - hex!("7ef8f8a0bd8a03d2faac7261a1627e834405975aa1c55c968b072ffa6db6c100d891c9b794deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc500000000000000070000000066649ddb000000000131eb9a000000000000000000000000000000000000000000000000000000023c03238b0000000000000000000000000000000000000000000000000000000000000001427035b1edf748d109f4a751c5e2e33122340b0e22961600d8b76cfde3c7a6b50000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985").into(), - hex!("02f8740a83180225840bebc200841dcd6500830249f0944ccc17a0cb35536d479d77adea2f8aa673e9b2d38703e871b540c00080c001a09e25fc89301001dc632d96e4ae9141953689fe57bb5f4925bb52d8ad113cec049f2a5e231b2ecf6a7f541b466d8f87445cb467cd5f632d7ffc2999c7dc580a5b").into(), - hex!("02f8750a83180226840bebc200841dcd6500830249f094212f4275087516892c3ee8a0b68fcf9c13f6edbd8703e871b540c00080c080a0df653a88e57f031682ef1e97ebed3cade860186ce6a2a1e56065929d1f9570aba075e2c34f0abad126a901d7947fdb8640d4b3d0c096b70be77cbd23f963645eb1").into(), - hex!("02f8750a83180227840bebc200841dcd6500830249f0944b178ebb31988b0b7df425e2fa9247113c9a9a8e8703e871b540c00080c001a06cf51a0ce263413929c7219f2696da810b1ac0b24c19417ed124f48f426b28e5a06caab14e2e884b1e6e4940b88a834a92465351db58a3b4abdc638adb2877ed6a").into(), - hex!("02f8750a83180228840bebc200841dcd6500830249f094169e79e9e33763aeba5c1eee6b265eb24a24b0598703e871b540c00080c001a0077aed7927363b13ee91ec719b9cbba48227c50ea80e72829e4c54a492402be7a034ffcf5d50d3821665266e217cb3edaf43aadd99837b14b36dd97054db837eeb").into(), - hex!("02f8750a83180229840bebc200841dcd6500830249f0941677c2a6d05056651bd8eeffb8834037a86b5a598703e871b540c00080c001a03f4c22cec9402f9d04c1f1e92406cc5a53ccccc906430047382ee0c477172990a0141ed5488e7b89eb22484e2f3685ade5933f8e4d6ae03c55722f81c48ce3e6ec").into(), - hex!("02f8750a8318022a840bebc200841dcd6500830249f094613849638013429abca858d60bab0c991da5e3dd8703e871b540c00080c001a0674d1cf0c2ec10ec8cf3ddf1ceb13d334b95e508b05ffb6ea07f3f1018c8886ca01b89992a74e451b929430e516529379abe853615b605669251a162123b6a319c").into(), - hex!("02f8750a8318022b840bebc200841dcd6500830249f094958f564d5a9586deee8cde55676400810796779c8703e871b540c00080c001a0d0dc11affeaa5f379ab4a8995cd00d7324cb7a6875c48f3ac8343c11d47b7ee1a02453699b07195ea21a807f88f39c01a1d809d45654399a2e4c852ca177eaaaed").into(), - hex!("02f904780a0c84068e778084068e77808302df9894ef4fb24ad0916217251f553c0596f8edc630eb668718cfb10af2a4f7b90404b930370100000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000018ff90a61f40000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000154232662c24f700000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000014c61b1fedfc00000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000000000000000000000000000000000000000001a000000000000000000000000046eef3e36b4e393922fa3c32e9f43f899b3f712700000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001446eef3e36b4e393922fa3c32e9f43f899b3f7127000000000000000000000000000000000000000000000000000000000000000000000000000000000000001446eef3e36b4e393922fa3c32e9f43f899b3f71270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410101010000e60075efbc77000000000000000000000000000000fced1f1bc61400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a0bd38744150a6226dd2a4d86fb406292059fb7e9599ad2ff0968815554aaa7127a01857d067cc9495cb8678d42732d1ee2717438ee248fc0c11c4881fd0e573905c").into(), - hex!("02f8ae0a0c83cc52e084062efafe829db294420000000000000000000000000000000000004280b844a9059cbb000000000000000000000000efb3cc77ebb75333112cc61ef19772f9155d2add00000000000000000000000000000000000000000000005150ae84a8cdf00000c080a05ec4c586fbbdee52dfaa903b1151a48bc5df2cd210e2a0d87daf15b433203467a060e3ee29b6d862c6ec0d1f91b241b8e45a142fda4dc69458ff2cac8738dd37b9").into(), - hex!("02f904130a8308267e839896808406538c1d8307a12094903f58ee6d6c3c2ca26427c8f917f6ae515827b180b903a4c9807539000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000007c2b7b4ac0fcc188b3e7ff5b83f6597f0005ed340209010308020507000406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000b575892db6100000000000000000000000000000000000000000000000000000b5c6a298fef00000000000000000000000000000000000000000000000000000b5c6a298fef00000000000000000000000000000000000000000000000000000b5c83646d3300000000000000000000000000000000000000000000000000000b5c8538f80000000000000000000000000000000000000000000000000000000b5c8538f80000000000000000000000000000000000000000000000000000000b5c8538f80000000000000000000000000000000000000000000000000000000b5c8baa58fb00000000000000000000000000000000000000000000000000000b5c99feb2d700000000000000000000000000000000000000000000000000000b5c9c9f4a780000000000000000000000000000000000000000000000000000000000000004dc74097b0e5cc36a7cdf0722fb9608cf7e9a5a535475e34b78efbc9a2ef2555cf24b376824df6cfc3fe2db6e24797c1efa2ff2dbb64d34fac96fa7b7fa31a8e1480b1b684b1bc449c33d8f1709efe37cce06183ceae81c69833c48ebcb1a216ce73e8eb98ce8cc7e71d39b5636b91951e671bce12498e604b57be8bff88e448f00000000000000000000000000000000000000000000000000000000000000044a328613d73f44e21da13f28f233958119f314e9e1ebe1f4541eb209436c36c16618e2edf999aa2d263d5a6734f6a341143633023235a81ccda6917bddfa340e5b2f76db20be0dbae19af99a2430e3f0c111880eaa98cd95580b441a1fc2621645e5d7610a6697a0178c67d6fa3812710c179e6a5c7ef0f607b19aedfeedc39cc001a0303b7d9a441823918d302b04cb58ca6b5c834d952af0429709a717ed2316a48da03d9a9af29b52b6d33678b79b6e794eea4e12519b7de717c9ccf495b2d4ee6f13").into(), - hex!("02f8b20a832cfaab834c4b4085012a05f20082cc149494b008aa00579c1307b0ef2c499ad98a8ce58e5880b844a9059cbb0000000000000000000000008bfd47c9c6ff6ae8757f2bbe78e585471348fb72000000000000000000000000000000000000000000000000000000000213c4d0c080a0dead8785821ccedfe19e14a59822a6798766268dc5eca2179e0be9f05f8e2431a053ef2c483ab1eb1d2feea63a2e3f40769f8cbe419853a4213e7bdd147cc64842").into(), - hex!("f869018403b83b4a82561394a061b7f22ba72df1bd64fc8980a66df01a9b21d086026f910a80f28038a0c43718694719ebcc8116e6ae21b1ab64487c43a56b4b3e78ae9a361a7ea57614a056f90d2b9f6e8a1776d61ed6eaf831e6e1c64310ebfd34e5b828bac83557a44d").into(), - hex!("f869018403afd9a6825dd894a061b7f22ba72df1bd64fc8980a66df01a9b21d086021ce0d33aa58037a0b471d2ea71e7d125e64ffd3d141318ce949a40cd0b39cca01625c41e57dead89a073f5fc7c2b79e98053907cd62dac09ed86eae297acd7f22c44ea11ab8a1ca26e").into(), - hex!("02f904da0a83012990830f424084045e2f258305e39c9400000000fc04c910a0b5fea33b03e0447ad0b0aa8702e5763b5ce075b90464a44c9ce700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029d7230c7d0257d69880fa5255bcb14863b0e6d100000000000000000000000000000000fcb080a4d6c39a9354da9eb9bc104cd7000000000000000000000000000000000000000000000000000000006664a0bd00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000041fe4bb48f83d1fba43c9f77e98386c43cf86872532b0b047c7c53080bf36e7d823a2206018d9ca46a93c21385de8ea5f2d37d5d9d3980cd4a89807ce1a2a415e51c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000006664a0bd00000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000020659a6d1a52778774ecc59ebdd05f205d8713b62ed4160cb76474c091f1cdb5f60000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000002ef790dd7993a35fd847c053eddae940d0555960000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000006664a0bd000000000000000000000000000000000000000000000000000000000000004139457ec7958ea305974201cf59c768e680ad098fd5b174d4653eb99e2077a9bc270b641cd87b6f4e52eba7d072cf169eb5c1fe995e442f0f7fd82df12bf2416f1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415056e9bcf742ba1be88d2fe14568d67f70bdf3c230a425d2152fa8d4097d68ba125c520e1e3a778992f0978913ccf51364799ac9a24a30dc70d156f67eff9a891b00000000000000000000000000000000000000000000000000000000000000c001a04ff321d98b0de90b4149b0e99ba8d291c6208d63d50fad85574e51f6eebbadb4a061590ed8c64190dcb7934c10073c670876c5e62de3eb17d8ffd5b061cf12d922").into(), - hex!("02f906770a81a0830f42408407566a76830927c09400000029e6005863bb2e1686a17c4ae0d17236698694b19b4eb054b9060424856bc300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000208010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000000049400000000000000000000000006d4b5289b981933e34af10817f352061bad6353000000000000000000000000000000000000000000000000000000000000012000000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005ae1b619cd6b0000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000070e3c000000000000000000000000000000000000000000000000000000000004e56c0000000000000000000000004939d67eeb427312c86d9f889bd7d90cbd1ca2660000000000000000000000000000000000000000000000000000000000a909920000000000000000000000000000000000000000000000000000000008e068db00000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d4b5289b981933e34af10817f352061bad635300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029e6005863bb2e1686a17c4ae0d17236690000000000000000000000000000000000000000000000000000000000000000000029e6005863bb2e1686a17c4ae0d172366900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000109000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000004939d67eeb427312c86d9f889bd7d90cbd1ca2660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c001a0412f0c2e72d680c2fedd9c1282ca4935f0646baea439ea372fa28a3febfcf648a0572980c28d5ba9522f592b7f3d39a94b5f5b123a62f6bb136685b12a1d9e7c52").into(), - hex!("02f904da0a83012933830f424084045e2f258305e39c9400000000fc04c910a0b5fea33b03e0447ad0b0aa8702e5763b5ce075b90464a44c9ce7000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff5f082dbf2d2f930eb3d2b51bb2f1010a4d5a8900000000000000000000000000000000fcb080a4d6c39a9354da9eb9bc104cd7000000000000000000000000000000000000000000000000000000006664a0bd00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000041819edf15e18a545cbbabbd24c9f3e136a3dcec10c65f5ce19d6fb903e586e6db5f2e154210d25768487e89cb7d9b62cc611421c3456538c7d9ac39f0fd619e111c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000006664a0bd000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000205183a065a3c67e765796c2969e67b960d2ae041a36070a7ed719b18b5682bdda0000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000002ef790dd7993a35fd847c053eddae940d0555960000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000006664a0bd0000000000000000000000000000000000000000000000000000000000000041dd6bb97a2c5250e07ba4b0df71715c81ac9adc5ee1111a0f8ff3845321ac7d5262a7cdd80df46391bc4e41b5f1492110a42badfb7b6ebdd8944e2c3c9a9d8e621c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d5ae1701d2a1750e608e1f2b5d10280db952ddb14cc35f819f7334e9eb5133a5072108be5f5134ac6c061fa9e3bcee464ad8c8e13e206cd5c6b632a7294cd34b1c00000000000000000000000000000000000000000000000000000000000000c001a0994107041475defdb265cdbe6da3df610516ec50a81dd9c0a3602c20d1c72b22a04b28a32d391ebdc15e63ffd26dc3a91e6c3c0565538e33e04558a9d1c9d70b3f").into(), - hex!("02f8b50a01830f424084045a3cc98306213f942a5c54c625220cb2166c94dd9329be1f8785977d866e5ceb32785cb844f5c358c60000000000000000000000000000000000000000000000000000000000000504000000000000000000000000000000000000000000000000000000000263b143c001a051a2584f761c7ef2216652d41840cb1e84c0576d076c72f06906777cb043d45aa02bdbb191600306e5f3ff6d65991f61979f8a10d60d0c6ccaaf1f6d5c7515dac2").into() - ]; - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 1717870185, - withdrawals: Default::default(), - prev_randao: b256!("23b3d2cb1b7216ef94837fdf94767b6235ce735a19de4f3feee7c1d603f2d10b"), - suggested_fee_recipient: address!("4200000000000000000000000000000000000011"), - parent_beacon_block_root: Some(b256!( - "8ab0d68c0fc4fe40d31baf01bcf73de45ddf15ab58e66738ca6c60648676f9af" - )), - }, - gas_limit: Some(30_000_000), - transactions: Some(raw_txs), - no_tx_pool: Some(false), - eip_1559_params: None, - }; - - op_mainnet_exec_bench("block_121135704_exec", parent_header, payload_attrs, b) - }); -} - -criterion_group! { - name = execution_benches; - config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = execution -} -criterion_main!(execution_benches); diff --git a/crates/proof/executor/src/builder/assemble.rs b/crates/proof/executor/src/builder/assemble.rs new file mode 100644 index 0000000000..8ce7b6aa9d --- /dev/null +++ b/crates/proof/executor/src/builder/assemble.rs @@ -0,0 +1,198 @@ +//! [Header] assembly logic for the [StatelessL2Builder]. + +use super::StatelessL2Builder; +use crate::{ + ExecutorError, ExecutorResult, TrieDBError, TrieDBProvider, + constants::{L2_TO_L1_BRIDGE, OUTPUT_ROOT_VERSION, SHA256_EMPTY}, + util::encode_holocene_eip_1559_params, +}; +use alloc::vec::Vec; +use alloy_consensus::{EMPTY_OMMER_ROOT_HASH, Header, Sealed}; +use alloy_eips::Encodable2718; +use alloy_evm::{EvmFactory, block::BlockExecutionResult}; +use alloy_primitives::{B256, Sealable, U256, hex, keccak256, logs_bloom}; +use alloy_trie::EMPTY_ROOT_HASH; +use kona_genesis::RollupConfig; +use kona_mpt::{TrieHinter, ordered_trie_with_encoder}; +use op_alloy_consensus::OpReceiptEnvelope; +use op_alloy_rpc_types_engine::OpPayloadAttributes; +use revm::{context::BlockEnv, database::BundleState}; + +impl StatelessL2Builder<'_, P, H, Evm> +where + P: TrieDBProvider, + H: TrieHinter, + Evm: EvmFactory, +{ + /// Seals the block executed from the given [OpPayloadAttributes] and [BlockEnv], returning the + /// computed [Header]. + pub(crate) fn seal_block( + &mut self, + attrs: &OpPayloadAttributes, + parent_hash: B256, + block_env: &BlockEnv, + ex_result: &BlockExecutionResult, + bundle: BundleState, + ) -> ExecutorResult> { + let timestamp = block_env.timestamp; + + // Compute the roots for the block header. + let state_root = self.trie_db.state_root(&bundle)?; + let transactions_root = ordered_trie_with_encoder( + // SAFETY: The OP Stack protocol will never generate a payload attributes with an empty + // transactions field. Panicking here is the desired behavior, as it indicates a severe + // protocol violation. + attrs.transactions.as_ref().expect("Transactions must be non-empty"), + |tx, buf| buf.put_slice(tx.as_ref()), + ) + .root(); + let receipts_root = + Self::compute_receipts_root(&ex_result.receipts, self.config, timestamp); + let withdrawals_root = if self.config.is_isthmus_active(timestamp) { + Some(self.message_passer_account(block_env.number)?) + } else if self.config.is_canyon_active(timestamp) { + Some(EMPTY_ROOT_HASH) + } else { + None + }; + + // Compute the logs bloom from the receipts generated during block execution. + let logs_bloom = logs_bloom(ex_result.receipts.iter().flat_map(|r| r.logs())); + + // Compute Cancun fields, if active. + let (blob_gas_used, excess_blob_gas) = self + .config + .is_ecotone_active(timestamp) + .then_some((Some(0), Some(0))) + .unwrap_or_default(); + + // At holocene activation, the base fee parameters from the payload are placed + // into the Header's `extra_data` field. + // + // If the payload's `eip_1559_params` are equal to `0`, then the header's `extraData` + // field is set to the encoded canyon base fee parameters. + let encoded_base_fee_params = self + .config + .is_holocene_active(timestamp) + .then(|| encode_holocene_eip_1559_params(self.config, attrs)) + .transpose()? + .unwrap_or_default(); + + // The requests hash on the OP Stack, if Isthmus is active, is always the empty SHA256 hash. + let requests_hash = self.config.is_isthmus_active(timestamp).then_some(SHA256_EMPTY); + + // Construct the new header. + let header = Header { + parent_hash, + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: attrs.payload_attributes.suggested_fee_recipient, + state_root, + transactions_root, + receipts_root, + withdrawals_root, + requests_hash, + logs_bloom, + difficulty: U256::ZERO, + number: block_env.number, + gas_limit: attrs.gas_limit.ok_or(ExecutorError::MissingGasLimit)?, + gas_used: ex_result.gas_used, + timestamp, + mix_hash: attrs.payload_attributes.prev_randao, + nonce: Default::default(), + base_fee_per_gas: Some(block_env.basefee), + blob_gas_used, + excess_blob_gas: excess_blob_gas.and_then(|x| x.try_into().ok()), + parent_beacon_block_root: attrs.payload_attributes.parent_beacon_block_root, + extra_data: encoded_base_fee_params, + } + .seal_slow(); + + Ok(header) + } + + /// Computes the current output root of the latest executed block, based on the parent header + /// and the underlying state trie. + /// + /// **CONSTRUCTION:** + /// ```text + /// output_root = keccak256(version_byte .. payload) + /// payload = state_root .. withdrawal_storage_root .. latest_block_hash + /// ``` + pub fn compute_output_root(&mut self) -> ExecutorResult { + let parent_number = self.trie_db.parent_block_header().number; + + info!( + target: "block_builder", + version = OUTPUT_ROOT_VERSION, + state_root = hex::encode(self.trie_db.parent_block_header().state_root), + block_number = parent_number, + "Computing output root", + ); + + let storage_root = self.message_passer_account(parent_number)?; + let parent_header = self.trie_db.parent_block_header(); + + // Construct the raw output and hash it. + let mut raw_output = [0u8; 128]; + raw_output[31] = OUTPUT_ROOT_VERSION; + raw_output[32..64].copy_from_slice(parent_header.state_root.as_ref()); + raw_output[64..96].copy_from_slice(storage_root.as_ref()); + raw_output[96..128].copy_from_slice(parent_header.seal().as_ref()); + let output_root = keccak256(raw_output); + + info!( + target: "block_builder", + block_number = parent_number, + output_root = hex::encode(output_root), + "Computed output root", + ); + + // Hash the output and return + Ok(output_root) + } + + /// Fetches the L2 to L1 message passer account from the cache or underlying trie. + fn message_passer_account(&mut self, block_number: u64) -> Result { + match self.trie_db.storage_roots().get(&L2_TO_L1_BRIDGE) { + Some(storage_root) => Ok(storage_root.blind()), + None => Ok(self + .trie_db + .get_trie_account(&L2_TO_L1_BRIDGE, block_number)? + .ok_or(TrieDBError::MissingAccountInfo)? + .storage_root), + } + } + + /// Computes the receipts root from the given set of receipts. + fn compute_receipts_root( + receipts: &[OpReceiptEnvelope], + config: &RollupConfig, + timestamp: u64, + ) -> B256 { + // There is a minor bug in op-geth and op-erigon where in the Regolith hardfork, + // the receipt root calculation does not inclide the deposit nonce in the + // receipt encoding. In the Regolith hardfork, we must strip the deposit nonce + // from the receipt encoding to match the receipt root calculation. + if config.is_regolith_active(timestamp) && !config.is_canyon_active(timestamp) { + let receipts = receipts + .iter() + .cloned() + .map(|receipt| match receipt { + OpReceiptEnvelope::Deposit(mut deposit_receipt) => { + deposit_receipt.receipt.deposit_nonce = None; + OpReceiptEnvelope::Deposit(deposit_receipt) + } + _ => receipt, + }) + .collect::>(); + + ordered_trie_with_encoder(receipts.as_ref(), |receipt, mut buf| { + receipt.encode_2718(&mut buf) + }) + .root() + } else { + ordered_trie_with_encoder(receipts, |receipt, mut buf| receipt.encode_2718(&mut buf)) + .root() + } + } +} diff --git a/crates/proof/executor/src/builder/core.rs b/crates/proof/executor/src/builder/core.rs new file mode 100644 index 0000000000..d71618c5fe --- /dev/null +++ b/crates/proof/executor/src/builder/core.rs @@ -0,0 +1,202 @@ +//! The [StatelessL2Builder] is a block builder that pulls state from a [TrieDB] during execution. + +use crate::{ExecutorError, ExecutorResult, TrieDB, TrieDBError, TrieDBProvider}; +use alloc::{string::ToString, vec::Vec}; +use alloy_consensus::{Header, Sealed}; +use alloy_evm::{ + EvmFactory, FromRecoveredTx, FromTxWithEncoded, + block::{BlockExecutionResult, BlockExecutor, BlockExecutorFactory}, +}; +use alloy_op_evm::{OpBlockExecutionCtx, OpBlockExecutorFactory, block::OpAlloyReceiptBuilder}; +use alloy_primitives::hex; +use kona_genesis::RollupConfig; +use kona_mpt::TrieHinter; +use op_alloy_consensus::{OpReceiptEnvelope, OpTxEnvelope}; +use op_alloy_rpc_types_engine::OpPayloadAttributes; +use op_revm::OpSpecId; +use revm::database::{State, states::bundle_state::BundleRetention}; + +/// The [`StatelessL2Builder`] is an OP Stack block builder that traverses a merkle patricia trie +/// via the [`TrieDB`] during execution. +#[derive(Debug)] +pub struct StatelessL2Builder<'a, P, H, Evm> +where + P: TrieDBProvider, + H: TrieHinter, + Evm: EvmFactory, +{ + /// The [RollupConfig]. + pub(crate) config: &'a RollupConfig, + /// The inner trie database. + pub(crate) trie_db: TrieDB, + /// The executor factory, used to create new [`op_revm::OpEvm`] instances for block building + /// routines. + pub(crate) factory: OpBlockExecutorFactory, +} + +impl<'a, P, H, Evm> StatelessL2Builder<'a, P, H, Evm> +where + P: TrieDBProvider, + H: TrieHinter, + Evm: EvmFactory + 'static, + ::Tx: FromTxWithEncoded + FromRecoveredTx, +{ + /// Creates a new [StatelessL2Builder] instance. + pub fn new( + config: &'a RollupConfig, + evm_factory: Evm, + provider: P, + hinter: H, + parent_header: Sealed
, + ) -> Self { + let trie_db = TrieDB::new(parent_header, provider, hinter); + let factory = OpBlockExecutorFactory::new( + OpAlloyReceiptBuilder::default(), + config.clone(), + evm_factory, + ); + Self { config, trie_db, factory } + } + + /// Builds a new block on top of the parent state, using the given [`OpPayloadAttributes`]. + pub fn build_block( + &mut self, + attrs: OpPayloadAttributes, + ) -> ExecutorResult { + // Step 1. Set up the execution environment. + let base_fee_params = + Self::active_base_fee_params(self.config, self.trie_db.parent_block_header(), &attrs)?; + let evm_env = self.evm_env( + self.config.spec_id(attrs.payload_attributes.timestamp), + self.trie_db.parent_block_header(), + &attrs, + &base_fee_params, + )?; + let block_env = evm_env.block_env().clone(); + let parent_hash = self.trie_db.parent_block_header().seal(); + + // Attempt to send a payload witness hint to the host. This hint instructs the host to + // populate its preimage store with the preimages required to statelessly execute + // this payload. This feature is experimental, so if the hint fails, we continue + // without it and fall back on on-demand preimage fetching for execution. + self.trie_db + .hinter + .hint_execution_witness(parent_hash, &attrs) + .map_err(|e| TrieDBError::Provider(e.to_string()))?; + + info!( + target: "block_builder", + block_number = block_env.number, + block_timestamp = block_env.timestamp, + block_gas_limit = block_env.gas_limit, + transactions = attrs.transactions.as_ref().map_or(0, |txs| txs.len()), + "Beginning block building." + ); + + // Step 2. Create the executor, using the trie database. + let mut state = State::builder() + .with_database(&mut self.trie_db) + .with_bundle_update() + .without_state_clear() + .build(); + let evm = self.factory.evm_factory().create_evm(&mut state, evm_env); + let ctx = OpBlockExecutionCtx { + parent_hash, + parent_beacon_block_root: attrs.payload_attributes.parent_beacon_block_root, + // This field is unused for individual block building jobs. + extra_data: Default::default(), + }; + let executor = self.factory.create_executor(evm, ctx); + + // Step 3. Execute the block containing the transactions within the payload attributes. + let transactions = attrs + .transactions + .clone() + .map(|txs| { + txs.iter().map(Self::decode_and_recover_tx).collect::>>() + }) + .ok_or(ExecutorError::MissingTransactions)??; + let ex_result = executor.execute_block(transactions.iter())?; + + info!( + target: "block_builder", + gas_used = ex_result.gas_used, + gas_limit = block_env.gas_limit, + "Finished block building. Beginning sealing job." + ); + + // Step 4. Merge state transitions and seal the block. + state.merge_transitions(BundleRetention::Reverts); + let bundle = state.take_bundle(); + let header = self.seal_block(&attrs, parent_hash, &block_env, &ex_result, bundle)?; + + info!( + target: "block_builder", + number = header.number, + hash = hex::encode(header.seal()), + state_root = hex::encode(header.state_root), + transactions_root = hex::encode(header.transactions_root), + receipts_root = hex::encode(header.receipts_root), + "Sealed new block", + ); + + // Update the parent block hash in the state database, preparing for the next block. + self.trie_db.set_parent_block_header(header.clone()); + Ok((header, ex_result).into()) + } +} + +/// The outcome of a block building operation, returning the sealed block [`Header`] and the +/// [`BlockExecutionResult`]. +#[derive(Debug, Clone)] +pub struct BlockBuildingOutcome { + /// The block header. + pub header: Sealed
, + /// The block execution result. + pub execution_result: BlockExecutionResult, +} + +impl From<(Sealed
, BlockExecutionResult)> for BlockBuildingOutcome { + fn from( + (header, execution_result): (Sealed
, BlockExecutionResult), + ) -> Self { + Self { header, execution_result } + } +} + +#[cfg(test)] +mod test { + use crate::test_utils::run_test_fixture; + use rstest::rstest; + use std::path::PathBuf; + + // To create new test fixtures, uncomment the following test and run it with parameters filled. + // #[tokio::test(flavor = "multi_thread")] + // async fn create_fixture() { + // let fixture_creator = crate::test_utils::ExecutorTestFixtureCreator::new( + // "", + // , + // PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata"), + // ); + // fixture_creator.create_static_fixture().await; + // } + + #[rstest] + #[case::small_block(26207960)] // OP Sepolia + #[case::small_block_2(26207961)] // OP Sepolia + #[case::medium_block(26207962)] // OP Sepolia + #[case::medium_block_2(26207963)] // OP Sepolia + #[case::medium_block_3(26208927)] // OP Sepolia + #[case::medium_block_4(26208858)] // OP Sepolia + #[case::big_block(26208858)] // OP Sepolia + #[case::big_block_2(26208384)] // OP Sepolia + #[case::big_block_3(26211680)] // OP Sepolia + #[tokio::test] + async fn test_statelessly_execute_block(#[case] block_number: u64) { + let fixture_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("testdata") + .join(format!("block-{block_number}.tar.gz")); + + run_test_fixture(fixture_dir).await; + } +} diff --git a/crates/proof/executor/src/builder/env.rs b/crates/proof/executor/src/builder/env.rs new file mode 100644 index 0000000000..8df1e28fed --- /dev/null +++ b/crates/proof/executor/src/builder/env.rs @@ -0,0 +1,128 @@ +//! Environment utility functions for [StatelessL2Builder]. + +use super::StatelessL2Builder; +use crate::{ExecutorError, ExecutorResult, TrieDBProvider, util::decode_holocene_eip_1559_params}; +use alloy_consensus::{BlockHeader, Header, transaction::Recovered}; +use alloy_eips::{Decodable2718, eip1559::BaseFeeParams, eip7840::BlobParams}; +use alloy_evm::{EvmEnv, EvmFactory}; +use alloy_primitives::Bytes; +use kona_genesis::RollupConfig; +use kona_mpt::TrieHinter; +use op_alloy_consensus::OpTxEnvelope; +use op_alloy_rpc_types_engine::OpPayloadAttributes; +use op_revm::OpSpecId; +use revm::{ + context::{BlockEnv, CfgEnv}, + context_interface::block::BlobExcessGasAndPrice, +}; + +impl StatelessL2Builder<'_, P, H, Evm> +where + P: TrieDBProvider, + H: TrieHinter, + Evm: EvmFactory, +{ + /// Returns the active [`EvmEnv`] for the executor. + pub(crate) fn evm_env( + &self, + spec_id: OpSpecId, + parent_header: &Header, + payload_attrs: &OpPayloadAttributes, + base_fee_params: &BaseFeeParams, + ) -> ExecutorResult> { + let block_env = + Self::prepare_block_env(spec_id, parent_header, payload_attrs, base_fee_params)?; + let cfg_env = self.evm_cfg_env(payload_attrs.payload_attributes.timestamp); + Ok(EvmEnv::new(cfg_env, block_env)) + } + + /// Returns the active [CfgEnv] for the executor. + pub(crate) fn evm_cfg_env(&self, timestamp: u64) -> CfgEnv { + CfgEnv::new() + .with_chain_id(self.config.l2_chain_id) + .with_spec(self.config.spec_id(timestamp)) + } + + /// Prepares a [BlockEnv] with the given [OpPayloadAttributes]. + pub(crate) fn prepare_block_env( + spec_id: OpSpecId, + parent_header: &Header, + payload_attrs: &OpPayloadAttributes, + base_fee_params: &BaseFeeParams, + ) -> ExecutorResult { + let blob_excess_gas_and_price = parent_header + .maybe_next_block_excess_blob_gas(if spec_id.is_enabled_in(OpSpecId::ISTHMUS) { + Some(BlobParams::prague()) + } else if spec_id.is_enabled_in(OpSpecId::ECOTONE) { + Some(BlobParams::cancun()) + } else { + None + }) + .or_else(|| spec_id.is_enabled_in(OpSpecId::ECOTONE).then_some(0)) + .map(|e| BlobExcessGasAndPrice::new(e, spec_id.is_enabled_in(OpSpecId::ISTHMUS))); + let next_block_base_fee = + parent_header.next_block_base_fee(*base_fee_params).unwrap_or_default(); + + Ok(BlockEnv { + number: parent_header.number + 1, + beneficiary: payload_attrs.payload_attributes.suggested_fee_recipient, + timestamp: payload_attrs.payload_attributes.timestamp, + gas_limit: payload_attrs.gas_limit.ok_or(ExecutorError::MissingGasLimit)?, + basefee: next_block_base_fee, + prevrandao: Some(payload_attrs.payload_attributes.prev_randao), + blob_excess_gas_and_price, + ..Default::default() + }) + } + + /// Returns the active base fee parameters for the given payload attributes. + pub(crate) fn active_base_fee_params( + config: &RollupConfig, + parent_header: &Header, + payload_attrs: &OpPayloadAttributes, + ) -> ExecutorResult { + let base_fee_params = + if config.is_holocene_active(payload_attrs.payload_attributes.timestamp) { + // After Holocene activation, the base fee parameters are stored in the + // `extraData` field of the parent header. If Holocene wasn't active in the + // parent block, the default base fee parameters are used. + config + .is_holocene_active(parent_header.timestamp) + .then(|| decode_holocene_eip_1559_params(parent_header)) + .transpose()? + .unwrap_or(config.chain_op_config.as_canyon_base_fee_params()) + } else if config.is_canyon_active(payload_attrs.payload_attributes.timestamp) { + // If the payload attribute timestamp is past canyon activation, + // use the canyon base fee params from the rollup config. + config.chain_op_config.as_canyon_base_fee_params() + } else { + // If the payload attribute timestamp is prior to canyon activation, + // use the default base fee params from the rollup config. + config.chain_op_config.as_base_fee_params() + }; + + Ok(base_fee_params) + } + + /// Decodes and recovers the signature of an EIP-2718-encoded transaction. + pub(crate) fn decode_and_recover_tx(tx: &Bytes) -> ExecutorResult> { + let decoded = + OpTxEnvelope::decode_2718(&mut tx.as_ref()).map_err(ExecutorError::RLPError)?; + let signer = match decoded.as_ref() { + OpTxEnvelope::Legacy(tx) => { + tx.recover_signer().map_err(ExecutorError::SignatureError)? + } + OpTxEnvelope::Eip2930(tx) => { + tx.recover_signer().map_err(ExecutorError::SignatureError)? + } + OpTxEnvelope::Eip1559(tx) => { + tx.recover_signer().map_err(ExecutorError::SignatureError)? + } + OpTxEnvelope::Eip7702(tx) => { + tx.recover_signer().map_err(ExecutorError::SignatureError)? + } + OpTxEnvelope::Deposit(tx) => tx.from, + }; + Ok(Recovered::new_unchecked(decoded, signer)) + } +} diff --git a/crates/proof/executor/src/builder/mod.rs b/crates/proof/executor/src/builder/mod.rs new file mode 100644 index 0000000000..7c30d9ccfe --- /dev/null +++ b/crates/proof/executor/src/builder/mod.rs @@ -0,0 +1,7 @@ +//! Stateless OP Stack block builder implementation. + +mod core; +pub use core::{BlockBuildingOutcome, StatelessL2Builder}; + +mod assemble; +mod env; diff --git a/crates/proof/executor/src/constants.rs b/crates/proof/executor/src/constants.rs index f3d1d0b038..d05e9ff505 100644 --- a/crates/proof/executor/src/constants.rs +++ b/crates/proof/executor/src/constants.rs @@ -2,9 +2,6 @@ use alloy_primitives::{Address, B256, address, b256}; -/// The address of the fee recipient. -pub(crate) const FEE_RECIPIENT: Address = address!("4200000000000000000000000000000000000011"); - /// The address of the L2 to L1 bridge predeploy. pub(crate) const L2_TO_L1_BRIDGE: Address = address!("4200000000000000000000000000000000000016"); diff --git a/crates/proof/executor/src/db/mod.rs b/crates/proof/executor/src/db/mod.rs index 68bd94c140..5141b8aa1d 100644 --- a/crates/proof/executor/src/db/mod.rs +++ b/crates/proof/executor/src/db/mod.rs @@ -1,4 +1,4 @@ -//! This module contains an implementation of an in-memory Trie DB for [revm], that allows for +//! This module contains an implementation of an in-memory Trie DB for [`revm`], that allows for //! incremental updates through fetching node preimages on the fly during execution. use crate::errors::{TrieDBError, TrieDBResult}; @@ -10,8 +10,9 @@ use alloy_trie::TrieAccount; use kona_mpt::{Nibbles, TrieHinter, TrieNode, TrieNodeError}; use revm::{ Database, - db::{BundleState, states::StorageSlot}, - primitives::{AccountInfo, BLOCK_HASH_HISTORY, Bytecode, HashMap}, + database::{BundleState, states::StorageSlot}, + primitives::{BLOCK_HASH_HISTORY, HashMap}, + state::{AccountInfo, Bytecode}, }; mod traits; @@ -19,12 +20,12 @@ pub use traits::{NoopTrieDBProvider, TrieDBProvider}; /// A Trie DB that caches open state in-memory. /// -/// When accounts that don't already exist within the cached [TrieNode] are queried, the database +/// When accounts that don't already exist within the cached [`TrieNode`] are queried, the database /// fetches the preimages of the trie nodes on the path to the account using the `PreimageFetcher` /// (`F` generic). This allows for data to be fetched in a verifiable manner given an initial /// trusted state root as it is needed during execution. /// -/// The [TrieDB] is intended to be wrapped by a [State], which is then used by the [revm::Evm] to +/// The [`TrieDB`] is intended to be wrapped by a [`State`], which is then used by [`revm`] to /// capture state transitions during block execution. /// /// **Behavior**: @@ -32,10 +33,10 @@ pub use traits::{NoopTrieDBProvider, TrieDBProvider}; /// fall through to the `PreimageFetcher` to fetch the preimages of the trie nodes on the path to /// the account. After it has been fetched, the path will be cached until the next call to /// [Self::state_root]. -/// - When querying for the code hash of an account, the `CodeHashFetcher` is consulted to fetch the -/// code hash of the account. -/// - When a [BundleState] changeset is committed to the parent [State] database, the changes are -/// first applied to the [State]'s cache, then the trie hash is recomputed with +/// - When querying for the code hash of an account, the [`TrieDBProvider`] is consulted to fetch +/// the code hash of the account. +/// - When a [`BundleState`] changeset is committed to the parent [`State`] database, the changes +/// are first applied to the [`State`]'s cache, then the trie hash is recomputed with /// [Self::state_root]. /// - When the block hash of a block number is needed via [Self::block_hash], the /// `HeaderByHashFetcher` is consulted to walk back to the desired block number by revealing the @@ -45,49 +46,52 @@ pub use traits::{NoopTrieDBProvider, TrieDBProvider}; /// **Example Construction**: /// ```rust /// use alloy_consensus::{Header, Sealable}; +/// use alloy_evm::{EvmEnv, EvmFactory, block::BlockExecutorFactory}; +/// use alloy_op_evm::{ +/// OpBlockExecutionCtx, OpBlockExecutorFactory, OpEvmFactory, block::OpAlloyReceiptBuilder, +/// }; +/// use alloy_op_hardforks::OpChainHardforks; /// use alloy_primitives::{B256, Bytes}; /// use kona_executor::{NoopTrieDBProvider, TrieDB}; /// use kona_mpt::NoopTrieHinter; -/// use revm::{EvmBuilder, StateBuilder, db::states::bundle_state::BundleRetention}; +/// use revm::database::{State, states::bundle_state::BundleRetention}; /// -/// let mock_starting_root = B256::default(); /// let mock_parent_block_header = Header::default(); -/// -/// let trie_db = TrieDB::new( -/// mock_starting_root, -/// mock_parent_block_header.seal_slow(), -/// NoopTrieDBProvider, -/// NoopTrieHinter, +/// let trie_db = +/// TrieDB::new(mock_parent_block_header.seal_slow(), NoopTrieDBProvider, NoopTrieHinter); +/// let executor_factory = OpBlockExecutorFactory::new( +/// OpAlloyReceiptBuilder::default(), +/// OpChainHardforks::op_mainnet(), +/// OpEvmFactory::default(), /// ); -/// let mut state = StateBuilder::new_with_database(trie_db).with_bundle_update().build(); -/// let evm = EvmBuilder::default().with_db(&mut state).build(); +/// let mut state = State::builder().with_database(trie_db).with_bundle_update().build(); +/// let evm = executor_factory.evm_factory().create_evm(&mut state, EvmEnv::default()); +/// let executor = executor_factory.create_executor(evm, OpBlockExecutionCtx::default()); /// /// // Execute your block's transactions... -/// -/// // Drop the EVM prior to merging the state transitions. -/// drop(evm); +/// drop(executor); /// /// state.merge_transitions(BundleRetention::Reverts); /// let bundle = state.take_bundle(); /// let state_root = state.database.state_root(&bundle).expect("Failed to compute state root"); /// ``` /// -/// [State]: revm::State +/// [`State`]: revm::database::State #[derive(Debug, Clone)] pub struct TrieDB where F: TrieDBProvider, H: TrieHinter, { - /// The [TrieNode] representation of the root node. + /// The [`TrieNode`] representation of the root node. root_node: TrieNode, /// Storage roots of accounts within the trie. storage_roots: HashMap, /// The parent block hash of the current block. parent_block_header: Sealed
, - /// The [TrieDBProvider] + /// The [`TrieDBProvider`] pub fetcher: F, - /// The [TrieHinter] + /// The [`TrieHinter`] pub hinter: H, } @@ -97,9 +101,9 @@ where H: TrieHinter, { /// Creates a new [TrieDB] with the given root node. - pub fn new(root: B256, parent_block_header: Sealed
, fetcher: F, hinter: H) -> Self { + pub fn new(parent_block_header: Sealed
, fetcher: F, hinter: H) -> Self { Self { - root_node: TrieNode::new_blinded(root), + root_node: TrieNode::new_blinded(parent_block_header.state_root), storage_roots: Default::default(), parent_block_header, fetcher, @@ -227,6 +231,7 @@ where let account_info = bundle_account.account_info().ok_or(TrieDBError::MissingAccountInfo)?; + let mut trie_account = TrieAccount { balance: account_info.balance, nonce: account_info.nonce, @@ -415,26 +420,21 @@ mod tests { use kona_mpt::NoopTrieHinter; fn new_test_db() -> TrieDB { - TrieDB::new( - B256::default(), - Header::default().seal_slow(), - NoopTrieDBProvider, - NoopTrieHinter, - ) + TrieDB::new(Header::default().seal_slow(), NoopTrieDBProvider, NoopTrieHinter) } #[test] fn test_trie_db_take_root_node() { let db = new_test_db(); let root_node = db.take_root_node(); - assert_eq!(root_node.blind(), B256::default()); + assert_eq!(root_node.blind(), EMPTY_ROOT_HASH); } #[test] fn test_trie_db_root_node_ref() { let db = new_test_db(); let root_node = db.root(); - assert_eq!(root_node.blind(), B256::default()); + assert_eq!(root_node.blind(), EMPTY_ROOT_HASH); } #[test] diff --git a/crates/proof/executor/src/errors.rs b/crates/proof/executor/src/errors.rs index 853badc5cc..af96c261bb 100644 --- a/crates/proof/executor/src/errors.rs +++ b/crates/proof/executor/src/errors.rs @@ -1,13 +1,14 @@ //! Errors for the `kona-executor` crate. use alloc::string::String; +use alloy_evm::block::BlockExecutionError; use kona_mpt::TrieNodeError; -use revm::primitives::EVMError; +use revm::context::DBErrorMarker; use thiserror::Error; -/// The error type for the [StatelessL2BlockExecutor]. +/// The error type for the [`StatelessL2Builder`]. /// -/// [StatelessL2BlockExecutor]: crate::StatelessL2BlockExecutor +/// [`StatelessL2Builder`]: crate::StatelessL2Builder #[derive(Error, Debug)] pub enum ExecutorError { /// Missing gas limit in the payload attributes. @@ -36,7 +37,7 @@ pub enum ExecutorError { TrieDBError(#[from] TrieDBError), /// Execution error. #[error("Execution error: {0}")] - ExecutionError(EVMError), + ExecutionError(#[from] BlockExecutionError), /// Signature error. #[error("Signature error: {0}")] SignatureError(alloy_primitives::SignatureError), @@ -48,15 +49,15 @@ pub enum ExecutorError { MissingExecutor, } -/// A [Result] type for the [ExecutorError] enum. +/// A [`Result`] type for the [`ExecutorError`] enum. pub type ExecutorResult = Result; -/// A [Result] type alias where the error is [TrieDBError]. +/// A [`Result`] type alias where the error is [`TrieDBError`]. pub type TrieDBResult = Result; -/// An error type for [TrieDB] operations. +/// An error type for [`TrieDB`] operations. /// -/// [TrieDB]: crate::TrieDB +/// [`TrieDB`]: crate::TrieDB #[derive(Error, Debug, PartialEq, Eq)] pub enum TrieDBError { /// Trie root node has not been blinded. @@ -72,3 +73,5 @@ pub enum TrieDBError { #[error("Trie provider error: {0}")] Provider(String), } + +impl DBErrorMarker for TrieDBError {} diff --git a/crates/proof/executor/src/executor/builder.rs b/crates/proof/executor/src/executor/builder.rs deleted file mode 100644 index ebce14d9a2..0000000000 --- a/crates/proof/executor/src/executor/builder.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Contains the builder pattern for the [StatelessL2BlockExecutor]. - -use super::StatelessL2BlockExecutor; -use crate::db::{TrieDB, TrieDBProvider}; -use alloy_consensus::{Header, Sealable, Sealed}; -use kona_genesis::RollupConfig; -use kona_mpt::TrieHinter; -use revm::{db::State, handler::register::EvmHandler}; - -/// A type alias for the [revm::handler::register::HandleRegister] for kona's block executor. -pub type KonaHandleRegister = - for<'i> fn(&mut EvmHandler<'i, (), &mut State<&mut TrieDB>>); - -/// The builder pattern for the [StatelessL2BlockExecutor]. -#[derive(Debug)] -pub struct StatelessL2BlockExecutorBuilder<'a, F, H> -where - F: TrieDBProvider, - H: TrieHinter, -{ - /// The [RollupConfig]. - config: &'a RollupConfig, - /// The [TrieDBProvider] to fetch the state trie preimages. - provider: F, - /// The [TrieHinter] to hint the state trie preimages. - hinter: H, - /// The parent [Header] to begin execution from. - parent_header: Option>, - /// The [KonaHandleRegister] to use during execution. - handler_register: Option>, -} - -impl<'a, F, H> StatelessL2BlockExecutorBuilder<'a, F, H> -where - F: TrieDBProvider, - H: TrieHinter, -{ - /// Instantiate a new builder with the given [RollupConfig]. - pub fn new(config: &'a RollupConfig, provider: F, hinter: H) -> Self { - Self { config, provider, hinter, parent_header: None, handler_register: None } - } - - /// Set the [Header] to begin execution from. - pub fn with_parent_header(mut self, parent_header: Sealed
) -> Self { - self.parent_header = Some(parent_header); - self - } - - /// Set the [KonaHandleRegister] for execution. - pub fn with_handle_register(mut self, handler_register: KonaHandleRegister) -> Self { - self.handler_register = Some(handler_register); - self - } - - /// Build the [StatelessL2BlockExecutor] from the builder configuration. - pub fn build(self) -> StatelessL2BlockExecutor<'a, F, H> { - let parent_header = self.parent_header.unwrap_or_else(|| { - let default_header = Header::default(); - default_header.seal_slow() - }); - - let trie_db = - TrieDB::new(parent_header.state_root, parent_header, self.provider, self.hinter); - StatelessL2BlockExecutor { - config: self.config, - trie_db, - handler_register: self.handler_register, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::NoopTrieDBProvider; - use kona_mpt::NoopTrieHinter; - - #[test] - fn test_build_full() { - let config = RollupConfig::default(); - let parent_header = Header::default().seal_slow(); - - fn test_handler_register(_: &mut EvmHandler<'_, (), &mut State<&mut TrieDB>>) - where - F: TrieDBProvider, - H: TrieHinter, - { - } - - let executor = - StatelessL2BlockExecutorBuilder::new(&config, NoopTrieDBProvider, NoopTrieHinter) - .with_handle_register(test_handler_register) - .build(); - - assert_eq!(*executor.config, config); - assert_eq!(*executor.trie_db.parent_block_header(), parent_header); - } -} diff --git a/crates/proof/executor/src/executor/env.rs b/crates/proof/executor/src/executor/env.rs deleted file mode 100644 index 56e4eeed0b..0000000000 --- a/crates/proof/executor/src/executor/env.rs +++ /dev/null @@ -1,245 +0,0 @@ -//! Environment preparation for the executor. - -use super::{StatelessL2BlockExecutor, util::decode_holocene_eip_1559_params}; -use crate::{ExecutorError, ExecutorResult, TrieDBProvider, constants::FEE_RECIPIENT}; -use alloy_consensus::Header; -use alloy_eips::{eip1559::BaseFeeParams, eip7840::BlobParams}; -use alloy_primitives::{TxKind, U256}; -use kona_genesis::RollupConfig; -use kona_mpt::TrieHinter; -use op_alloy_consensus::OpTxEnvelope; -use op_alloy_rpc_types_engine::OpPayloadAttributes; -use revm::primitives::{ - AuthorizationList, BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, - OptimismFields, SpecId, TransactTo, TxEnv, -}; - -impl StatelessL2BlockExecutor<'_, P, H> -where - P: TrieDBProvider, - H: TrieHinter, -{ - /// Returns the active [CfgEnvWithHandlerCfg] for the executor. - /// - /// ## Takes - /// - `timestamp`: The timestamp of the executing block. - /// - /// ## Returns - /// The active [CfgEnvWithHandlerCfg] for the executor. - pub(crate) fn evm_cfg_env(&self, timestamp: u64) -> CfgEnvWithHandlerCfg { - let cfg_env = CfgEnv::default().with_chain_id(self.config.l2_chain_id); - let mut cfg_handler_env = - CfgEnvWithHandlerCfg::new_with_spec_id(cfg_env, self.config.spec_id(timestamp)); - cfg_handler_env.enable_optimism(); - cfg_handler_env - } - - /// Prepares a [BlockEnv] with the given [OpPayloadAttributes]. - /// - /// ## Takes - /// - `spec_id`: The [SpecId] to prepare the environment for. - /// - `parent_header`: The parent header of the block to be executed. - /// - `payload_attrs`: The payload to prepare the environment for. - /// - `base_fee_params`: The active base fee parameters for the block. - pub(crate) fn prepare_block_env( - spec_id: SpecId, - parent_header: &Header, - payload_attrs: &OpPayloadAttributes, - base_fee_params: &BaseFeeParams, - ) -> ExecutorResult { - let blob_excess_gas_and_price = parent_header - .next_block_excess_blob_gas(if spec_id.is_enabled_in(SpecId::ISTHMUS) { - BlobParams::prague() - } else { - BlobParams::cancun() - }) - .or_else(|| spec_id.is_enabled_in(SpecId::ECOTONE).then_some(0)) - .map(|e| BlobExcessGasAndPrice::new(e, spec_id.is_enabled_in(SpecId::PRAGUE))); - let next_block_base_fee = - parent_header.next_block_base_fee(*base_fee_params).unwrap_or_default(); - - Ok(BlockEnv { - number: U256::from(parent_header.number + 1), - coinbase: FEE_RECIPIENT, - timestamp: U256::from(payload_attrs.payload_attributes.timestamp), - gas_limit: U256::from(payload_attrs.gas_limit.ok_or(ExecutorError::MissingGasLimit)?), - basefee: U256::from(next_block_base_fee), - difficulty: U256::ZERO, - prevrandao: Some(payload_attrs.payload_attributes.prev_randao), - blob_excess_gas_and_price, - }) - } - - /// Returns the active base fee parameters for the given payload attributes. - /// - /// ## Takes - /// - `config`: The rollup config to use for the computation. - /// - `parent_header`: The parent header of the block to be executed. - /// - `payload_attrs`: The payload attributes to use for the computation. - pub(crate) fn active_base_fee_params( - config: &RollupConfig, - parent_header: &Header, - payload_attrs: &OpPayloadAttributes, - ) -> ExecutorResult { - let base_fee_params = - if config.is_holocene_active(payload_attrs.payload_attributes.timestamp) { - // After Holocene activation, the base fee parameters are stored in the - // `extraData` field of the parent header. If Holocene wasn't active in the - // parent block, the default base fee parameters are used. - config - .is_holocene_active(parent_header.timestamp) - .then(|| decode_holocene_eip_1559_params(parent_header)) - .transpose()? - .unwrap_or(config.chain_op_config.as_canyon_base_fee_params()) - } else if config.is_canyon_active(payload_attrs.payload_attributes.timestamp) { - // If the payload attribute timestamp is past canyon activation, - // use the canyon base fee params from the rollup config. - config.chain_op_config.as_canyon_base_fee_params() - } else { - // If the payload attribute timestamp is prior to canyon activation, - // use the default base fee params from the rollup config. - config.chain_op_config.as_base_fee_params() - }; - - Ok(base_fee_params) - } - - /// Prepares a [TxEnv] with the given [OpTxEnvelope]. - /// - /// ## Takes - /// - `transaction`: The transaction to prepare the environment for. - /// - `env`: The transaction environment to prepare. - /// - /// ## Returns - /// - `Ok(())` if the environment was successfully prepared. - /// - `Err(_)` if an error occurred while preparing the environment. - pub(crate) fn prepare_tx_env( - transaction: &OpTxEnvelope, - encoded_transaction: &[u8], - ) -> ExecutorResult { - let mut env = TxEnv::default(); - match transaction { - OpTxEnvelope::Legacy(signed_tx) => { - let tx = signed_tx.tx(); - env.caller = signed_tx.recover_signer().map_err(ExecutorError::SignatureError)?; - env.gas_limit = tx.gas_limit; - env.gas_price = U256::from(tx.gas_price); - env.gas_priority_fee = None; - env.transact_to = match tx.to { - TxKind::Call(to) => TransactTo::Call(to), - TxKind::Create => TransactTo::Create, - }; - env.value = tx.value; - env.data = tx.input.clone(); - env.chain_id = tx.chain_id; - env.nonce = Some(tx.nonce); - env.access_list.clear(); - env.blob_hashes.clear(); - env.max_fee_per_blob_gas.take(); - env.optimism = OptimismFields { - source_hash: None, - mint: None, - is_system_transaction: Some(false), - enveloped_tx: Some(encoded_transaction.to_vec().into()), - }; - Ok(env) - } - OpTxEnvelope::Eip2930(signed_tx) => { - let tx = signed_tx.tx(); - env.caller = signed_tx.recover_signer().map_err(ExecutorError::SignatureError)?; - env.gas_limit = tx.gas_limit; - env.gas_price = U256::from(tx.gas_price); - env.gas_priority_fee = None; - env.transact_to = match tx.to { - TxKind::Call(to) => TransactTo::Call(to), - TxKind::Create => TransactTo::Create, - }; - env.value = tx.value; - env.data = tx.input.clone(); - env.chain_id = Some(tx.chain_id); - env.nonce = Some(tx.nonce); - env.access_list = tx.access_list.to_vec(); - env.blob_hashes.clear(); - env.max_fee_per_blob_gas.take(); - env.optimism = OptimismFields { - source_hash: None, - mint: None, - is_system_transaction: Some(false), - enveloped_tx: Some(encoded_transaction.to_vec().into()), - }; - Ok(env) - } - OpTxEnvelope::Eip1559(signed_tx) => { - let tx = signed_tx.tx(); - env.caller = signed_tx.recover_signer().map_err(ExecutorError::SignatureError)?; - env.gas_limit = tx.gas_limit; - env.gas_price = U256::from(tx.max_fee_per_gas); - env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); - env.transact_to = match tx.to { - TxKind::Call(to) => TransactTo::Call(to), - TxKind::Create => TransactTo::Create, - }; - env.value = tx.value; - env.data = tx.input.clone(); - env.chain_id = Some(tx.chain_id); - env.nonce = Some(tx.nonce); - env.access_list = tx.access_list.to_vec(); - env.blob_hashes.clear(); - env.max_fee_per_blob_gas.take(); - env.optimism = OptimismFields { - source_hash: None, - mint: None, - is_system_transaction: Some(false), - enveloped_tx: Some(encoded_transaction.to_vec().into()), - }; - Ok(env) - } - OpTxEnvelope::Eip7702(signed_tx) => { - let tx = signed_tx.tx(); - env.caller = signed_tx.recover_signer().map_err(ExecutorError::SignatureError)?; - env.gas_limit = tx.gas_limit; - env.gas_price = U256::from(tx.max_fee_per_gas); - env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); - env.transact_to = TransactTo::Call(tx.to); - env.value = tx.value; - env.data = tx.input.clone(); - env.chain_id = Some(tx.chain_id); - env.nonce = Some(tx.nonce); - env.access_list = tx.access_list.to_vec(); - env.blob_hashes.clear(); - env.max_fee_per_blob_gas.take(); - env.authorization_list = - Some(AuthorizationList::Signed(tx.authorization_list.to_vec())); - env.optimism = OptimismFields { - source_hash: None, - mint: None, - is_system_transaction: Some(false), - enveloped_tx: Some(encoded_transaction.to_vec().into()), - }; - Ok(env) - } - OpTxEnvelope::Deposit(tx) => { - env.caller = tx.from; - env.access_list.clear(); - env.gas_limit = tx.gas_limit; - env.gas_price = U256::ZERO; - env.gas_priority_fee = None; - match tx.to { - TxKind::Call(to) => env.transact_to = TransactTo::Call(to), - TxKind::Create => env.transact_to = TransactTo::Create, - } - env.value = tx.value; - env.data = tx.input.clone(); - env.chain_id = None; - env.nonce = None; - env.optimism = OptimismFields { - source_hash: Some(tx.source_hash), - mint: tx.mint, - is_system_transaction: Some(tx.is_system_transaction), - enveloped_tx: Some(encoded_transaction.to_vec().into()), - }; - Ok(env) - } - } - } -} diff --git a/crates/proof/executor/src/executor/mod.rs b/crates/proof/executor/src/executor/mod.rs deleted file mode 100644 index 333845aba0..0000000000 --- a/crates/proof/executor/src/executor/mod.rs +++ /dev/null @@ -1,551 +0,0 @@ -//! A stateless block executor for the OP Stack. - -use crate::{ - ExecutorError, ExecutorResult, TrieDBProvider, - constants::{L2_TO_L1_BRIDGE, OUTPUT_ROOT_VERSION, SHA256_EMPTY}, - db::TrieDB, - errors::TrieDBError, - syscalls::{ - ensure_create2_deployer_canyon, pre_block_beacon_root_contract_call, - pre_block_block_hash_contract_call, - }, -}; -use alloc::{string::ToString, vec::Vec}; -use alloy_consensus::{ - EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH, Header, Sealable, Sealed, Transaction, -}; -use alloy_eips::eip2718::{Decodable2718, Encodable2718}; -use alloy_primitives::{B256, Bytes, Log, U256, keccak256, logs_bloom}; -use kona_genesis::RollupConfig; -use kona_mpt::{TrieHinter, ordered_trie_with_encoder}; -use op_alloy_consensus::{OpReceiptEnvelope, OpTxEnvelope}; -use op_alloy_rpc_types_engine::OpPayloadAttributes; -use revm::{ - Evm, - db::{State, states::bundle_state::BundleRetention}, - primitives::{EnvWithHandlerCfg, calc_excess_blob_gas}, -}; - -mod builder; -pub use builder::{KonaHandleRegister, StatelessL2BlockExecutorBuilder}; - -mod env; - -mod util; -use util::encode_holocene_eip_1559_params; - -/// The [ExecutionArtifacts] holds the produced block header and receipts from the execution of a -/// block. -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct ExecutionArtifacts { - /// The block header. - pub block_header: Sealed
, - /// The receipts generated during execution. - pub receipts: Vec, -} - -/// The block executor for the L2 client program. Operates off of a [TrieDB] backed [State], -/// allowing for stateless block execution of OP Stack blocks. -#[derive(Debug)] -pub struct StatelessL2BlockExecutor<'a, F, H> -where - F: TrieDBProvider, - H: TrieHinter, -{ - /// The [RollupConfig]. - config: &'a RollupConfig, - /// The inner state database component. - trie_db: TrieDB, - /// The [KonaHandleRegister] to use during execution. - handler_register: Option>, -} - -impl<'a, F, H> StatelessL2BlockExecutor<'a, F, H> -where - F: TrieDBProvider, - H: TrieHinter, -{ - /// Constructs a new [StatelessL2BlockExecutorBuilder] with the given [RollupConfig]. - pub fn builder( - config: &'a RollupConfig, - provider: F, - hinter: H, - ) -> StatelessL2BlockExecutorBuilder<'a, F, H> { - StatelessL2BlockExecutorBuilder::new(config, provider, hinter) - } - - /// Fetches the L2 to L1 message passer account from the cache or underlying trie. - fn message_passer_account( - db: &mut TrieDB, - block_number: u64, - ) -> Result { - match db.storage_roots().get(&L2_TO_L1_BRIDGE) { - Some(storage_root) => Ok(storage_root.blind()), - None => Ok(db - .get_trie_account(&L2_TO_L1_BRIDGE, block_number)? - .ok_or(TrieDBError::MissingAccountInfo)? - .storage_root), - } - } - - /// Executes the given block, returning the resulting state root. - /// - /// ## Steps - /// 1. Prepare the block environment. - /// 2. Apply the pre-block EIP-4788 contract call. - /// 3. Prepare the EVM with the given L2 execution payload in the block environment. - /// - Reject any EIP-4844 transactions, as they are not supported on the OP Stack. - /// - If the transaction is a deposit, cache the depositor account prior to execution. - /// - Construct the EVM with the given configuration. - /// - Execute the transaction. - /// - Accumulate the gas used by the transaction to the block-scoped cumulative gas used - /// counter. - /// - Create a receipt envelope for the transaction. - /// 4. Merge all state transitions into the cache state. - /// 5. Compute the [state root, transactions root, receipts root, logs bloom] for the processed - /// block. - pub fn execute_payload( - &mut self, - payload: OpPayloadAttributes, - ) -> ExecutorResult { - // Prepare the `revm` environment. - let base_fee_params = Self::active_base_fee_params( - self.config, - self.trie_db.parent_block_header(), - &payload, - )?; - let initialized_block_env = Self::prepare_block_env( - self.config.spec_id(payload.payload_attributes.timestamp), - self.trie_db.parent_block_header(), - &payload, - &base_fee_params, - )?; - let initialized_cfg = self.evm_cfg_env(payload.payload_attributes.timestamp); - let block_number = initialized_block_env.number.to::(); - let base_fee = initialized_block_env.basefee.to::(); - let gas_limit = payload.gas_limit.ok_or(ExecutorError::MissingGasLimit)?; - let transactions = - payload.transactions.as_ref().ok_or(ExecutorError::MissingTransactions)?; - - info!( - target: "client_executor", - "Executing block # {block_number} | Gas limit: {gas_limit} | Tx count: {tx_len}", - block_number = block_number, - gas_limit = gas_limit, - tx_len = transactions.len(), - ); - - let parent_block_hash: B256 = self.trie_db.parent_block_header().seal(); - - // Attempt to send a payload witness hint to the host. This hint instructs the host to - // populate its preimage store with the preimages required to statelessly execute - // this payload. This feature is experimental, so if the hint fails, we continue - // without it and fall back on on-demand preimage fetching for execution. - self.trie_db - .hinter - .hint_execution_witness(parent_block_hash, &payload) - .map_err(|e| TrieDBError::Provider(e.to_string()))?; - - let mut state = - State::builder().with_database(&mut self.trie_db).with_bundle_update().build(); - - // Apply the pre-block EIP-4788 contract call. - pre_block_beacon_root_contract_call( - &mut state, - self.config, - block_number, - &initialized_cfg, - &initialized_block_env, - &payload, - )?; - - // Apply the pre-block EIP-2935 contract call. - pre_block_block_hash_contract_call( - &mut state, - self.config, - block_number, - &initialized_cfg, - &initialized_block_env, - parent_block_hash, - &payload, - )?; - - // Ensure that the create2 contract is deployed upon transition to the Canyon hardfork. - ensure_create2_deployer_canyon( - &mut state, - self.config, - payload.payload_attributes.timestamp, - )?; - - let mut cumulative_gas_used = 0u64; - let mut receipts: Vec = Vec::with_capacity(transactions.len()); - let is_regolith = self.config.is_regolith_active(payload.payload_attributes.timestamp); - - // Construct the block-scoped EVM with the given configuration. - // The transaction environment is set within the loop for each transaction. - let mut evm = { - let mut base = Evm::builder().with_db(&mut state).with_env_with_handler_cfg( - EnvWithHandlerCfg::new_with_cfg_env( - initialized_cfg.clone(), - initialized_block_env.clone(), - Default::default(), - ), - ); - - // If a handler register is provided, append it to the base EVM. - if let Some(handler) = self.handler_register { - base = base.append_handler_register(handler); - } - - base.build() - }; - - let is_isthmus = self.config.is_isthmus_active(payload.payload_attributes.timestamp); - - // Execute the transactions in the payload. - let decoded_txs = transactions - .iter() - .map(|raw_tx| { - let tx = OpTxEnvelope::decode_2718(&mut raw_tx.as_ref()) - .map_err(ExecutorError::RLPError)?; - Ok((tx, raw_tx.as_ref())) - }) - .collect::>>()?; - for (transaction, raw_transaction) in decoded_txs { - // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior, - // must be no greater than the block’s gasLimit. - let block_available_gas = (gas_limit - cumulative_gas_used) as u128; - if (transaction.gas_limit() as u128) > block_available_gas && - (is_regolith || !transaction.is_system_transaction()) - { - return Err(ExecutorError::BlockGasLimitExceeded); - } - - // Prevent EIP-7702 transactions pre-isthmus hardfork. - if !is_isthmus && matches!(transaction, OpTxEnvelope::Eip7702(_)) { - return Err(ExecutorError::UnsupportedTransactionType(transaction.tx_type() as u8)); - } - - // Modify the transaction environment with the current transaction. - evm = evm - .modify() - .with_tx_env(Self::prepare_tx_env(&transaction, raw_transaction)?) - .build(); - - // If the transaction is a deposit, cache the depositor account. - // - // This only needs to be done post-Regolith, as deposit nonces were not included in - // Bedrock. In addition, non-deposit transactions do not have deposit - // nonces. - let depositor = is_regolith - .then(|| { - if let OpTxEnvelope::Deposit(deposit) = &transaction { - evm.db_mut().load_cache_account(deposit.from).ok().cloned() - } else { - None - } - }) - .flatten(); - - // Execute the transaction. - let tx_hash = keccak256(raw_transaction); - debug!( - target: "client_executor", - "Executing transaction: {tx_hash}", - ); - let result = evm.transact_commit().map_err(ExecutorError::ExecutionError)?; - debug!( - target: "client_executor", - "Transaction executed: {tx_hash} | Gas used: {gas_used} | Success: {status}", - gas_used = result.gas_used(), - status = result.is_success() - ); - - // Accumulate the gas used by the transaction. - cumulative_gas_used += result.gas_used(); - - // Create receipt envelope. - let receipt = OpReceiptEnvelope::::from_parts( - result.is_success(), - cumulative_gas_used, - result.logs(), - transaction.tx_type(), - depositor - .as_ref() - .map(|depositor| depositor.account_info().unwrap_or_default().nonce), - depositor - .is_some() - .then(|| { - self.config - .is_canyon_active(payload.payload_attributes.timestamp) - .then_some(1) - }) - .flatten(), - ); - // Ensure the receipt is not an EIP-7702 receipt. - if matches!(receipt, OpReceiptEnvelope::Eip7702(_)) && !is_isthmus { - panic!( - "EIP-7702 receipts are not supported by the fault proof program before Isthmus" - ); - } - receipts.push(receipt); - } - - info!( - target: "client_executor", - "Transaction execution complete | Cumulative gas used: {cumulative_gas_used}", - cumulative_gas_used = cumulative_gas_used - ); - - // Drop the EVM to free the exclusive reference to the database. - drop(evm); - - // Merge all state transitions into the cache state. - debug!(target: "client_executor", "Merging state transitions"); - state.merge_transitions(BundleRetention::Reverts); - - // Take the bundle state. - let bundle = state.take_bundle(); - - // Recompute the header roots. - let state_root = state.database.state_root(&bundle)?; - - let transactions_root = Self::compute_transactions_root(transactions.as_slice()); - let receipts_root = Self::compute_receipts_root( - &receipts, - self.config, - payload.payload_attributes.timestamp, - ); - debug!( - target: "client_executor", - "Computed transactions root: {transactions_root} | receipts root: {receipts_root}", - ); - - // The withdrawals root on OP Stack chains, after Canyon activation, is always the empty - // root hash. - let mut withdrawals_root = self - .config - .is_canyon_active(payload.payload_attributes.timestamp) - .then_some(EMPTY_ROOT_HASH); - - // If the Isthmus hardfork is active, the withdrawals root is the L2 to L1 message passer - // account. - if self.config.is_isthmus_active(payload.payload_attributes.timestamp) { - withdrawals_root = Some(Self::message_passer_account(state.database, block_number)?); - } - - // Compute logs bloom filter for the block. - let logs_bloom = logs_bloom(receipts.iter().flat_map(|receipt| receipt.logs())); - - // Compute Cancun fields, if active. - let (blob_gas_used, excess_blob_gas) = self - .config - .is_ecotone_active(payload.payload_attributes.timestamp) - .then(|| { - let parent_header = state.database.parent_block_header(); - let excess_blob_gas = if self.config.is_ecotone_active(parent_header.timestamp) { - let parent_excess_blob_gas = parent_header.excess_blob_gas.unwrap_or_default(); - let parent_blob_gas_used = parent_header.blob_gas_used.unwrap_or_default(); - - calc_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used, 0) - } else { - // For the first post-fork block, both blob gas fields are evaluated to 0. - calc_excess_blob_gas(0, 0, 0) - }; - - (Some(0), Some(excess_blob_gas as u128)) - }) - .unwrap_or_default(); - - // At holocene activation, the base fee parameters from the payload are placed - // into the Header's `extra_data` field. - // - // If the payload's `eip_1559_params` are equal to `0`, then the header's `extraData` - // field is set to the encoded canyon base fee parameters. - let encoded_base_fee_params = self - .config - .is_holocene_active(payload.payload_attributes.timestamp) - .then(|| encode_holocene_eip_1559_params(self.config, &payload)) - .transpose()? - .unwrap_or_default(); - - // Compute the parent hash. - let parent_hash = state.database.parent_block_header().seal(); - - let requests_hash = self - .config - .is_isthmus_active(payload.payload_attributes.timestamp) - .then_some(SHA256_EMPTY); - - // Construct the new header. - let header = Header { - parent_hash, - ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: payload.payload_attributes.suggested_fee_recipient, - state_root, - transactions_root, - receipts_root, - withdrawals_root, - requests_hash, - logs_bloom, - difficulty: U256::ZERO, - number: block_number, - gas_limit, - gas_used: cumulative_gas_used, - timestamp: payload.payload_attributes.timestamp, - mix_hash: payload.payload_attributes.prev_randao, - nonce: Default::default(), - base_fee_per_gas: base_fee.try_into().ok(), - blob_gas_used, - excess_blob_gas: excess_blob_gas.and_then(|x| x.try_into().ok()), - parent_beacon_block_root: payload.payload_attributes.parent_beacon_block_root, - extra_data: encoded_base_fee_params, - } - .seal_slow(); - - info!( - target: "client_executor", - "Sealed new header | Hash: {header_hash} | State root: {state_root} | Transactions root: {transactions_root} | Receipts root: {receipts_root}", - header_hash = header.seal(), - state_root = header.state_root, - transactions_root = header.transactions_root, - receipts_root = header.receipts_root, - ); - - // Update the parent block hash in the state database. - state.database.set_parent_block_header(header.clone()); - Ok(ExecutionArtifacts { block_header: header, receipts }) - } - - /// Computes the current output root of the executor, based on the parent header and the - /// state's underlying trie. - /// - /// **CONSTRUCTION:** - /// ```text - /// output_root = keccak256(version_byte .. payload) - /// payload = state_root .. withdrawal_storage_root .. latest_block_hash - /// ``` - /// - /// ## Returns - /// - `Ok(output_root)`: The computed output root. - /// - `Err(_)`: If an error occurred while computing the output root. - pub fn compute_output_root(&mut self) -> ExecutorResult { - let parent_number = self.trie_db.parent_block_header().number; - let storage_root = Self::message_passer_account(&mut self.trie_db, parent_number)?; - let parent_header = self.trie_db.parent_block_header(); - - info!( - target: "client_executor", - "Computing output root | Version: {version} | State root: {state_root} | Storage root: {storage_root} | Block hash: {hash}", - version = OUTPUT_ROOT_VERSION, - state_root = self.trie_db.parent_block_header().state_root, - hash = parent_header.seal(), - ); - - // Construct the raw output. - let mut raw_output = [0u8; 128]; - raw_output[31] = OUTPUT_ROOT_VERSION; - raw_output[32..64].copy_from_slice(parent_header.state_root.as_ref()); - raw_output[64..96].copy_from_slice(storage_root.as_ref()); - raw_output[96..128].copy_from_slice(parent_header.seal().as_ref()); - let output_root = keccak256(raw_output); - - info!( - target: "client_executor", - "Computed output root for block # {block_number} | Output root: {output_root}", - block_number = parent_number, - ); - - // Hash the output and return - Ok(output_root) - } - - /// Computes the receipts root from the given set of receipts. - /// - /// ## Takes - /// - `receipts`: The receipts to compute the root for. - /// - `config`: The rollup config to use for the computation. - /// - `timestamp`: The timestamp to use for the computation. - /// - /// ## Returns - /// The computed receipts root. - fn compute_receipts_root( - receipts: &[OpReceiptEnvelope], - config: &RollupConfig, - timestamp: u64, - ) -> B256 { - // There is a minor bug in op-geth and op-erigon where in the Regolith hardfork, - // the receipt root calculation does not inclide the deposit nonce in the - // receipt encoding. In the Regolith hardfork, we must strip the deposit nonce - // from the receipt encoding to match the receipt root calculation. - if config.is_regolith_active(timestamp) && !config.is_canyon_active(timestamp) { - let receipts = receipts - .iter() - .cloned() - .map(|receipt| match receipt { - OpReceiptEnvelope::Deposit(mut deposit_receipt) => { - deposit_receipt.receipt.deposit_nonce = None; - OpReceiptEnvelope::Deposit(deposit_receipt) - } - _ => receipt, - }) - .collect::>(); - - ordered_trie_with_encoder(receipts.as_ref(), |receipt, mut buf| { - receipt.encode_2718(&mut buf) - }) - .root() - } else { - ordered_trie_with_encoder(receipts, |receipt, mut buf| receipt.encode_2718(&mut buf)) - .root() - } - } - - /// Computes the transactions root from the given set of encoded transactions. - /// - /// ## Takes - /// - `transactions`: The transactions to compute the root for. - /// - /// ## Returns - /// The computed transactions root. - fn compute_transactions_root(transactions: &[Bytes]) -> B256 { - ordered_trie_with_encoder(transactions, |tx, buf| buf.put_slice(tx.as_ref())).root() - } -} - -#[cfg(test)] -mod test { - use crate::test_utils::run_test_fixture; - use rstest::rstest; - use std::path::PathBuf; - - // To create new test fixtures, uncomment the following test and run it with parameters filled. - // - // #[tokio::test(flavor = "multi_thread")] - // async fn create_fixture() { - // let fixture_creator = crate::test_utils::ExecutorTestFixtureCreator::new( - // "", - // , - // PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata"), - // ); - // fixture_creator.create_static_fixture().await; - // } - - #[rstest] - #[case::small_block(10311000)] // Unichain Mainnet - #[case::small_block_2(10211000)] // Unichain Mainnet - #[case::small_block_3(10215000)] // Unichain Mainnet - #[case::medium_block_1(132795025)] // OP Mainnet - #[case::medium_block_2(132796000)] // OP Mainnet - #[case::medium_block_3(132797000)] // OP Mainnet - #[case::medium_block_4(132798000)] // OP Mainnet - #[case::medium_block_5(132799000)] // OP Mainnet - #[tokio::test] - async fn test_statelessly_execute_block(#[case] block_number: u64) { - let fixture_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("testdata") - .join(format!("block-{block_number}.tar.gz")); - - run_test_fixture(fixture_dir).await; - } -} diff --git a/crates/proof/executor/src/lib.rs b/crates/proof/executor/src/lib.rs index 9e602fbe98..fee0c87d9e 100644 --- a/crates/proof/executor/src/lib.rs +++ b/crates/proof/executor/src/lib.rs @@ -12,20 +12,18 @@ extern crate alloc; #[macro_use] extern crate tracing; +mod db; +pub use db::{NoopTrieDBProvider, TrieDB, TrieDBProvider}; + +mod builder; +pub use builder::{BlockBuildingOutcome, StatelessL2Builder}; + mod errors; pub use errors::{ExecutorError, ExecutorResult, TrieDBError, TrieDBResult}; -mod executor; -pub use executor::{ - ExecutionArtifacts, KonaHandleRegister, StatelessL2BlockExecutor, - StatelessL2BlockExecutorBuilder, -}; - -mod db; -pub use db::{NoopTrieDBProvider, TrieDB, TrieDBProvider}; +pub(crate) mod util; -mod constants; -mod syscalls; +pub(crate) mod constants; #[cfg(test)] mod test_utils; diff --git a/crates/proof/executor/src/syscalls/canyon.rs b/crates/proof/executor/src/syscalls/canyon.rs deleted file mode 100644 index 7c1c4302ff..0000000000 --- a/crates/proof/executor/src/syscalls/canyon.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Contains logic specific to Canyon hardfork activation. - -use crate::{TrieDBProvider, db::TrieDB, errors::ExecutorResult}; -use alloy_primitives::{Address, B256, Bytes, address, b256, hex}; -use kona_genesis::RollupConfig; -use kona_mpt::TrieHinter; -use revm::{ - DatabaseCommit, State, - primitives::{Account, Bytecode, HashMap}, -}; - -/// The address of the create2 deployer -const CREATE_2_DEPLOYER_ADDR: Address = address!("13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"); - -/// The codehash of the create2 deployer contract. -const CREATE_2_DEPLOYER_CODEHASH: B256 = - b256!("b0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2"); - -/// The raw bytecode of the create2 deployer contract. -const CREATE_2_DEPLOYER_BYTECODE: [u8; 1584] = hex!( - "6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033" -); - -/// The Canyon hardfork issues an irregular state transition that force-deploys the create2 -/// deployer contract. This is done by directly setting the code of the create2 deployer account -/// prior to executing any transactions on the timestamp activation of the fork. -pub(crate) fn ensure_create2_deployer_canyon( - db: &mut State<&mut TrieDB>, - config: &RollupConfig, - timestamp: u64, -) -> ExecutorResult<()> -where - F: TrieDBProvider, - H: TrieHinter, -{ - // If the canyon hardfork is active at the current timestamp, and it was not active at the - // previous block timestamp, then we need to force-deploy the create2 deployer contract. - if config.is_canyon_active(timestamp) && - !config.is_canyon_active(db.database.parent_block_header().timestamp) - { - // Load the create2 deployer account from the cache. - let acc = db.load_cache_account(CREATE_2_DEPLOYER_ADDR)?; - - // Update the account info with the create2 deployer codehash and bytecode. - let mut acc_info = acc.account_info().unwrap_or_default(); - acc_info.code_hash = CREATE_2_DEPLOYER_CODEHASH; - acc_info.code = Some(Bytecode::new_raw(Bytes::from_static(&CREATE_2_DEPLOYER_BYTECODE))); - - // Convert the cache account back into a revm account and mark it as touched. - let mut revm_acc: Account = acc_info.into(); - revm_acc.mark_touch(); - - // Commit the create2 deployer account to the database. - db.commit(HashMap::from_iter([(CREATE_2_DEPLOYER_ADDR, revm_acc)])); - return Ok(()); - } - - Ok(()) -} diff --git a/crates/proof/executor/src/syscalls/eip2935.rs b/crates/proof/executor/src/syscalls/eip2935.rs deleted file mode 100644 index be300a739a..0000000000 --- a/crates/proof/executor/src/syscalls/eip2935.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! Contains the [EIP-2935][eip-2935] syscall. -//! -//! [eip-2935]: https://eips.ethereum.org/EIPS/eip-2935 - -use crate::{ - TrieDBProvider, - db::TrieDB, - errors::{ExecutorError, ExecutorResult}, - syscalls::fill_tx_env_for_contract_call, -}; -use alloc::boxed::Box; -use alloy_primitives::B256; -use kona_genesis::RollupConfig; -use kona_mpt::TrieHinter; -use op_alloy_rpc_types_engine::OpPayloadAttributes; -use revm::{ - DatabaseCommit, Evm, - db::State, - primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg}, -}; - -/// Execute the [EIP-2935][EIP-2935] pre-block block hash contract call. -/// -/// If Isthmus is not activated, or the block is the genesis block, then this is a no-op, and no -/// state changes are made. -/// -/// Note: this does not commit the state changes to the database, it only transact the call. -/// -/// Returns `None` if Isthmus is not active or the block is the genesis block, otherwise returns the -/// result of the call. -/// -/// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935 -pub(crate) fn pre_block_block_hash_contract_call( - db: &mut State<&mut TrieDB>, - config: &RollupConfig, - block_number: u64, - initialized_cfg: &CfgEnvWithHandlerCfg, - initialized_block_env: &BlockEnv, - parent_block_hash: B256, - payload: &OpPayloadAttributes, -) -> ExecutorResult<()> -where - F: TrieDBProvider, - H: TrieHinter, -{ - // apply pre-block EIP-2935 contract call - let mut evm_pre_block = Evm::builder() - .with_db(db) - .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( - initialized_cfg.clone(), - initialized_block_env.clone(), - Default::default(), - )) - .build(); - - // initialize a block from the env, because the pre block call needs the block itself - apply_block_hash_contract_call( - config, - payload.payload_attributes.timestamp, - block_number, - parent_block_hash, - &mut evm_pre_block, - ) -} - -/// Apply the EIP-2935 pre-block block hash accumulator contract call to a given EVM instance. -fn apply_block_hash_contract_call( - config: &RollupConfig, - timestamp: u64, - block_number: u64, - parent_block_hash: B256, - evm: &mut Evm<'_, (), &mut State<&mut TrieDB>>, -) -> ExecutorResult<()> -where - F: TrieDBProvider, - H: TrieHinter, -{ - if !config.is_isthmus_active(timestamp) { - return Ok(()); - } - - // If the block number is zero (genesis block) then no system - // transaction may occur as per EIP-2935. - if block_number == 0 { - return Ok(()); - } - - // Get the previous environment - let previous_env = Box::new(evm.context.evm.env().clone()); - - // modify env for pre block call - fill_tx_env_for_contract_call( - &mut evm.context.evm.env, - alloy_eips::eip4788::SYSTEM_ADDRESS, - alloy_eips::eip2935::HISTORY_STORAGE_ADDRESS, - parent_block_hash.into(), - ); - - let mut state = match evm.transact() { - Ok(res) => res.state, - Err(e) => { - evm.context.evm.env = previous_env; - return Err(ExecutorError::ExecutionError(e)); - } - }; - - // NOTE: Revm currently marks these accounts as "touched" when we do the above transact calls, - // and includes them in the result. - // - // There should be no state changes to these addresses anyways as a result of this system call, - // so we can just remove them from the state returned. - state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS); - state.remove(&evm.block().coinbase); - - evm.context.evm.db.commit(state); - - // re-set the previous env - evm.context.evm.env = previous_env; - - Ok(()) -} diff --git a/crates/proof/executor/src/syscalls/eip4788.rs b/crates/proof/executor/src/syscalls/eip4788.rs deleted file mode 100644 index e3c901b632..0000000000 --- a/crates/proof/executor/src/syscalls/eip4788.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Contains the logic for executing the pre-block beacon root call. - -use crate::{ - TrieDBProvider, - db::TrieDB, - errors::{ExecutorError, ExecutorResult}, - syscalls::fill_tx_env_for_contract_call, -}; -use alloc::boxed::Box; -use alloy_primitives::B256; -use kona_genesis::RollupConfig; -use kona_mpt::TrieHinter; -use op_alloy_rpc_types_engine::OpPayloadAttributes; -use revm::{ - DatabaseCommit, Evm, - db::State, - primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg}, -}; - -/// Execute the EIP-4788 pre-block beacon root contract call. -pub(crate) fn pre_block_beacon_root_contract_call( - db: &mut State<&mut TrieDB>, - config: &RollupConfig, - block_number: u64, - initialized_cfg: &CfgEnvWithHandlerCfg, - initialized_block_env: &BlockEnv, - payload: &OpPayloadAttributes, -) -> ExecutorResult<()> -where - F: TrieDBProvider, - H: TrieHinter, -{ - // apply pre-block EIP-4788 contract call - let mut evm_pre_block = Evm::builder() - .with_db(db) - .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( - initialized_cfg.clone(), - initialized_block_env.clone(), - Default::default(), - )) - .build(); - - // initialize a block from the env, because the pre block call needs the block itself - apply_beacon_root_contract_call( - config, - payload.payload_attributes.timestamp, - block_number, - payload.payload_attributes.parent_beacon_block_root, - &mut evm_pre_block, - ) -} - -/// Apply the EIP-4788 pre-block beacon root contract call to a given EVM instance. -fn apply_beacon_root_contract_call( - config: &RollupConfig, - timestamp: u64, - block_number: u64, - parent_beacon_block_root: Option, - evm: &mut Evm<'_, (), &mut State<&mut TrieDB>>, -) -> ExecutorResult<()> -where - F: TrieDBProvider, - H: TrieHinter, -{ - if !config.is_ecotone_active(timestamp) { - return Ok(()); - } - - let parent_beacon_block_root = - parent_beacon_block_root.ok_or(ExecutorError::MissingParentBeaconBlockRoot)?; - - // if the block number is zero (genesis block) then the parent beacon block root must - // be 0x0 and no system transaction may occur as per EIP-4788 - if block_number == 0 { - if parent_beacon_block_root != B256::ZERO { - return Err(ExecutorError::MissingParentBeaconBlockRoot); - } - return Ok(()); - } - - // Get the previous environment - let previous_env = Box::new(evm.context.evm.env().clone()); - - // modify env for pre block call - fill_tx_env_for_contract_call( - &mut evm.context.evm.env, - alloy_eips::eip4788::SYSTEM_ADDRESS, - alloy_eips::eip4788::BEACON_ROOTS_ADDRESS, - parent_beacon_block_root.0.into(), - ); - - let mut state = match evm.transact() { - Ok(res) => res.state, - Err(e) => { - evm.context.evm.env = previous_env; - return Err(ExecutorError::ExecutionError(e)); - } - }; - - state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS); - state.remove(&evm.block().coinbase); - - evm.context.evm.db.commit(state); - - // re-set the previous env - evm.context.evm.env = previous_env; - - Ok(()) -} diff --git a/crates/proof/executor/src/syscalls/mod.rs b/crates/proof/executor/src/syscalls/mod.rs deleted file mode 100644 index 2071a2e104..0000000000 --- a/crates/proof/executor/src/syscalls/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Optimism EVM System calls. - -mod eip2935; -pub(crate) use eip2935::pre_block_block_hash_contract_call; - -mod eip4788; -pub(crate) use eip4788::pre_block_beacon_root_contract_call; - -mod canyon; -pub(crate) use canyon::ensure_create2_deployer_canyon; - -mod tx_env; -pub(crate) use tx_env::fill_tx_env_for_contract_call; diff --git a/crates/proof/executor/src/syscalls/tx_env.rs b/crates/proof/executor/src/syscalls/tx_env.rs deleted file mode 100644 index f2aac0b74e..0000000000 --- a/crates/proof/executor/src/syscalls/tx_env.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Contains a helper function to fill the [`TxEnv`] for the given system call. - -use alloc::vec::Vec; -use alloy_primitives::{Address, B256, Bytes, U256}; -use revm::primitives::{Env, OptimismFields, TransactTo, TxEnv}; - -/// Fill transaction environment with the system caller and the system -/// contract address and message data. -/// -/// This is a system operation and therefore: -/// * the call must execute to completion -/// * the call does not count against the block’s gas limit -/// * the call does not follow the EIP-1559 burn semantics - no value should be transferred as part -/// of the call -/// * if no code exists at the provided address, the call will fail silently -pub(crate) fn fill_tx_env_for_contract_call( - env: &mut Env, - caller: Address, - contract: Address, - data: Bytes, -) { - env.tx = TxEnv { - caller, - transact_to: TransactTo::Call(contract), - // Explicitly set nonce to None so revm does not do any nonce checks - nonce: None, - gas_limit: 30_000_000, - value: U256::ZERO, - data, - // Setting the gas price to zero enforces that no value is transferred as part of the call, - // and that the call will not count against the block's gas limit - gas_price: U256::ZERO, - // The chain ID check is not relevant here and is disabled if set to None - chain_id: None, - // Setting the gas priority fee to None ensures the effective gas price is derived from the - // `gas_price` field, which we need to be zero - gas_priority_fee: None, - access_list: Vec::new(), - authorization_list: None, - // blob fields can be None for this tx - blob_hashes: Vec::new(), - max_fee_per_blob_gas: None, - optimism: OptimismFields { - source_hash: Some(B256::ZERO), - mint: None, - is_system_transaction: Some(false), - // The L1 fee is not charged for system transactions, submit zero bytes for the - // enveloped tx size. - enveloped_tx: Some(Bytes::default()), - }, - }; - - // ensure the block gas limit is >= the tx - env.block.gas_limit = U256::from(env.tx.gas_limit); - - // disable the base fee check for this call by setting the base fee to zero - env.block.basefee = U256::ZERO; -} diff --git a/crates/proof/executor/src/test_utils.rs b/crates/proof/executor/src/test_utils.rs index 2e8b251c60..4c8b3d0a08 100644 --- a/crates/proof/executor/src/test_utils.rs +++ b/crates/proof/executor/src/test_utils.rs @@ -2,8 +2,9 @@ #![allow(missing_docs, unused)] -use crate::{StatelessL2BlockExecutor, TrieDBProvider, constants::FEE_RECIPIENT}; +use crate::{StatelessL2Builder, TrieDBProvider}; use alloy_consensus::Header; +use alloy_op_evm::OpEvmFactory; use alloy_primitives::{B256, Bytes, Sealable}; use alloy_provider::{ Provider, RootProvider, @@ -17,6 +18,7 @@ use kona_genesis::RollupConfig; use kona_mpt::{NoopTrieHinter, TrieNode, TrieProvider}; use kona_registry::ROLLUP_CONFIGS; use op_alloy_rpc_types_engine::OpPayloadAttributes; +use op_revm::OpEvm; use rocksdb::{DB, Options}; use serde::{Deserialize, Serialize}; use std::{env::temp_dir, path::PathBuf, sync::Arc}; @@ -120,10 +122,10 @@ impl ExecutorTestFixtureCreator { let payload_attrs = OpPayloadAttributes { payload_attributes: PayloadAttributes { timestamp: executing_header.timestamp, - parent_beacon_block_root: parent_header.parent_beacon_block_root, - prev_randao: parent_header.mix_hash, + parent_beacon_block_root: executing_header.parent_beacon_block_root, + prev_randao: executing_header.mix_hash, withdrawals: Default::default(), - suggested_fee_recipient: FEE_RECIPIENT, + suggested_fee_recipient: executing_header.beneficiary, }, gas_limit: Some(executing_header.gas_limit), transactions: Some(encoded_executing_transactions), @@ -145,14 +147,17 @@ impl ExecutorTestFixtureCreator { expected_block_hash: executing_header.hash_slow(), }; - let mut executor = StatelessL2BlockExecutor::builder(rollup_config, self, NoopTrieHinter) - .with_parent_header(parent_header) - .build(); - let exec_artifacts = - executor.execute_payload(payload_attrs).expect("Failed to execute block").clone(); + let mut executor = StatelessL2Builder::new( + rollup_config, + OpEvmFactory::default(), + self, + NoopTrieHinter, + parent_header, + ); + let outcome = executor.build_block(payload_attrs).expect("Failed to execute block"); assert_eq!( - exec_artifacts.block_header.inner(), + outcome.header.inner(), &executing_header.inner, "Produced header does not match the expected header" ); @@ -342,15 +347,18 @@ pub(crate) async fn run_test_fixture(fixture_path: PathBuf) { serde_json::from_slice(&fs::read(fixture_dir.path().join("fixture.json")).await.unwrap()) .expect("Failed to deserialize fixture"); - let mut executor = - StatelessL2BlockExecutor::builder(&fixture.rollup_config, provider, NoopTrieHinter) - .with_parent_header(fixture.parent_header.seal_slow()) - .build(); + let mut executor = StatelessL2Builder::new( + &fixture.rollup_config, + OpEvmFactory::default(), + provider, + NoopTrieHinter, + fixture.parent_header.seal_slow(), + ); - let exec_artifacts = executor.execute_payload(fixture.executing_payload).unwrap(); + let outcome = executor.build_block(fixture.executing_payload).unwrap(); assert_eq!( - exec_artifacts.block_header.hash(), + outcome.header.hash(), fixture.expected_block_hash, "Produced header does not match the expected header" ); diff --git a/crates/proof/executor/src/executor/util.rs b/crates/proof/executor/src/util.rs similarity index 98% rename from crates/proof/executor/src/executor/util.rs rename to crates/proof/executor/src/util.rs index 013926a002..588762280e 100644 --- a/crates/proof/executor/src/executor/util.rs +++ b/crates/proof/executor/src/util.rs @@ -85,7 +85,7 @@ pub(crate) fn encode_canyon_base_fee_params(config: &RollupConfig) -> B64 { #[cfg(test)] mod test { use super::decode_holocene_eip_1559_params; - use crate::executor::util::{encode_canyon_base_fee_params, encode_holocene_eip_1559_params}; + use crate::util::{encode_canyon_base_fee_params, encode_holocene_eip_1559_params}; use alloy_consensus::Header; use alloy_primitives::{B64, b64, hex}; use alloy_rpc_types_engine::PayloadAttributes; diff --git a/crates/proof/executor/testdata/block-10211000.tar.gz b/crates/proof/executor/testdata/block-10211000.tar.gz deleted file mode 100644 index 9ebc64f895..0000000000 Binary files a/crates/proof/executor/testdata/block-10211000.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-10215000.tar.gz b/crates/proof/executor/testdata/block-10215000.tar.gz deleted file mode 100644 index 36b67f13a6..0000000000 Binary files a/crates/proof/executor/testdata/block-10215000.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-10311000.tar.gz b/crates/proof/executor/testdata/block-10311000.tar.gz deleted file mode 100644 index 633d34b7fd..0000000000 Binary files a/crates/proof/executor/testdata/block-10311000.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-132795025.tar.gz b/crates/proof/executor/testdata/block-132795025.tar.gz deleted file mode 100644 index 1e4a7ed770..0000000000 Binary files a/crates/proof/executor/testdata/block-132795025.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-132796000.tar.gz b/crates/proof/executor/testdata/block-132796000.tar.gz deleted file mode 100644 index 757ee9bb5c..0000000000 Binary files a/crates/proof/executor/testdata/block-132796000.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-132796100.tar.gz b/crates/proof/executor/testdata/block-132796100.tar.gz deleted file mode 100644 index 2f6628af7f..0000000000 Binary files a/crates/proof/executor/testdata/block-132796100.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-132797000.tar.gz b/crates/proof/executor/testdata/block-132797000.tar.gz deleted file mode 100644 index a25d255e27..0000000000 Binary files a/crates/proof/executor/testdata/block-132797000.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-132798000.tar.gz b/crates/proof/executor/testdata/block-132798000.tar.gz deleted file mode 100644 index 847f486ab5..0000000000 Binary files a/crates/proof/executor/testdata/block-132798000.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-132799000.tar.gz b/crates/proof/executor/testdata/block-132799000.tar.gz deleted file mode 100644 index bfb9a4feea..0000000000 Binary files a/crates/proof/executor/testdata/block-132799000.tar.gz and /dev/null differ diff --git a/crates/proof/executor/testdata/block-26207960.tar.gz b/crates/proof/executor/testdata/block-26207960.tar.gz new file mode 100644 index 0000000000..3363ed961b Binary files /dev/null and b/crates/proof/executor/testdata/block-26207960.tar.gz differ diff --git a/crates/proof/executor/testdata/block-26207961.tar.gz b/crates/proof/executor/testdata/block-26207961.tar.gz new file mode 100644 index 0000000000..798aa2ac3a Binary files /dev/null and b/crates/proof/executor/testdata/block-26207961.tar.gz differ diff --git a/crates/proof/executor/testdata/block-26207962.tar.gz b/crates/proof/executor/testdata/block-26207962.tar.gz new file mode 100644 index 0000000000..3260a40fb3 Binary files /dev/null and b/crates/proof/executor/testdata/block-26207962.tar.gz differ diff --git a/crates/proof/executor/testdata/block-26207963.tar.gz b/crates/proof/executor/testdata/block-26207963.tar.gz new file mode 100644 index 0000000000..5fd96eb30c Binary files /dev/null and b/crates/proof/executor/testdata/block-26207963.tar.gz differ diff --git a/crates/proof/executor/testdata/block-26208384.tar.gz b/crates/proof/executor/testdata/block-26208384.tar.gz new file mode 100644 index 0000000000..079ad68d3e Binary files /dev/null and b/crates/proof/executor/testdata/block-26208384.tar.gz differ diff --git a/crates/proof/executor/testdata/block-26208858.tar.gz b/crates/proof/executor/testdata/block-26208858.tar.gz new file mode 100644 index 0000000000..3b495ea85e Binary files /dev/null and b/crates/proof/executor/testdata/block-26208858.tar.gz differ diff --git a/crates/proof/executor/testdata/block-26208927.tar.gz b/crates/proof/executor/testdata/block-26208927.tar.gz new file mode 100644 index 0000000000..dc85091948 Binary files /dev/null and b/crates/proof/executor/testdata/block-26208927.tar.gz differ diff --git a/crates/proof/executor/testdata/block-26211680.tar.gz b/crates/proof/executor/testdata/block-26211680.tar.gz new file mode 100644 index 0000000000..9e669fb2eb Binary files /dev/null and b/crates/proof/executor/testdata/block-26211680.tar.gz differ diff --git a/crates/proof/proof-interop/Cargo.toml b/crates/proof/proof-interop/Cargo.toml index 3c1d658405..e176810ee2 100644 --- a/crates/proof/proof-interop/Cargo.toml +++ b/crates/proof/proof-interop/Cargo.toml @@ -31,6 +31,7 @@ alloy-rpc-types-engine.workspace = true # OP Alloy op-alloy-consensus.workspace = true op-alloy-rpc-types-engine.workspace = true +alloy-op-evm.workspace = true # General serde.workspace = true diff --git a/crates/proof/proof-interop/src/consolidation.rs b/crates/proof/proof-interop/src/consolidation.rs index 8d3222def0..a8be1a90e5 100644 --- a/crates/proof/proof-interop/src/consolidation.rs +++ b/crates/proof/proof-interop/src/consolidation.rs @@ -3,9 +3,10 @@ use crate::{BootInfo, OptimisticBlock, OracleInteropProvider, PreState}; use alloc::{boxed::Box, vec::Vec}; use alloy_consensus::{Header, Sealed}; +use alloy_op_evm::OpEvmFactory; use alloy_primitives::Sealable; use alloy_rpc_types_engine::PayloadAttributes; -use kona_executor::{ExecutorError, StatelessL2BlockExecutor}; +use kona_executor::{ExecutorError, StatelessL2Builder}; use kona_interop::{MessageGraph, MessageGraphError}; use kona_mpt::OrderedListWalker; use kona_preimage::CommsClient; @@ -160,18 +161,17 @@ where let l2_provider = self.l2_providers.get(chain_id).expect("TODO: Handle gracefully"); // Create a new stateless L2 block executor for the current chain. - let mut executor = StatelessL2BlockExecutor::builder( + let mut executor = StatelessL2Builder::new( rollup_config, + OpEvmFactory::default(), l2_provider.clone(), l2_provider.clone(), - ) - .with_parent_header(parent_header.seal_slow()) - .build(); + parent_header.seal_slow(), + ); // Execute the block and take the new header. At this point, the block is guaranteed to // be canonical. - let new_header = - executor.execute_payload(deposit_only_payload).unwrap().block_header.clone(); + let new_header = executor.build_block(deposit_only_payload).unwrap().header; let new_output_root = executor.compute_output_root().unwrap(); // Replace the original optimistic block with the deposit only block. diff --git a/crates/proof/proof/Cargo.toml b/crates/proof/proof/Cargo.toml index 1769334d71..725cd8e063 100644 --- a/crates/proof/proof/Cargo.toml +++ b/crates/proof/proof/Cargo.toml @@ -34,6 +34,11 @@ alloy-trie.workspace = true op-alloy-consensus.workspace = true op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] } +# Execution +alloy-evm.workspace = true +alloy-op-evm.workspace = true +op-revm.workspace = true + # General lru.workspace = true spin.workspace = true diff --git a/crates/proof/proof/src/executor.rs b/crates/proof/proof/src/executor.rs index a255949ed2..d797d1d43a 100644 --- a/crates/proof/proof/src/executor.rs +++ b/crates/proof/proof/src/executor.rs @@ -2,22 +2,24 @@ use alloc::boxed::Box; use alloy_consensus::{Header, Sealed}; +use alloy_evm::{EvmFactory, FromRecoveredTx, FromTxWithEncoded}; use alloy_primitives::B256; use async_trait::async_trait; use kona_driver::Executor; -use kona_executor::{ - ExecutionArtifacts, KonaHandleRegister, StatelessL2BlockExecutor, TrieDBProvider, -}; +use kona_executor::{BlockBuildingOutcome, StatelessL2Builder, TrieDBProvider}; use kona_genesis::RollupConfig; use kona_mpt::TrieHinter; +use op_alloy_consensus::OpTxEnvelope; use op_alloy_rpc_types_engine::OpPayloadAttributes; +use op_revm::OpSpecId; /// An executor wrapper type. #[derive(Debug)] -pub struct KonaExecutor<'a, P, H> +pub struct KonaExecutor<'a, P, H, Evm> where P: TrieDBProvider + Send + Sync + Clone, H: TrieHinter + Send + Sync + Clone, + Evm: EvmFactory + Send + Sync + Clone, { /// The rollup config for the executor. rollup_config: &'a RollupConfig, @@ -25,34 +27,37 @@ where trie_provider: P, /// The trie hinter for the executor. trie_hinter: H, - /// The handle register for the executor. - handle_register: Option>, + /// The evm factory for the executor. + evm_factory: Evm, /// The executor. - inner: Option>, + inner: Option>, } -impl<'a, P, H> KonaExecutor<'a, P, H> +impl<'a, P, H, Evm> KonaExecutor<'a, P, H, Evm> where P: TrieDBProvider + Send + Sync + Clone, H: TrieHinter + Send + Sync + Clone, + Evm: EvmFactory + Send + Sync + Clone, { /// Creates a new executor. pub const fn new( rollup_config: &'a RollupConfig, trie_provider: P, trie_hinter: H, - handle_register: Option>, - inner: Option>, + evm_factory: Evm, + inner: Option>, ) -> Self { - Self { rollup_config, trie_provider, trie_hinter, handle_register, inner } + Self { rollup_config, trie_provider, trie_hinter, evm_factory, inner } } } #[async_trait] -impl Executor for KonaExecutor<'_, P, H> +impl Executor for KonaExecutor<'_, P, H, Evm> where P: TrieDBProvider + Send + Sync + Clone, H: TrieHinter + Send + Sync + Clone, + Evm: EvmFactory + Send + Sync + Clone + 'static, + ::Tx: FromTxWithEncoded + FromRecoveredTx, { type Error = kona_executor::ExecutorError; @@ -67,27 +72,23 @@ where /// Since the L2 block executor is stateless, on an update to the safe head, /// a new executor is created with the updated header. fn update_safe_head(&mut self, header: Sealed
) { - let mut builder = StatelessL2BlockExecutor::builder( + self.inner = Some(StatelessL2Builder::new( self.rollup_config, + self.evm_factory.clone(), self.trie_provider.clone(), self.trie_hinter.clone(), - ) - .with_parent_header(header); - - if let Some(register) = self.handle_register { - builder = builder.with_handle_register(register); - } - self.inner = Some(builder.build()); + header, + )); } /// Execute the given payload attributes. async fn execute_payload( &mut self, attributes: OpPayloadAttributes, - ) -> Result { + ) -> Result { self.inner.as_mut().map_or_else( || Err(kona_executor::ExecutorError::MissingExecutor), - |e| e.execute_payload(attributes), + |e| e.build_block(attributes), ) } diff --git a/crates/protocol/comp/Cargo.toml b/crates/protocol/comp/Cargo.toml index 844a2df81a..256f9274ab 100644 --- a/crates/protocol/comp/Cargo.toml +++ b/crates/protocol/comp/Cargo.toml @@ -54,7 +54,6 @@ tracing-subscriber = { workspace = true, features = ["fmt"], optional = true } [dev-dependencies] brotli = { workspace = true, features = ["std"] } -revm.workspace = true spin.workspace = true rand = { workspace = true, features = ["std", "std_rng"] } proptest.workspace = true diff --git a/crates/protocol/comp/examples/batch_to_frames.rs b/crates/protocol/comp/examples/batch_to_frames.rs index 94ba8d3a55..3a41d15a4d 100644 --- a/crates/protocol/comp/examples/batch_to_frames.rs +++ b/crates/protocol/comp/examples/batch_to_frames.rs @@ -56,7 +56,7 @@ fn main() { fn example_transactions() -> Vec { use alloy_consensus::{SignableTransaction, TxEip1559, TxEnvelope}; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; - use alloy_primitives::{Address, PrimitiveSignature, U256}; + use alloy_primitives::{Address, Signature, U256}; let mut transactions = Vec::new(); @@ -72,7 +72,7 @@ fn example_transactions() -> Vec { input: vec![8].into(), access_list: Default::default(), }; - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); @@ -93,7 +93,7 @@ fn example_transactions() -> Vec { input: vec![8].into(), access_list: Default::default(), }; - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); diff --git a/crates/protocol/derive/src/sources/calldata.rs b/crates/protocol/derive/src/sources/calldata.rs index e887367615..87a15c1eeb 100644 --- a/crates/protocol/derive/src/sources/calldata.rs +++ b/crates/protocol/derive/src/sources/calldata.rs @@ -98,7 +98,7 @@ mod tests { use crate::{errors::PipelineErrorKind, test_utils::TestChainProvider}; use alloc::{vec, vec::Vec}; use alloy_consensus::{Signed, TxEip2930, TxEip4844, TxEip4844Variant, TxEip7702, TxLegacy}; - use alloy_primitives::{Address, PrimitiveSignature as Signature, TxKind, address}; + use alloy_primitives::{Address, Signature, TxKind, address}; pub(crate) fn test_legacy_tx(to: Address) -> TxEnvelope { let sig = Signature::test_signature(); diff --git a/crates/protocol/driver/Cargo.toml b/crates/protocol/driver/Cargo.toml index cd6f713c53..881b9f4aae 100644 --- a/crates/protocol/driver/Cargo.toml +++ b/crates/protocol/driver/Cargo.toml @@ -23,6 +23,7 @@ kona-protocol.workspace = true alloy-rlp.workspace = true alloy-consensus.workspace = true alloy-primitives.workspace = true +alloy-evm.workspace = true # OP Alloy op-alloy-consensus.workspace = true diff --git a/crates/protocol/driver/src/core.rs b/crates/protocol/driver/src/core.rs index 3d22722a8f..6b11ea99d3 100644 --- a/crates/protocol/driver/src/core.rs +++ b/crates/protocol/driver/src/core.rs @@ -11,7 +11,7 @@ use kona_derive::{ traits::{Pipeline, SignalReceiver}, types::Signal, }; -use kona_executor::ExecutionArtifacts; +use kona_executor::BlockBuildingOutcome; use kona_genesis::RollupConfig; use kona_protocol::L2BlockInfo; use kona_rpc::OpAttributesWithParent; @@ -35,7 +35,7 @@ where /// A pipeline abstraction. pub pipeline: DP, /// The safe head's execution artifacts + Transactions - pub safe_head_artifacts: Option<(ExecutionArtifacts, Vec)>, + pub safe_head_artifacts: Option<(BlockBuildingOutcome, Vec)>, } impl Driver @@ -116,8 +116,8 @@ where }; self.executor.update_safe_head(tip_cursor.l2_safe_head_header.clone()); - let execution_result = match self.executor.execute_payload(attributes.clone()).await { - Ok(header) => header, + let outcome = match self.executor.execute_payload(attributes.clone()).await { + Ok(outcome) => outcome, Err(e) => { error!(target: "client", "Failed to execute L2 block: {}", e); @@ -159,7 +159,7 @@ where // Construct the block. let block = OpBlock { - header: execution_result.block_header.inner().clone(), + header: outcome.header.inner().clone(), body: BlockBody { transactions: attributes .transactions @@ -181,7 +181,7 @@ where )?; let tip_cursor = TipCursor::new( l2_info, - execution_result.block_header.clone(), + outcome.header.clone(), self.executor.compute_output_root().map_err(DriverError::Executor)?, ); @@ -190,8 +190,7 @@ where self.cursor.write().advance(origin, tip_cursor); // Update the latest safe head artifacts. - self.safe_head_artifacts = - Some((execution_result, attributes.transactions.unwrap_or_default())); + self.safe_head_artifacts = Some((outcome, attributes.transactions.unwrap_or_default())); } } } diff --git a/crates/protocol/driver/src/executor.rs b/crates/protocol/driver/src/executor.rs index d1855f5b7e..c92f8a53e7 100644 --- a/crates/protocol/driver/src/executor.rs +++ b/crates/protocol/driver/src/executor.rs @@ -1,16 +1,14 @@ //! An abstraction for the driver's block executor. -use alloc::boxed::Box; +use alloc::{boxed::Box, string::ToString}; +use alloy_consensus::{Header, Sealed}; +use alloy_primitives::B256; +use async_trait::async_trait; use core::{ error::Error, fmt::{Debug, Display}, }; -use kona_executor::ExecutionArtifacts; - -use alloc::string::ToString; -use alloy_consensus::{Header, Sealed}; -use alloy_primitives::B256; -use async_trait::async_trait; +use kona_executor::BlockBuildingOutcome; use op_alloy_rpc_types_engine::OpPayloadAttributes; /// Executor @@ -31,7 +29,7 @@ pub trait Executor { async fn execute_payload( &mut self, attributes: OpPayloadAttributes, - ) -> Result; + ) -> Result; /// Computes the output root. /// Expected to be called after the payload has been executed. diff --git a/crates/protocol/genesis/Cargo.toml b/crates/protocol/genesis/Cargo.toml index d76fb73187..c4eca2b298 100644 --- a/crates/protocol/genesis/Cargo.toml +++ b/crates/protocol/genesis/Cargo.toml @@ -20,13 +20,15 @@ alloy-sol-types.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true alloy-eips.workspace = true +alloy-hardforks.workspace = true +alloy-op-hardforks.workspace = true # Misc thiserror.workspace = true derive_more = { workspace = true, features = ["from"] } # `revm` feature -revm = { workspace = true, optional = true, features = ["optimism"] } +op-revm = { workspace = true, optional = true } # `arbitrary` feature arbitrary = { workspace = true, features = ["derive"], optional = true } @@ -45,7 +47,7 @@ alloy-primitives = { workspace = true, features = ["rand", "arbitrary"] } [features] default = [] -revm = ["dep:revm"] +revm = ["dep:op-revm"] std = [ "alloy-primitives/std", "alloy-sol-types/std", diff --git a/crates/protocol/genesis/src/rollup.rs b/crates/protocol/genesis/src/rollup.rs index 7c28b0407a..702dc5fbe7 100644 --- a/crates/protocol/genesis/src/rollup.rs +++ b/crates/protocol/genesis/src/rollup.rs @@ -1,8 +1,9 @@ //! Rollup Config Types -use alloy_primitives::Address; - use crate::{AltDAConfig, BaseFeeConfig, ChainGenesis, HardForkConfig, OP_MAINNET_BASE_FEE_CONFIG}; +use alloy_hardforks::{EthereumHardfork, EthereumHardforks, ForkCondition}; +use alloy_op_hardforks::{OpHardfork, OpHardforks}; +use alloy_primitives::Address; /// The max rlp bytes per channel for the Bedrock hardfork. pub const MAX_RLP_BYTES_PER_CHANNEL_BEDROCK: u64 = 10_000_000; @@ -159,28 +160,30 @@ impl Default for RollupConfig { #[cfg(feature = "revm")] impl RollupConfig { - /// Returns the active [`revm::primitives::SpecId`] for the executor. + /// Returns the active [`op_revm::OpSpecId`] for the executor. /// /// ## Takes /// - `timestamp`: The timestamp of the executing block. /// /// ## Returns - /// The active [`revm::primitives::SpecId`] for the executor. - pub fn spec_id(&self, timestamp: u64) -> revm::primitives::SpecId { - if self.is_isthmus_active(timestamp) { - revm::primitives::SpecId::ISTHMUS + /// The active [`op_revm::OpSpecId`] for the executor. + pub fn spec_id(&self, timestamp: u64) -> op_revm::OpSpecId { + if self.is_interop_active(timestamp) { + op_revm::OpSpecId::INTEROP + } else if self.is_isthmus_active(timestamp) { + op_revm::OpSpecId::ISTHMUS } else if self.is_holocene_active(timestamp) { - revm::primitives::SpecId::HOLOCENE + op_revm::OpSpecId::HOLOCENE } else if self.is_fjord_active(timestamp) { - revm::primitives::SpecId::FJORD + op_revm::OpSpecId::FJORD } else if self.is_ecotone_active(timestamp) { - revm::primitives::SpecId::ECOTONE + op_revm::OpSpecId::ECOTONE } else if self.is_canyon_active(timestamp) { - revm::primitives::SpecId::CANYON + op_revm::OpSpecId::CANYON } else if self.is_regolith_active(timestamp) { - revm::primitives::SpecId::REGOLITH + op_revm::OpSpecId::REGOLITH } else { - revm::primitives::SpecId::BEDROCK + op_revm::OpSpecId::BEDROCK } } } @@ -307,6 +310,77 @@ impl RollupConfig { } } +impl EthereumHardforks for RollupConfig { + fn ethereum_fork_activation(&self, fork: EthereumHardfork) -> ForkCondition { + if fork <= EthereumHardfork::Berlin { + // We assume that OP chains were launched with all forks before Berlin activated. + ForkCondition::Block(0) + } else if fork <= EthereumHardfork::Paris { + // Bedrock activates all hardforks up to Paris. + self.op_fork_activation(OpHardfork::Bedrock) + } else if fork <= EthereumHardfork::Shanghai { + // Canyon activates Shanghai hardfork. + self.op_fork_activation(OpHardfork::Canyon) + } else if fork <= EthereumHardfork::Cancun { + // Ecotone activates Cancun hardfork. + self.op_fork_activation(OpHardfork::Ecotone) + } else if fork <= EthereumHardfork::Prague { + // Isthmus activates Prague hardfork. + self.op_fork_activation(OpHardfork::Isthmus) + } else { + ForkCondition::Never + } + } +} + +impl OpHardforks for RollupConfig { + fn op_fork_activation(&self, fork: OpHardfork) -> ForkCondition { + match fork { + OpHardfork::Bedrock => ForkCondition::Block(0), + OpHardfork::Regolith => self + .hardforks + .regolith_time + .map(ForkCondition::Timestamp) + .unwrap_or(self.op_fork_activation(OpHardfork::Canyon)), + OpHardfork::Canyon => self + .hardforks + .canyon_time + .map(ForkCondition::Timestamp) + .unwrap_or(self.op_fork_activation(OpHardfork::Ecotone)), + OpHardfork::Ecotone => self + .hardforks + .ecotone_time + .map(ForkCondition::Timestamp) + .unwrap_or(self.op_fork_activation(OpHardfork::Fjord)), + OpHardfork::Fjord => self + .hardforks + .fjord_time + .map(ForkCondition::Timestamp) + .unwrap_or(self.op_fork_activation(OpHardfork::Granite)), + OpHardfork::Granite => self + .hardforks + .granite_time + .map(ForkCondition::Timestamp) + .unwrap_or(self.op_fork_activation(OpHardfork::Holocene)), + OpHardfork::Holocene => self + .hardforks + .holocene_time + .map(ForkCondition::Timestamp) + .unwrap_or(self.op_fork_activation(OpHardfork::Isthmus)), + OpHardfork::Isthmus => self + .hardforks + .isthmus_time + .map(ForkCondition::Timestamp) + .unwrap_or(self.op_fork_activation(OpHardfork::Interop)), + OpHardfork::Interop => self + .hardforks + .interop_time + .map(ForkCondition::Timestamp) + .unwrap_or(ForkCondition::Never), + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -334,18 +408,18 @@ mod tests { hardforks: HardForkConfig { regolith_time: Some(10), ..Default::default() }, ..Default::default() }; - assert_eq!(config.spec_id(0), revm::primitives::SpecId::BEDROCK); - assert_eq!(config.spec_id(10), revm::primitives::SpecId::REGOLITH); + assert_eq!(config.spec_id(0), op_revm::OpSpecId::BEDROCK); + assert_eq!(config.spec_id(10), op_revm::OpSpecId::REGOLITH); config.hardforks.canyon_time = Some(20); - assert_eq!(config.spec_id(20), revm::primitives::SpecId::CANYON); + assert_eq!(config.spec_id(20), op_revm::OpSpecId::CANYON); config.hardforks.ecotone_time = Some(30); - assert_eq!(config.spec_id(30), revm::primitives::SpecId::ECOTONE); + assert_eq!(config.spec_id(30), op_revm::OpSpecId::ECOTONE); config.hardforks.fjord_time = Some(40); - assert_eq!(config.spec_id(40), revm::primitives::SpecId::FJORD); + assert_eq!(config.spec_id(40), op_revm::OpSpecId::FJORD); config.hardforks.holocene_time = Some(50); - assert_eq!(config.spec_id(50), revm::primitives::SpecId::HOLOCENE); + assert_eq!(config.spec_id(50), op_revm::OpSpecId::HOLOCENE); config.hardforks.isthmus_time = Some(60); - assert_eq!(config.spec_id(60), revm::primitives::SpecId::ISTHMUS); + assert_eq!(config.spec_id(60), op_revm::OpSpecId::ISTHMUS); } #[test] diff --git a/crates/protocol/genesis/src/system/errors.rs b/crates/protocol/genesis/src/system/errors.rs index e1229b8c25..117957b853 100644 --- a/crates/protocol/genesis/src/system/errors.rs +++ b/crates/protocol/genesis/src/system/errors.rs @@ -58,18 +58,27 @@ pub enum BatcherUpdateError { /// Invalid data length. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLen(usize), + /// Failed to type check the data pointer argument from the batcher update log. + #[error("Failed to decode batcher update log: data pointer type check failed")] + PointerTypeCheck, /// Failed to decode the data pointer argument from the batcher update log. #[error("Failed to decode batcher update log: data pointer")] PointerDecodingError, /// The data pointer is invalid. #[error("Invalid config update log: invalid data pointer: {0}")] InvalidDataPointer(u64), + /// Failed to type check the data length argument from the batcher update log. + #[error("Failed to decode batcher update log: data length type check failed")] + LengthTypeCheck, /// Failed to decode the data length argument from the batcher update log. #[error("Failed to decode batcher update log: data length")] LengthDecodingError, /// The data length is invalid. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLength(u64), + /// Failed to type check the batcher address argument from the batcher update log. + #[error("Failed to decode batcher update log: batcher address type check failed")] + BatcherAddressTypeCheck, /// Failed to decode the batcher address argument from the batcher update log. #[error("Failed to decode batcher update log: batcher address")] BatcherAddressDecodingError, @@ -82,18 +91,29 @@ pub enum UnsafeBlockSignerUpdateError { /// Invalid data length. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLen(usize), + /// Failed to type check the data pointer argument from the update log. + #[error("Failed to decode unsafe block signer update log: data pointer type check failed")] + PointerTypeCheck, /// Failed to decode the data pointer argument from the update log. #[error("Failed to decode unsafe block signer update log: data pointer")] PointerDecodingError, /// The data pointer is invalid. #[error("Invalid config update log: invalid data pointer: {0}")] InvalidDataPointer(u64), + /// Failed to type check the data length argument from the update log. + #[error("Failed to decode unsafe block signer update log: data length type check failed")] + LengthTypeCheck, /// Failed to decode the data length argument from the update log. #[error("Failed to decode unsafe block signer update log: data length")] LengthDecodingError, /// The data length is invalid. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLength(u64), + /// Failed to type check the unsafe block signer address argument from the update log. + #[error( + "Failed to decode unsafe block signer update log: unsafe block signer address type check failed" + )] + UnsafeBlockSignerAddressTypeCheck, /// Failed to decode the unsafe block signer address argument from the update log. #[error("Failed to decode unsafe block signer update log: unsafe block signer address")] UnsafeBlockSignerAddressDecodingError, @@ -106,12 +126,18 @@ pub enum GasConfigUpdateError { /// Invalid data length. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLen(usize), + /// Failed to type check the data pointer argument from the gas config update log. + #[error("Failed to decode gas config update log: data pointer type check failed")] + PointerTypeCheck, /// Failed to decode the data pointer argument from the gas config update log. #[error("Failed to decode gas config update log: data pointer")] PointerDecodingError, /// The data pointer is invalid. #[error("Invalid config update log: invalid data pointer: {0}")] InvalidDataPointer(u64), + /// Failed to type check the data length argument from the gas config update log. + #[error("Failed to decode gas config update log: data length type check failed")] + LengthTypeCheck, /// Failed to decode the data length argument from the gas config update log. #[error("Failed to decode gas config update log: data length")] LengthDecodingError, @@ -133,12 +159,18 @@ pub enum GasLimitUpdateError { /// Invalid data length. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLen(usize), + /// Failed to type check the data pointer argument from the gas limit update log. + #[error("Failed to decode gas limit update log: data pointer type check failed")] + PointerTypeCheck, /// Failed to decode the data pointer argument from the gas limit update log. #[error("Failed to decode gas limit update log: data pointer")] PointerDecodingError, /// The data pointer is invalid. #[error("Invalid config update log: invalid data pointer: {0}")] InvalidDataPointer(u64), + /// Failed to type check the data length argument from the gas limit update log. + #[error("Failed to type check gas limit update log: data length type check failed")] + LengthTypeCheck, /// Failed to decode the data length argument from the gas limit update log. #[error("Failed to decode gas limit update log: data length")] LengthDecodingError, @@ -157,6 +189,9 @@ pub enum EIP1559UpdateError { /// Invalid data length. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLen(usize), + /// Failed to type check the data pointer argument from the eip 1559 update log. + #[error("Failed to decode eip1559 parameter update log: data pointer type check failed")] + PointerTypeCheck, /// Failed to decode the data pointer argument from the eip 1559 update log. #[error("Failed to decode eip1559 parameter update log: data pointer")] PointerDecodingError, @@ -164,11 +199,17 @@ pub enum EIP1559UpdateError { #[error("Invalid config update log: invalid data pointer: {0}")] InvalidDataPointer(u64), /// Failed to decode the data length argument from the eip 1559 update log. + #[error("Failed to decode eip1559 parameter update log: data length type check failed")] + LengthTypeCheck, + /// Failed to decode the data length argument from the eip 1559 update log. #[error("Failed to decode eip1559 parameter update log: data length")] LengthDecodingError, /// The data length is invalid. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLength(u64), + /// Failed to type check the eip1559 params argument from the eip 1559 update log. + #[error("Failed to decode eip1559 parameter update log: eip1559 parameters type check failed")] + EIP1559TypeCheckError, /// Failed to decode the eip1559 params argument from the eip 1559 update log. #[error("Failed to decode eip1559 parameter update log: eip1559 parameters")] EIP1559DecodingError, @@ -181,14 +222,20 @@ pub enum OperatorFeeUpdateError { /// Invalid data length. #[error("Invalid config update log: invalid data length: {0}")] InvalidDataLen(usize), - /// Failed to decode the data pointer argument from the eip 1559 update log. - #[error("Failed to decode eip1559 parameter update log: data pointer")] + /// Failed to type check the data pointer argument from the operator fee update log. + #[error("Failed to decode operator fee parameter update log: data pointer type check failed")] + PointerTypeCheck, + /// Failed to decode the data pointer argument from the operator fee update log. + #[error("Failed to decode operator fee parameter update log: data pointer")] PointerDecodingError, /// The data pointer is invalid. #[error("Invalid config update log: invalid data pointer: {0}")] InvalidDataPointer(u64), - /// Failed to decode the data length argument from the eip 1559 update log. - #[error("Failed to decode eip1559 parameter update log: data length")] + /// Failed to type check the data length argument from the operator fee update log. + #[error("Failed to decode operator fee parameter update log: data length type check failed")] + LengthTypeCheck, + /// Failed to decode the data length argument from the operator fee update log. + #[error("Failed to decode operator fee parameter update log: data length")] LengthDecodingError, /// The data length is invalid. #[error("Invalid config update log: invalid data length: {0}")] diff --git a/crates/protocol/genesis/src/updates/batcher.rs b/crates/protocol/genesis/src/updates/batcher.rs index e592533b2b..98132f9048 100644 --- a/crates/protocol/genesis/src/updates/batcher.rs +++ b/crates/protocol/genesis/src/updates/batcher.rs @@ -1,7 +1,7 @@ //! The batcher update type. use alloy_primitives::Address; -use alloy_sol_types::{SolType, sol}; +use alloy_sol_types::{SolType, SolValue, sol}; use crate::{BatcherUpdateError, SystemConfig, SystemConfigLog}; @@ -29,20 +29,36 @@ impl TryFrom<&SystemConfigLog> for BatcherUpdate { return Err(BatcherUpdateError::InvalidDataLen(log.data.data.len())); } - let Ok(pointer) = ::abi_decode(&log.data.data[0..32], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[0..32].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| BatcherUpdateError::PointerTypeCheck)?; + let Ok(pointer) = ::abi_decode(&word) else { return Err(BatcherUpdateError::PointerDecodingError); }; if pointer != 32 { return Err(BatcherUpdateError::InvalidDataPointer(pointer)); } - let Ok(length) = ::abi_decode(&log.data.data[32..64], true) else { + + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[32..64].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| BatcherUpdateError::LengthTypeCheck)?; + let Ok(length) = ::abi_decode(&word) else { return Err(BatcherUpdateError::LengthDecodingError); }; if length != 32 { return Err(BatcherUpdateError::InvalidDataLength(length)); } - let Ok(batcher_address) = ::abi_decode(&log.data.data[64..], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[64..96].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| BatcherUpdateError::BatcherAddressTypeCheck)?; + let Ok(batcher_address) = ::abi_decode(&word) else { return Err(BatcherUpdateError::BatcherAddressDecodingError); }; @@ -103,7 +119,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = BatcherUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, BatcherUpdateError::PointerDecodingError); + assert_eq!(err, BatcherUpdateError::PointerTypeCheck); } #[test] @@ -141,7 +157,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = BatcherUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, BatcherUpdateError::LengthDecodingError); + assert_eq!(err, BatcherUpdateError::LengthTypeCheck); } #[test] @@ -179,6 +195,6 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = BatcherUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, BatcherUpdateError::BatcherAddressDecodingError); + assert_eq!(err, BatcherUpdateError::BatcherAddressTypeCheck); } } diff --git a/crates/protocol/genesis/src/updates/eip1559.rs b/crates/protocol/genesis/src/updates/eip1559.rs index f926ec0313..6de8342d72 100644 --- a/crates/protocol/genesis/src/updates/eip1559.rs +++ b/crates/protocol/genesis/src/updates/eip1559.rs @@ -1,6 +1,6 @@ //! The EIP-1559 update type. -use alloy_sol_types::{SolType, sol}; +use alloy_sol_types::{SolType, SolValue, sol}; use crate::{EIP1559UpdateError, SystemConfig, SystemConfigLog}; @@ -31,20 +31,36 @@ impl TryFrom<&SystemConfigLog> for Eip1559Update { return Err(EIP1559UpdateError::InvalidDataLen(log.data.data.len())); } - let Ok(pointer) = ::abi_decode(&log.data.data[0..32], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[0..32].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| EIP1559UpdateError::PointerTypeCheck)?; + let Ok(pointer) = ::abi_decode(&word) else { return Err(EIP1559UpdateError::PointerDecodingError); }; if pointer != 32 { return Err(EIP1559UpdateError::InvalidDataPointer(pointer)); } - let Ok(length) = ::abi_decode(&log.data.data[32..64], true) else { + + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[32..64].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| EIP1559UpdateError::LengthTypeCheck)?; + let Ok(length) = ::abi_decode(&word) else { return Err(EIP1559UpdateError::LengthDecodingError); }; if length != 32 { return Err(EIP1559UpdateError::InvalidDataLength(length)); } - let Ok(eip1559_params) = ::abi_decode(&log.data.data[64..], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[64..96].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| EIP1559UpdateError::EIP1559TypeCheckError)?; + let Ok(eip1559_params) = ::abi_decode(&word) else { return Err(EIP1559UpdateError::EIP1559DecodingError); }; @@ -110,7 +126,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = Eip1559Update::try_from(&system_log).unwrap_err(); - assert_eq!(err, EIP1559UpdateError::PointerDecodingError); + assert_eq!(err, EIP1559UpdateError::PointerTypeCheck); } #[test] @@ -148,7 +164,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = Eip1559Update::try_from(&system_log).unwrap_err(); - assert_eq!(err, EIP1559UpdateError::LengthDecodingError); + assert_eq!(err, EIP1559UpdateError::LengthTypeCheck); } #[test] @@ -186,6 +202,6 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = Eip1559Update::try_from(&system_log).unwrap_err(); - assert_eq!(err, EIP1559UpdateError::EIP1559DecodingError); + assert_eq!(err, EIP1559UpdateError::EIP1559TypeCheckError); } } diff --git a/crates/protocol/genesis/src/updates/gas_config.rs b/crates/protocol/genesis/src/updates/gas_config.rs index e75f616897..08a575645e 100644 --- a/crates/protocol/genesis/src/updates/gas_config.rs +++ b/crates/protocol/genesis/src/updates/gas_config.rs @@ -1,7 +1,7 @@ //! The gas config update type. use alloy_primitives::U256; -use alloy_sol_types::{SolType, sol}; +use alloy_sol_types::{SolType, SolValue, sol}; use crate::{GasConfigUpdateError, RollupConfig, SystemConfig, SystemConfigLog}; @@ -36,23 +36,34 @@ impl TryFrom<&SystemConfigLog> for GasConfigUpdate { return Err(GasConfigUpdateError::InvalidDataLen(log.data.data.len())); } - let Ok(pointer) = ::abi_decode(&log.data.data[0..32], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[0..32].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| GasConfigUpdateError::PointerTypeCheck)?; + let Ok(pointer) = ::abi_decode(&word) else { return Err(GasConfigUpdateError::PointerDecodingError); }; if pointer != 32 { return Err(GasConfigUpdateError::InvalidDataPointer(pointer)); } - let Ok(length) = ::abi_decode(&log.data.data[32..64], true) else { + + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[32..64].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| GasConfigUpdateError::LengthTypeCheck)?; + let Ok(length) = ::abi_decode(&word) else { return Err(GasConfigUpdateError::LengthDecodingError); }; if length != 64 { return Err(GasConfigUpdateError::InvalidDataLength(length)); } - let Ok(overhead) = ::abi_decode(&log.data.data[64..96], true) else { + let Ok(overhead) = ::abi_decode(&log.data.data[64..96]) else { return Err(GasConfigUpdateError::OverheadDecodingError); }; - let Ok(scalar) = ::abi_decode(&log.data.data[96..], true) else { + let Ok(scalar) = ::abi_decode(&log.data.data[96..]) else { return Err(GasConfigUpdateError::ScalarDecodingError); }; @@ -125,7 +136,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = GasConfigUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, GasConfigUpdateError::PointerDecodingError); + assert_eq!(err, GasConfigUpdateError::PointerTypeCheck); } #[test] @@ -163,7 +174,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = GasConfigUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, GasConfigUpdateError::LengthDecodingError); + assert_eq!(err, GasConfigUpdateError::LengthTypeCheck); } #[test] diff --git a/crates/protocol/genesis/src/updates/gas_limit.rs b/crates/protocol/genesis/src/updates/gas_limit.rs index 86b05e445a..d35cc07d5c 100644 --- a/crates/protocol/genesis/src/updates/gas_limit.rs +++ b/crates/protocol/genesis/src/updates/gas_limit.rs @@ -1,7 +1,7 @@ //! The gas limit update type. use alloy_primitives::{U64, U256}; -use alloy_sol_types::{SolType, sol}; +use alloy_sol_types::{SolType, SolValue, sol}; use crate::{GasLimitUpdateError, SystemConfig, SystemConfigLog}; @@ -29,20 +29,31 @@ impl TryFrom<&SystemConfigLog> for GasLimitUpdate { return Err(GasLimitUpdateError::InvalidDataLen(log.data.data.len())); } - let Ok(pointer) = ::abi_decode(&log.data.data[0..32], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[0..32].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| GasLimitUpdateError::PointerTypeCheck)?; + let Ok(pointer) = ::abi_decode(&word) else { return Err(GasLimitUpdateError::PointerDecodingError); }; if pointer != 32 { return Err(GasLimitUpdateError::InvalidDataPointer(pointer)); } - let Ok(length) = ::abi_decode(&log.data.data[32..64], true) else { + + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[32..64].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| GasLimitUpdateError::LengthTypeCheck)?; + let Ok(length) = ::abi_decode(&word) else { return Err(GasLimitUpdateError::LengthDecodingError); }; if length != 32 { return Err(GasLimitUpdateError::InvalidDataLength(length)); } - let Ok(gas_limit) = ::abi_decode(&log.data.data[64..], true) else { + let Ok(gas_limit) = ::abi_decode(&log.data.data[64..]) else { return Err(GasLimitUpdateError::GasLimitDecodingError); }; @@ -110,7 +121,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = GasLimitUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, GasLimitUpdateError::PointerDecodingError); + assert_eq!(err, GasLimitUpdateError::PointerTypeCheck); } #[test] @@ -148,7 +159,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = GasLimitUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, GasLimitUpdateError::LengthDecodingError); + assert_eq!(err, GasLimitUpdateError::LengthTypeCheck); } #[test] diff --git a/crates/protocol/genesis/src/updates/operator_fee.rs b/crates/protocol/genesis/src/updates/operator_fee.rs index efbd1e0229..e428664a2f 100644 --- a/crates/protocol/genesis/src/updates/operator_fee.rs +++ b/crates/protocol/genesis/src/updates/operator_fee.rs @@ -1,6 +1,6 @@ //! The Operator Fee update type. -use alloy_sol_types::{SolType, sol}; +use alloy_sol_types::{SolType, SolValue, sol}; use crate::{OperatorFeeUpdateError, SystemConfig, SystemConfigLog}; @@ -31,13 +31,24 @@ impl TryFrom<&SystemConfigLog> for OperatorFeeUpdate { return Err(OperatorFeeUpdateError::InvalidDataLen(log.data.data.len())); } - let Ok(pointer) = ::abi_decode(&log.data.data[0..32], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[0..32].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| OperatorFeeUpdateError::PointerTypeCheck)?; + let Ok(pointer) = ::abi_decode(&log.data.data[0..32]) else { return Err(OperatorFeeUpdateError::PointerDecodingError); }; if pointer != 32 { return Err(OperatorFeeUpdateError::InvalidDataPointer(pointer)); } - let Ok(length) = ::abi_decode(&log.data.data[32..64], true) else { + + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[32..64].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| OperatorFeeUpdateError::LengthTypeCheck)?; + let Ok(length) = ::abi_decode(&log.data.data[32..64]) else { return Err(OperatorFeeUpdateError::LengthDecodingError); }; if length != 32 { @@ -114,7 +125,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = OperatorFeeUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, OperatorFeeUpdateError::PointerDecodingError); + assert_eq!(err, OperatorFeeUpdateError::PointerTypeCheck); } #[test] @@ -152,7 +163,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = OperatorFeeUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, OperatorFeeUpdateError::LengthDecodingError); + assert_eq!(err, OperatorFeeUpdateError::LengthTypeCheck); } #[test] diff --git a/crates/protocol/genesis/src/updates/signer.rs b/crates/protocol/genesis/src/updates/signer.rs index d0ce85b58f..7c03648ad4 100644 --- a/crates/protocol/genesis/src/updates/signer.rs +++ b/crates/protocol/genesis/src/updates/signer.rs @@ -1,7 +1,7 @@ //! The unsafe block signer update. use alloy_primitives::Address; -use alloy_sol_types::{SolType, sol}; +use alloy_sol_types::{SolType, SolValue, sol}; use crate::{SystemConfigLog, UnsafeBlockSignerUpdateError}; @@ -22,21 +22,36 @@ impl TryFrom<&SystemConfigLog> for UnsafeBlockSignerUpdate { return Err(UnsafeBlockSignerUpdateError::InvalidDataLen(log.data.data.len())); } - let Ok(pointer) = ::abi_decode(&log.data.data[0..32], true) else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[0..32].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| UnsafeBlockSignerUpdateError::PointerTypeCheck)?; + let Ok(pointer) = ::abi_decode(&log.data.data[0..32]) else { return Err(UnsafeBlockSignerUpdateError::PointerDecodingError); }; if pointer != 32 { return Err(UnsafeBlockSignerUpdateError::InvalidDataPointer(pointer)); } - let Ok(length) = ::abi_decode(&log.data.data[32..64], true) else { + + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[32..64].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| UnsafeBlockSignerUpdateError::LengthTypeCheck)?; + let Ok(length) = ::abi_decode(&log.data.data[32..64]) else { return Err(UnsafeBlockSignerUpdateError::LengthDecodingError); }; if length != 32 { return Err(UnsafeBlockSignerUpdateError::InvalidDataLength(length)); } - let Ok(unsafe_block_signer) = ::abi_decode(&log.data.data[64..], true) - else { + // SAFETY: The data's length is 32 bytes, conversion from the slice to `[u8; 32]` + // can never fail. + let word: [u8; 32] = log.data.data[64..96].try_into().unwrap(); + ::type_check(&word.tokenize()) + .map_err(|_| UnsafeBlockSignerUpdateError::UnsafeBlockSignerAddressTypeCheck)?; + let Ok(unsafe_block_signer) = ::abi_decode(&log.data.data[64..]) else { return Err(UnsafeBlockSignerUpdateError::UnsafeBlockSignerAddressDecodingError); }; @@ -100,7 +115,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = UnsafeBlockSignerUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, UnsafeBlockSignerUpdateError::PointerDecodingError); + assert_eq!(err, UnsafeBlockSignerUpdateError::PointerTypeCheck); } #[test] @@ -138,7 +153,7 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = UnsafeBlockSignerUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, UnsafeBlockSignerUpdateError::LengthDecodingError); + assert_eq!(err, UnsafeBlockSignerUpdateError::LengthTypeCheck); } #[test] @@ -176,6 +191,6 @@ mod tests { let system_log = SystemConfigLog::new(log, false); let err = UnsafeBlockSignerUpdate::try_from(&system_log).unwrap_err(); - assert_eq!(err, UnsafeBlockSignerUpdateError::UnsafeBlockSignerAddressDecodingError); + assert_eq!(err, UnsafeBlockSignerUpdateError::UnsafeBlockSignerAddressTypeCheck); } } diff --git a/crates/protocol/interop/src/message.rs b/crates/protocol/interop/src/message.rs index 277350bda4..17b380651c 100644 --- a/crates/protocol/interop/src/message.rs +++ b/crates/protocol/interop/src/message.rs @@ -144,6 +144,6 @@ pub fn parse_logs_to_executing_msgs<'a>( /// executing message event. pub fn parse_log_to_executing_message(log: &Log) -> Option { (log.address == CROSS_L2_INBOX_ADDRESS && log.topics().len() == 2) - .then(|| ExecutingMessage::decode_log_data(&log.data, true).ok()) + .then(|| ExecutingMessage::decode_log_data(&log.data).ok()) .flatten() } diff --git a/crates/protocol/protocol/Cargo.toml b/crates/protocol/protocol/Cargo.toml index 3e1afe36cc..92e91475a1 100644 --- a/crates/protocol/protocol/Cargo.toml +++ b/crates/protocol/protocol/Cargo.toml @@ -54,7 +54,6 @@ tracing-subscriber = { workspace = true, features = ["fmt"], optional = true } [dev-dependencies] brotli = { workspace = true, features = ["std"] } -revm.workspace = true spin.workspace = true rand = { workspace = true, features = ["std", "std_rng"] } rstest.workspace = true diff --git a/crates/protocol/protocol/examples/frames_to_batch.rs b/crates/protocol/protocol/examples/frames_to_batch.rs index 79ed0666db..0b7535f9d3 100644 --- a/crates/protocol/protocol/examples/frames_to_batch.rs +++ b/crates/protocol/protocol/examples/frames_to_batch.rs @@ -2,7 +2,7 @@ use alloy_consensus::{SignableTransaction, TxEip1559, TxEnvelope}; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; -use alloy_primitives::{Address, BlockHash, Bytes, PrimitiveSignature, U256, hex}; +use alloy_primitives::{Address, BlockHash, Bytes, Signature, U256, hex}; use kona_genesis::RollupConfig; use kona_protocol::{Batch, BlockInfo, Channel, Frame, SingleBatch, decompress_brotli}; @@ -70,7 +70,7 @@ fn example_transactions() -> Vec { input: vec![8].into(), access_list: Default::default(), }; - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); @@ -91,7 +91,7 @@ fn example_transactions() -> Vec { input: vec![8].into(), access_list: Default::default(), }; - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); diff --git a/crates/protocol/protocol/src/batch/core.rs b/crates/protocol/protocol/src/batch/core.rs index eec60e3615..df5ca4c23f 100644 --- a/crates/protocol/protocol/src/batch/core.rs +++ b/crates/protocol/protocol/src/batch/core.rs @@ -76,7 +76,7 @@ mod tests { use crate::{SpanBatchElement, SpanBatchError, SpanBatchTransactions}; use alloc::{vec, vec::Vec}; use alloy_consensus::{Signed, TxEip2930, TxEnvelope}; - use alloy_primitives::{Bytes, PrimitiveSignature as Signature, TxKind, address, hex}; + use alloy_primitives::{Bytes, Signature, TxKind, address, hex}; #[test] fn test_single_batch_encode_decode() { diff --git a/crates/protocol/protocol/src/batch/single.rs b/crates/protocol/protocol/src/batch/single.rs index 7c66712e18..332920586b 100644 --- a/crates/protocol/protocol/src/batch/single.rs +++ b/crates/protocol/protocol/src/batch/single.rs @@ -181,7 +181,7 @@ mod tests { use alloc::vec; use alloy_consensus::{SignableTransaction, TxEip1559, TxEip7702, TxEnvelope}; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; - use alloy_primitives::{Address, PrimitiveSignature, Sealed, TxKind, U256}; + use alloy_primitives::{Address, Sealed, Signature, TxKind, U256}; use kona_genesis::HardForkConfig; use op_alloy_consensus::{OpTxEnvelope, TxDeposit}; @@ -368,7 +368,7 @@ mod tests { // First Transaction in the batch. let tx = eip_1559_tx(); - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); @@ -380,7 +380,7 @@ mod tests { // Second transaction in the batch. let mut tx = eip_1559_tx(); tx.to = Address::left_padding_from(&[7]).into(); - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); @@ -440,7 +440,7 @@ mod tests { // Extend the transactions with the 7702 transaction let eip_7702_tx = eip_7702_tx(); - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = eip_7702_tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); @@ -476,7 +476,7 @@ mod tests { // Extend the transactions with the 7702 transaction let eip_7702_tx = eip_7702_tx(); - let sig = PrimitiveSignature::test_signature(); + let sig = Signature::test_signature(); let tx_signed = eip_7702_tx.into_signed(sig); let envelope: TxEnvelope = tx_signed.into(); let encoded = envelope.encoded_2718(); diff --git a/crates/protocol/protocol/src/batch/span.rs b/crates/protocol/protocol/src/batch/span.rs index ad424fa5ac..513864adb4 100644 --- a/crates/protocol/protocol/src/batch/span.rs +++ b/crates/protocol/protocol/src/batch/span.rs @@ -905,7 +905,7 @@ mod tests { value: alloy_primitives::U256::from(3), ..Default::default() }, - alloy_primitives::PrimitiveSignature::test_signature(), + alloy_primitives::Signature::test_signature(), alloy_primitives::B256::ZERO, ), )], diff --git a/crates/protocol/protocol/src/batch/transactions.rs b/crates/protocol/protocol/src/batch/transactions.rs index db0cf2fb3f..ffc60f6e30 100644 --- a/crates/protocol/protocol/src/batch/transactions.rs +++ b/crates/protocol/protocol/src/batch/transactions.rs @@ -8,7 +8,7 @@ use crate::{ use alloc::vec::Vec; use alloy_consensus::{Transaction, TxEnvelope, TxType}; use alloy_eips::eip2718::Encodable2718; -use alloy_primitives::{Address, Bytes, PrimitiveSignature as Signature, U256, bytes}; +use alloy_primitives::{Address, Bytes, Signature, U256, bytes}; use alloy_rlp::{Buf, Decodable, Encodable}; /// This struct contains the decoded information for transactions in a span batch. @@ -350,7 +350,7 @@ mod tests { use super::*; use alloc::vec; use alloy_consensus::{Signed, TxEip1559, TxEip2930, TxEip7702}; - use alloy_primitives::{PrimitiveSignature as Signature, TxKind, address}; + use alloy_primitives::{Signature, TxKind, address}; #[test] fn test_span_batch_transactions_add_empty_txs() { diff --git a/crates/protocol/protocol/src/batch/tx_data/eip1559.rs b/crates/protocol/protocol/src/batch/tx_data/eip1559.rs index be3b6823d4..e7221efaad 100644 --- a/crates/protocol/protocol/src/batch/tx_data/eip1559.rs +++ b/crates/protocol/protocol/src/batch/tx_data/eip1559.rs @@ -3,7 +3,7 @@ use crate::{SpanBatchError, SpanDecodingError}; use alloy_consensus::{SignableTransaction, Signed, TxEip1559}; use alloy_eips::eip2930::AccessList; -use alloy_primitives::{Address, PrimitiveSignature as Signature, TxKind, U256}; +use alloy_primitives::{Address, Signature, TxKind, U256}; use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for an EIP-1559 transaction within a span batch. diff --git a/crates/protocol/protocol/src/batch/tx_data/eip2930.rs b/crates/protocol/protocol/src/batch/tx_data/eip2930.rs index 47e5116ee9..45c7d6f641 100644 --- a/crates/protocol/protocol/src/batch/tx_data/eip2930.rs +++ b/crates/protocol/protocol/src/batch/tx_data/eip2930.rs @@ -3,7 +3,7 @@ use crate::{SpanBatchError, SpanDecodingError}; use alloy_consensus::{SignableTransaction, Signed, TxEip2930}; use alloy_eips::eip2930::AccessList; -use alloy_primitives::{Address, PrimitiveSignature as Signature, TxKind, U256}; +use alloy_primitives::{Address, Signature, TxKind, U256}; use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for an EIP-2930 transaction within a span batch. diff --git a/crates/protocol/protocol/src/batch/tx_data/eip7702.rs b/crates/protocol/protocol/src/batch/tx_data/eip7702.rs index d472a34988..a4c98569a4 100644 --- a/crates/protocol/protocol/src/batch/tx_data/eip7702.rs +++ b/crates/protocol/protocol/src/batch/tx_data/eip7702.rs @@ -4,7 +4,7 @@ use crate::SpanBatchError; use alloc::vec::Vec; use alloy_consensus::{SignableTransaction, Signed, TxEip7702}; use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization}; -use alloy_primitives::{Address, PrimitiveSignature as Signature, U256}; +use alloy_primitives::{Address, Signature, U256}; use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for an EIP-7702 transaction within a span batch. @@ -68,7 +68,7 @@ mod test { use crate::SpanBatchTransactionData; use alloc::{vec, vec::Vec}; use alloy_rlp::{Decodable, Encodable}; - use revm::primitives::Authorization; + use alloy_rpc_types_eth::Authorization; #[test] fn test_eip7702_to_signed_tx() { diff --git a/crates/protocol/protocol/src/batch/tx_data/legacy.rs b/crates/protocol/protocol/src/batch/tx_data/legacy.rs index daf2865005..17cebae6f5 100644 --- a/crates/protocol/protocol/src/batch/tx_data/legacy.rs +++ b/crates/protocol/protocol/src/batch/tx_data/legacy.rs @@ -2,7 +2,7 @@ use crate::{SpanBatchError, SpanDecodingError}; use alloy_consensus::{SignableTransaction, Signed, TxLegacy}; -use alloy_primitives::{Address, PrimitiveSignature as Signature, TxKind, U256}; +use alloy_primitives::{Address, Signature, TxKind, U256}; use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for a legacy transaction within a span batch. diff --git a/crates/protocol/protocol/src/batch/tx_data/wrapper.rs b/crates/protocol/protocol/src/batch/tx_data/wrapper.rs index d2ea9f8805..e0b0cf5c98 100644 --- a/crates/protocol/protocol/src/batch/tx_data/wrapper.rs +++ b/crates/protocol/protocol/src/batch/tx_data/wrapper.rs @@ -1,7 +1,7 @@ //! This module contains the top level span batch transaction data type. use alloy_consensus::{Transaction, TxEnvelope, TxType}; -use alloy_primitives::{Address, PrimitiveSignature as Signature, U256}; +use alloy_primitives::{Address, Signature, U256}; use alloy_rlp::{Bytes, Decodable, Encodable}; use crate::{ diff --git a/crates/protocol/protocol/src/utils.rs b/crates/protocol/protocol/src/utils.rs index 2b2868bee8..74d4f343e2 100644 --- a/crates/protocol/protocol/src/utils.rs +++ b/crates/protocol/protocol/src/utils.rs @@ -225,7 +225,7 @@ mod tests { value: U256::ZERO, input: alloy_primitives::Bytes::new(), }, - alloy_primitives::PrimitiveSignature::new(U256::ZERO, U256::ZERO, false), + alloy_primitives::Signature::new(U256::ZERO, U256::ZERO, false), Default::default(), ), )],