diff --git a/.env.example b/.env.example index b9f81cad..c92824d4 100644 --- a/.env.example +++ b/.env.example @@ -20,3 +20,7 @@ SP1_PRIVATE_KEY= SP1_PROVER=network # Skips simulation of the proof before sending to the SP1 server. SKIP_SIMULATION=true + +# Config for deploying contract +ETHERSCAN_API_KEY= +USE_CACHED_STARTING_BLOCK=false diff --git a/.gitignore b/.gitignore index f9546943..935d8f16 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,7 @@ data **.txt !LICENSE.txt -# Reports +# Execution Report execution-reports/ # Rollup Config diff --git a/Cargo.lock b/Cargo.lock index 82406fc4..70a4b50a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,8 +54,8 @@ name = "aggregation" version = "0.1.0" dependencies = [ "alloy-consensus", - "alloy-primitives 0.8.3", - "itertools 0.13.0", + "alloy-primitives 0.8.0", + "alloy-sol-types 0.8.0", "op-succinct-client-utils", "serde_cbor", "sha2", @@ -147,7 +147,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1468e3128e07c7afe4ff13c17e8170c330d12c322f8924b8bf6986a27e0aad3d" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "alloy-serde", "c-kzg", @@ -164,11 +164,11 @@ dependencies = [ "alloy-json-abi", "alloy-network", "alloy-network-primitives", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-provider", "alloy-pubsub", "alloy-rpc-types-eth", - "alloy-sol-types 0.8.3", + "alloy-sol-types 0.8.0", "alloy-transport", "futures", "futures-util", @@ -177,26 +177,26 @@ dependencies = [ [[package]] name = "alloy-core" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b095eb0533144b4497e84a9cc3e44a5c2e3754a3983c0376a55a2f9183a53e" +checksum = "8e6dbb79f4e3285cc87f50c0d4be9a3a812643623b2e3558d425b41cbd795ceb" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-primitives 0.8.3", - "alloy-sol-types 0.8.3", + "alloy-primitives 0.8.0", + "alloy-sol-types 0.8.0", ] [[package]] name = "alloy-dyn-abi" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4004925bff5ba0a11739ae84dbb6601a981ea692f3bd45b626935ee90a6b8471" +checksum = "ba5b68572f5dfa99ede0a491d658c9842626c956b840d0b97d0bbc9637742504" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-sol-type-parser", - "alloy-sol-types 0.8.3", + "alloy-sol-types 0.8.0", "const-hex", "itoa", "serde", @@ -210,7 +210,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "serde", ] @@ -221,7 +221,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d319bb544ca6caeab58c39cea8921c55d924d4f68f2c60f24f914673f9a74a" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "k256", "serde", @@ -235,7 +235,7 @@ checksum = "0c35df7b972b06f1b2f4e8b7a53328522fa788054a9d3e556faf2411c5a51d5a" dependencies = [ "alloy-eip2930", "alloy-eip7702", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "alloy-serde", "c-kzg", @@ -251,18 +251,18 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7210f9206c0fa2a83c824cf8cb6c962126bc9fdc4f41ade1932f14150ef5f6" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-serde", "serde", ] [[package]] name = "alloy-json-abi" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9996daf962fd0a90d3c93b388033228865953b92de7bb1959b891d78750a4091" +checksum = "299d2a937b6c60968df3dad2a988b0f0e03277b344639a4f7a31bd68e6285e59" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-sol-type-parser", "serde", "serde_json", @@ -274,8 +274,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8866562186d237f1dfeaf989ef941a24764f764bf5c33311e37ead3519c6a429" dependencies = [ - "alloy-primitives 0.8.3", - "alloy-sol-types 0.8.3", + "alloy-primitives 0.8.0", + "alloy-sol-types 0.8.0", "serde", "serde_json", "thiserror", @@ -292,11 +292,11 @@ dependencies = [ "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rpc-types-eth", "alloy-serde", "alloy-signer", - "alloy-sol-types 0.8.3", + "alloy-sol-types 0.8.0", "async-trait", "auto_impl", "futures-utils-wasm", @@ -310,7 +310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c5a38117974c5776a45e140226745a0b664f79736aa900995d8e4121558e064" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-serde", "serde", ] @@ -318,7 +318,8 @@ dependencies = [ [[package]] name = "alloy-primitives" version = "0.7.7" -source = "git+https://github.com/sp1-patches/alloy-core?branch=patch-v0.7.7#7d03e2576454bba809abcf45e2f44c313eaa33d0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" dependencies = [ "alloy-rlp", "bytes", @@ -333,21 +334,19 @@ dependencies = [ "rand", "ruint", "serde", - "sha3", "tiny-keccak", ] [[package]] name = "alloy-primitives" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "411aff151f2a73124ee473708e82ed51b2535f68928b6a1caa8bc1246ae6f7cd" +version = "0.8.0" +source = "git+https://github.com/sp1-patches/alloy-core?branch=patch-v0.8.0#251d8f1000fb84fa5b36ae6662637598622a7a19" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", - "derive_more 1.0.0", + "derive_more 0.99.18", "hex-literal", "itoa", "k256", @@ -356,6 +355,7 @@ dependencies = [ "rand", "ruint", "serde", + "sha3", "tiny-keccak", ] @@ -371,7 +371,7 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-network-primitives", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types-eth", @@ -403,7 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "949db89abae6193b44cc90ebf2eeb74eb8d2a474383c5e62b45bdcd362e84f8f" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-transport", "bimap", "futures", @@ -444,7 +444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fc328bb5d440599ba1b5aa44c0b9ab0625fbc3a403bb5ee94ed4a01ba23e07" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-pubsub", "alloy-transport", "alloy-transport-http", @@ -482,7 +482,7 @@ checksum = "b66bb45f4c5efe227bcb51d89c97221225169976e18097671a0bd4393d8248a4" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "alloy-rpc-types-eth", "alloy-serde", @@ -499,10 +499,10 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-network-primitives", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "alloy-serde", - "alloy-sol-types 0.8.3", + "alloy-sol-types 0.8.0", "itertools 0.13.0", "serde", "serde_json", @@ -515,7 +515,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51db8a6428a2159e01b7a43ec7aac801edd0c4db1d4de06f310c288940f16fd3" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "serde", "serde_json", ] @@ -526,7 +526,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bebc1760c13592b7ba3fcd964abba546b8d6a9f10d15e8d92a8263731be33f36" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "async-trait", "auto_impl", "elliptic-curve", @@ -542,7 +542,7 @@ checksum = "3bfb3508485aa798efb5725322e414313239274d3780079b7f8c6746b8ee6e1b" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-signer", "async-trait", "k256", @@ -566,13 +566,13 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0458ccb02a564228fcd76efb8eb5a520521a8347becde37b402afec9a1b83859" +checksum = "183bcfc0f3291d9c41a3774172ee582fb2ce6eb6569085471d8f225de7bb86fc" dependencies = [ - "alloy-sol-macro-expander 0.8.3", - "alloy-sol-macro-input 0.8.3", - "proc-macro-error2", + "alloy-sol-macro-expander 0.8.0", + "alloy-sol-macro-input 0.8.0", + "proc-macro-error", "proc-macro2", "quote", "syn 2.0.77", @@ -598,20 +598,20 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc65475025fc1e84bf86fc840f04f63fcccdcf3cf12053c99918e4054dfbc69" +checksum = "71c4d842beb7a6686d04125603bc57614d5ed78bf95e4753274db3db4ba95214" dependencies = [ "alloy-json-abi", - "alloy-sol-macro-input 0.8.3", + "alloy-sol-macro-input 0.8.0", "const-hex", "heck", "indexmap 2.5.0", - "proc-macro-error2", + "proc-macro-error", "proc-macro2", "quote", "syn 2.0.77", - "syn-solidity 0.8.3", + "syn-solidity 0.8.0", "tiny-keccak", ] @@ -632,9 +632,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed10f0715a0b69fde3236ff3b9ae5f6f7c97db5a387747100070d3016b9266b" +checksum = "1306e8d3c9e6e6ecf7a39ffaf7291e73a5f655a2defd366ee92c2efebcdf7fee" dependencies = [ "alloy-json-abi", "const-hex", @@ -644,7 +644,7 @@ dependencies = [ "quote", "serde_json", "syn 2.0.77", - "syn-solidity 0.8.3", + "syn-solidity 0.8.0", ] [[package]] @@ -671,13 +671,13 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eb88e4da0a1b697ed6a9f811fdba223cf4d5c21410804fd1707836af73a462b" +checksum = "577e262966e92112edbd15b1b2c0947cc434d6e8311df96d3329793fe8047da9" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.3", - "alloy-sol-macro 0.8.3", + "alloy-primitives 0.8.0", + "alloy-sol-macro 0.8.0", "const-hex", "serde", ] @@ -759,7 +759,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "398a977d774db13446b8cead8cfa9517aebf9e03fc8a1512892dc1e03e70bb04" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "derive_more 1.0.0", "hashbrown 0.14.5", @@ -843,9 +843,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" +checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" [[package]] name = "ark-ff" @@ -2519,6 +2519,7 @@ dependencies = [ "kona-executor", "kona-primitives", "op-succinct-client-utils", + "serde_json", "sp1-zkvm", ] @@ -3430,7 +3431,7 @@ source = "git+https://github.com/anton-rs/kona?tag=kona-client-v0.1.0-alpha.3#37 dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "anyhow", "async-trait", @@ -3443,7 +3444,7 @@ dependencies = [ "kona-preimage", "kona-primitives", "lru", - "op-alloy-consensus 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "op-alloy-consensus", "revm", "serde", "serde_json", @@ -3482,7 +3483,7 @@ dependencies = [ "alloc-no-stdlib", "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-provider", "alloy-rlp", "alloy-transport", @@ -3493,7 +3494,7 @@ dependencies = [ "kona-primitives", "lru", "miniz_oxide", - "op-alloy-consensus 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "op-alloy-consensus", "reqwest 0.12.7", "tracing", "unsigned-varint", @@ -3506,11 +3507,11 @@ source = "git+https://github.com/anton-rs/kona?tag=kona-client-v0.1.0-alpha.3#37 dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "anyhow", "kona-mpt", "kona-primitives", - "op-alloy-consensus 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "op-alloy-consensus", "revm", "tracing", ] @@ -3522,7 +3523,7 @@ source = "git+https://github.com/anton-rs/kona?tag=kona-client-v0.1.0-alpha.3#37 dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-provider", "alloy-rlp", "alloy-rpc-client", @@ -3556,7 +3557,7 @@ version = "0.0.3" source = "git+https://github.com/anton-rs/kona?tag=kona-client-v0.1.0-alpha.3#3759e2f4295a9b0c18d94b99ce008d28263d201f" dependencies = [ "alloy-consensus", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "alloy-trie", "anyhow", @@ -3569,7 +3570,7 @@ name = "kona-preimage" version = "0.0.3" source = "git+https://github.com/anton-rs/kona?tag=kona-client-v0.1.0-alpha.3#3759e2f4295a9b0c18d94b99ce008d28263d201f" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "anyhow", "async-trait", "kona-common", @@ -3584,11 +3585,11 @@ source = "git+https://github.com/anton-rs/kona?tag=kona-client-v0.1.0-alpha.3#37 dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "anyhow", "c-kzg", - "op-alloy-consensus 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "op-alloy-consensus", "op-alloy-protocol", "revm", "serde", @@ -4080,20 +4081,7 @@ checksum = "ad134a77fdfebac469526756b207c7889593657eeaca374200332ec89175e27a" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", - "alloy-rlp", - "derive_more 1.0.0", - "spin 0.9.8", -] - -[[package]] -name = "op-alloy-consensus" -version = "0.2.9" -source = "git+https://github.com/alloy-rs/op-alloy#e72a1ca6ad7206c89ebc0921fc0b2d819ffef76b" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "derive_more 1.0.0", "spin 0.9.8", @@ -4102,14 +4090,14 @@ dependencies = [ [[package]] name = "op-alloy-protocol" version = "0.2.9" -source = "git+https://github.com/alloy-rs/op-alloy#e72a1ca6ad7206c89ebc0921fc0b2d819ffef76b" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae2170e65eeef408d336e8f378b8c1341e5f6bbc618839f020b8b1a82786327" dependencies = [ - "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", "hashbrown 0.14.5", - "op-alloy-consensus 0.2.9 (git+https://github.com/alloy-rs/op-alloy)", + "op-alloy-consensus", "superchain-primitives", ] @@ -4119,9 +4107,9 @@ version = "0.1.0" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-rlp", - "alloy-sol-types 0.8.3", + "alloy-sol-types 0.8.0", "anyhow", "async-trait", "cfg-if", @@ -4135,10 +4123,11 @@ dependencies = [ "kona-primitives", "kzg-rs", "log", - "op-alloy-consensus 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "op-alloy-consensus", "revm", "rkyv", "serde", + "serde_json", "sha2", ] @@ -4148,19 +4137,23 @@ version = "0.1.0" dependencies = [ "alloy", "alloy-consensus", - "alloy-primitives 0.8.3", - "alloy-sol-types 0.8.3", + "alloy-primitives 0.8.0", + "alloy-sol-types 0.8.0", "anyhow", "cargo_metadata", "dotenv", "futures", "kona-host", "kona-preimage", + "kona-primitives", + "log", "num-format", "op-succinct-client-utils", + "reqwest 0.12.7", "rkyv", "serde", "serde_cbor", + "serde_json", "sp1-sdk", "tokio", ] @@ -4169,17 +4162,22 @@ dependencies = [ name = "op-succinct-proposer" version = "0.1.0" dependencies = [ - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "anyhow", "axum", "base64 0.22.1", "bincode", "cargo_metadata", + "csv", "dotenv", + "futures", "log", "op-succinct-client-utils", "op-succinct-host-utils", + "rayon", + "reqwest 0.12.7", "serde", + "serde_json", "sp1-build", "sp1-sdk", "tokio", @@ -4191,7 +4189,8 @@ name = "op-succinct-prove" version = "0.1.0" dependencies = [ "alloy", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", + "alloy-sol-types 0.8.0", "anyhow", "cargo_metadata", "clap", @@ -4206,6 +4205,7 @@ dependencies = [ "rayon", "reqwest 0.12.7", "serde", + "serde_json", "sp1-build", "sp1-sdk", "tokio", @@ -4219,7 +4219,9 @@ dependencies = [ "clap", "kona-host", "log", + "sp1-sdk", "tokio", + "tracing", ] [[package]] @@ -4911,28 +4913,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "proc-macro2" version = "1.0.86" @@ -5133,8 +5113,9 @@ dependencies = [ "kona-executor", "kona-primitives", "log", - "op-alloy-consensus 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "op-alloy-consensus", "op-succinct-client-utils", + "serde_json", "sp1-zkvm", ] @@ -5175,9 +5156,9 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] @@ -5400,7 +5381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ccb981ede47ccf87c68cebf1ba30cdbb7ec935233ea305f3dfff4c1e10ae541" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "auto_impl", "bitflags 2.6.0", "bitvec", @@ -5800,9 +5781,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -6844,9 +6825,9 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.3", + "alloy-primitives 0.8.0", "alloy-serde", - "alloy-sol-types 0.8.3", + "alloy-sol-types 0.8.0", "anyhow", "serde", "serde_repr", @@ -6888,9 +6869,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b95156f8b577cb59dc0b1df15c6f29a10afc5f8a7ac9786b0b5c68c19149278" +checksum = "284c41c2919303438fcf8dede4036fd1e82d4fc0fbb2b279bd2a1442c909ca92" dependencies = [ "paste", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index be8b01fe..1642ae08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,10 +88,6 @@ tiny-keccak = { git = "https://github.com/sp1-patches/tiny-keccak", branch = "pa sha2 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" } ecdsa = { git = "https://github.com/sp1-patches/signatures", branch = "patch-ecdsa-v0.16.8" } bn = { git = "https://github.com/0xWOLAND/bn.git", package = "substrate-bn" } -# Note: Patch alloy-primitives to use sha3 instead of tiny-keccak. Reduces cycle count for Keccak by 50%. sha3 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha3", branch = "patch-sha3-v0.10.8" } -alloy-primitives = { git = "https://github.com/sp1-patches/alloy-core", branch = "patch-v0.7.7" } - -# Patch op-alloy-protocol for recent exports for compatibility with kona. -# TODO: Can remove later, currently patched in Kona. -op-alloy-protocol = { git = "https://github.com/alloy-rs/op-alloy" } +# This patch uses sha3 instead of tiny-keccak. Reduces cycle count for Keccak by 50%. +alloy-primitives = { git = "https://github.com/sp1-patches/alloy-core", branch = "patch-v0.8.0" } diff --git a/README.md b/README.md index 38c37e2a..8c831114 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ OP Succinct turns any OP stack rollup into a full type-1 zkEVM Rollup in 1 hour ## Getting Started -Today, you can already use OP Succinct to upgrade any existing OP Stack rollup to a type-1 zkEVM rollup. To get started, make sure you have [Rust](https://rustup.rs/), [Foundry](https://book.getfoundry.sh/), and [Docker](https://docs.docker.com/engine/install/) installed. Then, follow the steps in the [book]() to deploy the `ZKL2OutputOracle` contract and start the `op-succinct-proposer` service. +Today, you can already use OP Succinct to upgrade any existing OP Stack rollup to a type-1 zkEVM rollup. To get started, make sure you have [Rust](https://rustup.rs/), [Foundry](https://book.getfoundry.sh/), and [Docker](https://docs.docker.com/engine/install/) installed. Then, follow the steps in the [book](https://succinctlabs.github.io/op-succinct/) to deploy the `ZKL2OutputOracle` contract and start the `op-succinct-proposer` service. ## Repository Overview diff --git a/book/deploy/intro.md b/book/deploy/intro.md deleted file mode 100644 index e74b87d1..00000000 --- a/book/deploy/intro.md +++ /dev/null @@ -1 +0,0 @@ -# Deploy OP Succinct diff --git a/book/deploy/op-stack.md b/book/deploy/op-stack.md deleted file mode 100644 index 1c81bb2f..00000000 --- a/book/deploy/op-stack.md +++ /dev/null @@ -1 +0,0 @@ -# Base OP Stack Rollup diff --git a/book/deploy/smart-contract.md b/book/deploy/smart-contract.md deleted file mode 100644 index ea0945c3..00000000 --- a/book/deploy/smart-contract.md +++ /dev/null @@ -1,65 +0,0 @@ -# Deploy Smart Contracts - -The first step in deploying OP Succinct is to deploy a Solidity smart contract that will verify ZKPs of OP derivation (OP's name for their state transition function) and contain the latest state root of your rollup. - -## Overview - -The `contracts/` directory has the relevant smart contracts and deployment scripts for this step. In particular, it contains: - -1) The `ZKL2OutputOracle.sol` contract which verifies a ZKP of OP derivation, and is a small of Optimism's `L2OutputOracle.sol` contract with the necessary changes to support ZK validity proofs. - -2) The `ZKUpgrader.s.sol` script, which deploys the `ZKL2OutputOracle.sol` implementation contract, upgrades an existing `L2OutputOracleProxy` to point to it, and initializes the new contract with values from `zkconfig.json`. - -[TODO: insert a diagram of how all the OP stack contracts interact with the ZKL2OutputOracle.sol] - -## Deployment - -### Upgrading an existing `L2OutputOracle.sol` - -### Deploying `ZKL2OutputOracle.sol` - -### ... -3) The `ZKDeployer.s.sol` script, which deploys the `ZKL2OutputOracle.sol` implementation contract, upgrades an existing `L2OutputOracleProxy` to point to it, and initializes the new contract with values from `zkconfig.json`. - -## Deploy Fresh Proxy - -For OP Sepolia, you can deploy a fresh proxy with the following command: - -```shell -forge script script/ZKDeployer.s.sol:ZKDeployer --rpc-url --private-key --verify --verifier etherscan --etherscan-api-key --broadcast --slow -vvvv --ffi -``` - -## Upgrade Existing Proxy - -To deploy and upgrade the contract for existing chains, run the following command (where `ADMIN_PK` is the private key of the admin address for the L1 proxy contracts): - -```shell -forge script script/ZKUpgrader.s.sol:ZKUpgrader --rpc-url --private-key --verify --verifier etherscan --etherscan-api-key --broadcast --slow --vvvv -``` - -## Starting Output Root - -Since the `ZKL2OutputOracle.sol` contract requires valid ZK proofs to transition the state, the contract must be seeded with an honest first value to be able to honestly prove transitions. - -For existing contracts upgrading, they already have honest values in the contract. For new chains, the `ZKUpgrader` script will initialize the contract as follows: - -- The `zkconfig.json` file includes a starting output block number, as well as an L2 Rollup RPC. -- The script queries the rollup node and gets the corresponding output root and timestamp for that block. -- It uses these three values to seed the contract, and all future output roots posted must be proved against this starting state. - -To retrieve these values manually, use: -``` -cast rpc --rpc-url optimism_outputAtBlock $(cast 2h ) | jq '.outputRoot .blockRef.timestamp' -``` - -New chains will likely use a starting output block number of 0 (genesis) and prove all transitions against this state. - -## vKey - -The `ZKL2OutputOracle.sol` contract requires a verification key to be able to verify the validity proofs. - -This key can be generated by running the following command from the root of the repo: - -```shell -cargo run --bin vkey --release -``` diff --git a/book/deploy/zk-proposer.md b/book/deploy/zk-proposer.md deleted file mode 100644 index db6e43a1..00000000 --- a/book/deploy/zk-proposer.md +++ /dev/null @@ -1,54 +0,0 @@ -# Deploy ZK Proposer - -After deploying the `ZKL2OutputOracle.sol`, the final step is to launch a "ZKP" version of the `op-proposer` that will call to [Succinct's Prover Network](TODO) to generate proofs and submit them onchain. - -## Deployment - -First, create a `.env` file that matches the `.env.example` file in the root of the `op-succinct` repo. - -```bash -cp .env.example .env -``` - - - - -Then, to run the OP proposer, follow these steps: - -Build the server with: - -```bash -docker compose build -``` - -Then, start the server: -```bash -docker compose up -d -``` - -To stop the server, run: -```bash -docker compose down -``` - -This launches a Docker container with a modified version of the `op-proposer` (which can be found at [our fork](https://github.com/succinctlabs/optimism/tree/zk-proposer)). - -The modified `op-proposer` performs the following tasks: -- Monitors L1 state to determine when to request a proof. -- Requests proofs from the Kona SP1 server. -- Once proofs have been generated for a sufficiently large range (specified by `SUBMISSION_INTERVAL` in `zkconfig.json`), aggregates batch proofs and submits them on-chain. - - -## Underneath the Hood - -Underneath the hood, there are a very components involved in running the `op-succinct` proposer: - -**`op-succinct` Server**: -- There is a very lightweight server running with [op-succinct-proposer/bin/server.rs] that is is responsible or given a block range, it will generate the witness data for that block range by running the "native host" and then dispatch the proof request to the Succinct Prover Network. - -**`op-succinct` Proposer**: - - Runs the modified `op-proposer` binary from the Optimism repository which keeps the `ZKL2OutputOracle` contract up to date with the latest L2 state using - SP1 proofs. - - When a new L2 block is detected, the proposer requests a ZK proof from the OP Succinct Server. Once the proof is generated, it's - posted to the `ZKL2OutputOracle` contract. - - Uses a SQLite database (`proofs.db`) to keep track of processed blocks and proofs. diff --git a/book/getting-started/l2-output-oracle.md b/book/getting-started/l2-output-oracle.md index 718cf117..f627977a 100644 --- a/book/getting-started/l2-output-oracle.md +++ b/book/getting-started/l2-output-oracle.md @@ -12,21 +12,38 @@ git clone https://github.com/succinctlabs/op-succinct.git cd op-succinct ``` -### 2) Navigate to the contracts directory: +### 2) Set environment variables: + +```bash +cp .env.example .env +``` + +Set the following environment variables: + +```bash +L1_RPC=... +L2_RPC=... +L2_NODE_RPC=... +PRIVATE_KEY=... +ETHERSCAN_API_KEY=... +``` + +### 3) Navigate to the contracts directory: ```bash cd contracts ``` -### 3) Set Deployment Parameters +### 4) Set Deployment Parameters + +Inside the `contracts` folder there is a file called `zkl2ooconfig.json` that contains the parameters for the deployment. You will need to fill it with your chain's specific details. -Inside the `contracts` folder there is a file called `zkconfig.json` that contains the parameters for the deployment. You will need to fill it with your chain's specific details. +The following parameters are required: `proposer`, `challenger`, `finalizationPeriod`, `owner`, `verifierGateway`. The rest of the fields (`startingBlockNumber`, `l2BlockTime`, `chainId` and `vkey`) are automatically fetched by the `fetch-rollup-config` script which is invoked by the `ZKDeployer` forge script. To use a manually set `startingBlockNumber`, set `USE_CACHED_STARTING_BLOCK` to `true`. | Parameter | Description | |-----------|-------------| | `startingBlockNumber` | The L2 block number at which to start generating validity proofs. This should be set to the current L2 block number. You can fetch this with `cast bn --rpc-url `. | -| `l2RollupNode` | The URL of the L2 rollup node. (After the tutorial, this is `http://localhost:8545`) | | `submissionInterval` | The number of L2 blocks between each L1 output submission. | | `l2BlockTime` | The time in seconds between each L2 block. | | `proposer` | The Ethereum address of the proposer account. If `address(0)`, anyone can submit proofs. | @@ -35,23 +52,13 @@ Inside the `contracts` folder there is a file called `zkconfig.json` that contai | `chainId` | The chain ID of the L2 network. | | `owner` | The Ethereum address of the `ZKL2OutputOracle` owner, who can update the verification key and verifier address. | | `vkey` | The verification key for the aggregate program. Run `cargo run --bin vkey --release` to generate this. | -| `verifierGateway` | The address of the verifier gateway contract. | -| `l2OutputOracleProxy` | The address of your OP Stack chain's L2 Output Oracle proxy contract which will be upgraded. | - -### 4) Deploy the `ZKL2OutputOracle` contract: +| `rollupConfigHash` | The hash of the rollup config. This is used for non-superchain OP stack configurations. | +| `verifierGateway` | The address of the verifier gateway contract. The canonical Succinct verifiers can be found [here](https://docs.succinct.xyz/onchain-verification/contract-addresses.html). | +| `l2OutputOracleProxy` | The address of your OP Stack chain's L2 Output Oracle proxy contract which will be upgraded. Only used in `ZKUpgrader`. | -This foundry script will deploy the `ZKL2OutputOracle` contract to the specified L1 RPC and use the provided private key to sign the transaction. - -Make sure to set your env with the following variables: - -``` -L1_RPC=... -L2_NODE_RPC=... -PRIVATE_KEY=... -ETHERSCAN_API_KEY=... -``` +### 5) Deploy the `ZKL2OutputOracle` contract: -and then run the following command to deploy the contract: +This foundry script will deploy the `ZKL2OutputOracle` contract to the specified L1 RPC and use the provided private key to sign the transaction: ```bash forge script script/ZKDeployer.s.sol:ZKDeployer \ diff --git a/contracts/.env.example b/contracts/.env.example deleted file mode 100644 index 91118ddb..00000000 --- a/contracts/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -L1_RPC= -# Rollup RPC URL -L2_NODE_RPC= -PRIVATE_KEY= -ETHERSCAN_API_KEY= \ No newline at end of file diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 8c01286a..42668e90 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -17,8 +17,7 @@ remappings = [ "src/L2/=lib/optimism/packages/contracts-bedrock/src/L2/", ] -# Enable read-write access to zkconfig.json -fs_permissions = [{ access = "read-write", path = "./zkconfig.json" }] +# Enable read-write access to zkl2ooconfig.json +fs_permissions = [{ access = "read-write", path = "./zkl2ooconfig.json" }] -dotenv = ".env" # See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/contracts/script/ZKDeployer.s.sol b/contracts/script/ZKDeployer.s.sol index 51fec67d..04b8be42 100644 --- a/contracts/script/ZKDeployer.s.sol +++ b/contracts/script/ZKDeployer.s.sol @@ -10,13 +10,16 @@ contract ZKDeployer is Script, Utils { function run() public returns (address) { vm.startBroadcast(); - Config memory config = readJsonWithRPCFromEnv("zkconfig.json"); - // Note: The owner of the proxy shouldn't be the msg.sender. + // Update the rollup config to match the current chain. If the starting block number is 0, the latest block number and starting output root will be fetched. + updateRollupConfig(); + + Config memory config = readJson("zkl2ooconfig.json"); + config.l2OutputOracleProxy = address(new Proxy(config.owner)); address zkL2OutputOracleImpl = address(new ZKL2OutputOracle()); - upgradeAndInitialize(zkL2OutputOracleImpl, config, address(0), bytes32(0), 0); + upgradeAndInitialize(zkL2OutputOracleImpl, config, address(0)); vm.stopBroadcast(); diff --git a/contracts/script/ZKUpgrader.s.sol b/contracts/script/ZKUpgrader.s.sol index 3c90f871..7f74982e 100644 --- a/contracts/script/ZKUpgrader.s.sol +++ b/contracts/script/ZKUpgrader.s.sol @@ -7,12 +7,15 @@ import {Utils} from "../test/helpers/Utils.sol"; contract ZKUpgrader is Script, Utils { function run() public { - Config memory config = readJson("zkconfig.json"); + // Update the rollup config to match the current chain. If the starting block number is 0, the latest block number and starting output root will be fetched. + updateRollupConfig(); + + Config memory config = readJson("zkl2ooconfig.json"); vm.startBroadcast(vm.envUint("ADMIN_PK")); address zkL2OutputOracleImpl = address(new ZKL2OutputOracle()); - upgradeAndInitialize(zkL2OutputOracleImpl, config, address(0), bytes32(0), 0); + upgradeAndInitialize(zkL2OutputOracleImpl, config, address(0)); vm.stopBroadcast(); } diff --git a/contracts/src/ZKL2OutputOracle.sol b/contracts/src/ZKL2OutputOracle.sol index e8d5ab4c..44452e2e 100644 --- a/contracts/src/ZKL2OutputOracle.sol +++ b/contracts/src/ZKL2OutputOracle.sol @@ -56,6 +56,9 @@ contract ZKL2OutputOracle is Initializable, ISemver { /// @notice The owner of the contract, who has admin permissions. address public owner; + /// @notice The hash of the chain's rollup config, used to verify ZK proofs. + bytes32 public rollupConfigHash; + /// @notice A trusted mapping of block numbers to block hashes. mapping(uint256 => bytes32) public historicBlockHashes; @@ -66,6 +69,7 @@ contract ZKL2OutputOracle is Initializable, ISemver { address verifierGateway; bytes32 startingOutputRoot; address owner; + bytes32 rollupConfigHash; } /// @notice Struct containing the public values committed to for the SP1 proof. @@ -75,6 +79,7 @@ contract ZKL2OutputOracle is Initializable, ISemver { bytes32 claimRoot; uint256 claimBlockNum; uint256 chainId; + bytes32 rollupConfigHash; } //////////////////////////////////////////////////////////// @@ -110,6 +115,11 @@ contract ZKL2OutputOracle is Initializable, ISemver { /// @param newOwner The new owner. event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + /// @notice Emitted when the rollup config hash is updated. + /// @param oldRollupConfigHash The old rollup config hash. + /// @param newRollupConfigHash The new rollup config hash. + event UpdatedRollupConfigHash(bytes32 indexed oldRollupConfigHash, bytes32 indexed newRollupConfigHash); + /// @notice Semantic version. /// @custom:semver 2.0.0 string public constant version = "2.0.0"; @@ -183,6 +193,7 @@ contract ZKL2OutputOracle is Initializable, ISemver { _transferOwnership(_zkInitParams.owner); _updateVKey(_zkInitParams.vkey); _updateVerifierGateway(_zkInitParams.verifierGateway); + _updateRollupConfigHash(_zkInitParams.rollupConfigHash); } /// @notice Getter for the submissionInterval. @@ -296,7 +307,8 @@ contract ZKL2OutputOracle is Initializable, ISemver { l2PreRoot: l2Outputs[latestOutputIndex()].outputRoot, claimRoot: _outputRoot, claimBlockNum: _l2BlockNumber, - chainId: chainId + chainId: chainId, + rollupConfigHash: rollupConfigHash }); verifierGateway.verifyProof(vkey, abi.encode(publicValues), _proof); @@ -432,4 +444,13 @@ contract ZKL2OutputOracle is Initializable, ISemver { emit UpdatedVerifierGateway(address(verifierGateway), _verifierGateway); verifierGateway = SP1VerifierGateway(_verifierGateway); } + + function updateRollupConfigHash(bytes32 _rollupConfigHash) external onlyOwner { + _updateRollupConfigHash(_rollupConfigHash); + } + + function _updateRollupConfigHash(bytes32 _rollupConfigHash) internal { + emit UpdatedRollupConfigHash(rollupConfigHash, _rollupConfigHash); + rollupConfigHash = _rollupConfigHash; + } } diff --git a/contracts/test/Upgrade.t.sol b/contracts/test/Upgrade.t.sol index e7b9cb40..9a01d64b 100644 --- a/contracts/test/Upgrade.t.sol +++ b/contracts/test/Upgrade.t.sol @@ -9,7 +9,7 @@ import {Utils} from "./helpers/Utils.sol"; contract UpgradeTest is Test, Utils { function testReadJsonSucceeds() public { - Config memory config = readJson("zkconfig.json"); + Config memory config = readJson("zkl2ooconfig.json"); assertEq(config.l2BlockTime, 2); assertEq(config.proposer, address(0)); } @@ -19,20 +19,14 @@ contract UpgradeTest is Test, Utils { vm.warp(12345678); uint256 exampleTimestamp = block.timestamp - 1; - Config memory config = readJson("zkconfig.json"); + Config memory config = readJson("zkl2ooconfig.json"); // This is never called, so we just need to add some code to the address so the check passes. config.verifierGateway = address(new Proxy(address(this))); - ZKL2OutputOracle l2oo = ZKL2OutputOracle(deployWithConfig(config, exampleOutputRoot, exampleTimestamp)); + config.startingOutputRoot = exampleOutputRoot; + config.startingTimestamp = exampleTimestamp; + ZKL2OutputOracle l2oo = ZKL2OutputOracle(deployWithConfig(config)); assertEq(l2oo.getL2Output(l2oo.latestOutputIndex()).outputRoot, exampleOutputRoot); assertEq(l2oo.getL2Output(l2oo.latestOutputIndex()).timestamp, exampleTimestamp); } - - function testHexString() public { - assertEq(createHexString(0), "0x0"); - assertEq(createHexString(1), "0x1"); - assertEq(createHexString(15), "0xf"); - assertEq(createHexString(16), "0x10"); - assertEq(createHexString(256), "0x100"); - } } diff --git a/contracts/test/ZKL2OutputOracle.t.sol b/contracts/test/ZKL2OutputOracle.t.sol index 96139314..7542eb00 100644 --- a/contracts/test/ZKL2OutputOracle.t.sol +++ b/contracts/test/ZKL2OutputOracle.t.sol @@ -26,7 +26,7 @@ contract ZKL2OutputOracleTest is Test, Utils { function setUp() public { vm.createSelectFork("https://sepolia.gateway.tenderly.co", L1_BLOCK_NUM + 1); - config = readJson("zkconfig.json"); + config = readJson("zkl2ooconfig.json"); // set default params for testing config.vkey = VK; @@ -42,27 +42,10 @@ contract ZKL2OutputOracleTest is Test, Utils { l2oo.proposeL2Output(claimedOutputRoot, claimedL2BlockNum, L1_HEAD, L1_BLOCK_NUM, proof); } - function testZKL2OOFreshDeployment() public { - l2oo = ZKL2OutputOracle(deployWithConfig(config, STARTING_OUTPUT_ROOT, STARTING_TIMESTAMP)); - vm.startPrank(l2oo.PROPOSER()); - - // fails if block hash hasn't been checkpointed - vm.expectRevert(); - l2oo.proposeL2Output(claimedOutputRoot, claimedL2BlockNum, L1_HEAD, L1_BLOCK_NUM, proof); - - // set block hash - vm.setBlockhash(L1_BLOCK_NUM, L1_HEAD); - l2oo.checkpointBlockHash(L1_BLOCK_NUM, L1_HEAD); - vm.warp(block.timestamp * 2); - - // succeeds after - l2oo.proposeL2Output(claimedOutputRoot, claimedL2BlockNum, L1_HEAD, L1_BLOCK_NUM, proof); - - assertEq(l2oo.getL2Output(1).outputRoot, claimedOutputRoot); - } - function testZKL2OOFailsWithWrongParams() public { - l2oo = ZKL2OutputOracle(deployWithConfig(config, STARTING_OUTPUT_ROOT, STARTING_TIMESTAMP)); + config.startingOutputRoot = STARTING_OUTPUT_ROOT; + config.startingTimestamp = STARTING_TIMESTAMP; + l2oo = ZKL2OutputOracle(deployWithConfig(config)); vm.setBlockhash(L1_BLOCK_NUM, L1_HEAD); l2oo.checkpointBlockHash(L1_BLOCK_NUM, L1_HEAD); diff --git a/contracts/test/helpers/JSONDecoder.sol b/contracts/test/helpers/JSONDecoder.sol index 4736974b..e94e4a06 100644 --- a/contracts/test/helpers/JSONDecoder.sol +++ b/contracts/test/helpers/JSONDecoder.sol @@ -8,10 +8,12 @@ contract JSONDecoder { uint256 finalizationPeriod; uint256 l2BlockTime; address l2OutputOracleProxy; - string l2RollupNode; address owner; address proposer; + bytes32 rollupConfigHash; uint256 startingBlockNumber; + bytes32 startingOutputRoot; + uint256 startingTimestamp; uint256 submissionInterval; address verifierGateway; bytes32 vkey; diff --git a/contracts/test/helpers/Utils.sol b/contracts/test/helpers/Utils.sol index 96b81cc1..fca2c902 100644 --- a/contracts/test/helpers/Utils.sol +++ b/contracts/test/helpers/Utils.sol @@ -8,16 +8,13 @@ import {Proxy} from "@optimism/src/universal/Proxy.sol"; import {ZKL2OutputOracle} from "src/ZKL2OutputOracle.sol"; contract Utils is Test, JSONDecoder { - function deployWithConfig(Config memory cfg, bytes32 startingOutputRoot, uint256 startingTimestamp) - public - returns (address) - { + function deployWithConfig(Config memory cfg) public returns (address) { address zkL2OutputOracleImpl = address(new ZKL2OutputOracle()); cfg.l2OutputOracleProxy = address(new Proxy(address(this))); // Upgrade the proxy to point to the implementation and call initialize(). // Override the starting output root and timestmp with the passed values. - upgradeAndInitialize(zkL2OutputOracleImpl, cfg, address(0), startingOutputRoot, startingTimestamp); + upgradeAndInitialize(zkL2OutputOracleImpl, cfg, address(0)); // Transfer ownership of proxy to owner specified in the config. Proxy(payable(cfg.l2OutputOracleProxy)).changeAdmin(cfg.owner); @@ -25,30 +22,17 @@ contract Utils is Test, JSONDecoder { return cfg.l2OutputOracleProxy; } - function upgradeAndInitialize( - address impl, - Config memory cfg, - address _spoofedAdmin, - bytes32 startingOutputRoot, - uint256 startingTimestamp - ) public { + function upgradeAndInitialize(address impl, Config memory cfg, address _spoofedAdmin) public { // require that the verifier gateway is deployed require(address(cfg.verifierGateway).code.length > 0, "ZKUpgrader: verifier gateway not deployed"); - // If we passed a starting output root or starting timestamp, use it. - // Otherwise, use the L2 Rollup Node to fetch the values based on the starting block number in the config. - if (startingOutputRoot == bytes32(0) || startingTimestamp == 0) { - (bytes32 returnedStartingOutputRoot, uint256 returnedStartingTimestamp) = fetchOutputRoot(cfg); - if (startingOutputRoot == bytes32(0)) startingOutputRoot = returnedStartingOutputRoot; - if (startingTimestamp == 0) startingTimestamp = returnedStartingTimestamp; - } - ZKL2OutputOracle.ZKInitParams memory zkInitParams = ZKL2OutputOracle.ZKInitParams({ chainId: cfg.chainId, verifierGateway: cfg.verifierGateway, vkey: cfg.vkey, owner: cfg.owner, - startingOutputRoot: startingOutputRoot + startingOutputRoot: cfg.startingOutputRoot, + rollupConfigHash: cfg.rollupConfigHash }); // If we are spoofing the admin (used in testing), start prank. @@ -62,7 +46,7 @@ contract Utils is Test, JSONDecoder { cfg.submissionInterval, cfg.l2BlockTime, cfg.startingBlockNumber, - startingTimestamp, + cfg.startingTimestamp, cfg.proposer, cfg.challenger, cfg.finalizationPeriod, @@ -72,6 +56,7 @@ contract Utils is Test, JSONDecoder { ); } + // Read the config from the json file. function readJson(string memory filepath) public view returns (Config memory) { string memory root = vm.projectRoot(); string memory path = string.concat(root, "/", filepath); @@ -80,52 +65,28 @@ contract Utils is Test, JSONDecoder { return abi.decode(data, (Config)); } - function readJsonWithRPCFromEnv(string memory filepath) public view returns (Config memory) { - Config memory config = readJson(filepath); - config.l2RollupNode = vm.envString("L2_NODE_RPC"); - return config; - } - - function fetchOutputRoot(Config memory config) - public - returns (bytes32 startingOutputRoot, uint256 startingTimestamp) - { - string memory hexStartingBlockNumber = createHexString(config.startingBlockNumber); - + // This script updates the rollup config hash and the block number in the config. + function updateRollupConfig() public { + // Build the fetch-rollup-config binary. Use the quiet flag to suppress build output. string[] memory inputs = new string[](6); - inputs[0] = "cast"; - inputs[1] = "rpc"; - inputs[2] = "--rpc-url"; - inputs[3] = config.l2RollupNode; - inputs[4] = "optimism_outputAtBlock"; - inputs[5] = hexStartingBlockNumber; - - string memory jsonRes = string(vm.ffi(inputs)); - bytes memory outputRootBytes = vm.parseJson(jsonRes, ".outputRoot"); - bytes memory startingTimestampBytes = vm.parseJson(jsonRes, ".blockRef.timestamp"); - - startingOutputRoot = abi.decode(outputRootBytes, (bytes32)); - startingTimestamp = abi.decode(startingTimestampBytes, (uint256)); - } - - function createHexString(uint256 value) public pure returns (string memory) { - string memory hexStartingBlockNum = Strings.toHexString(value); - bytes memory startingBlockNumAsBytes = bytes(hexStartingBlockNum); - require( - startingBlockNumAsBytes.length >= 4 && startingBlockNumAsBytes[0] == "0" - && startingBlockNumAsBytes[1] == "x", - "Invalid input" - ); - - if (startingBlockNumAsBytes[2] == "0") { - bytes memory result = new bytes(startingBlockNumAsBytes.length - 1); - result[0] = "0"; - result[1] = "x"; - for (uint256 i = 3; i < startingBlockNumAsBytes.length; i++) { - result[i - 1] = startingBlockNumAsBytes[i]; - } - return string(result); - } - return hexStartingBlockNum; + inputs[0] = "cargo"; + inputs[1] = "build"; + inputs[2] = "--bin"; + inputs[3] = "fetch-rollup-config"; + inputs[4] = "--release"; + inputs[5] = "--quiet"; + vm.ffi(inputs); + + // Run the fetch-rollup-config binary which updates the rollup config hash and the block number in the config. + // Use the quiet flag to suppress build output. + string[] memory inputs2 = new string[](6); + inputs2[0] = "cargo"; + inputs2[1] = "run"; + inputs2[2] = "--bin"; + inputs2[3] = "fetch-rollup-config"; + inputs2[4] = "--release"; + inputs2[5] = "--quiet"; + + vm.ffi(inputs2); } } diff --git a/contracts/zkl2ooconfig.json b/contracts/zkl2ooconfig.json new file mode 100644 index 00000000..b5983ea8 --- /dev/null +++ b/contracts/zkl2ooconfig.json @@ -0,0 +1,16 @@ +{ + "chainId": 13269, + "challenger": "0x0000000000000000000000000000000000000000", + "finalizationPeriod": 0, + "l2BlockTime": 2, + "l2OutputOracleProxy": "0x863508f057c09f7b94e582d74404859ecd36a306", + "owner": "0x0000000000000000000000000000000000000000", + "proposer": "0x0000000000000000000000000000000000000000", + "rollupConfigHash": "0x25c30030889fc3619b7da5ac7937c0d3c34f27d69a9afb053e2e73f344593af8", + "startingBlockNumber": 1339701, + "startingOutputRoot": "0xb966e2f5672253db3a49e17cf88173715b018ec7d6424719643b858966b23176", + "startingTimestamp": 1726166754, + "submissionInterval": 150, + "verifierGateway": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", + "vkey": "0x003ed12d1c9d67fd4f92dfe4e00badc5c38a886f0d233971132515e0c4ee13ec" +} \ No newline at end of file diff --git a/elf/aggregation-elf b/elf/aggregation-elf index cdce60bb..27a04b1a 100755 Binary files a/elf/aggregation-elf and b/elf/aggregation-elf differ diff --git a/elf/fault-proof-elf b/elf/fault-proof-elf index a80844f1..916eef8d 100755 Binary files a/elf/fault-proof-elf and b/elf/fault-proof-elf differ diff --git a/elf/range-elf b/elf/range-elf index 5b621e2b..03cd9c0b 100755 Binary files a/elf/range-elf and b/elf/range-elf differ diff --git a/elf/riscv32im-succinct-zkvm-elf b/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 00000000..c8a8d373 Binary files /dev/null and b/elf/riscv32im-succinct-zkvm-elf differ diff --git a/justfile b/justfile index 79cfef61..74f5fa12 100644 --- a/justfile +++ b/justfile @@ -89,9 +89,9 @@ run-client-native l2_block_num l1_rpc='${L1_RPC}' l1_beacon_rpc='${L1_BEACON_RPC upgrade-l2oo l1_rpc admin_pk etherscan_api_key="": #!/usr/bin/env bash - CHAIN_ID=$(jq -r '.chainId' contracts/zkconfig.json) + CHAIN_ID=$(jq -r '.chainId' contracts/zkl2ooconfig.json) if [ "$CHAIN_ID" = "0" ] || [ -z "$CHAIN_ID" ]; then - echo "Are you sure you've filled out your zkconfig.json? Your chain ID is currently set to 0." + echo "Are you sure you've filled out your zkl2ooconfig.json? Your chain ID is currently set to 0." exit 1 fi diff --git a/programs/aggregation/Cargo.toml b/programs/aggregation/Cargo.toml index b9b650a4..1f6c7748 100644 --- a/programs/aggregation/Cargo.toml +++ b/programs/aggregation/Cargo.toml @@ -14,5 +14,5 @@ sp1-lib = { workspace = true } op-succinct-client-utils = { workspace = true } alloy-consensus = { workspace = true } alloy-primitives = { workspace = true } +alloy-sol-types = { workspace = true } serde_cbor.workspace = true -itertools.workspace = true diff --git a/programs/aggregation/src/main.rs b/programs/aggregation/src/main.rs index e10e7571..f8b2d23a 100644 --- a/programs/aggregation/src/main.rs +++ b/programs/aggregation/src/main.rs @@ -4,58 +4,61 @@ #[cfg(target_os = "zkvm")] sp1_zkvm::entrypoint!(main); -use std::collections::HashMap; - use alloy_consensus::Header; use alloy_primitives::B256; -use itertools::Itertools; -use op_succinct_client_utils::{types::AggregationInputs, RawBootInfo}; +use alloy_sol_types::SolValue; +use std::collections::HashMap; + +use op_succinct_client_utils::{boot::BootInfoStruct, types::AggregationInputs}; use sha2::{Digest, Sha256}; /// The verification key for the multi-block program. /// /// Whenever the multi-block program changes, you will need to update this. const MULTI_BLOCK_PROGRAM_VKEY_DIGEST: [u32; 8] = - [941772999, 1277538870, 1655999821, 1372179823, 58726408, 594788167, 675948275, 736718718]; + [1433563224, 915959902, 1739327614, 1467493203, 514223451, 768124479, 1632058379, 944956804]; -fn main() { - // Read in the aggregation inputs corresponding to each multi-block proof. +pub fn main() { + // Read in the public values corresponding to each multi-block proof. let agg_inputs = sp1_zkvm::io::read::(); - - // Read in the headers. - // - // Note: The headers are in order from start to end. We use [serde_cbor] as bincode - // serialization causes issues with the zkVM. + // Note: The headers are in order from start to end. We use serde_cbor as bincode serialization + // causes issues with the zkVM. let headers_bytes = sp1_zkvm::io::read_vec(); let headers: Vec
= serde_cbor::from_slice(&headers_bytes).unwrap(); assert!(!agg_inputs.boot_infos.is_empty()); // Confirm that the boot infos are sequential. - agg_inputs.boot_infos.iter().tuples().for_each(|(prev_boot_info, curr_boot_info)| { - // The claimed block of the previous boot info must be the l2 output root of the current + agg_inputs.boot_infos.windows(2).for_each(|pair| { + let (prev_boot_info, boot_info) = (&pair[0], &pair[1]); + + // The claimed block of the previous boot info must be the L2 output root of the current // boot. - assert_eq!(prev_boot_info.l2_claim, curr_boot_info.l2_output_root); + assert_eq!(prev_boot_info.l2PostRoot, boot_info.l2PreRoot); + + // The chain ID must be the same for all the boot infos, to ensure they're + // from the same chain and span batch range. + assert_eq!(prev_boot_info.chainId, boot_info.chainId); - // The chain id must be the same for all the boot infos, to ensure they're + // The rollup config must be the same for all the boot infos, to ensure they're // from the same chain and span batch range. - assert_eq!(prev_boot_info.chain_id, curr_boot_info.chain_id); + assert_eq!(prev_boot_info.rollupConfigHash, boot_info.rollupConfigHash); }); // Verify each multi-block program proof. agg_inputs.boot_infos.iter().for_each(|boot_info| { - // Compute the public values digest as the hash of the abi-encoded [`RawBootInfo`]. + // In the multi-block program, the public values digest is just the hash of the ABI encoded + // boot info. let abi_encoded_boot_info = boot_info.abi_encode(); let pv_digest = Sha256::digest(abi_encoded_boot_info); - // Verify the proof against the public values digest. if cfg!(target_os = "zkvm") { sp1_lib::verify::verify_sp1_proof(&MULTI_BLOCK_PROGRAM_VKEY_DIGEST, &pv_digest.into()); } }); - // Create a map of each l1 head in the [`RawBootInfo`]s to booleans + // Create a map of each l1 head in the [`BootInfoStruct`]'s to booleans let mut l1_heads_map: HashMap = - agg_inputs.boot_infos.iter().map(|boot_info| (boot_info.l1_head, false)).collect(); + agg_inputs.boot_infos.iter().map(|boot_info| (boot_info.l1Head, false)).collect(); // Iterate through the headers in reverse order. The headers should be sequentially linked and // include the l1 head of each boot info. @@ -78,16 +81,17 @@ fn main() { let first_boot_info = &agg_inputs.boot_infos[0]; let last_boot_info = &agg_inputs.boot_infos[agg_inputs.boot_infos.len() - 1]; - - // Consolidate the boot info into an aggregated [`RawBootInfo`] that proves the range. - let final_boot_info = RawBootInfo { - l2_output_root: first_boot_info.l2_output_root, - l2_claim_block: last_boot_info.l2_claim_block, - l2_claim: last_boot_info.l2_claim, - l1_head: agg_inputs.latest_l1_checkpoint_head, - chain_id: last_boot_info.chain_id, + // Consolidate the boot info into a single BootInfo struct that represents the range proven. + let final_boot_info = BootInfoStruct { + // The first boot info's L2 output root is the L2 output root of the range. + l2PreRoot: first_boot_info.l2PreRoot, + l2BlockNumber: last_boot_info.l2BlockNumber, + l2PostRoot: last_boot_info.l2PostRoot, + l1Head: agg_inputs.latest_l1_checkpoint_head, + chainId: last_boot_info.chainId, + rollupConfigHash: last_boot_info.rollupConfigHash, }; - // Commit to the aggregated [`RawBootInfo`]. + // Commit to the aggregated [`BootInfoStruct`]. sp1_zkvm::io::commit_slice(&final_boot_info.abi_encode()); } diff --git a/programs/fault-proof/Cargo.toml b/programs/fault-proof/Cargo.toml index ad4ddd77..080d6925 100644 --- a/programs/fault-proof/Cargo.toml +++ b/programs/fault-proof/Cargo.toml @@ -9,6 +9,9 @@ homepage.workspace = true [dependencies] cfg-if.workspace = true +serde_json.workspace = true + +# workspace (ethereum) alloy-consensus.workspace = true # sp1 diff --git a/programs/fault-proof/src/main.rs b/programs/fault-proof/src/main.rs index 6e3031b3..cda44677 100644 --- a/programs/fault-proof/src/main.rs +++ b/programs/fault-proof/src/main.rs @@ -26,8 +26,10 @@ use op_succinct_client_utils::precompiles::zkvm_handle_register; cfg_if! { if #[cfg(target_os = "zkvm")] { sp1_zkvm::entrypoint!(main); - use op_succinct_client_utils::{RawBootInfo, InMemoryOracle}; + use op_succinct_client_utils::{InMemoryOracle, boot::BootInfoStruct, BootInfoWithBytesConfig}; + use kona_primitives::RollupConfig; use alloc::vec::Vec; + use serde_json; } else { use kona_client::CachingOracle; use op_succinct_client_utils::pipes::{ORACLE_READER, HINT_WRITER}; @@ -45,9 +47,23 @@ fn main() { // and in memory oracle. if #[cfg(target_os = "zkvm")] { println!("cycle-tracker-start: boot-load"); - let raw_boot_info = sp1_zkvm::io::read::(); - sp1_zkvm::io::commit_slice(&raw_boot_info.abi_encode()); - let boot: Arc = Arc::new(raw_boot_info.into()); + let boot_info_with_bytes_config = sp1_zkvm::io::read::(); + + // BootInfoStruct is identical to BootInfoWithBytesConfig, except it replaces + // the rollup_config_bytes with a hash of those bytes (rollupConfigHash). Securely + // hashes the rollup config bytes. + let boot_info_struct = BootInfoStruct::from(boot_info_with_bytes_config.clone()); + sp1_zkvm::io::commit::(&boot_info_struct); + + let rollup_config: RollupConfig = serde_json::from_slice(&boot_info_with_bytes_config.rollup_config_bytes).expect("failed to parse rollup config"); + let boot: Arc = Arc::new(BootInfo { + l1_head: boot_info_with_bytes_config.l1_head, + l2_output_root: boot_info_with_bytes_config.l2_output_root, + l2_claim: boot_info_with_bytes_config.l2_claim, + l2_claim_block: boot_info_with_bytes_config.l2_claim_block, + chain_id: boot_info_with_bytes_config.chain_id, + rollup_config, + }); println!("cycle-tracker-end: boot-load"); println!("cycle-tracker-start: oracle-load"); diff --git a/programs/range/Cargo.toml b/programs/range/Cargo.toml index 663000a1..ccc2e3ea 100644 --- a/programs/range/Cargo.toml +++ b/programs/range/Cargo.toml @@ -9,7 +9,10 @@ repository.workspace = true [dependencies] cfg-if.workspace = true +serde_json.workspace = true log.workspace = true + +# workspace (ethereum) op-alloy-consensus.workspace = true alloy-consensus.workspace = true alloy-eips.workspace = true @@ -23,4 +26,4 @@ kona-executor.workspace = true kona-client.workspace = true # op-succinct -op-succinct-client-utils.workspace = true \ No newline at end of file +op-succinct-client-utils.workspace = true diff --git a/programs/range/src/main.rs b/programs/range/src/main.rs index 68249123..b725d658 100644 --- a/programs/range/src/main.rs +++ b/programs/range/src/main.rs @@ -32,11 +32,13 @@ cfg_if! { if #[cfg(target_os = "zkvm")] { sp1_zkvm::entrypoint!(main); + use kona_primitives::RollupConfig; use op_succinct_client_utils::{ - RawBootInfo, + BootInfoWithBytesConfig, boot::BootInfoStruct, InMemoryOracle }; use alloc::vec::Vec; + use serde_json; } else { use kona_client::CachingOracle; use op_succinct_client_utils::pipes::{ORACLE_READER, HINT_WRITER}; @@ -54,9 +56,23 @@ fn main() { // and in memory oracle. if #[cfg(target_os = "zkvm")] { println!("cycle-tracker-start: boot-load"); - let boot = sp1_zkvm::io::read::(); - sp1_zkvm::io::commit_slice(&boot.abi_encode()); - let boot: Arc = Arc::new(boot.into()); + let boot_info_with_bytes_config = sp1_zkvm::io::read::(); + + // BootInfoStruct is identical to BootInfoWithBytesConfig, except it replaces + // the rollup_config_bytes with a hash of those bytes (rollupConfigHash). Securely + // hashes the rollup config bytes. + let boot_info_struct = BootInfoStruct::from(boot_info_with_bytes_config.clone()); + sp1_zkvm::io::commit::(&boot_info_struct); + + let rollup_config: RollupConfig = serde_json::from_slice(&boot_info_with_bytes_config.rollup_config_bytes).expect("failed to parse rollup config"); + let boot: Arc = Arc::new(BootInfo { + l1_head: boot_info_with_bytes_config.l1_head, + l2_output_root: boot_info_with_bytes_config.l2_output_root, + l2_claim: boot_info_with_bytes_config.l2_claim, + l2_claim_block: boot_info_with_bytes_config.l2_claim_block, + chain_id: boot_info_with_bytes_config.chain_id, + rollup_config, + }); println!("cycle-tracker-end: boot-load"); println!("cycle-tracker-start: oracle-load"); @@ -155,8 +171,10 @@ fn main() { Sealed::new_unchecked(new_block_header.clone(), new_block_header.hash_slow()), ); - // Produce the next payload. + println!("cycle-tracker-report-start: payload-derivation"); + // Produce the next payload. If a span batch boundary is passed, the driver will step until the next batch. payload = driver.produce_payloads().await.unwrap(); + println!("cycle-tracker-report-end: payload-derivation"); } println!("cycle-tracker-start: output-root"); diff --git a/proposer/op/Dockerfile.op_proposer b/proposer/op/Dockerfile.op_proposer index e60e964c..dfc07dd6 100644 --- a/proposer/op/Dockerfile.op_proposer +++ b/proposer/op/Dockerfile.op_proposer @@ -25,6 +25,9 @@ COPY --from=optimism-builder /optimism/op-proposer/proposer/bin/op-proposer /usr # Set the entrypoint to run op-proposer with environment variables COPY ./proposer/op/op_proposer.sh /usr/local/bin/op_proposer.sh +# Copy the rollup configs +COPY ../rollup-configs /rollup-configs + # Make the binary and entrypoint executable. RUN ls -l /usr/local/bin/ RUN chmod +x /usr/local/bin/op-proposer diff --git a/proposer/op/Dockerfile.span_batch_server b/proposer/op/Dockerfile.span_batch_server index fd3e008c..06ebffc2 100644 --- a/proposer/op/Dockerfile.span_batch_server +++ b/proposer/op/Dockerfile.span_batch_server @@ -25,6 +25,9 @@ WORKDIR /app # Copy the local proposer/op directory COPY ./proposer/op /app/op-proposer-go +# Copy the rollup configs +COPY ../rollup-configs /rollup-configs + # Change to the server directory and build the application WORKDIR /app/op-proposer-go/server diff --git a/proposer/op/Makefile b/proposer/op/Makefile index fb56e50e..ee008f1b 100644 --- a/proposer/op/Makefile +++ b/proposer/op/Makefile @@ -5,9 +5,9 @@ SHELL := /bin/bash bindings: @echo "Generating bindings for ZKL2OutputOracle.sol..." @mkdir -p bin generated_bindings - @cd ../contracts/ && forge install && forge build - @cd ../contracts/ && forge inspect src/ZKL2OutputOracle.sol:ZKL2OutputOracle abi > ../proposer/op/generated_bindings/ZKL2OutputOracle.abi - @cd ../contracts/ && forge inspect src/ZKL2OutputOracle.sol:ZKL2OutputOracle bytecode > ../proposer/op/generated_bindings/ZKL2OutputOracle.bin + @cd ../../contracts/ && forge install && forge build + @cd ../../contracts/ && forge inspect src/ZKL2OutputOracle.sol:ZKL2OutputOracle abi > ../proposer/op/generated_bindings/ZKL2OutputOracle.abi + @cd ../../contracts/ && forge inspect src/ZKL2OutputOracle.sol:ZKL2OutputOracle bytecode > ../proposer/op/generated_bindings/ZKL2OutputOracle.bin @abigen --abi generated_bindings/ZKL2OutputOracle.abi --bin generated_bindings/ZKL2OutputOracle.bin --pkg bindings --type ZKL2OutputOracle --out ./bindings/zkl2outputoracle.go @rm -rf generated_bindings @echo "Bindings generated successfully." diff --git a/proposer/op/bindings/zkl2outputoracle.go b/proposer/op/bindings/zkl2outputoracle.go index 18cec46e..cc6b8a7f 100644 --- a/proposer/op/bindings/zkl2outputoracle.go +++ b/proposer/op/bindings/zkl2outputoracle.go @@ -43,12 +43,13 @@ type ZKL2OutputOracleZKInitParams struct { VerifierGateway common.Address StartingOutputRoot [32]byte Owner common.Address + RollupConfigHash [32]byte } // ZKL2OutputOracleMetaData contains all meta data concerning the ZKL2OutputOracle contract. var ZKL2OutputOracleMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"CHALLENGER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"FINALIZATION_PERIOD_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L2_BLOCK_TIME\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PROPOSER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBMISSION_INTERVAL\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"chainId\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"challenger\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBlockHash\",\"inputs\":[{\"name\":\"_blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_blockHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"computeL2Timestamp\",\"inputs\":[{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deleteL2Outputs\",\"inputs\":[{\"name\":\"_l2OutputIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizationPeriodSeconds\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL2Output\",\"inputs\":[{\"name\":\"_l2OutputIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structTypes.OutputProposal\",\"components\":[{\"name\":\"outputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"timestamp\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"l2BlockNumber\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL2OutputAfter\",\"inputs\":[{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structTypes.OutputProposal\",\"components\":[{\"name\":\"outputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"timestamp\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"l2BlockNumber\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL2OutputIndexAfter\",\"inputs\":[{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"historicBlockHashes\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_submissionInterval\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_l2BlockTime\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_startingBlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_startingTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_proposer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_challenger\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_zkInitParams\",\"type\":\"tuple\",\"internalType\":\"structZKL2OutputOracle.ZKInitParams\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"vkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"verifierGateway\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"startingOutputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"l2BlockTime\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"latestBlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"latestOutputIndex\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nextBlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nextOutputIndex\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposeL2Output\",\"inputs\":[{\"name\":\"_outputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_l1BlockHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_l1BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"proposer\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"startingBlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"startingTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submissionInterval\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"_newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateVKey\",\"inputs\":[{\"name\":\"_vkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateVerifierGateway\",\"inputs\":[{\"name\":\"_verifierGateway\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifierGateway\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractSP1VerifierGateway\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"vkey\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutputProposed\",\"inputs\":[{\"name\":\"outputRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"l2OutputIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"l2BlockNumber\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"l1Timestamp\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutputsDeleted\",\"inputs\":[{\"name\":\"prevNextOutputIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"newNextOutputIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedVKey\",\"inputs\":[{\"name\":\"oldVkey\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newVkey\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedVerifierGateway\",\"inputs\":[{\"name\":\"oldVerifierGateway\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newVerifierGateway\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", - Bin: "0x608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6119bd806100ed6000396000f3fe6080604052600436106101ed5760003560e01c80639a8a05921161010d578063cf8e5cf0116100a0578063dcec33481161006f578063dcec334814610575578063e1a41bcf1461058a578063f2fde38b146105a0578063f4daa291146105c0578063fb3c491c146105d557600080fd5b8063cf8e5cf0146104f5578063d1de856c14610515578063d946a45614610535578063dbf330741461055557600080fd5b8063a9efd6b8116100dc578063a9efd6b814610498578063bffa7f0f146104ab578063c69b0eb1146104c9578063ce5db8d6146104df57600080fd5b80639a8a0592146103e2578063a196b525146103f8578063a25ae55714610425578063a8e4fb901461047857600080fd5b80636abcf563116101855780638878627211610154578063887862721461037657806389c44cbb1461038c5780638da5cb5b146103ac57806393991af3146103cc57600080fd5b80636abcf5631461030d5780636b4d98dd1461032257806370872aa5146103405780637f0064201461035657600080fd5b8063529933df116101c1578063529933df1461026d578063534db0e21461028257806354fd4d50146102ba57806369f16eec146102f857600080fd5b80622134cc146101f25780634418db5e146102165780634599c788146102385780634600df381461024d575b600080fd5b3480156101fe57600080fd5b506005545b6040519081526020015b60405180910390f35b34801561022257600080fd5b506102366102313660046115bf565b6105f5565b005b34801561024457600080fd5b50610203610634565b34801561025957600080fd5b50610236610268366004611651565b610691565b34801561027957600080fd5b50600454610203565b34801561028e57600080fd5b506006546102a2906001600160a01b031681565b6040516001600160a01b03909116815260200161020d565b3480156102c657600080fd5b506102eb604051806040016040528060058152602001640322e302e360dc1b81525081565b60405161020d9190611765565b34801561030457600080fd5b506102036109fe565b34801561031957600080fd5b50600354610203565b34801561032e57600080fd5b506006546001600160a01b03166102a2565b34801561034c57600080fd5b5061020360015481565b34801561036257600080fd5b50610203610371366004611778565b610a10565b34801561038257600080fd5b5061020360025481565b34801561039857600080fd5b506102366103a7366004611778565b610bae565b3480156103b857600080fd5b50600c546102a2906001600160a01b031681565b3480156103d857600080fd5b5061020360055481565b3480156103ee57600080fd5b5061020360095481565b34801561040457600080fd5b50610203610413366004611778565b600d6020526000908152604090205481565b34801561043157600080fd5b50610445610440366004611778565b610db3565b60408051825181526020808401516001600160801b0390811691830191909152928201519092169082015260600161020d565b34801561048457600080fd5b506007546102a2906001600160a01b031681565b6102366104a6366004611791565b610e31565b3480156104b757600080fd5b506007546001600160a01b03166102a2565b3480156104d557600080fd5b50610203600a5481565b3480156104eb57600080fd5b5061020360085481565b34801561050157600080fd5b50610445610510366004611778565b61134a565b34801561052157600080fd5b50610203610530366004611778565b611382565b34801561054157600080fd5b50610236610550366004611778565b6113b2565b34801561056157600080fd5b5061023661057036600461184d565b6113e5565b34801561058157600080fd5b5061020361146d565b34801561059657600080fd5b5061020360045481565b3480156105ac57600080fd5b506102366105bb3660046115bf565b611484565b3480156105cc57600080fd5b50600854610203565b3480156105e157600080fd5b50600b546102a2906001600160a01b031681565b600c546001600160a01b031633146106285760405162461bcd60e51b815260040161061f9061186f565b60405180910390fd5b610631816114b7565b50565b60035460009015610688576003805461064f906001906118cc565b8154811061065f5761065f6118e3565b6000918252602090912060029091020160010154600160801b90046001600160801b0316919050565b6001545b905090565b600054600290610100900460ff161580156106b3575060005460ff8083169116105b6107165760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161061f565b6000805461ffff191660ff8316176101001790558861079d5760405162461bcd60e51b815260206004820152603a60248201527f4c324f75747075744f7261636c653a207375626d697373696f6e20696e74657260448201527f76616c206d7573742062652067726561746572207468616e2030000000000000606482015260840161061f565b6000881161080a5760405162461bcd60e51b815260206004820152603460248201527f4c324f75747075744f7261636c653a204c3220626c6f636b2074696d65206d75604482015273073742062652067726561746572207468616e20360641b606482015260840161061f565b4286111561088e5760405162461bcd60e51b8152602060048201526044602482018190527f4c324f75747075744f7261636c653a207374617274696e67204c322074696d65908201527f7374616d70206d757374206265206c657373207468616e2063757272656e742060648201526374696d6560e01b608482015260a40161061f565b60048990556005889055600780546001600160a01b038088166001600160a01b0319928316179092556006805492871692909116919091179055600883905560035460000361098557604080516060808201835284015181526001600160801b03808916602083019081528a82169383019384526003805460018181018355600092909252935160029485027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810191909155915194518316600160801b0294909216939093177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c90930192909255908890558690555b8151600955608082015161099890611513565b6109a5826020015161156f565b6109b282604001516114b7565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b60035460009061068c906001906118cc565b6000610a1a610634565b821115610aa05760405162461bcd60e51b815260206004820152604860248201527f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707560448201527f7420666f72206120626c6f636b207468617420686173206e6f74206265656e206064820152671c1c9bdc1bdcd95960c21b608482015260a40161061f565b600354610b245760405162461bcd60e51b815260206004820152604660248201527f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707560448201527f74206173206e6f206f7574707574732068617665206265656e2070726f706f736064820152651959081e595d60d21b608482015260a40161061f565b6003546000905b80821015610ba75760006002610b4183856118f9565b610b4b9190611911565b90508460038281548110610b6157610b616118e3565b6000918252602090912060029091020160010154600160801b90046001600160801b03161015610b9d57610b968160016118f9565b9250610ba1565b8091505b50610b2b565b5092915050565b6006546001600160a01b03163314610c2e5760405162461bcd60e51b815260206004820152603e60248201527f4c324f75747075744f7261636c653a206f6e6c7920746865206368616c6c656e60448201527f67657220616464726573732063616e2064656c657465206f7574707574730000606482015260840161061f565b6003548110610cb15760405162461bcd60e51b815260206004820152604360248201527f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7560448201527f747075747320616674657220746865206c6174657374206f757470757420696e6064820152620c8caf60eb1b608482015260a40161061f565b60085460038281548110610cc757610cc76118e3565b6000918252602090912060016002909202010154610cee906001600160801b0316426118cc565b10610d705760405162461bcd60e51b815260206004820152604660248201527f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7560448201527f74707574732074686174206861766520616c7265616479206265656e2066696e606482015265185b1a5e995960d21b608482015260a40161061f565b6000610d7b60035490565b90508160035581817f4ee37ac2c786ec85e87592d3c5c8a1dd66f8496dda3f125d9ea8ca5f657629b660405160405180910390a35050565b604080516060810182526000808252602082018190529181019190915260038281548110610de357610de36118e3565b600091825260209182902060408051606081018252600290930290910180548352600101546001600160801b0380821694840194909452600160801b90049092169181019190915292915050565b6007546001600160a01b0316331480610e5357506007546001600160a01b0316155b610ecf5760405162461bcd60e51b815260206004820152604160248201527f4c324f75747075744f7261636c653a206f6e6c79207468652070726f706f736560448201527f7220616464726573732063616e2070726f706f7365206e6577206f75747075746064820152607360f81b608482015260a40161061f565b610ed761146d565b841015610f725760405162461bcd60e51b815260206004820152605860248201527f4c324f75747075744f7261636c653a20626c6f636b206e756d626572206d757360448201527f742062652067726561746572207468616e206f7220657175616c20746f206e6560648201527f787420657870656374656420626c6f636b206e756d6265720000000000000000608482015260a40161061f565b42610f7c85611382565b10610fe85760405162461bcd60e51b815260206004820152603660248201527f4c324f75747075744f7261636c653a2063616e6e6f742070726f706f7365204c60448201527532206f757470757420696e207468652066757475726560501b606482015260840161061f565b8461105b5760405162461bcd60e51b815260206004820152603a60248201527f4c324f75747075744f7261636c653a204c32206f75747075742070726f706f7360448201527f616c2063616e6e6f7420626520746865207a65726f2068617368000000000000606482015260840161061f565b600a546110d05760405162461bcd60e51b815260206004820152603b60248201527f4c324f75747075744f7261636c653a20766b6579206d7573742062652073657460448201527f206265666f72652070726f706f73696e6720616e206f75747075740000000000606482015260840161061f565b6000828152600d6020526040902054831461115f5760405162461bcd60e51b815260206004820152604360248201527f4c324f75747075744f7261636c653a2070726f706f73656420626c6f636b206860448201527f61736820616e64206e756d62657220617265206e6f7420636865636b706f696e6064820152621d195960ea1b608482015260a40161061f565b60006040518060a00160405280858152602001600361117c6109fe565b8154811061118c5761118c6118e3565b60009182526020918290206002909102015482528181018990526040808301899052600954606093840152600b54600a548251865181860152938601518484015291850151838501529284015160808084019190915284015160a08301529293506001600160a01b03909116916341493c609160c001604051602081830303815290604052856040518463ffffffff1660e01b815260040161123093929190611933565b60006040518083038186803b15801561124857600080fd5b505afa15801561125c573d6000803e3d6000fd5b505050508461126a60035490565b877fa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e24260405161129c91815260200190565b60405180910390a45050604080516060810182529485526001600160801b034281166020870190815294811691860191825260038054600181018255600091909152955160029096027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810196909655935190518416600160801b029316929092177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c909301929092555050565b6040805160608101825260008082526020820181905291810191909152600361137283610a10565b81548110610de357610de36118e3565b60006005546001548361139591906118cc565b61139f9190611968565b6002546113ac91906118f9565b92915050565b600c546001600160a01b031633146113dc5760405162461bcd60e51b815260040161061f9061186f565b6106318161156f565b8082401461145b5760405162461bcd60e51b815260206004820152603c60248201527f4c324f75747075744f7261636c653a20626c6f636b206861736820616e64206e60448201527f756d6265722063616e6e6f7420626520636865636b706f696e74656400000000606482015260840161061f565b6000918252600d602052604090912055565b600060045461147a610634565b61068c91906118f9565b600c546001600160a01b031633146114ae5760405162461bcd60e51b815260040161061f9061186f565b61063181611513565b600b546040516001600160a01b038084169216907f1379941631ff0ed9178ab16ab67a2e5db3aeada7f87e518f761e79c8e38377e390600090a3600b80546001600160a01b0319166001600160a01b0392909216919091179055565b600c546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c80546001600160a01b0319166001600160a01b0392909216919091179055565b600a546040518291907f9950c7ae9575688726be5b8ba4f28af88f91a9ad6853bc02658104b62cfcd77d90600090a3600a55565b80356001600160a01b03811681146115ba57600080fd5b919050565b6000602082840312156115d157600080fd5b6115da826115a3565b9392505050565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561161a5761161a6115e1565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611649576116496115e1565b604052919050565b600080600080600080600080888a0361018081121561166f57600080fd5b8935985060208a0135975060408a0135965060608a0135955061169460808b016115a3565b94506116a260a08b016115a3565b935060c08a0135925060a060df19820112156116bd57600080fd5b506116c66115f7565b60e08a013581526101008a013560208201526116e56101208b016115a3565b60408201526101408a013560608201526117026101608b016115a3565b6080820152809150509295985092959890939650565b6000815180845260005b8181101561173e57602081850181015186830182015201611722565b81811115611750576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006115da6020830184611718565b60006020828403121561178a57600080fd5b5035919050565b600080600080600060a086880312156117a957600080fd5b8535945060208087013594506040870135935060608701359250608087013567ffffffffffffffff808211156117de57600080fd5b818901915089601f8301126117f257600080fd5b813581811115611804576118046115e1565b611816601f8201601f19168501611620565b91508082528a8482850101111561182c57600080fd5b80848401858401376000848284010152508093505050509295509295909350565b6000806040838503121561186057600080fd5b50508035926020909101359150565b60208082526027908201527f4c324f75747075744f7261636c653a2063616c6c6572206973206e6f74207468604082015266329037bbb732b960c91b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6000828210156118de576118de6118b6565b500390565b634e487b7160e01b600052603260045260246000fd5b6000821982111561190c5761190c6118b6565b500190565b60008261192e57634e487b7160e01b600052601260045260246000fd5b500490565b83815260606020820152600061194c6060830185611718565b828103604084015261195e8185611718565b9695505050505050565b6000816000190483118215151615611982576119826118b6565b50029056fea26469706673582212208dc273e9d7370a4a3a9910063406b0007f50fcc3b19a1675a6eff11e22e4fb8064736f6c634300080f0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"CHALLENGER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"FINALIZATION_PERIOD_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L2_BLOCK_TIME\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PROPOSER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBMISSION_INTERVAL\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"chainId\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"challenger\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBlockHash\",\"inputs\":[{\"name\":\"_blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_blockHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"computeL2Timestamp\",\"inputs\":[{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deleteL2Outputs\",\"inputs\":[{\"name\":\"_l2OutputIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizationPeriodSeconds\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL2Output\",\"inputs\":[{\"name\":\"_l2OutputIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structTypes.OutputProposal\",\"components\":[{\"name\":\"outputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"timestamp\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"l2BlockNumber\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL2OutputAfter\",\"inputs\":[{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structTypes.OutputProposal\",\"components\":[{\"name\":\"outputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"timestamp\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"l2BlockNumber\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL2OutputIndexAfter\",\"inputs\":[{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"historicBlockHashes\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_submissionInterval\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_l2BlockTime\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_startingBlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_startingTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_proposer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_challenger\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_zkInitParams\",\"type\":\"tuple\",\"internalType\":\"structZKL2OutputOracle.ZKInitParams\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"vkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"verifierGateway\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"startingOutputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"rollupConfigHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"l2BlockTime\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"latestBlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"latestOutputIndex\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nextBlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nextOutputIndex\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposeL2Output\",\"inputs\":[{\"name\":\"_outputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_l1BlockHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_l1BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"proposer\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"rollupConfigHash\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"startingBlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"startingTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submissionInterval\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"_newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateRollupConfigHash\",\"inputs\":[{\"name\":\"_rollupConfigHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateVKey\",\"inputs\":[{\"name\":\"_vkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateVerifierGateway\",\"inputs\":[{\"name\":\"_verifierGateway\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifierGateway\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractSP1VerifierGateway\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"vkey\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutputProposed\",\"inputs\":[{\"name\":\"outputRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"l2OutputIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"l2BlockNumber\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"l1Timestamp\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutputsDeleted\",\"inputs\":[{\"name\":\"prevNextOutputIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"newNextOutputIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedRollupConfigHash\",\"inputs\":[{\"name\":\"oldRollupConfigHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newRollupConfigHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedVKey\",\"inputs\":[{\"name\":\"oldVkey\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newVkey\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedVerifierGateway\",\"inputs\":[{\"name\":\"oldVerifierGateway\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newVerifierGateway\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + Bin: "0x608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611a9b806100ed6000396000f3fe6080604052600436106102035760003560e01c80639a8a059211610118578063d1de856c116100a0578063e1a41bcf1161006f578063e1a41bcf146105b6578063ec2372ac146105cc578063f2fde38b146105ec578063f4daa2911461060c578063fb3c491c1461062157600080fd5b8063d1de856c14610541578063d946a45614610561578063dbf3307414610581578063dcec3348146105a157600080fd5b8063a9efd6b8116100e7578063a9efd6b8146104c4578063bffa7f0f146104d7578063c69b0eb1146104f5578063ce5db8d61461050b578063cf8e5cf01461052157600080fd5b80639a8a05921461040e578063a196b52514610424578063a25ae55714610451578063a8e4fb90146104a457600080fd5b80636abcf5631161019b5780637f0064201161016a5780637f0064201461038257806388786272146103a257806389c44cbb146103b85780638da5cb5b146103d857806393991af3146103f857600080fd5b80636abcf563146103235780636b4d98dd146103385780636d9a1c8b1461035657806370872aa51461036c57600080fd5b8063529933df116101d7578063529933df14610283578063534db0e21461029857806354fd4d50146102d057806369f16eec1461030e57600080fd5b80622134cc146102085780631bdd450c1461022c5780634418db5e1461024e5780634599c7881461026e575b600080fd5b34801561021457600080fd5b506005545b6040519081526020015b60405180910390f35b34801561023857600080fd5b5061024c610247366004611677565b610641565b005b34801561025a57600080fd5b5061024c6102693660046116ac565b610680565b34801561027a57600080fd5b506102196106b3565b34801561028f57600080fd5b50600454610219565b3480156102a457600080fd5b506006546102b8906001600160a01b031681565b6040516001600160a01b039091168152602001610223565b3480156102dc57600080fd5b50610301604051806040016040528060058152602001640322e302e360dc1b81525081565b604051610223919061171b565b34801561031a57600080fd5b50610219610710565b34801561032f57600080fd5b50600354610219565b34801561034457600080fd5b506006546001600160a01b03166102b8565b34801561036257600080fd5b50610219600d5481565b34801561037857600080fd5b5061021960015481565b34801561038e57600080fd5b5061021961039d366004611677565b610722565b3480156103ae57600080fd5b5061021960025481565b3480156103c457600080fd5b5061024c6103d3366004611677565b6108c0565b3480156103e457600080fd5b50600c546102b8906001600160a01b031681565b34801561040457600080fd5b5061021960055481565b34801561041a57600080fd5b5061021960095481565b34801561043057600080fd5b5061021961043f366004611677565b600e6020526000908152604090205481565b34801561045d57600080fd5b5061047161046c366004611677565b610ac5565b60408051825181526020808401516001600160801b03908116918301919091529282015190921690820152606001610223565b3480156104b057600080fd5b506007546102b8906001600160a01b031681565b61024c6104d236600461179e565b610b43565b3480156104e357600080fd5b506007546001600160a01b03166102b8565b34801561050157600080fd5b50610219600a5481565b34801561051757600080fd5b5061021960085481565b34801561052d57600080fd5b5061047161053c366004611677565b611070565b34801561054d57600080fd5b5061021961055c366004611677565b6110a8565b34801561056d57600080fd5b5061024c61057c366004611677565b6110d8565b34801561058d57600080fd5b5061024c61059c36600461185a565b61110b565b3480156105ad57600080fd5b50610219611193565b3480156105c257600080fd5b5061021960045481565b3480156105d857600080fd5b5061024c6105e736600461187c565b6111aa565b3480156105f857600080fd5b5061024c6106073660046116ac565b611524565b34801561061857600080fd5b50600854610219565b34801561062d57600080fd5b50600b546102b8906001600160a01b031681565b600c546001600160a01b031633146106745760405162461bcd60e51b815260040161066b9061194d565b60405180910390fd5b61067d81611557565b50565b600c546001600160a01b031633146106aa5760405162461bcd60e51b815260040161066b9061194d565b61067d8161158b565b6003546000901561070757600380546106ce906001906119aa565b815481106106de576106de6119c1565b6000918252602090912060029091020160010154600160801b90046001600160801b0316919050565b6001545b905090565b60035460009061070b906001906119aa565b600061072c6106b3565b8211156107b25760405162461bcd60e51b815260206004820152604860248201527f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707560448201527f7420666f72206120626c6f636b207468617420686173206e6f74206265656e206064820152671c1c9bdc1bdcd95960c21b608482015260a40161066b565b6003546108365760405162461bcd60e51b815260206004820152604660248201527f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707560448201527f74206173206e6f206f7574707574732068617665206265656e2070726f706f736064820152651959081e595d60d21b608482015260a40161066b565b6003546000905b808210156108b9576000600261085383856119d7565b61085d91906119ef565b90508460038281548110610873576108736119c1565b6000918252602090912060029091020160010154600160801b90046001600160801b031610156108af576108a88160016119d7565b92506108b3565b8091505b5061083d565b5092915050565b6006546001600160a01b031633146109405760405162461bcd60e51b815260206004820152603e60248201527f4c324f75747075744f7261636c653a206f6e6c7920746865206368616c6c656e60448201527f67657220616464726573732063616e2064656c657465206f7574707574730000606482015260840161066b565b60035481106109c35760405162461bcd60e51b815260206004820152604360248201527f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7560448201527f747075747320616674657220746865206c6174657374206f757470757420696e6064820152620c8caf60eb1b608482015260a40161066b565b600854600382815481106109d9576109d96119c1565b6000918252602090912060016002909202010154610a00906001600160801b0316426119aa565b10610a825760405162461bcd60e51b815260206004820152604660248201527f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7560448201527f74707574732074686174206861766520616c7265616479206265656e2066696e606482015265185b1a5e995960d21b608482015260a40161066b565b6000610a8d60035490565b90508160035581817f4ee37ac2c786ec85e87592d3c5c8a1dd66f8496dda3f125d9ea8ca5f657629b660405160405180910390a35050565b604080516060810182526000808252602082018190529181019190915260038281548110610af557610af56119c1565b600091825260209182902060408051606081018252600290930290910180548352600101546001600160801b0380821694840194909452600160801b90049092169181019190915292915050565b6007546001600160a01b0316331480610b6557506007546001600160a01b0316155b610be15760405162461bcd60e51b815260206004820152604160248201527f4c324f75747075744f7261636c653a206f6e6c79207468652070726f706f736560448201527f7220616464726573732063616e2070726f706f7365206e6577206f75747075746064820152607360f81b608482015260a40161066b565b610be9611193565b841015610c845760405162461bcd60e51b815260206004820152605860248201527f4c324f75747075744f7261636c653a20626c6f636b206e756d626572206d757360448201527f742062652067726561746572207468616e206f7220657175616c20746f206e6560648201527f787420657870656374656420626c6f636b206e756d6265720000000000000000608482015260a40161066b565b42610c8e856110a8565b10610cfa5760405162461bcd60e51b815260206004820152603660248201527f4c324f75747075744f7261636c653a2063616e6e6f742070726f706f7365204c60448201527532206f757470757420696e207468652066757475726560501b606482015260840161066b565b84610d6d5760405162461bcd60e51b815260206004820152603a60248201527f4c324f75747075744f7261636c653a204c32206f75747075742070726f706f7360448201527f616c2063616e6e6f7420626520746865207a65726f2068617368000000000000606482015260840161066b565b600a54610de25760405162461bcd60e51b815260206004820152603b60248201527f4c324f75747075744f7261636c653a20766b6579206d7573742062652073657460448201527f206265666f72652070726f706f73696e6720616e206f75747075740000000000606482015260840161066b565b6000828152600e60205260409020548314610e715760405162461bcd60e51b815260206004820152604360248201527f4c324f75747075744f7261636c653a2070726f706f73656420626c6f636b206860448201527f61736820616e64206e756d62657220617265206e6f7420636865636b706f696e6064820152621d195960ea1b608482015260a40161066b565b60006040518060c001604052808581526020016003610e8e610710565b81548110610e9e57610e9e6119c1565b60009182526020918290206002909102015482528181018990526040808301899052600954606080850191909152600d54608094850152600b54600a5483518751818701529487015185850152928601518483015290850151838501529284015160a08084019190915284015160c08301529293506001600160a01b03909116916341493c609160e001604051602081830303815290604052856040518463ffffffff1660e01b8152600401610f5693929190611a11565b60006040518083038186803b158015610f6e57600080fd5b505afa158015610f82573d6000803e3d6000fd5b5050505084610f9060035490565b877fa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e242604051610fc291815260200190565b60405180910390a45050604080516060810182529485526001600160801b034281166020870190815294811691860191825260038054600181018255600091909152955160029096027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810196909655935190518416600160801b029316929092177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c909301929092555050565b6040805160608101825260008082526020820181905291810191909152600361109883610722565b81548110610af557610af56119c1565b6000600554600154836110bb91906119aa565b6110c59190611a46565b6002546110d291906119d7565b92915050565b600c546001600160a01b031633146111025760405162461bcd60e51b815260040161066b9061194d565b61067d816115e7565b808240146111815760405162461bcd60e51b815260206004820152603c60248201527f4c324f75747075744f7261636c653a20626c6f636b206861736820616e64206e60448201527f756d6265722063616e6e6f7420626520636865636b706f696e74656400000000606482015260840161066b565b6000918252600e602052604090912055565b60006004546111a06106b3565b61070b91906119d7565b600054600290610100900460ff161580156111cc575060005460ff8083169116105b61122f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161066b565b6000805461ffff191660ff831617610100179055886112b65760405162461bcd60e51b815260206004820152603a60248201527f4c324f75747075744f7261636c653a207375626d697373696f6e20696e74657260448201527f76616c206d7573742062652067726561746572207468616e2030000000000000606482015260840161066b565b600088116113235760405162461bcd60e51b815260206004820152603460248201527f4c324f75747075744f7261636c653a204c3220626c6f636b2074696d65206d75604482015273073742062652067726561746572207468616e20360641b606482015260840161066b565b428611156113a75760405162461bcd60e51b8152602060048201526044602482018190527f4c324f75747075744f7261636c653a207374617274696e67204c322074696d65908201527f7374616d70206d757374206265206c657373207468616e2063757272656e742060648201526374696d6560e01b608482015260a40161066b565b60048990556005889055600780546001600160a01b038088166001600160a01b0319928316179092556006805492871692909116919091179055600883905560035460000361149e57604080516060808201835284015181526001600160801b03808916602083019081528a82169383019384526003805460018181018355600092909252935160029485027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810191909155915194518316600160801b0294909216939093177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c90930192909255908890558690555b815160095560808201516114b19061161b565b6114be82602001516115e7565b6114cb826040015161158b565b6114d88260a00151611557565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b600c546001600160a01b0316331461154e5760405162461bcd60e51b815260040161066b9061194d565b61067d8161161b565b600d546040518291907fda2f5f014ada26cff39a0f2a9dc6fa4fca1581376fc91ec09506c8fb8657bc3590600090a3600d55565b600b546040516001600160a01b038084169216907f1379941631ff0ed9178ab16ab67a2e5db3aeada7f87e518f761e79c8e38377e390600090a3600b80546001600160a01b0319166001600160a01b0392909216919091179055565b600a546040518291907f9950c7ae9575688726be5b8ba4f28af88f91a9ad6853bc02658104b62cfcd77d90600090a3600a55565b600c546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c80546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561168957600080fd5b5035919050565b80356001600160a01b03811681146116a757600080fd5b919050565b6000602082840312156116be57600080fd5b6116c782611690565b9392505050565b6000815180845260005b818110156116f4576020818501810151868301820152016116d8565b81811115611706576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006116c760208301846116ce565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff811182821017156117675761176761172e565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156117965761179661172e565b604052919050565b600080600080600060a086880312156117b657600080fd5b8535945060208087013594506040870135935060608701359250608087013567ffffffffffffffff808211156117eb57600080fd5b818901915089601f8301126117ff57600080fd5b8135818111156118115761181161172e565b611823601f8201601f1916850161176d565b91508082528a8482850101111561183957600080fd5b80848401858401376000848284010152508093505050509295509295909350565b6000806040838503121561186d57600080fd5b50508035926020909101359150565b600080600080600080600080888a036101a081121561189a57600080fd5b8935985060208a0135975060408a0135965060608a013595506118bf60808b01611690565b94506118cd60a08b01611690565b935060c08a810135935060df19820112156118e757600080fd5b506118f0611744565b60e08a013581526101008a0135602082015261190f6101208b01611690565b60408201526101408a0135606082015261192c6101608b01611690565b60808201526101808a013560a0820152809150509295985092959890939650565b60208082526027908201527f4c324f75747075744f7261636c653a2063616c6c6572206973206e6f74207468604082015266329037bbb732b960c91b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6000828210156119bc576119bc611994565b500390565b634e487b7160e01b600052603260045260246000fd5b600082198211156119ea576119ea611994565b500190565b600082611a0c57634e487b7160e01b600052601260045260246000fd5b500490565b838152606060208201526000611a2a60608301856116ce565b8281036040840152611a3c81856116ce565b9695505050505050565b6000816000190483118215151615611a6057611a60611994565b50029056fea264697066735822122095d42c91d57f64b4b65518c51a61ab9cf2605f2e30b15ddd1ad7fa9944b7979964736f6c634300080f0033", } // ZKL2OutputOracleABI is the input ABI used to generate the binding from. @@ -838,6 +839,37 @@ func (_ZKL2OutputOracle *ZKL2OutputOracleCallerSession) Proposer() (common.Addre return _ZKL2OutputOracle.Contract.Proposer(&_ZKL2OutputOracle.CallOpts) } +// RollupConfigHash is a free data retrieval call binding the contract method 0x6d9a1c8b. +// +// Solidity: function rollupConfigHash() view returns(bytes32) +func (_ZKL2OutputOracle *ZKL2OutputOracleCaller) RollupConfigHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ZKL2OutputOracle.contract.Call(opts, &out, "rollupConfigHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// RollupConfigHash is a free data retrieval call binding the contract method 0x6d9a1c8b. +// +// Solidity: function rollupConfigHash() view returns(bytes32) +func (_ZKL2OutputOracle *ZKL2OutputOracleSession) RollupConfigHash() ([32]byte, error) { + return _ZKL2OutputOracle.Contract.RollupConfigHash(&_ZKL2OutputOracle.CallOpts) +} + +// RollupConfigHash is a free data retrieval call binding the contract method 0x6d9a1c8b. +// +// Solidity: function rollupConfigHash() view returns(bytes32) +func (_ZKL2OutputOracle *ZKL2OutputOracleCallerSession) RollupConfigHash() ([32]byte, error) { + return _ZKL2OutputOracle.Contract.RollupConfigHash(&_ZKL2OutputOracle.CallOpts) +} + // StartingBlockNumber is a free data retrieval call binding the contract method 0x70872aa5. // // Solidity: function startingBlockNumber() view returns(uint256) @@ -1066,23 +1098,23 @@ func (_ZKL2OutputOracle *ZKL2OutputOracleTransactorSession) DeleteL2Outputs(_l2O return _ZKL2OutputOracle.Contract.DeleteL2Outputs(&_ZKL2OutputOracle.TransactOpts, _l2OutputIndex) } -// Initialize is a paid mutator transaction binding the contract method 0x4600df38. +// Initialize is a paid mutator transaction binding the contract method 0xec2372ac. // -// Solidity: function initialize(uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, uint256 _finalizationPeriodSeconds, (uint256,bytes32,address,bytes32,address) _zkInitParams) returns() +// Solidity: function initialize(uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, uint256 _finalizationPeriodSeconds, (uint256,bytes32,address,bytes32,address,bytes32) _zkInitParams) returns() func (_ZKL2OutputOracle *ZKL2OutputOracleTransactor) Initialize(opts *bind.TransactOpts, _submissionInterval *big.Int, _l2BlockTime *big.Int, _startingBlockNumber *big.Int, _startingTimestamp *big.Int, _proposer common.Address, _challenger common.Address, _finalizationPeriodSeconds *big.Int, _zkInitParams ZKL2OutputOracleZKInitParams) (*types.Transaction, error) { return _ZKL2OutputOracle.contract.Transact(opts, "initialize", _submissionInterval, _l2BlockTime, _startingBlockNumber, _startingTimestamp, _proposer, _challenger, _finalizationPeriodSeconds, _zkInitParams) } -// Initialize is a paid mutator transaction binding the contract method 0x4600df38. +// Initialize is a paid mutator transaction binding the contract method 0xec2372ac. // -// Solidity: function initialize(uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, uint256 _finalizationPeriodSeconds, (uint256,bytes32,address,bytes32,address) _zkInitParams) returns() +// Solidity: function initialize(uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, uint256 _finalizationPeriodSeconds, (uint256,bytes32,address,bytes32,address,bytes32) _zkInitParams) returns() func (_ZKL2OutputOracle *ZKL2OutputOracleSession) Initialize(_submissionInterval *big.Int, _l2BlockTime *big.Int, _startingBlockNumber *big.Int, _startingTimestamp *big.Int, _proposer common.Address, _challenger common.Address, _finalizationPeriodSeconds *big.Int, _zkInitParams ZKL2OutputOracleZKInitParams) (*types.Transaction, error) { return _ZKL2OutputOracle.Contract.Initialize(&_ZKL2OutputOracle.TransactOpts, _submissionInterval, _l2BlockTime, _startingBlockNumber, _startingTimestamp, _proposer, _challenger, _finalizationPeriodSeconds, _zkInitParams) } -// Initialize is a paid mutator transaction binding the contract method 0x4600df38. +// Initialize is a paid mutator transaction binding the contract method 0xec2372ac. // -// Solidity: function initialize(uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, uint256 _finalizationPeriodSeconds, (uint256,bytes32,address,bytes32,address) _zkInitParams) returns() +// Solidity: function initialize(uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, uint256 _finalizationPeriodSeconds, (uint256,bytes32,address,bytes32,address,bytes32) _zkInitParams) returns() func (_ZKL2OutputOracle *ZKL2OutputOracleTransactorSession) Initialize(_submissionInterval *big.Int, _l2BlockTime *big.Int, _startingBlockNumber *big.Int, _startingTimestamp *big.Int, _proposer common.Address, _challenger common.Address, _finalizationPeriodSeconds *big.Int, _zkInitParams ZKL2OutputOracleZKInitParams) (*types.Transaction, error) { return _ZKL2OutputOracle.Contract.Initialize(&_ZKL2OutputOracle.TransactOpts, _submissionInterval, _l2BlockTime, _startingBlockNumber, _startingTimestamp, _proposer, _challenger, _finalizationPeriodSeconds, _zkInitParams) } @@ -1129,6 +1161,27 @@ func (_ZKL2OutputOracle *ZKL2OutputOracleTransactorSession) TransferOwnership(_n return _ZKL2OutputOracle.Contract.TransferOwnership(&_ZKL2OutputOracle.TransactOpts, _newOwner) } +// UpdateRollupConfigHash is a paid mutator transaction binding the contract method 0x1bdd450c. +// +// Solidity: function updateRollupConfigHash(bytes32 _rollupConfigHash) returns() +func (_ZKL2OutputOracle *ZKL2OutputOracleTransactor) UpdateRollupConfigHash(opts *bind.TransactOpts, _rollupConfigHash [32]byte) (*types.Transaction, error) { + return _ZKL2OutputOracle.contract.Transact(opts, "updateRollupConfigHash", _rollupConfigHash) +} + +// UpdateRollupConfigHash is a paid mutator transaction binding the contract method 0x1bdd450c. +// +// Solidity: function updateRollupConfigHash(bytes32 _rollupConfigHash) returns() +func (_ZKL2OutputOracle *ZKL2OutputOracleSession) UpdateRollupConfigHash(_rollupConfigHash [32]byte) (*types.Transaction, error) { + return _ZKL2OutputOracle.Contract.UpdateRollupConfigHash(&_ZKL2OutputOracle.TransactOpts, _rollupConfigHash) +} + +// UpdateRollupConfigHash is a paid mutator transaction binding the contract method 0x1bdd450c. +// +// Solidity: function updateRollupConfigHash(bytes32 _rollupConfigHash) returns() +func (_ZKL2OutputOracle *ZKL2OutputOracleTransactorSession) UpdateRollupConfigHash(_rollupConfigHash [32]byte) (*types.Transaction, error) { + return _ZKL2OutputOracle.Contract.UpdateRollupConfigHash(&_ZKL2OutputOracle.TransactOpts, _rollupConfigHash) +} + // UpdateVKey is a paid mutator transaction binding the contract method 0xd946a456. // // Solidity: function updateVKey(bytes32 _vkey) returns() @@ -1774,6 +1827,159 @@ func (_ZKL2OutputOracle *ZKL2OutputOracleFilterer) ParseOwnershipTransferred(log return event, nil } +// ZKL2OutputOracleUpdatedRollupConfigHashIterator is returned from FilterUpdatedRollupConfigHash and is used to iterate over the raw logs and unpacked data for UpdatedRollupConfigHash events raised by the ZKL2OutputOracle contract. +type ZKL2OutputOracleUpdatedRollupConfigHashIterator struct { + Event *ZKL2OutputOracleUpdatedRollupConfigHash // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ZKL2OutputOracleUpdatedRollupConfigHashIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ZKL2OutputOracleUpdatedRollupConfigHash) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ZKL2OutputOracleUpdatedRollupConfigHash) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ZKL2OutputOracleUpdatedRollupConfigHashIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ZKL2OutputOracleUpdatedRollupConfigHashIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ZKL2OutputOracleUpdatedRollupConfigHash represents a UpdatedRollupConfigHash event raised by the ZKL2OutputOracle contract. +type ZKL2OutputOracleUpdatedRollupConfigHash struct { + OldRollupConfigHash [32]byte + NewRollupConfigHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterUpdatedRollupConfigHash is a free log retrieval operation binding the contract event 0xda2f5f014ada26cff39a0f2a9dc6fa4fca1581376fc91ec09506c8fb8657bc35. +// +// Solidity: event UpdatedRollupConfigHash(bytes32 indexed oldRollupConfigHash, bytes32 indexed newRollupConfigHash) +func (_ZKL2OutputOracle *ZKL2OutputOracleFilterer) FilterUpdatedRollupConfigHash(opts *bind.FilterOpts, oldRollupConfigHash [][32]byte, newRollupConfigHash [][32]byte) (*ZKL2OutputOracleUpdatedRollupConfigHashIterator, error) { + + var oldRollupConfigHashRule []interface{} + for _, oldRollupConfigHashItem := range oldRollupConfigHash { + oldRollupConfigHashRule = append(oldRollupConfigHashRule, oldRollupConfigHashItem) + } + var newRollupConfigHashRule []interface{} + for _, newRollupConfigHashItem := range newRollupConfigHash { + newRollupConfigHashRule = append(newRollupConfigHashRule, newRollupConfigHashItem) + } + + logs, sub, err := _ZKL2OutputOracle.contract.FilterLogs(opts, "UpdatedRollupConfigHash", oldRollupConfigHashRule, newRollupConfigHashRule) + if err != nil { + return nil, err + } + return &ZKL2OutputOracleUpdatedRollupConfigHashIterator{contract: _ZKL2OutputOracle.contract, event: "UpdatedRollupConfigHash", logs: logs, sub: sub}, nil +} + +// WatchUpdatedRollupConfigHash is a free log subscription operation binding the contract event 0xda2f5f014ada26cff39a0f2a9dc6fa4fca1581376fc91ec09506c8fb8657bc35. +// +// Solidity: event UpdatedRollupConfigHash(bytes32 indexed oldRollupConfigHash, bytes32 indexed newRollupConfigHash) +func (_ZKL2OutputOracle *ZKL2OutputOracleFilterer) WatchUpdatedRollupConfigHash(opts *bind.WatchOpts, sink chan<- *ZKL2OutputOracleUpdatedRollupConfigHash, oldRollupConfigHash [][32]byte, newRollupConfigHash [][32]byte) (event.Subscription, error) { + + var oldRollupConfigHashRule []interface{} + for _, oldRollupConfigHashItem := range oldRollupConfigHash { + oldRollupConfigHashRule = append(oldRollupConfigHashRule, oldRollupConfigHashItem) + } + var newRollupConfigHashRule []interface{} + for _, newRollupConfigHashItem := range newRollupConfigHash { + newRollupConfigHashRule = append(newRollupConfigHashRule, newRollupConfigHashItem) + } + + logs, sub, err := _ZKL2OutputOracle.contract.WatchLogs(opts, "UpdatedRollupConfigHash", oldRollupConfigHashRule, newRollupConfigHashRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ZKL2OutputOracleUpdatedRollupConfigHash) + if err := _ZKL2OutputOracle.contract.UnpackLog(event, "UpdatedRollupConfigHash", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseUpdatedRollupConfigHash is a log parse operation binding the contract event 0xda2f5f014ada26cff39a0f2a9dc6fa4fca1581376fc91ec09506c8fb8657bc35. +// +// Solidity: event UpdatedRollupConfigHash(bytes32 indexed oldRollupConfigHash, bytes32 indexed newRollupConfigHash) +func (_ZKL2OutputOracle *ZKL2OutputOracleFilterer) ParseUpdatedRollupConfigHash(log types.Log) (*ZKL2OutputOracleUpdatedRollupConfigHash, error) { + event := new(ZKL2OutputOracleUpdatedRollupConfigHash) + if err := _ZKL2OutputOracle.contract.UnpackLog(event, "UpdatedRollupConfigHash", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + // ZKL2OutputOracleUpdatedVKeyIterator is returned from FilterUpdatedVKey and is used to iterate over the raw logs and unpacked data for UpdatedVKey events raised by the ZKL2OutputOracle contract. type ZKL2OutputOracleUpdatedVKeyIterator struct { Event *ZKL2OutputOracleUpdatedVKey // Event containing the contract specifics and raw log diff --git a/proposer/op/cmd/main.go b/proposer/op/cmd/main.go index 3e9f5851..46d029bc 100644 --- a/proposer/op/cmd/main.go +++ b/proposer/op/cmd/main.go @@ -1,12 +1,13 @@ package main import ( + "context" "fmt" "log" "os" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum-optimism/optimism/op-service/dial" + "github.com/ethereum/go-ethereum/ethclient" "github.com/joho/godotenv" "github.com/succinctlabs/op-succinct-go/proposer/utils" "github.com/urfave/cli/v2" @@ -60,7 +61,18 @@ func main() { }, }, Action: func(cliCtx *cli.Context) error { - rollupCfg, err := utils.GetRollupConfigFromL2Rpc(cliCtx.String("l2")) + // Get the chain ID from the L2 RPC. + l2Client, err := ethclient.Dial(cliCtx.String("l2")) + if err != nil { + log.Fatal(err) + } + chainID, err := l2Client.ChainID(context.Background()) + if err != nil { + log.Fatal(err) + } + + // Load the rollup config for the given L2 chain ID. + rollupCfg, err := utils.LoadOPStackRollupConfigFromChainID(chainID.Uint64()) if err != nil { log.Fatal(err) } diff --git a/proposer/op/proposer/prove.go b/proposer/op/proposer/prove.go index 6f464455..0e2561fb 100644 --- a/proposer/op/proposer/prove.go +++ b/proposer/op/proposer/prove.go @@ -143,7 +143,6 @@ func (l *L2OutputSubmitter) RequestQueuedProofs(ctx context.Context) error { return } - // TODO: There's a better way to structure the flow of the server. err = l.RequestOPSuccinctProof(p) if err != nil { l.Log.Error("failed to request proof from the OP Succinct server", "err", err, "proof", p) diff --git a/proposer/op/proposer/span_batches.go b/proposer/op/proposer/span_batches.go index 894c0e18..9da7e67c 100644 --- a/proposer/op/proposer/span_batches.go +++ b/proposer/op/proposer/span_batches.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/succinctlabs/op-succinct-go/proposer/db/ent" "github.com/succinctlabs/op-succinct-go/proposer/utils" @@ -51,7 +50,7 @@ func (l *L2OutputSubmitter) DeriveNewSpanBatches(ctx context.Context) error { } // Get the rollup config for the chain to fetch the batcher address. - rollupCfg, err := rollup.LoadOPStackRollupConfig(l.Cfg.L2ChainID) + rollupCfg, err := utils.LoadOPStackRollupConfigFromChainID(l.Cfg.L2ChainID) if err != nil { return fmt.Errorf("failed to load rollup config: %w", err) } diff --git a/proposer/op/proposer/utils/utils.go b/proposer/op/proposer/utils/utils.go index 57be880e..c0fd6f7f 100644 --- a/proposer/op/proposer/utils/utils.go +++ b/proposer/op/proposer/utils/utils.go @@ -2,12 +2,17 @@ package utils import ( "context" + "encoding/json" "errors" "fmt" "io" "log" "math/big" "os" + "path/filepath" + "runtime" + "strconv" + "strings" "time" "github.com/ethereum-optimism/optimism/op-node/cmd/batch_decoder/fetch" @@ -47,24 +52,135 @@ type BatchDecoderConfig struct { DataDir string } -// Get the rollup config from the given L2 RPC. -func GetRollupConfigFromL2Rpc(l2Rpc string) (*rollup.Config, error) { - l2Client, err := ethclient.Dial(l2Rpc) +// CustomBytes32 is a wrapper around eth.Bytes32 that can unmarshal from both +// full-length and minimal hex strings. +type CustomBytes32 eth.Bytes32 + +// Unmarshal some data into a CustomBytes32. +func (b *CustomBytes32) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + // Remove "0x" prefix if present. + s = strings.TrimPrefix(s, "0x") + + // Pad the string to 64 characters (32 bytes) with leading zeros. + s = fmt.Sprintf("%064s", s) + + // Add back the "0x" prefix. + s = "0x" + s + + bytes, err := common.ParseHexOrString(s) if err != nil { - return nil, fmt.Errorf("failed to dial L2 client: %w", err) + return err + } + + if len(bytes) != 32 { + return fmt.Errorf("invalid length for Bytes32: got %d, want 32", len(bytes)) } - chainID, err := l2Client.ChainID(context.Background()) + copy((*b)[:], bytes) + return nil +} + +// LoadOPStackRollupConfigFromChainID loads and parses the rollup config for the given L2 chain ID. +func LoadOPStackRollupConfigFromChainID(l2ChainId uint64) (*rollup.Config, error) { + // Determine the path to the rollup config file. + _, currentFile, _, _ := runtime.Caller(0) + currentDir := filepath.Dir(currentFile) + path := filepath.Join(currentDir, "..", "..", "..", "..", "rollup-configs", fmt.Sprintf("%d.json", l2ChainId)) + + // Read the rollup config file. + rollupCfg, err := os.ReadFile(path) if err != nil { - return nil, fmt.Errorf("failed to get chain ID: %w", err) + return nil, fmt.Errorf("failed to read rollup config: %w", err) } - rollupCfg, err := rollup.LoadOPStackRollupConfig(chainID.Uint64()) + // Parse the JSON config. + var rawConfig map[string]interface{} + if err := json.Unmarshal(rollupCfg, &rawConfig); err != nil { + return nil, fmt.Errorf("failed to unmarshal rollup config: %w", err) + } + + // Convert the Rust SuperchainConfig types to Go types, as they differ in a few places. + convertedConfig, err := convertConfigTypes(rawConfig) if err != nil { - return nil, fmt.Errorf("failed to load rollup config: %w", err) + return nil, fmt.Errorf("failed to convert config types: %w", err) } - return rollupCfg, nil + // Marshal the converted config back to JSON. + modifiedConfig, err := json.Marshal(convertedConfig) + if err != nil { + return nil, fmt.Errorf("failed to re-marshal modified config: %w", err) + } + + // Unmarshal into the actual rollup.Config struct. + var config rollup.Config + if err := json.Unmarshal(modifiedConfig, &config); err != nil { + return nil, fmt.Errorf("failed to unmarshal modified rollup config: %w", err) + } + + return &config, nil +} + +// The JSON serialization of the Rust superchain-primitives types differ from the Go types (ex. U256 instead of Bytes32, U64 instead of uint64, etc.) +// This function converts the Rust types in the rollup config JSON to the Go types. +func convertConfigTypes(rawConfig map[string]interface{}) (map[string]interface{}, error) { + // Convert genesis block numbers. + if genesis, ok := rawConfig["genesis"].(map[string]interface{}); ok { + convertBlockNumber(genesis, "l1") + convertBlockNumber(genesis, "l2") + convertSystemConfig(genesis) + } + + // Convert base fee parameters. + convertBaseFeeParams(rawConfig, "base_fee_params") + convertBaseFeeParams(rawConfig, "canyon_base_fee_params") + + return rawConfig, nil +} + +// convertBlockNumber converts the block number from hex string to integer. +func convertBlockNumber(data map[string]interface{}, key string) { + if block, ok := data[key].(map[string]interface{}); ok { + if number, ok := block["number"].(string); ok { + if intNumber, err := strconv.ParseInt(strings.TrimPrefix(number, "0x"), 16, 64); err == nil { + block["number"] = intNumber + } + } + } +} + +// convertSystemConfig converts the overhead and scalar fields in the system config. +func convertSystemConfig(genesis map[string]interface{}) { + if systemConfig, ok := genesis["system_config"].(map[string]interface{}); ok { + convertBytes32Field(systemConfig, "overhead") + convertBytes32Field(systemConfig, "scalar") + } +} + +// convertBytes32Field converts a hex string to CustomBytes32 which can unmarshal from both +// full-length and minimal hex strings. +func convertBytes32Field(data map[string]interface{}, key string) { + if value, ok := data[key].(string); ok { + var customValue CustomBytes32 + if err := customValue.UnmarshalJSON([]byte(`"` + value + `"`)); err == nil { + data[key] = eth.Bytes32(customValue) + } + } +} + +// convertBaseFeeParams converts the max_change_denominator from hex string to integer. +func convertBaseFeeParams(rawConfig map[string]interface{}, key string) { + if params, ok := rawConfig[key].(map[string]interface{}); ok { + if maxChangeDenominator, ok := params["max_change_denominator"].(string); ok { + if intValue, err := strconv.ParseInt(strings.TrimPrefix(maxChangeDenominator, "0x"), 16, 64); err == nil { + params["max_change_denominator"] = intValue + } + } + } } // GetAllSpanBatchesInBlockRange fetches span batches within a range of L2 blocks. @@ -104,6 +220,7 @@ func GetAllSpanBatchesInL2BlockRange(config BatchDecoderConfig) ([]SpanBatchRang return ranges, nil } +// / Get the L2 block number for the given L2 timestamp. func TimestampToBlock(rollupCfg *rollup.Config, l2Timestamp uint64) uint64 { return ((l2Timestamp - rollupCfg.Genesis.L2Time) / rollupCfg.BlockTime) + rollupCfg.Genesis.L2.Number } @@ -128,7 +245,10 @@ func GetSpanBatchRanges(config reassemble.Config, rollupCfg *rollup.Config, star batchStartBlock := TimestampToBlock(rollupCfg, b.GetTimestamp()) spanBatch, success := b.AsSpanBatch() if !success { - log.Fatalf("couldn't convert batch %v to span batch\n", idx) + // If AsSpanBatch fails, return the entire range. + log.Printf("couldn't convert batch %v to span batch\n", idx) + ranges = append(ranges, SpanBatchRange{Start: startBlock, End: endBlock}) + return ranges, nil } blockCount := spanBatch.GetBlockCount() batchEndBlock := batchStartBlock + uint64(blockCount) - 1 @@ -144,42 +264,9 @@ func GetSpanBatchRanges(config reassemble.Config, rollupCfg *rollup.Config, star return ranges, nil } -// Find the span batch that contains the given L2 block. If no span batch contains the given block, return the start block of the span batch that is closest to the given block. -func GetSpanBatchRange(config reassemble.Config, rollupCfg *rollup.Config, l2Block, maxSpanBatchDeviation uint64) (uint64, uint64, error) { - frames := reassemble.LoadFrames(config.InDirectory, config.BatchInbox) - framesByChannel := make(map[derive.ChannelID][]reassemble.FrameWithMetadata) - for _, frame := range frames { - framesByChannel[frame.Frame.ID] = append(framesByChannel[frame.Frame.ID], frame) - } - for id, frames := range framesByChannel { - ch := processFrames(config, rollupCfg, id, frames) - if len(ch.Batches) == 0 { - log.Fatalf("no span batches in channel") - return 0, 0, errors.New("no span batches in channel") - } - - for idx, b := range ch.Batches { - startBlock := TimestampToBlock(rollupCfg, b.GetTimestamp()) - spanBatch, success := b.AsSpanBatch() - if !success { - log.Fatalf("couldn't convert batch %v to span batch\n", idx) - return 0, 0, errors.New("couldn't convert batch to span batch") - } - blockCount := spanBatch.GetBlockCount() - endBlock := startBlock + uint64(blockCount) - 1 - if l2Block >= startBlock && l2Block <= endBlock { - return startBlock, endBlock, nil - } else if l2Block+maxSpanBatchDeviation < startBlock { - return l2Block, startBlock - 1, ErrMaxDeviationExceeded - } - } - } - return 0, 0, ErrNoSpanBatchFound -} - // Set up the batch decoder config. func setupBatchDecoderConfig(config *BatchDecoderConfig) (*rollup.Config, error) { - rollupCfg, err := rollup.LoadOPStackRollupConfig(config.L2ChainID.Uint64()) + rollupCfg, err := LoadOPStackRollupConfigFromChainID(config.L2ChainID.Uint64()) if err != nil { return nil, err } diff --git a/proposer/op/server/main_test.go b/proposer/op/server/main_test.go index a7d40f33..539daef1 100644 --- a/proposer/op/server/main_test.go +++ b/proposer/op/server/main_test.go @@ -28,8 +28,17 @@ func TestHandleSpanBatchRanges(t *testing.T) { t.Fatalf("Required environment variables are not set") } - // Rollup config - rollupCfg, err := utils.GetRollupConfigFromL2Rpc(l2Rpc) + // Get the L2 chain ID from the L2 RPC. + l2Client, err := ethclient.Dial(l2Rpc) + if err != nil { + t.Fatalf("Failed to connect to L2 RPC: %v", err) + } + chainID, err := l2Client.ChainID(context.Background()) + if err != nil { + t.Fatalf("Failed to get chain ID: %v", err) + } + // Load the rollup config for the given L2 chain ID. + rollupCfg, err := utils.LoadOPStackRollupConfigFromChainID(chainID.Uint64()) if err != nil { t.Fatalf("Failed to get rollup config: %v", err) } diff --git a/proposer/succinct/Cargo.toml b/proposer/succinct/Cargo.toml index e020f7e0..7cf8d1fb 100644 --- a/proposer/succinct/Cargo.toml +++ b/proposer/succinct/Cargo.toml @@ -27,6 +27,7 @@ anyhow.workspace = true dotenv.workspace = true op-succinct-client-utils.workspace = true serde = { workspace = true } +serde_json.workspace = true # server axum = "0.7.4" @@ -34,6 +35,11 @@ bincode.workspace = true log.workspace = true base64.workspace = true tower-http.workspace = true +cargo_metadata.workspace = true +reqwest.workspace = true +futures.workspace = true +csv.workspace = true +rayon = "1.10.0" [build-dependencies] sp1-build = { workspace = true } diff --git a/proposer/succinct/bin/server.rs b/proposer/succinct/bin/server.rs index 86ea9b85..5ca4a30f 100644 --- a/proposer/succinct/bin/server.rs +++ b/proposer/succinct/bin/server.rs @@ -8,7 +8,7 @@ use axum::{ }; use base64::{engine::general_purpose, Engine as _}; use log::info; -use op_succinct_client_utils::{RawBootInfo, BOOT_INFO_SIZE}; +use op_succinct_client_utils::boot::BootInfoStruct; use op_succinct_host_utils::{ fetcher::{CacheMode, OPSuccinctDataFetcher}, get_agg_proof_stdin, get_proof_stdin, @@ -76,7 +76,7 @@ async fn request_span_proof( dotenv::dotenv().ok(); // TODO: Save data fetcher, NetworkProver, and NetworkClient globally // and access via Store. - let data_fetcher = OPSuccinctDataFetcher::new(); + let data_fetcher = OPSuccinctDataFetcher::new().await; let host_cli = data_fetcher .get_host_cli_args(payload.start, payload.end, ProgramType::Multi, CacheMode::DeleteCache) @@ -105,14 +105,8 @@ async fn request_agg_proof( let mut proofs_with_pv: Vec = payload.subproofs.iter().map(|sp| bincode::deserialize(sp).unwrap()).collect(); - let boot_infos: Vec = proofs_with_pv - .iter_mut() - .map(|proof| { - let mut boot_info_buf = [0u8; BOOT_INFO_SIZE]; - proof.public_values.read_slice(&mut boot_info_buf); - RawBootInfo::abi_decode(&boot_info_buf).unwrap() - }) - .collect(); + let boot_infos: Vec = + proofs_with_pv.iter_mut().map(|proof| proof.public_values.read()).collect(); let proofs: Vec = proofs_with_pv.iter_mut().map(|proof| proof.proof.clone()).collect(); @@ -121,7 +115,7 @@ async fn request_agg_proof( hex::decode(payload.head.strip_prefix("0x").expect("Invalid L1 head, no 0x prefix."))?; let l1_head: [u8; 32] = l1_head_bytes.try_into().unwrap(); - let fetcher = OPSuccinctDataFetcher::new(); + let fetcher = OPSuccinctDataFetcher::new().await; let headers = fetcher.get_header_preimages(&boot_infos, l1_head.into()).await?; let prover = NetworkProver::new(); diff --git a/rollup-configs/10.json b/rollup-configs/10.json new file mode 100644 index 00000000..c7cea127 --- /dev/null +++ b/rollup-configs/10.json @@ -0,0 +1,46 @@ +{ + "genesis": { + "l1": { + "hash": "0x438335a20d98863a4c0c97999eb2481921ccd28553eac6f913af7c12aec04108", + "number": "0x109d8fe" + }, + "l2": { + "hash": "0xdbf6a80fef073de06add9b0d14026d6e5a86c85f6d102c36d3d8e9cf89c2afd3", + "number": "0x645c277" + }, + "l2_time": 1686068903, + "system_config": { + "batcherAddr": "0x6887246668a3b87f54deb3b94ba47a6f63f32985", + "overhead": "0xbc", + "scalar": "0xa6fe0", + "gasLimit": 30000000, + "baseFeeScalar": null, + "blobBaseFeeScalar": null + } + }, + "block_time": 2, + "max_sequencer_drift": 600, + "seq_window_size": 3600, + "channel_timeout": 300, + "granite_channel_timeout": 50, + "l1_chain_id": 1, + "l2_chain_id": 10, + "base_fee_params": { + "max_change_denominator": "0x32", + "elasticity_multiplier": "0x6" + }, + "canyon_base_fee_params": { + "max_change_denominator": "0xfa", + "elasticity_multiplier": "0x6" + }, + "regolith_time": 0, + "canyon_time": 1704992401, + "delta_time": 1708560000, + "ecotone_time": 1710374401, + "fjord_time": 1720627201, + "granite_time": 1726070401, + "batch_inbox_address": "0xff00000000000000000000000000000000000010", + "deposit_contract_address": "0xbeb5fc579115071764c7423a4f12edde41f106ed", + "l1_system_config_address": "0x229047fed2591dbec1ef1118d64f7af3db9eb290", + "protocol_versions_address": "0x0000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/rollup-configs/11155420.json b/rollup-configs/11155420.json new file mode 100644 index 00000000..afefedb9 --- /dev/null +++ b/rollup-configs/11155420.json @@ -0,0 +1,46 @@ +{ + "genesis": { + "l1": { + "hash": "0x48f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b", + "number": "0x3e1ff0" + }, + "l2": { + "hash": "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", + "number": "0x0" + }, + "l2_time": 1691802540, + "system_config": { + "batcherAddr": "0x8f23bb38f531600e5d8fddaaec41f13fab46e98c", + "overhead": "0xbc", + "scalar": "0xa6fe0", + "gasLimit": 30000000, + "baseFeeScalar": null, + "blobBaseFeeScalar": null + } + }, + "block_time": 2, + "max_sequencer_drift": 600, + "seq_window_size": 3600, + "channel_timeout": 300, + "granite_channel_timeout": 50, + "l1_chain_id": 11155111, + "l2_chain_id": 11155420, + "base_fee_params": { + "max_change_denominator": "0x32", + "elasticity_multiplier": "0x6" + }, + "canyon_base_fee_params": { + "max_change_denominator": "0xfa", + "elasticity_multiplier": "0x6" + }, + "regolith_time": 0, + "canyon_time": 1699981200, + "delta_time": 1703203200, + "ecotone_time": 1708534800, + "fjord_time": 1716998400, + "granite_time": 1723478400, + "batch_inbox_address": "0xff00000000000000000000000000000011155420", + "deposit_contract_address": "0x16fc5058f25648194471939df75cf27a2fdc48bc", + "l1_system_config_address": "0x034edd2a225f7f429a63e0f1d2084b9e0a93b538", + "protocol_versions_address": "0x79add5713b383daa0a138d3c4780c7a1804a8090" +} \ No newline at end of file diff --git a/rollup-configs/13269.json b/rollup-configs/13269.json new file mode 100644 index 00000000..bb03f30c --- /dev/null +++ b/rollup-configs/13269.json @@ -0,0 +1,46 @@ +{ + "genesis": { + "l1": { + "hash": "0x327e6431af3e1e05df17598ae31977cd545ea996f2755920fe75fb9fb65941e3", + "number": "0x62fd94" + }, + "l2": { + "hash": "0xa3344560b989c772875de98d68ccc3f8b5503c94e2e4ad2f403bca6bb186c6bf", + "number": "0x0" + }, + "l2_time": 1723487352, + "system_config": { + "batcherAddr": "0x6322c47fee60e15fc1b7ba65f1cfd66201e4c61d", + "overhead": "0xbc", + "scalar": "0xa6fe0", + "gasLimit": 30000000, + "baseFeeScalar": null, + "blobBaseFeeScalar": null + } + }, + "block_time": 2, + "max_sequencer_drift": 600, + "seq_window_size": 3600, + "channel_timeout": 300, + "granite_channel_timeout": 50, + "l1_chain_id": 11155111, + "l2_chain_id": 13269, + "base_fee_params": { + "max_change_denominator": "0x32", + "elasticity_multiplier": "0x6" + }, + "canyon_base_fee_params": { + "max_change_denominator": "0xfa", + "elasticity_multiplier": "0x6" + }, + "regolith_time": 0, + "canyon_time": 0, + "delta_time": 0, + "ecotone_time": 0, + "fjord_time": 0, + "granite_time": 1725984001, + "batch_inbox_address": "0x136b12db1fbac1d6aa6d0a1d2b724892c6fba921", + "deposit_contract_address": "0x16839f9f6a11195a72b88744336edff036e7b3d5", + "l1_system_config_address": "0x19145e3aee49c40d9f499f705f25ac1ea7409834", + "protocol_versions_address": "0x0000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/rollup-configs/8453.json b/rollup-configs/8453.json new file mode 100644 index 00000000..803a9958 --- /dev/null +++ b/rollup-configs/8453.json @@ -0,0 +1,46 @@ +{ + "genesis": { + "l1": { + "hash": "0x5c13d307623a926cd31415036c8b7fa14572f9dac64528e857a470511fc30771", + "number": "0x10ac028" + }, + "l2": { + "hash": "0xf712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd", + "number": "0x0" + }, + "l2_time": 1686789347, + "system_config": { + "batcherAddr": "0x5050f69a9786f081509234f1a7f4684b5e5b76c9", + "overhead": "0xbc", + "scalar": "0xa6fe0", + "gasLimit": 30000000, + "baseFeeScalar": null, + "blobBaseFeeScalar": null + } + }, + "block_time": 2, + "max_sequencer_drift": 600, + "seq_window_size": 3600, + "channel_timeout": 300, + "granite_channel_timeout": 50, + "l1_chain_id": 1, + "l2_chain_id": 8453, + "base_fee_params": { + "max_change_denominator": "0x32", + "elasticity_multiplier": "0x6" + }, + "canyon_base_fee_params": { + "max_change_denominator": "0xfa", + "elasticity_multiplier": "0x6" + }, + "regolith_time": 0, + "canyon_time": 1704992401, + "delta_time": 1708560000, + "ecotone_time": 1710374401, + "fjord_time": 1720627201, + "granite_time": 1726070401, + "batch_inbox_address": "0xff00000000000000000000000000000000008453", + "deposit_contract_address": "0x49048044d57e1c92a77f79988d21fa8faf74e97e", + "l1_system_config_address": "0x73a79fab69143498ed3712e519a88a918e1f4072", + "protocol_versions_address": "0x0000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/scripts/prove/Cargo.toml b/scripts/prove/Cargo.toml index f4b66904..b823fd06 100644 --- a/scripts/prove/Cargo.toml +++ b/scripts/prove/Cargo.toml @@ -31,6 +31,10 @@ path = "bin/vkey.rs" name = "cost_estimator" path = "bin/cost_estimator.rs" +[[bin]] +name = "fetch-rollup-config" +path = "bin/fetch_rollup_config.rs" + [dependencies] # workspace @@ -39,6 +43,17 @@ alloy = { workspace = true } tokio = { workspace = true } clap = { workspace = true } cargo_metadata = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow.workspace = true +dotenv.workspace = true +num-format.workspace = true +log.workspace = true +csv.workspace = true +serde = { workspace = true } +reqwest = { workspace = true } +rayon = "1.10.0" +serde_json.workspace = true + # kona kona-host = { workspace = true } @@ -50,14 +65,6 @@ op-succinct-client-utils.workspace = true # sp1 sp1-sdk = { workspace = true } -anyhow.workspace = true -dotenv.workspace = true -num-format.workspace = true -log.workspace = true -csv.workspace = true -serde = { workspace = true } -reqwest = { workspace = true } -rayon = "1.10.0" [build-dependencies] sp1-build = { workspace = true } diff --git a/scripts/prove/bin/agg.rs b/scripts/prove/bin/agg.rs index 559d7603..d95ce193 100644 --- a/scripts/prove/bin/agg.rs +++ b/scripts/prove/bin/agg.rs @@ -1,11 +1,12 @@ use std::fs; +use alloy_sol_types::SolValue; use anyhow::Result; use cargo_metadata::MetadataCommand; use clap::Parser; -use op_succinct_client_utils::{RawBootInfo, BOOT_INFO_SIZE}; +use op_succinct_client_utils::{boot::BootInfoStruct, BOOT_INFO_SIZE}; use op_succinct_host_utils::{ - fetcher::{ChainMode, OPSuccinctDataFetcher}, + fetcher::{OPSuccinctDataFetcher, RPCMode}, get_agg_proof_stdin, }; use sp1_sdk::{utils, HashableKey, ProverClient, SP1Proof, SP1ProofWithPublicValues}; @@ -33,7 +34,7 @@ struct Args { fn load_aggregation_proof_data( proof_names: Vec, l2_chain_id: u64, -) -> (Vec, Vec) { +) -> (Vec, Vec) { let metadata = MetadataCommand::new().exec().unwrap(); let workspace_root = metadata.workspace_root; let proof_directory = format!("{}/data/{}/proofs", workspace_root, l2_chain_id); @@ -50,10 +51,10 @@ fn load_aggregation_proof_data( SP1ProofWithPublicValues::load(proof_path).expect("loading proof failed"); proofs.push(deserialized_proof.proof); - // The public values are the ABI-encoded RawBootInfo. + // The public values are the ABI-encoded BootInfoStruct. let mut raw_boot_info_bytes = [0u8; BOOT_INFO_SIZE]; deserialized_proof.public_values.read_slice(&mut raw_boot_info_bytes); - let boot_info = RawBootInfo::abi_decode(&raw_boot_info_bytes).unwrap(); + let boot_info = BootInfoStruct::abi_decode(&raw_boot_info_bytes, false).unwrap(); boot_infos.push(boot_info); } @@ -68,12 +69,12 @@ async fn main() -> Result<()> { let args = Args::parse(); let prover = ProverClient::new(); - let fetcher = OPSuccinctDataFetcher::new(); + let fetcher = OPSuccinctDataFetcher::new().await; - let l2_chain_id = fetcher.get_chain_id(ChainMode::L2).await?; + let l2_chain_id = fetcher.get_chain_id(RPCMode::L2).await?; let (proofs, boot_infos) = load_aggregation_proof_data(args.proofs, l2_chain_id); let latest_checkpoint_head = fetcher - .get_header_by_number(ChainMode::L1, args.latest_checkpoint_head_nb) + .get_header_by_number(RPCMode::L1, args.latest_checkpoint_head_nb) .await? .hash_slow(); let headers = fetcher.get_header_preimages(&boot_infos, latest_checkpoint_head).await?; diff --git a/scripts/prove/bin/cost_estimator.rs b/scripts/prove/bin/cost_estimator.rs index 4a3a02ba..3a0cfa58 100644 --- a/scripts/prove/bin/cost_estimator.rs +++ b/scripts/prove/bin/cost_estimator.rs @@ -4,8 +4,9 @@ use kona_host::HostCli; use kona_primitives::RollupConfig; use log::info; use op_succinct_host_utils::{ - fetcher::{CacheMode, ChainMode, OPSuccinctDataFetcher}, + fetcher::{CacheMode, OPSuccinctDataFetcher, RPCMode}, get_proof_stdin, + rollup_config::read_rollup_config, stats::{get_execution_stats, ExecutionStats}, witnessgen::WitnessGenExecutor, ProgramType, @@ -16,7 +17,8 @@ use serde::{Deserialize, Serialize}; use sp1_sdk::{utils, ProverClient}; use std::{ cmp::{max, min}, - env, fs, + env, + fs::{self}, future::Future, net::TcpListener, path::PathBuf, @@ -95,6 +97,7 @@ async fn get_span_batch_ranges_from_server( env::var("SPAN_BATCH_SERVER_URL").unwrap_or("http://localhost:8089".to_string()); let query_url = format!("{}/span-batch-ranges", span_batch_server_url); + // Send the request to the span batch server. If the request fails, return the corresponding error. let response: SpanBatchResponse = client.post(&query_url).json(&request).send().await?.json().await?; @@ -114,7 +117,8 @@ struct BatchHostCli { } fn get_max_span_batch_range_size(chain_id: u64) -> u64 { - const DEFAULT_SIZE: u64 = 20; + // TODO: The default size/batch size should be dynamic based on the L2 chain. Specifically, look at the gas used across the block range (should be fast to compute) and then set the batch size accordingly. + const DEFAULT_SIZE: u64 = 1000; match chain_id { 8453 => 5, // Base 11155111 => 20, // OP Sepolia @@ -124,21 +128,38 @@ fn get_max_span_batch_range_size(chain_id: u64) -> u64 { } /// Split ranges according to the max span batch range size per L2 chain. +/// +/// If the width of the span batch range returned by the server is 0, expand it to 1, and propogate those changes. fn split_ranges(span_batch_ranges: Vec, l2_chain_id: u64) -> Vec { + // Sort the ranges by start block. + let mut span_batch_ranges = span_batch_ranges.clone(); + span_batch_ranges.sort_by_key(|range| range.start); + let batch_size = get_max_span_batch_range_size(l2_chain_id); let mut split_ranges = Vec::new(); - for range in span_batch_ranges { + for range in span_batch_ranges.iter() { if range.end - range.start > batch_size { let mut start = range.start; while start < range.end { let end = min(start + batch_size, range.end); split_ranges.push(SpanBatchRange { start, end }); - // The start of the next range should be the end of the current range + 1. start = end + 1; } } else { - split_ranges.push(range); + split_ranges.push(range.clone()); + } + } + + // Iterate through the split ranges and fix any ranges that have the same start and end block. + // Ensure that the start of the next range gets incremented by one as well. + for i in 0..split_ranges.len() { + if split_ranges[i].start == split_ranges[i].end { + split_ranges[i].end += 1; + // Only increment the start of the next range if it's not the last range. + if i < split_ranges.len() - 1 { + split_ranges[i + 1].start += 1; + } } } @@ -150,7 +171,7 @@ async fn run_native_data_generation( data_fetcher: &OPSuccinctDataFetcher, split_ranges: &[SpanBatchRange], ) -> Vec { - const CONCURRENT_NATIVE_HOST_RUNNERS: usize = 5; + const CONCURRENT_NATIVE_HOST_RUNNERS: usize = 1; // Split the entire range into chunks of size CONCURRENT_NATIVE_HOST_RUNNERS and process chunks // serially. Generate witnesses within each chunk in parallel. This prevents the RPC from @@ -324,8 +345,6 @@ fn manage_span_batch_server_container() -> Result<()> { // Start the Docker container. let run_status = Command::new("docker") .args(["run", "-p", "8089:8089", "-d", "span_batch_server"]) - .stdout(Stdio::null()) - .stderr(Stdio::null()) .status()?; if !run_status.success() { return Err(anyhow::anyhow!("Failed to start Docker container")); @@ -371,10 +390,12 @@ async fn main() -> Result<()> { utils::setup_logger(); let args = HostArgs::parse(); - let data_fetcher = OPSuccinctDataFetcher::new(); + let data_fetcher = OPSuccinctDataFetcher::new().await; + + let l2_chain_id = data_fetcher.get_chain_id(RPCMode::L2).await?; - let l2_chain_id = data_fetcher.get_chain_id(ChainMode::L2).await?; - let rollup_config = RollupConfig::from_l2_chain_id(l2_chain_id).unwrap(); + // Read the rollup config. + let rollup_config: RollupConfig = read_rollup_config(l2_chain_id).unwrap(); // Start the Docker container if it doesn't exist. manage_span_batch_server_container()?; diff --git a/scripts/prove/bin/fetch_and_save_proof.rs b/scripts/prove/bin/fetch_and_save_proof.rs index 34d747f3..72dd2dde 100644 --- a/scripts/prove/bin/fetch_and_save_proof.rs +++ b/scripts/prove/bin/fetch_and_save_proof.rs @@ -1,8 +1,8 @@ -use alloy::hex; +use alloy::{hex, sol_types::SolValue}; use anyhow::Result; use clap::Parser; use dotenv::dotenv; -use op_succinct_client_utils::{RawBootInfo, BOOT_INFO_SIZE}; +use op_succinct_client_utils::{boot::BootInfoStruct, BOOT_INFO_SIZE}; use sp1_sdk::{NetworkProver, SP1ProofWithPublicValues}; use std::{fs, path::Path}; @@ -46,7 +46,7 @@ async fn main() -> Result<()> { if args.agg_proof { let mut raw_boot_info = [0u8; BOOT_INFO_SIZE]; proof.public_values.read_slice(&mut raw_boot_info); - let boot_info = RawBootInfo::abi_decode(&raw_boot_info).unwrap(); + let boot_info = BootInfoStruct::abi_decode(&raw_boot_info, false).unwrap(); let proof_bytes = proof.bytes(); println!("Proof bytes: {:?}", hex::encode(proof_bytes)); diff --git a/scripts/prove/bin/fetch_rollup_config.rs b/scripts/prove/bin/fetch_rollup_config.rs new file mode 100644 index 00000000..a873d8a9 --- /dev/null +++ b/scripts/prove/bin/fetch_rollup_config.rs @@ -0,0 +1,127 @@ +use alloy_primitives::B256; +use anyhow::{bail, Result}; +use op_succinct_client_utils::boot::hash_rollup_config; +use op_succinct_host_utils::fetcher::{OPSuccinctDataFetcher, RPCMode}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use sp1_sdk::{HashableKey, ProverClient}; +use std::{ + env, fs, + path::{Path, PathBuf}, +}; + +pub const AGG_ELF: &[u8] = include_bytes!("../../../elf/aggregation-elf"); + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +/// The config for deploying the ZK L2OutputOracle. +/// Note: The fields should be in alphabetical order for Solidity to parse it correctly. +struct L2OOConfig { + chain_id: u64, + challenger: String, + finalization_period: u64, + l2_block_time: u64, + l2_output_oracle_proxy: String, + owner: String, + proposer: String, + rollup_config_hash: String, + starting_block_number: u64, + starting_output_root: String, + starting_timestamp: u64, + submission_interval: u64, + verifier_gateway: String, + vkey: String, +} + +/// Update the L2OO config with the rollup config hash and other relevant data before the contract is deployed. +/// +/// Specifically, updates the following fields in `zkl2ooconfig.json`: +/// - rollup_config_hash: Get the hash of the rollup config in rollup-configs/{l2_chain_id}.json. +/// - l2_block_time: Get the block time from the rollup config. +/// - starting_block_number: If `USE_CACHED_STARTING_BLOCK` is `false`, set starting_block_number to 10 blocks before the latest block on L2. +/// - starting_output_root: Set to the output root of the starting block number. +/// - starting_timestamp: Set to the timestamp of the starting block number. +/// - chain_id: Get the chain id from the rollup config. +/// - vkey: Get the vkey from the aggregation program ELF. +async fn update_l2oo_config() -> Result<()> { + let data_fetcher = OPSuccinctDataFetcher::default(); + + // Get the workspace root with cargo metadata to make the paths. + let workspace_root = + PathBuf::from(cargo_metadata::MetadataCommand::new().exec()?.workspace_root); + + // Read the L2OO config from the contracts directory. + let mut l2oo_config = get_existing_l2oo_config(&workspace_root)?; + + // If we are not using a cached starting block number, set it to 10 blocks before the latest block on L2. + if env::var("USE_CACHED_STARTING_BLOCK").unwrap_or("false".to_string()) != "true" { + // Set the starting block number to 10 blocks before the latest block on L2. + let latest_block = data_fetcher.get_head(RPCMode::L2).await?; + l2oo_config.starting_block_number = latest_block.number - 10; + } + + // Convert the starting block number to a hex string for the optimism_outputAtBlock RPC call. + let starting_block_number_hex = format!("0x{:x}", l2oo_config.starting_block_number); + let optimism_output_data: Value = data_fetcher + .fetch_rpc_data( + RPCMode::L2Node, + "optimism_outputAtBlock", + vec![starting_block_number_hex.into()], + ) + .await?; + + // Hash the rollup config. + let hash: B256 = hash_rollup_config(&data_fetcher.rollup_config); + // Set the rollup config hash. + let hash_str = format!("0x{:x}", hash); + l2oo_config.rollup_config_hash = hash_str; + + // Set the L2 block time from the rollup config. + l2oo_config.l2_block_time = data_fetcher.rollup_config.block_time; + + // Set the starting output root and starting timestamp. + l2oo_config.starting_output_root = + optimism_output_data["outputRoot"].as_str().unwrap().to_string(); + l2oo_config.starting_timestamp = + optimism_output_data["blockRef"]["timestamp"].as_u64().unwrap(); + + // Set the chain id. + l2oo_config.chain_id = data_fetcher.get_chain_id(RPCMode::L2).await?; + + // Set the vkey. + let prover = ProverClient::new(); + let (_, vkey) = prover.setup(AGG_ELF); + l2oo_config.vkey = vkey.vk.bytes32(); + + // Write the L2OO rollup config to the zkl2ooconfig.json file. + write_l2oo_config(l2oo_config, &workspace_root)?; + + Ok(()) +} + +/// Get the L2OO rollup config from the contracts directory. +/// +/// Note: The L2OO config is stored in `contracts/zkl2ooconfig.json`. +fn get_existing_l2oo_config(workspace_root: &Path) -> Result { + let zkconfig_path = workspace_root.join("contracts/zkl2ooconfig.json").canonicalize()?; + if fs::metadata(&zkconfig_path).is_ok() { + let zkconfig_str = fs::read_to_string(zkconfig_path)?; + Ok(serde_json::from_str(&zkconfig_str)?) + } else { + bail!("Missing zkl2ooconfig.json"); + } +} + +/// Write the L2OO rollup config to `contracts/zkl2ooconfig.json`. +fn write_l2oo_config(config: L2OOConfig, workspace_root: &Path) -> Result<()> { + let zkconfig_path = workspace_root.join("contracts/zkl2ooconfig.json").canonicalize()?; + // Write the L2OO rollup config to the zkl2ooconfig.json file. + fs::write(zkconfig_path, serde_json::to_string_pretty(&config)?)?; + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<()> { + dotenv::dotenv().ok(); + update_l2oo_config().await +} diff --git a/scripts/prove/bin/multi.rs b/scripts/prove/bin/multi.rs index ffbe25c9..888979a7 100644 --- a/scripts/prove/bin/multi.rs +++ b/scripts/prove/bin/multi.rs @@ -3,7 +3,7 @@ use std::{fs, time::Instant}; use anyhow::Result; use clap::Parser; use op_succinct_host_utils::{ - fetcher::{CacheMode, ChainMode, OPSuccinctDataFetcher}, + fetcher::{CacheMode, OPSuccinctDataFetcher, RPCMode}, get_proof_stdin, stats::get_execution_stats, witnessgen::WitnessGenExecutor, @@ -44,7 +44,7 @@ async fn main() -> Result<()> { utils::setup_logger(); let args = Args::parse(); - let data_fetcher = OPSuccinctDataFetcher::new(); + let data_fetcher = OPSuccinctDataFetcher::new().await; let cache_mode = if args.use_cache { CacheMode::KeepCache } else { CacheMode::DeleteCache }; @@ -77,7 +77,7 @@ async fn main() -> Result<()> { // Create a proof directory for the chain ID if it doesn't exist. let proof_dir = - format!("data/{}/proofs", data_fetcher.get_chain_id(ChainMode::L2).await.unwrap()); + format!("data/{}/proofs", data_fetcher.get_chain_id(RPCMode::L2).await.unwrap()); if !std::path::Path::new(&proof_dir).exists() { fs::create_dir_all(&proof_dir).unwrap(); } @@ -90,7 +90,7 @@ async fn main() -> Result<()> { let (_, report) = prover.execute(MULTI_BLOCK_ELF, sp1_stdin.clone()).run().unwrap(); let execution_duration = start_time.elapsed(); - let l2_chain_id = data_fetcher.get_chain_id(ChainMode::L2).await.unwrap(); + let l2_chain_id = data_fetcher.get_chain_id(RPCMode::L2).await.unwrap(); let report_path = format!("execution-reports/multi/{}/{}-{}.csv", l2_chain_id, args.start, args.end); diff --git a/scripts/prove/build.rs b/scripts/prove/build.rs index 3492d2c8..da56e742 100644 --- a/scripts/prove/build.rs +++ b/scripts/prove/build.rs @@ -55,7 +55,7 @@ fn build_zkvm_program(program: &str) { } fn main() { - let programs = vec!["range"]; + let programs = vec!["fault-proof", "range"]; for program in programs { // Note: Don't comment this out, because the Docker program depends on the native program diff --git a/scripts/witnessgen/Cargo.toml b/scripts/witnessgen/Cargo.toml index 2515f4ca..1b3d096e 100644 --- a/scripts/witnessgen/Cargo.toml +++ b/scripts/witnessgen/Cargo.toml @@ -17,3 +17,5 @@ tokio = { workspace = true } clap = { workspace = true } anyhow = { workspace = true } log = { workspace = true } +sp1-sdk = { workspace = true } +tracing = "0.1.40" diff --git a/scripts/witnessgen/bin/native_host_runner.rs b/scripts/witnessgen/bin/native_host_runner.rs index 60652efa..c4677123 100644 --- a/scripts/witnessgen/bin/native_host_runner.rs +++ b/scripts/witnessgen/bin/native_host_runner.rs @@ -1,7 +1,6 @@ use anyhow::Result; use clap::Parser; use kona_host::{init_tracing_subscriber, start_server, start_server_and_native_client, HostCli}; -use log::info; // Source: https://github.com/ethereum-optimism/kona/blob/main/bin/host/src/main.rs #[tokio::main(flavor = "multi_thread")] @@ -15,6 +14,6 @@ async fn main() -> Result<()> { start_server_and_native_client(cfg).await?; } - info!("Exiting host program."); - Ok(()) + println!("Exiting host program."); + std::process::exit(0); } diff --git a/utils/client/Cargo.toml b/utils/client/Cargo.toml index 3f3902cf..53c4f04a 100644 --- a/utils/client/Cargo.toml +++ b/utils/client/Cargo.toml @@ -8,6 +8,7 @@ edition.workspace = true # workspace (general) anyhow.workspace = true async-trait.workspace = true +serde_json.workspace = true # workspace (ethereum) op-alloy-consensus.workspace = true @@ -19,13 +20,13 @@ alloy-sol-types.workspace = true revm.workspace = true # workspace (kona) +kona-common.workspace = true kona-primitives.workspace = true kona-executor.workspace = true kona-client.workspace = true kona-preimage.workspace = true kona-mpt.workspace = true kona-derive.workspace = true -kona-common.workspace = true # general serde.workspace = true diff --git a/utils/client/src/boot.rs b/utils/client/src/boot.rs index 1abd1b38..66e571ff 100644 --- a/utils/client/src/boot.rs +++ b/utils/client/src/boot.rs @@ -2,76 +2,64 @@ //! information, which is passed to the zkVM a public inputs to be verified on chain. use alloy_primitives::B256; -use alloy_sol_types::{sol, SolValue}; -use anyhow::Result; -use kona_client::BootInfo; +use alloy_sol_types::sol; use kona_primitives::RollupConfig; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; -// ABI encoding of BootInfo is 5 * 32 bytes. -pub const BOOT_INFO_SIZE: usize = 5 * 32; +// ABI encoding of BootInfo is 6 * 32 bytes. +pub const BOOT_INFO_SIZE: usize = 6 * 32; -/// Boot information that is committed to the zkVM as public inputs. -/// This struct contains all information needed to generate BootInfo, -/// as the RollupConfig can be derived from the `chain_id`. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct RawBootInfo { - /// From [`BootInfo::l1_head`]. - pub l1_head: B256, - /// From [`BootInfo::l2_output_root`]. - pub l2_output_root: B256, - /// From [`BootInfo::l2_claim`]. - pub l2_claim: B256, - /// From [`BootInfo::l2_claim_block`]. - pub l2_claim_block: u64, - /// From [`BootInfo::chain_id`]. - pub chain_id: u64, -} +/// Hash the serialized rollup config using SHA256. Note: The rollup config is never unrolled +/// on-chain, so switching to a different hash function is not a concern, as long as the config hash +/// is consistent with the one on the contract. +pub fn hash_rollup_config(config: &RollupConfig) -> B256 { + let serialized_config = serde_json::to_string_pretty(config).unwrap(); -impl From for BootInfo { - /// Convert the BootInfoWithoutRollupConfig into BootInfo by deriving the RollupConfig. - fn from(boot_info_without_rollup_config: RawBootInfo) -> Self { - let RawBootInfo { l1_head, l2_output_root, l2_claim, l2_claim_block, chain_id } = - boot_info_without_rollup_config; - let rollup_config = RollupConfig::from_l2_chain_id(chain_id).unwrap(); + // Create a SHA256 hasher + let mut hasher = Sha256::new(); - Self { l1_head, l2_output_root, l2_claim, l2_claim_block, chain_id, rollup_config } - } + // Hash the serialized config + hasher.update(serialized_config.as_bytes()); + + // Finalize and convert to B256 + let hash = hasher.finalize(); + B256::from_slice(hash.as_slice()) } sol! { - struct RawBootInfoStruct { + #[derive(Debug, Serialize, Deserialize)] + struct BootInfoStruct { bytes32 l1Head; bytes32 l2PreRoot; bytes32 l2PostRoot; uint64 l2BlockNumber; uint64 chainId; + bytes32 rollupConfigHash; } } -impl RawBootInfo { - /// ABI encode the boot info. This is used to commit to in the zkVM, - /// so that we can verify on chain that the correct values were used in - /// the proof. - pub fn abi_encode(&self) -> Vec { - RawBootInfoStruct { - l1Head: self.l1_head, - l2PreRoot: self.l2_output_root, - l2PostRoot: self.l2_claim, - l2BlockNumber: self.l2_claim_block, - chainId: self.chain_id, +impl From for BootInfoStruct { + /// Convert a `BootInfoWithBytesConfig` to a `BootInfoStruct`. + fn from(boot_info: BootInfoWithBytesConfig) -> Self { + let rollup_config = serde_json::from_slice(&boot_info.rollup_config_bytes).unwrap(); + BootInfoStruct { + l1Head: boot_info.l1_head, + l2PreRoot: boot_info.l2_output_root, + l2PostRoot: boot_info.l2_claim, + l2BlockNumber: boot_info.l2_claim_block, + chainId: boot_info.chain_id, + rollupConfigHash: hash_rollup_config(&rollup_config), } - .abi_encode() } +} - pub fn abi_decode(bytes: &[u8]) -> Result { - let boot_info = RawBootInfoStruct::abi_decode(bytes, true)?; - Ok(Self { - l1_head: boot_info.l1Head, - l2_output_root: boot_info.l2PreRoot, - l2_claim: boot_info.l2PostRoot, - l2_claim_block: boot_info.l2BlockNumber, - chain_id: boot_info.chainId, - }) - } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BootInfoWithBytesConfig { + pub l1_head: B256, + pub l2_output_root: B256, + pub l2_claim: B256, + pub l2_claim_block: u64, + pub chain_id: u64, + pub rollup_config_bytes: Vec, } diff --git a/utils/client/src/lib.rs b/utils/client/src/lib.rs index 8b2ada7c..1edf99e6 100644 --- a/utils/client/src/lib.rs +++ b/utils/client/src/lib.rs @@ -1,8 +1,8 @@ mod hasher; pub use hasher::BytesHasherBuilder; -mod boot; -pub use boot::{RawBootInfo, BOOT_INFO_SIZE}; +pub mod boot; +pub use boot::{BootInfoWithBytesConfig, BOOT_INFO_SIZE}; mod executor; pub use executor::block_on; diff --git a/utils/client/src/oracle/mod.rs b/utils/client/src/oracle/mod.rs index dfe3cf73..401c4b12 100644 --- a/utils/client/src/oracle/mod.rs +++ b/utils/client/src/oracle/mod.rs @@ -24,8 +24,12 @@ impl InMemoryOracle { /// Creates a new [InMemoryOracle] from the raw bytes passed into the zkVM. /// These values are deserialized using rkyv for zero copy deserialization. pub fn from_raw_bytes(input: Vec) -> Self { + println!("cycle-tracker-start: in-memory-oracle-from-raw-bytes-archive"); let archived = unsafe { rkyv::archived_root::(&input) }; + println!("cycle-tracker-end: in-memory-oracle-from-raw-bytes-archive"); + println!("cycle-tracker-start: in-memory-oracle-from-raw-bytes-deserialize"); let deserialized: Self = archived.deserialize(&mut Infallible).unwrap(); + println!("cycle-tracker-end: in-memory-oracle-from-raw-bytes-deserialize"); deserialized } diff --git a/utils/client/src/precompiles/mod.rs b/utils/client/src/precompiles/mod.rs index b89d8766..30d2c124 100644 --- a/utils/client/src/precompiles/mod.rs +++ b/utils/client/src/precompiles/mod.rs @@ -5,8 +5,7 @@ use revm::{ db::states::state::State, handler::register::EvmHandler, precompile::{ - bn128, secp256k1, secp256r1, Precompile, PrecompileResult, PrecompileSpecId, - PrecompileWithAddress, + bn128, secp256r1, Precompile, PrecompileResult, PrecompileSpecId, PrecompileWithAddress, }, primitives::Bytes, ContextPrecompiles, @@ -43,8 +42,8 @@ pub(crate) const ANNOTATED_KZG_EVAL: PrecompileWithAddress = create_annotated_pr revm::precompile::kzg_point_evaluation::POINT_EVALUATION, "kzg-eval" ); -pub(crate) const ANNOTATED_EC_RECOVER: PrecompileWithAddress = - create_annotated_precompile!(secp256k1::ECRECOVER, "ec-recover"); +// pub(crate) const ANNOTATED_EC_RECOVER: PrecompileWithAddress = +// create_annotated_precompile!(secp256k1::ECRECOVER, "ec-recover"); // Source: https://github.com/anton-rs/kona/blob/main/bin/client/src/fault/handler/mod.rs#L20-L42 pub fn zkvm_handle_register(handler: &mut EvmHandler<'_, (), &mut State<&mut TrieDB>>) @@ -69,7 +68,8 @@ where ANNOTATED_BN_MUL, ANNOTATED_BN_PAIR, ANNOTATED_KZG_EVAL, - ANNOTATED_EC_RECOVER, + // Note: Removed annotations for the ec-recover precompile as it's not a large contributor to cycle count. + // ANNOTATED_EC_RECOVER, ]; ctx_precompiles.extend(override_precompiles); diff --git a/utils/client/src/types.rs b/utils/client/src/types.rs index ac5d8127..e9ef2883 100644 --- a/utils/client/src/types.rs +++ b/utils/client/src/types.rs @@ -1,10 +1,10 @@ use alloy_primitives::B256; use serde::{Deserialize, Serialize}; -use crate::RawBootInfo; +use crate::boot::BootInfoStruct; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AggregationInputs { - pub boot_infos: Vec, + pub boot_infos: Vec, pub latest_l1_checkpoint_head: B256, } diff --git a/utils/host/Cargo.toml b/utils/host/Cargo.toml index 379b63f5..f7008143 100644 --- a/utils/host/Cargo.toml +++ b/utils/host/Cargo.toml @@ -5,15 +5,14 @@ license.workspace = true edition.workspace = true [dependencies] + +# workspace alloy.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true alloy-sol-types.workspace = true -op-succinct-client-utils.workspace = true rkyv.workspace = true -kona-host.workspace = true -kona-preimage.workspace = true -sp1-sdk.workspace = true +serde_json.workspace = true anyhow.workspace = true cargo_metadata.workspace = true serde_cbor.workspace = true @@ -22,3 +21,16 @@ tokio.workspace = true futures.workspace = true num-format.workspace = true serde.workspace = true +log.workspace = true +reqwest.workspace = true + +# sp1 +sp1-sdk.workspace = true + +# local +op-succinct-client-utils.workspace = true + +# kona +kona-host.workspace = true +kona-preimage.workspace = true +kona-primitives.workspace = true diff --git a/utils/host/src/fetcher.rs b/utils/host/src/fetcher.rs index 284f0be0..1ee611dd 100644 --- a/utils/host/src/fetcher.rs +++ b/utils/host/src/fetcher.rs @@ -9,17 +9,24 @@ use alloy_sol_types::SolValue; use anyhow::Result; use cargo_metadata::MetadataCommand; use kona_host::HostCli; -use op_succinct_client_utils::RawBootInfo; +use kona_primitives::RollupConfig; +use op_succinct_client_utils::boot::BootInfoStruct; +use serde_json::{json, Value}; +use sp1_sdk::block_on; use std::{cmp::Ordering, env, fs, path::Path, str::FromStr, sync::Arc, time::Duration}; use tokio::time::sleep; use alloy_primitives::keccak256; -use crate::{L2Output, ProgramType}; +use crate::{ + rollup_config::{merge_rollup_config, save_rollup_config}, + L2Output, ProgramType, +}; #[derive(Clone)] /// The OPSuccinctDataFetcher struct is used to fetch the L2 output data and L2 claim data for a /// given block number. It is used to generate the boot info for the native host program. +/// TODO: Add retries for all requests (3 retries). pub struct OPSuccinctDataFetcher { pub l1_rpc: String, pub l1_provider: Arc>>, @@ -27,19 +34,22 @@ pub struct OPSuccinctDataFetcher { pub l2_rpc: String, pub l2_node_rpc: String, pub l2_provider: Arc>>, + pub rollup_config: RollupConfig, } impl Default for OPSuccinctDataFetcher { fn default() -> Self { - OPSuccinctDataFetcher::new() + block_on(OPSuccinctDataFetcher::new()) } } /// The mode corresponding to the chain we are fetching data for. #[derive(Clone, Copy)] -pub enum ChainMode { +pub enum RPCMode { L1, + L1Beacon, L2, + L2Node, } /// Whether to keep the cache or delete the cache. @@ -57,7 +67,8 @@ pub struct BlockInfo { } impl OPSuccinctDataFetcher { - pub fn new() -> Self { + /// Gets the RPC URL's and saves the rollup config for the chain to `rollup-configs/{l2_chain_id}.json`. + pub async fn new() -> Self { dotenv::dotenv().ok(); let l1_rpc = env::var("L1_RPC").unwrap_or_else(|_| "http://localhost:8545".to_string()); let l1_provider = @@ -69,33 +80,93 @@ impl OPSuccinctDataFetcher { env::var("L2_NODE_RPC").unwrap_or_else(|_| "http://localhost:5058".to_string()); let l2_provider = Arc::new(ProviderBuilder::default().on_http(Url::from_str(&l2_rpc).unwrap())); - OPSuccinctDataFetcher { + + let mut fetcher = OPSuccinctDataFetcher { l1_rpc, l1_provider, l1_beacon_rpc, l2_rpc, - l2_node_rpc, l2_provider, + l2_node_rpc, + rollup_config: RollupConfig::default(), + }; + + // Load and save the rollup config. + let rollup_config = + fetcher.fetch_rollup_config().await.expect("Failed to fetch rollup config"); + save_rollup_config(&rollup_config).expect("Failed to save rollup config"); + fetcher.rollup_config = rollup_config; + + fetcher + } + + /// Get the RPC URL for the given RPC mode. + pub fn get_rpc_url(&self, rpc_mode: RPCMode) -> String { + match rpc_mode { + RPCMode::L1 => self.l1_rpc.clone(), + RPCMode::L2 => self.l2_rpc.clone(), + RPCMode::L1Beacon => self.l1_beacon_rpc.clone(), + RPCMode::L2Node => self.l2_node_rpc.clone(), } } - pub fn get_provider(&self, chain_mode: ChainMode) -> Arc>> { - match chain_mode { - ChainMode::L1 => self.l1_provider.clone(), - ChainMode::L2 => self.l2_provider.clone(), + /// Get the provider for the given RPC mode. Note: Will panic if the RPC mode is not L1 or L2. + pub fn get_provider(&self, rpc_mode: RPCMode) -> Arc>> { + match rpc_mode { + RPCMode::L1 => self.l1_provider.clone(), + RPCMode::L2 => self.l2_provider.clone(), + RPCMode::L1Beacon | RPCMode::L2Node => { + panic!("L1Beacon and L2Node modes do not have associated providers") + } } } + /// Fetch the rollup config. Combines the rollup config from `optimism_rollupConfig` and the + /// chain config from `debug_chainConfig`. + pub async fn fetch_rollup_config(&self) -> Result { + let rollup_config = + self.fetch_rpc_data(RPCMode::L2Node, "optimism_rollupConfig", vec![]).await?; + let chain_config = self.fetch_rpc_data(RPCMode::L2, "debug_chainConfig", vec![]).await?; + merge_rollup_config(&rollup_config, &chain_config) + } + + /// Fetch arbitrary data from the RPC. + pub async fn fetch_rpc_data( + &self, + rpc_mode: RPCMode, + method: &str, + params: Vec, + ) -> Result + where + T: serde::de::DeserializeOwned, + { + let client = reqwest::Client::new(); + let response = client + .post(self.get_rpc_url(rpc_mode)) + .json(&json!({ + "jsonrpc": "2.0", + "method": method, + "params": params, + "id": 1 + })) + .send() + .await? + .json::() + .await?; + + serde_json::from_value(response["result"].clone()).map_err(Into::into) + } + /// Get the earliest L1 header in a batch of boot infos. pub async fn get_earliest_l1_head_in_batch( &self, - boot_infos: &[RawBootInfo], + boot_infos: &Vec, ) -> Result
{ let mut earliest_block_num: u64 = u64::MAX; let mut earliest_l1_header: Option
= None; for boot_info in boot_infos { - let l1_block_header = self.get_header_by_hash(ChainMode::L1, boot_info.l1_head).await?; + let l1_block_header = self.get_header_by_hash(RPCMode::L1, boot_info.l1Head).await?; if l1_block_header.number < earliest_block_num { earliest_block_num = l1_block_header.number; earliest_l1_header = Some(l1_block_header); @@ -106,7 +177,7 @@ impl OPSuccinctDataFetcher { /// Fetch headers for a range of blocks inclusive. pub async fn fetch_headers_in_range(&self, start: u64, end: u64) -> Result> { - let mut headers: Vec
= Vec::with_capacity((end - start + 1) as usize); + let mut headers: Vec
= Vec::with_capacity((end - start + 1).try_into().unwrap()); // Note: Node rate limits at 300 requests per second. let batch_size = 200; @@ -115,7 +186,7 @@ impl OPSuccinctDataFetcher { let batch_end = block_number + batch_size - 1; let batch_headers: Vec
= futures::future::join_all( (block_number..=batch_end.min(end)) - .map(|num| self.get_header_by_number(ChainMode::L1, num)), + .map(|num| self.get_header_by_number(RPCMode::L1, num)), ) .await .into_iter() @@ -133,14 +204,14 @@ impl OPSuccinctDataFetcher { /// headers corresponding to the boot infos and the latest L1 head. pub async fn get_header_preimages( &self, - boot_infos: &[RawBootInfo], + boot_infos: &Vec, checkpoint_block_hash: B256, ) -> Result> { // Get the earliest L1 Head from the boot_infos. let start_header = self.get_earliest_l1_head_in_batch(boot_infos).await?; // Fetch the full header for the latest L1 Head (which is validated on chain). - let latest_header = self.get_header_by_hash(ChainMode::L1, checkpoint_block_hash).await?; + let latest_header = self.get_header_by_hash(RPCMode::L1, checkpoint_block_hash).await?; // Create a vector of futures for fetching all headers let headers = @@ -149,12 +220,8 @@ impl OPSuccinctDataFetcher { Ok(headers) } - pub async fn get_header_by_hash( - &self, - chain_mode: ChainMode, - block_hash: B256, - ) -> Result
{ - let provider = self.get_provider(chain_mode); + pub async fn get_header_by_hash(&self, rpc_mode: RPCMode, block_hash: B256) -> Result
{ + let provider = self.get_provider(rpc_mode); let header = provider .get_block_by_hash(block_hash, alloy::rpc::types::BlockTransactionsKind::Full) .await? @@ -163,14 +230,14 @@ impl OPSuccinctDataFetcher { Ok(header.try_into().unwrap()) } - pub async fn get_chain_id(&self, chain_mode: ChainMode) -> Result { - let provider = self.get_provider(chain_mode); + pub async fn get_chain_id(&self, rpc_mode: RPCMode) -> Result { + let provider = self.get_provider(rpc_mode); let chain_id = provider.get_chain_id().await?; Ok(chain_id) } - pub async fn get_head(&self, chain_mode: ChainMode) -> Result
{ - let provider = self.get_provider(chain_mode); + pub async fn get_head(&self, rpc_mode: RPCMode) -> Result
{ + let provider = self.get_provider(rpc_mode); let header = provider.get_block_by_number(BlockNumberOrTag::Latest, false).await?.unwrap().header; Ok(header.try_into().unwrap()) @@ -178,10 +245,10 @@ impl OPSuccinctDataFetcher { pub async fn get_header_by_number( &self, - chain_mode: ChainMode, + rpc_mode: RPCMode, block_number: u64, ) -> Result
{ - let provider = self.get_provider(chain_mode); + let provider = self.get_provider(rpc_mode); let header = provider.get_block_by_number(block_number.into(), false).await?.unwrap().header; Ok(header.try_into().unwrap()) @@ -190,13 +257,13 @@ impl OPSuccinctDataFetcher { /// Get the block data for a range of blocks inclusive. pub async fn get_block_data_range( &self, - chain_mode: ChainMode, + rpc_mode: RPCMode, start: u64, end: u64, ) -> Result> { let mut block_data = Vec::new(); for block_number in start..=end { - let provider = self.get_provider(chain_mode); + let provider = self.get_provider(rpc_mode); let block = provider.get_block_by_number(block_number.into(), false).await?.unwrap(); block_data.push(BlockInfo { block_number, @@ -210,10 +277,10 @@ impl OPSuccinctDataFetcher { /// Find the block with the closest timestamp to the target timestamp. async fn find_block_by_timestamp( &self, - chain_mode: ChainMode, + rpc_mode: RPCMode, target_timestamp: u64, ) -> Result { - let provider = self.get_provider(chain_mode); + let provider = self.get_provider(rpc_mode); let latest_block = provider.get_block_by_number(BlockNumberOrTag::Latest, false).await?.unwrap(); let mut low = 0; @@ -247,7 +314,11 @@ impl OPSuccinctDataFetcher { cache_mode: CacheMode, ) -> Result { if l2_start_block >= l2_end_block { - return Err(anyhow::anyhow!("L2 start block is greater than or equal to L2 end block")); + return Err(anyhow::anyhow!( + "L2 start block is greater than or equal to L2 end block. Start: {}, End: {}", + l2_start_block, + l2_end_block + )); } let l2_provider = self.l2_provider.clone(); @@ -295,7 +366,7 @@ impl OPSuccinctDataFetcher { // Note: This limit is set so that the l1 head is always ahead of the l2 claim block. // E.g. Origin Advance Error: BlockInfoFetch(Block number past L1 head.) let target_timestamp = l2_block_timestamp + 600; - let l1_head = self.find_block_by_timestamp(ChainMode::L1, target_timestamp).await?; + let l1_head = self.find_block_by_timestamp(RPCMode::L1, target_timestamp).await?; // Get the chain id. let l2_chain_id = l2_provider.get_chain_id().await?; @@ -336,6 +407,9 @@ impl OPSuccinctDataFetcher { } } + // Create the path to the rollup config file. + let rollup_config_path = format!("{}/rollup-configs/{}.json", workspace_root, l2_chain_id); + // Creates the data directory if it doesn't exist, or no-ops if it does. Used to store the // witness data. fs::create_dir_all(&data_directory)?; @@ -353,7 +427,7 @@ impl OPSuccinctDataFetcher { data_dir: Some(data_directory.into()), exec: Some(exec_directory), server: false, - rollup_config_path: None, + rollup_config_path: Some(rollup_config_path.into()), v: 0, }) } diff --git a/utils/host/src/lib.rs b/utils/host/src/lib.rs index 993ad34e..34bcc88c 100644 --- a/utils/host/src/lib.rs +++ b/utils/host/src/lib.rs @@ -1,5 +1,6 @@ pub mod fetcher; pub mod helpers; +pub mod rollup_config; pub mod stats; pub mod witnessgen; @@ -9,8 +10,11 @@ use kona_host::{ kv::{DiskKeyValueStore, MemoryKeyValueStore}, HostCli, }; -use op_succinct_client_utils::{types::AggregationInputs, InMemoryOracle, RawBootInfo}; +use op_succinct_client_utils::{ + boot::BootInfoStruct, types::AggregationInputs, BootInfoWithBytesConfig, InMemoryOracle, +}; use sp1_sdk::{SP1Proof, SP1Stdin}; +use std::{fs::File, io::Read}; use anyhow::Result; @@ -42,12 +46,17 @@ sol! { pub fn get_proof_stdin(host_cli: &HostCli) -> Result { let mut stdin = SP1Stdin::new(); - let boot_info = RawBootInfo { + let mut rollup_config_file = File::open(host_cli.rollup_config_path.as_ref().unwrap())?; + let mut rollup_config_bytes = Vec::new(); + rollup_config_file.read_to_end(&mut rollup_config_bytes)?; + + let boot_info = BootInfoWithBytesConfig { l1_head: host_cli.l1_head, l2_output_root: host_cli.l2_output_root, l2_claim: host_cli.l2_claim, l2_claim_block: host_cli.l2_block_number, chain_id: host_cli.l2_chain_id, + rollup_config_bytes, }; stdin.write(&boot_info); @@ -79,7 +88,7 @@ pub fn get_proof_stdin(host_cli: &HostCli) -> Result { /// Get the stdin for the aggregation proof. pub fn get_agg_proof_stdin( proofs: Vec, - boot_infos: Vec, + boot_infos: Vec, headers: Vec
, vkey: &sp1_sdk::SP1VerifyingKey, latest_checkpoint_head: B256, diff --git a/utils/host/src/rollup_config.rs b/utils/host/src/rollup_config.rs new file mode 100644 index 00000000..4478950e --- /dev/null +++ b/utils/host/src/rollup_config.rs @@ -0,0 +1,138 @@ +use std::fs; + +use alloy::eips::eip1559::BaseFeeParams; +use alloy_primitives::Address; +use anyhow::Result; +use kona_primitives::{ChainGenesis, RollupConfig}; +use serde::{Deserialize, Serialize}; + +/// Matches the output of the optimism_rollupConfig RPC call. +#[derive(Debug, Deserialize, Serialize)] +pub(crate) struct OptimismRollupConfigRPC { + genesis: ChainGenesis, + block_time: u64, + max_sequencer_drift: u64, + seq_window_size: u64, + channel_timeout: u64, + l1_chain_id: u64, + l2_chain_id: u64, + regolith_time: Option, + canyon_time: Option, + delta_time: Option, + ecotone_time: Option, + fjord_time: Option, + granite_time: Option, + holocene_time: Option, + batch_inbox_address: Address, + deposit_contract_address: Address, + l1_system_config_address: Address, + protocol_versions_address: Address, + da_challenge_contract_address: Option
, +} + +/// The chain config returned by the `debug_chainConfig` RPC call. +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ChainConfig { + chain_id: u64, + homestead_block: u64, + eip150_block: u64, + eip155_block: u64, + eip158_block: u64, + byzantium_block: u64, + constantinople_block: u64, + petersburg_block: u64, + istanbul_block: u64, + muir_glacier_block: u64, + berlin_block: u64, + london_block: u64, + arrow_glacier_block: u64, + gray_glacier_block: u64, + merge_netsplit_block: u64, + shanghai_time: u64, + cancun_time: u64, + bedrock_block: u64, + regolith_time: u64, + canyon_time: u64, + ecotone_time: u64, + fjord_time: u64, + terminal_total_difficulty: u64, + terminal_total_difficulty_passed: bool, + optimism: OptimismConfig, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct OptimismConfig { + eip1559_elasticity: u128, + eip1559_denominator: u128, + eip1559_denominator_canyon: u128, +} + +/// Merge the rollup and chain configs. +pub(crate) fn merge_rollup_config( + op_rollup_config_rpc: &OptimismRollupConfigRPC, + chain: &ChainConfig, +) -> Result { + let mut rollup_config = RollupConfig { + genesis: op_rollup_config_rpc.genesis.clone(), + block_time: op_rollup_config_rpc.block_time, + max_sequencer_drift: op_rollup_config_rpc.max_sequencer_drift, + seq_window_size: op_rollup_config_rpc.seq_window_size, + channel_timeout: op_rollup_config_rpc.channel_timeout, + l1_chain_id: op_rollup_config_rpc.l1_chain_id, + l2_chain_id: op_rollup_config_rpc.l2_chain_id, + regolith_time: op_rollup_config_rpc.regolith_time, + canyon_time: op_rollup_config_rpc.canyon_time, + delta_time: op_rollup_config_rpc.delta_time, + ecotone_time: op_rollup_config_rpc.ecotone_time, + fjord_time: op_rollup_config_rpc.fjord_time, + granite_time: op_rollup_config_rpc.granite_time, + holocene_time: op_rollup_config_rpc.holocene_time, + batch_inbox_address: op_rollup_config_rpc.batch_inbox_address, + deposit_contract_address: op_rollup_config_rpc.deposit_contract_address, + l1_system_config_address: op_rollup_config_rpc.l1_system_config_address, + protocol_versions_address: op_rollup_config_rpc.protocol_versions_address, + da_challenge_address: op_rollup_config_rpc.da_challenge_contract_address, + ..Default::default() + }; + + // Add the base fee params from the chain config. + rollup_config.base_fee_params = BaseFeeParams { + elasticity_multiplier: chain.optimism.eip1559_elasticity, + max_change_denominator: chain.optimism.eip1559_denominator, + }; + + // Add the canyon base fee params from the chain config. + rollup_config.canyon_base_fee_params = BaseFeeParams { + elasticity_multiplier: chain.optimism.eip1559_elasticity, + max_change_denominator: chain.optimism.eip1559_denominator_canyon, + }; + + Ok(rollup_config) +} + +/// Save rollup config to rollup-configs/{l2_chain_id}.json in the workspace root. +pub fn save_rollup_config(rollup_config: &RollupConfig) -> Result<()> { + let workspace_root = cargo_metadata::MetadataCommand::new().exec()?.workspace_root; + // Create rollup-configs directory if it doesn't exist. + let rollup_configs_dir = workspace_root.join("rollup-configs"); + if !rollup_configs_dir.exists() { + fs::create_dir_all(&rollup_configs_dir)?; + } + let rollup_config_path = + workspace_root.join(format!("rollup-configs/{}.json", rollup_config.l2_chain_id)); + + let rollup_config_str = serde_json::to_string_pretty(rollup_config)?; + fs::write(rollup_config_path, rollup_config_str)?; + Ok(()) +} + +/// Read rollup config from rollup-configs/{l2_chain_id}.json in the workspace root. +pub fn read_rollup_config(l2_chain_id: u64) -> Result { + let workspace_root = cargo_metadata::MetadataCommand::new().exec()?.workspace_root; + let rollup_config_path = workspace_root.join(format!("rollup-configs/{}.json", l2_chain_id)); + let rollup_config_str = fs::read_to_string(rollup_config_path)?; + let rollup_config: RollupConfig = serde_json::from_str(&rollup_config_str)?; + Ok(rollup_config) +} diff --git a/utils/host/src/stats.rs b/utils/host/src/stats.rs index 136fc5ad..6c58f496 100644 --- a/utils/host/src/stats.rs +++ b/utils/host/src/stats.rs @@ -1,6 +1,6 @@ use std::{fmt, time::Duration}; -use crate::fetcher::{ChainMode, OPSuccinctDataFetcher}; +use crate::fetcher::{OPSuccinctDataFetcher, RPCMode}; use num_format::{Locale, ToFormattedString}; use serde::{Deserialize, Serialize}; use sp1_sdk::{CostEstimator, ExecutionReport}; @@ -90,7 +90,7 @@ pub async fn get_execution_stats( // Fetch the number of transactions in the blocks from the L2 RPC. let block_data_range = data_fetcher - .get_block_data_range(ChainMode::L2, start, end) + .get_block_data_range(RPCMode::L2, start, end) .await .expect("Failed to fetch block data range."); diff --git a/utils/host/src/witnessgen.rs b/utils/host/src/witnessgen.rs index f5f90e3b..1dece71a 100644 --- a/utils/host/src/witnessgen.rs +++ b/utils/host/src/witnessgen.rs @@ -14,6 +14,11 @@ pub fn convert_host_cli_to_args(host_cli: &HostCli) -> Vec { format!("--l2-block-number={}", host_cli.l2_block_number), format!("--l2-chain-id={}", host_cli.l2_chain_id), ]; + // The verbosity should be passed as -v, -vv, -vvv, etc. + if host_cli.v > 0 { + args.push(format!("-{}", "v".repeat(host_cli.v as usize))); + } + if let Some(addr) = &host_cli.l2_node_address { args.push("--l2-node-address".to_string()); args.push(addr.to_string()); @@ -37,11 +42,15 @@ pub fn convert_host_cli_to_args(host_cli: &HostCli) -> Vec { if host_cli.server { args.push("--server".to_string()); } + if let Some(rollup_config_path) = &host_cli.rollup_config_path { + args.push("--rollup-config-path".to_string()); + args.push(rollup_config_path.to_string_lossy().into_owned()); + } args } /// Default timeout for witness generation. -pub const WITNESSGEN_TIMEOUT: Duration = Duration::from_secs(120); +pub const WITNESSGEN_TIMEOUT: Duration = Duration::from_secs(1000); struct WitnessGenProcess { child: tokio::process::Child,