diff --git a/Cargo.lock b/Cargo.lock index c86e8fcf91..a0396b5411 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -31,24 +31,45 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alloy-consensus" +version = "0.1.0" +source = "git+https://github.com/clabby/alloy?branch=cl/consensus-expose-encoding#1956325c245f48e3828ff79cc66cb8c5c54ffcda" +dependencies = [ + "alloy-eips 0.1.0 (git+https://github.com/clabby/alloy?branch=cl/consensus-expose-encoding)", + "alloy-primitives", + "alloy-rlp", + "sha2", +] [[package]] name = "alloy-consensus" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy?rev=e3f2f07#e3f2f075a9e7ad9753a255dbe71dbad6a91ba96d" dependencies = [ - "alloy-eips", + "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "c-kzg", "serde", "sha2", ] +[[package]] +name = "alloy-eips" +version = "0.1.0" +source = "git+https://github.com/clabby/alloy?branch=cl/consensus-expose-encoding#1956325c245f48e3828ff79cc66cb8c5c54ffcda" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.1.0 (git+https://github.com/clabby/alloy?branch=cl/consensus-expose-encoding)", +] + [[package]] name = "alloy-eips" version = "0.1.0" @@ -56,7 +77,7 @@ source = "git+https://github.com/alloy-rs/alloy?rev=e3f2f07#e3f2f075a9e7ad9753a2 dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "c-kzg", "once_cell", "serde", @@ -68,7 +89,7 @@ version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy?rev=e3f2f07#e3f2f075a9e7ad9753a255dbe71dbad6a91ba96d" dependencies = [ "alloy-primitives", - "alloy-serde", + "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "serde", ] @@ -88,8 +109,8 @@ name = "alloy-network" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy?rev=e3f2f07#e3f2f075a9e7ad9753a255dbe71dbad6a91ba96d" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", + "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "alloy-json-rpc", "alloy-primitives", "alloy-rpc-types", @@ -166,7 +187,7 @@ checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -194,12 +215,12 @@ name = "alloy-rpc-types" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy?rev=e3f2f07#e3f2f075a9e7ad9753a255dbe71dbad6a91ba96d" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", + "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "alloy-genesis", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "alloy-sol-types", "itertools 0.12.1", "serde", @@ -214,7 +235,17 @@ source = "git+https://github.com/alloy-rs/alloy?rev=e3f2f07#e3f2f075a9e7ad9753a2 dependencies = [ "alloy-primitives", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "0.1.0" +source = "git+https://github.com/clabby/alloy?branch=cl/consensus-expose-encoding#1956325c245f48e3828ff79cc66cb8c5c54ffcda" +dependencies = [ + "alloy-primitives", "serde", "serde_json", ] @@ -255,7 +286,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", "syn-solidity", "tiny-keccak", ] @@ -271,7 +302,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", "syn-solidity", ] @@ -292,7 +323,7 @@ version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy?rev=e3f2f07#e3f2f075a9e7ad9753a255dbe71dbad6a91ba96d" dependencies = [ "alloy-json-rpc", - "base64 0.22.0", + "base64", "futures-util", "futures-utils-wasm", "serde", @@ -319,9 +350,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "ark-ff" @@ -472,18 +503,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -494,20 +525,20 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -524,12 +555,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.0" @@ -565,9 +590,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitvec" @@ -604,9 +629,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-slice-cast" @@ -622,9 +647,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" dependencies = [ "serde", ] @@ -645,9 +670,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.87" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3286b845d0fccbdd15af433f61c5970e711987036cb468f437ff6badd70f4e24" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" [[package]] name = "cfg-if" @@ -657,9 +682,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const-hex" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbd12d49ab0eaf8193ba9175e45f56bbc2e4b27d57b8cfe62aa47942a46b9a9" +checksum = "5ba00838774b4ab0233e355d26710fbfc8327a05c017f6dc4873f876d1f79f78" dependencies = [ "cfg-if", "cpufeatures", @@ -823,9 +848,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "elliptic-curve" @@ -864,9 +889,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "fastrlp" @@ -993,7 +1018,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -1045,9 +1070,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -1101,9 +1126,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1256,9 +1281,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -1290,9 +1315,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -1339,8 +1364,8 @@ dependencies = [ name = "kona-derive" version = "0.0.1" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", + "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=e3f2f07)", "alloy-primitives", "alloy-provider", "alloy-rlp", @@ -1351,6 +1376,7 @@ dependencies = [ "hashbrown", "lru", "miniz_oxide", + "op-alloy-consensus", "proptest", "reqwest", "serde", @@ -1434,9 +1460,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mime" @@ -1547,13 +1573,24 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "op-alloy-consensus" +version = "0.1.0" +source = "git+https://github.com/clabby/op-alloy?branch=refcell/consensus-port#2d72c8ee077360ae0358e9c61f1bb37ac27be3b0" +dependencies = [ + "alloy-consensus 0.1.0 (git+https://github.com/clabby/alloy?branch=cl/consensus-expose-encoding)", + "alloy-eips 0.1.0 (git+https://github.com/clabby/alloy?branch=cl/consensus-expose-encoding)", + "alloy-primitives", + "alloy-rlp", +] + [[package]] name = "openssl" version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -1570,7 +1607,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -1686,14 +1723,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1770,9 +1807,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1785,7 +1822,7 @@ checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.2", + "bitflags 2.5.0", "lazy_static", "num-traits", "rand", @@ -1805,9 +1842,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1868,9 +1905,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" @@ -1878,7 +1915,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e6cc1e89e689536eb5aeede61520e874df5a4707df811cd5da4aa5fbb2aae19" dependencies = [ - "base64 0.22.0", + "base64", "bytes", "futures-core", "futures-util", @@ -1933,9 +1970,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825" +checksum = "8f308135fef9fc398342da5472ce7c484529df23743fb7c734e0f3d472971e62" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -1957,9 +1994,9 @@ dependencies = [ [[package]] name = "ruint-macro" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" +checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" [[package]] name = "rustc-demangle" @@ -1993,11 +2030,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -2006,11 +2043,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.21.7", + "base64", "rustls-pki-types", ] @@ -2131,7 +2168,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -2217,9 +2254,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2284,9 +2321,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.50" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -2302,7 +2339,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -2319,9 +2356,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", @@ -2346,7 +2383,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -2394,9 +2431,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -2419,7 +2456,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -2522,7 +2559,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -2697,7 +2734,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -2731,7 +2768,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2789,7 +2826,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.5", ] [[package]] @@ -2809,17 +2846,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2830,9 +2868,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2842,9 +2880,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2854,9 +2892,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2866,9 +2910,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2878,9 +2922,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2890,9 +2934,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2902,9 +2946,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" @@ -2951,7 +2995,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] [[package]] @@ -2971,5 +3015,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.58", ] diff --git a/crates/derive/Cargo.toml b/crates/derive/Cargo.toml index 40032c94c5..e382c87f08 100644 --- a/crates/derive/Cargo.toml +++ b/crates/derive/Cargo.toml @@ -14,6 +14,7 @@ anyhow.workspace = true tracing.workspace = true # External +op-alloy-consensus = { git = "https://github.com/clabby/op-alloy", branch = "refcell/consensus-port", default-features = false } alloy-primitives = { version = "0.7.0", default-features = false, features = ["rlp"] } alloy-rlp = { version = "0.3.4", default-features = false, features = ["derive"] } alloy-sol-types = { version = "0.7.0", default-features = false } @@ -24,6 +25,7 @@ hashbrown = "0.14.3" unsigned-varint = "0.8.0" miniz_oxide = { version = "0.7.2" } lru = "0.12.3" +spin = { version = "0.9.8", features = ["mutex"] } # `serde` feature dependencies serde = { version = "1.0.197", default-features = false, features = ["derive"], optional = true } @@ -36,7 +38,6 @@ reqwest = { version = "0.12", default-features = false, optional = true } [dev-dependencies] tokio = { version = "1.36", features = ["full"] } proptest = "1.4.0" -spin = { version = "0.9.8", features = ["mutex"] } # Spin is used for testing synchronization primitives tracing-subscriber = "0.3.18" [features] diff --git a/crates/derive/src/alloy_providers.rs b/crates/derive/src/alloy_providers.rs index 0ceb133d97..9a1db6db69 100644 --- a/crates/derive/src/alloy_providers.rs +++ b/crates/derive/src/alloy_providers.rs @@ -28,6 +28,8 @@ const CACHE_SIZE: usize = 16; pub struct AlloyChainProvider>> { /// The inner Ethereum JSON-RPC provider. inner: T, + /// `header_by_hash` LRU cache. + header_by_hash_cache: LruCache, /// `block_info_by_number` LRU cache. block_info_by_number_cache: LruCache, /// `block_info_by_number` LRU cache. @@ -41,6 +43,7 @@ impl>> AlloyChainProvider { pub fn new(inner: T) -> Self { Self { inner, + header_by_hash_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), block_info_by_number_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), receipts_by_hash_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), block_info_and_transactions_by_hash_cache: LruCache::new( @@ -52,6 +55,20 @@ impl>> AlloyChainProvider { #[async_trait] impl>> ChainProvider for AlloyChainProvider { + async fn header_by_hash(&mut self, hash: B256) -> Result
{ + if let Some(header) = self.header_by_hash_cache.get(&hash) { + return Ok(header.clone()); + } + + let raw_header: Bytes = self + .inner + .client() + .request("debug_getRawHeader", [hash]) + .await + .map_err(|e| anyhow!(e))?; + Header::decode(&mut raw_header.as_ref()).map_err(|e| anyhow!(e)) + } + async fn block_info_by_number(&mut self, number: u64) -> Result { if let Some(block_info) = self.block_info_by_number_cache.get(&number) { return Ok(*block_info); diff --git a/crates/derive/src/lib.rs b/crates/derive/src/lib.rs index c2a42ac9ad..3d575ea874 100644 --- a/crates/derive/src/lib.rs +++ b/crates/derive/src/lib.rs @@ -14,8 +14,9 @@ use types::RollupConfig; mod params; pub use params::{ ChannelID, CHANNEL_ID_LENGTH, CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC, - DERIVATION_VERSION_0, FRAME_OVERHEAD, MAX_CHANNEL_BANK_SIZE, MAX_FRAME_LEN, - MAX_RLP_BYTES_PER_CHANNEL, MAX_SPAN_BATCH_BYTES, + DEPOSIT_EVENT_ABI, DEPOSIT_EVENT_ABI_HASH, DEPOSIT_EVENT_VERSION_0, DERIVATION_VERSION_0, + FRAME_OVERHEAD, MAX_CHANNEL_BANK_SIZE, MAX_FRAME_LEN, MAX_RLP_BYTES_PER_CHANNEL, + MAX_SPAN_BATCH_BYTES, SEQUENCER_FEE_VAULT_ADDRESS, }; pub mod sources; diff --git a/crates/derive/src/params.rs b/crates/derive/src/params.rs index 8c6f1f5630..e2c8b60cff 100644 --- a/crates/derive/src/params.rs +++ b/crates/derive/src/params.rs @@ -1,6 +1,10 @@ //! This module contains the parameters and identifying types for the derivation pipeline. -use alloy_primitives::{b256, B256}; +use alloy_primitives::{address, b256, Address, B256}; + +/// The sequencer fee vault address. +pub const SEQUENCER_FEE_VAULT_ADDRESS: Address = + address!("4200000000000000000000000000000000000011"); /// Count the tagging info as 200 in terms of buffer size. pub const FRAME_OVERHEAD: usize = 200; @@ -37,3 +41,16 @@ pub const CONFIG_UPDATE_EVENT_VERSION_0: B256 = B256::ZERO; /// Data transactions that carry frames are generally not larger than 128 KB due to L1 network /// conditions, but we leave space to grow larger anyway (gas limit allows for more data). pub const MAX_FRAME_LEN: usize = 1000; + +/// Deposit log event abi signature. +pub const DEPOSIT_EVENT_ABI: &str = "TransactionDeposited(address,address,uint256,bytes)"; + +/// Deposit event abi hash. +/// +/// This is the keccak256 hash of the deposit event ABI signature. +/// `keccak256("TransactionDeposited(address,address,uint256,bytes)")` +pub const DEPOSIT_EVENT_ABI_HASH: B256 = + b256!("b3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32"); + +/// The initial version of the deposit event log. +pub const DEPOSIT_EVENT_VERSION_0: B256 = B256::ZERO; diff --git a/crates/derive/src/stages/attributes_queue.rs b/crates/derive/src/stages/attributes_queue.rs index d4b61aef53..f64992fe46 100644 --- a/crates/derive/src/stages/attributes_queue.rs +++ b/crates/derive/src/stages/attributes_queue.rs @@ -3,8 +3,8 @@ use crate::{ traits::{OriginProvider, ResettableStage}, types::{ - AttributesWithParent, BlockID, BlockInfo, L2BlockInfo, PayloadAttributes, ResetError, - RollupConfig, SingleBatch, StageError, StageResult, SystemConfig, + AttributesWithParent, BlockInfo, L2BlockInfo, PayloadAttributes, ResetError, RollupConfig, + SingleBatch, StageError, StageResult, SystemConfig, }, }; use alloc::boxed::Box; @@ -12,14 +12,11 @@ use async_trait::async_trait; use core::fmt::Debug; use tracing::info; -pub trait AttributesBuilder { - /// Prepare the payload attributes. - fn prepare_payload_attributes( - &mut self, - l2_parent: L2BlockInfo, - epoch: BlockID, - ) -> anyhow::Result; -} +mod deposits; +pub(crate) use deposits::derive_deposits; + +mod builder; +pub use builder::{AttributesBuilder, StatefulAttributesBuilder}; /// [AttributesProvider] is a trait abstraction that generalizes the [BatchQueue] stage. #[async_trait] @@ -124,6 +121,7 @@ where let mut attributes = self .builder .prepare_payload_attributes(parent, batch.epoch()) + .await .map_err(StageError::AttributesBuild)?; attributes.no_tx_pool = true; attributes.transactions.extend(batch.transactions); @@ -173,7 +171,7 @@ mod tests { stages::test_utils::{ new_attributes_provider, MockAttributesBuilder, MockAttributesProvider, }, - types::RawTransaction, + types::{BuilderError, RawTransaction}, }; use alloc::{vec, vec::Vec}; use alloy_primitives::b256; @@ -264,7 +262,9 @@ mod tests { let result = attributes_queue.create_next_attributes(batch, parent).await.unwrap_err(); assert_eq!( result, - StageError::AttributesBuild(anyhow::anyhow!("missing payload attribute")) + StageError::AttributesBuild(BuilderError::Custom(anyhow::anyhow!( + "missing payload attribute" + ))) ); } diff --git a/crates/derive/src/stages/attributes_queue/builder.rs b/crates/derive/src/stages/attributes_queue/builder.rs new file mode 100644 index 0000000000..806e646d50 --- /dev/null +++ b/crates/derive/src/stages/attributes_queue/builder.rs @@ -0,0 +1,167 @@ +//! The [`AttributesBuilder`] and it's default implementation. + +use super::derive_deposits; +use crate::{ + params::SEQUENCER_FEE_VAULT_ADDRESS, + traits::ChainProvider, + types::{ + BlockID, BuilderError, EcotoneTransactionBuilder, L2BlockInfo, PayloadAttributes, + RawTransaction, RollupConfig, SystemConfig, + }, +}; +use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec, vec::Vec}; +use alloy_primitives::B256; +use async_trait::async_trait; + +/// The [AttributesBuilder] is responsible for preparing [PayloadAttributes] +/// that can be used to construct an L2 Block containing only deposits. +#[async_trait] +pub trait AttributesBuilder { + /// Prepares a template [PayloadAttributes] that is ready to be used to build an L2 block. + /// The block will contain deposits only, on top of the given L2 parent, with the L1 origin + /// set to the given epoch. + /// By default, the [PayloadAttributes] template will have `no_tx_pool` set to true, + /// and no sequencer transactions. The caller has to modify the template to add transactions. + /// This can be done by either setting the `no_tx_pool` to false as sequencer, or by appending + /// batch transactions as the verifier. + async fn prepare_payload_attributes( + &mut self, + l2_parent: L2BlockInfo, + epoch: BlockID, + ) -> Result; +} + +/// The [SystemConfigL2Fetcher] fetches the system config by L2 hash. +pub trait SystemConfigL2Fetcher { + /// Fetch the system config by L2 hash. + fn system_config_by_l2_hash(&self, hash: B256) -> anyhow::Result; +} + +/// A stateful implementation of the [AttributesBuilder]. +#[derive(Debug, Default)] +pub struct StatefulAttributesBuilder +where + S: SystemConfigL2Fetcher + Debug, + R: ChainProvider + Debug, +{ + /// The rollup config. + rollup_cfg: Arc, + /// The system config fetcher. + config_fetcher: S, + /// The L1 receipts fetcher. + receipts_fetcher: R, +} + +impl StatefulAttributesBuilder +where + S: SystemConfigL2Fetcher + Debug, + R: ChainProvider + Debug, +{ + /// Create a new [StatefulAttributesBuilder] with the given epoch. + pub fn new(rcfg: Arc, cfg: S, receipts: R) -> Self { + Self { rollup_cfg: rcfg, config_fetcher: cfg, receipts_fetcher: receipts } + } +} + +#[async_trait] +impl AttributesBuilder for StatefulAttributesBuilder +where + S: SystemConfigL2Fetcher + Send + Debug, + R: ChainProvider + Send + Debug, +{ + async fn prepare_payload_attributes( + &mut self, + l2_parent: L2BlockInfo, + epoch: BlockID, + ) -> Result { + let l1_header; + let deposit_transactions: Vec; + // let mut sequence_number = 0u64; + let mut sys_config = + self.config_fetcher.system_config_by_l2_hash(l2_parent.block_info.hash)?; + + // If the L1 origin changed in this block, then we are in the first block of the epoch. + // In this case we need to fetch all transaction receipts from the L1 origin block so + // we can scan for user deposits. + if l2_parent.l1_origin.number != epoch.number { + let header = self.receipts_fetcher.header_by_hash(epoch.hash).await?; + if l2_parent.l1_origin.hash != header.parent_hash { + return Err(BuilderError::BlockMismatchEpochReset( + epoch, + l2_parent.l1_origin, + header.parent_hash, + )); + } + let receipts = self.receipts_fetcher.receipts_by_hash(epoch.hash).await?; + sys_config.update_with_receipts(&receipts, &self.rollup_cfg, header.timestamp)?; + let deposits = + derive_deposits(epoch.hash, receipts, self.rollup_cfg.deposit_contract_address) + .await?; + l1_header = header; + deposit_transactions = deposits; + // sequence_number = 0; + } else { + #[allow(clippy::collapsible_else_if)] + if l2_parent.l1_origin.hash != epoch.hash { + return Err(BuilderError::BlockMismatch(epoch, l2_parent.l1_origin)); + } + + let header = self.receipts_fetcher.header_by_hash(epoch.hash).await?; + l1_header = header; + deposit_transactions = vec![]; + // sequence_number = l2_parent.seq_num + 1; + } + + // Sanity check the L1 origin was correctly selected to maintain the time invariant + // between L1 and L2. + let next_l2_time = l2_parent.block_info.timestamp + self.rollup_cfg.block_time; + if next_l2_time < l1_header.timestamp { + return Err(BuilderError::BrokenTimeInvariant( + l2_parent.l1_origin, + next_l2_time, + BlockID { hash: l1_header.hash_slow(), number: l1_header.number }, + l1_header.timestamp, + )); + } + + let mut upgrade_transactions: Vec = vec![]; + if self.rollup_cfg.is_ecotone_active(next_l2_time) { + upgrade_transactions = + EcotoneTransactionBuilder::build_txs().map_err(BuilderError::Custom)?; + } + + // TODO(clabby): `L1BlockInfo` parsing from calldata. + // let l1_info_tx = l1_info_deposit_bytes(self.rollup_cfg, sys_config, sequence_number, + // l1_info, next_l2_time)?; + + let mut txs = + Vec::with_capacity(1 + deposit_transactions.len() + upgrade_transactions.len()); + // txs.push(l1_info_tx); + txs.extend(deposit_transactions); + txs.extend(upgrade_transactions); + + let mut withdrawals = None; + if self.rollup_cfg.is_canyon_active(next_l2_time) { + withdrawals = Some(Vec::default()); + } + + let mut parent_beacon_root = None; + if self.rollup_cfg.is_ecotone_active(next_l2_time) { + // if the parent beacon root is not available, default to zero hash + parent_beacon_root = Some(l1_header.parent_beacon_block_root.unwrap_or_default()); + } + + Ok(PayloadAttributes { + timestamp: next_l2_time, + prev_randao: l1_header.mix_hash, + fee_recipient: SEQUENCER_FEE_VAULT_ADDRESS, + transactions: txs, + no_tx_pool: true, + gas_limit: Some(u64::from_be_bytes( + alloy_primitives::U64::from(sys_config.gas_limit).to_be_bytes(), + )), + withdrawals, + parent_beacon_block_root: parent_beacon_root, + }) + } +} diff --git a/crates/derive/src/stages/attributes_queue/deposits.rs b/crates/derive/src/stages/attributes_queue/deposits.rs new file mode 100644 index 0000000000..2909ccdc1a --- /dev/null +++ b/crates/derive/src/stages/attributes_queue/deposits.rs @@ -0,0 +1,35 @@ +//! Contains a helper method to derive deposit transactions from L1 Receipts. + +use crate::{ + params::DEPOSIT_EVENT_ABI_HASH, + types::{decode_deposit, DepositError, RawTransaction}, +}; +use alloc::vec::Vec; +use alloy_consensus::Receipt; +use alloy_primitives::{Address, Log, B256}; + +/// Derive deposits for transaction receipts. +/// +/// Successful deposits must be emitted by the deposit contract and have the correct event +/// signature. So the receipt address must equal the specified deposit contract and the first topic +/// must be the [DEPOSIT_EVENT_ABI_HASH]. +pub(crate) async fn derive_deposits( + block_hash: B256, + receipts: Vec, + deposit_contract: Address, +) -> anyhow::Result> { + let receipts = receipts.into_iter().filter(|r| r.status).collect::>(); + // Flatten the list of receipts into a list of logs. + let addr = |l: &Log| l.address == deposit_contract; + let topics = |l: &Log| l.data.topics().first().map_or(false, |i| *i == DEPOSIT_EVENT_ABI_HASH); + let filter_logs = + |r: Receipt| r.logs.into_iter().filter(|l| addr(l) && topics(l)).collect::>(); + let logs = receipts.into_iter().flat_map(filter_logs).collect::>(); + // TODO(refcell): are logs **and** receipts guaranteed to be _in order_? + // If not, we need to somehow get the index of each log in the block. + logs.iter() + .enumerate() + .map(|(i, l)| decode_deposit(block_hash, i, l)) + .collect::, DepositError>>() + .map_err(|e| anyhow::anyhow!(e)) +} diff --git a/crates/derive/src/stages/mod.rs b/crates/derive/src/stages/mod.rs index 78d80cf41c..a428572e7c 100644 --- a/crates/derive/src/stages/mod.rs +++ b/crates/derive/src/stages/mod.rs @@ -32,7 +32,9 @@ mod batch_queue; pub use batch_queue::{BatchQueue, BatchQueueProvider}; mod attributes_queue; -pub use attributes_queue::{AttributesProvider, AttributesQueue}; +pub use attributes_queue::{ + AttributesBuilder, AttributesProvider, AttributesQueue, StatefulAttributesBuilder, +}; #[cfg(test)] pub mod test_utils; diff --git a/crates/derive/src/stages/test_utils/attributes_queue.rs b/crates/derive/src/stages/test_utils/attributes_queue.rs index aec67c5b65..1adaa0c2d8 100644 --- a/crates/derive/src/stages/test_utils/attributes_queue.rs +++ b/crates/derive/src/stages/test_utils/attributes_queue.rs @@ -4,7 +4,8 @@ use crate::{ stages::attributes_queue::{AttributesBuilder, AttributesProvider}, traits::OriginProvider, types::{ - BlockID, BlockInfo, L2BlockInfo, PayloadAttributes, SingleBatch, StageError, StageResult, + BlockID, BlockInfo, BuilderError, L2BlockInfo, PayloadAttributes, SingleBatch, StageError, + StageResult, }, }; use alloc::{boxed::Box, vec::Vec}; @@ -17,14 +18,19 @@ pub struct MockAttributesBuilder { pub attributes: Vec>, } +#[async_trait] impl AttributesBuilder for MockAttributesBuilder { /// Prepares the [PayloadAttributes] for the next payload. - fn prepare_payload_attributes( + async fn prepare_payload_attributes( &mut self, _l2_parent: L2BlockInfo, _epoch: BlockID, - ) -> anyhow::Result { - self.attributes.pop().ok_or(anyhow::anyhow!("missing payload attribute"))? + ) -> Result { + match self.attributes.pop() { + Some(Ok(attrs)) => Ok(attrs), + Some(Err(err)) => Err(BuilderError::Custom(err)), + None => Err(BuilderError::Custom(anyhow::anyhow!("no attributes available"))), + } } } diff --git a/crates/derive/src/traits/data_sources.rs b/crates/derive/src/traits/data_sources.rs index 051e2821b2..c94b7b5758 100644 --- a/crates/derive/src/traits/data_sources.rs +++ b/crates/derive/src/traits/data_sources.rs @@ -5,7 +5,7 @@ use crate::types::{ Blob, BlockInfo, ExecutionPayloadEnvelope, IndexedBlobHash, L2BlockInfo, StageResult, }; use alloc::{boxed::Box, fmt::Debug, vec::Vec}; -use alloy_consensus::{Receipt, TxEnvelope}; +use alloy_consensus::{Header, Receipt, TxEnvelope}; use alloy_primitives::{Address, Bytes, B256}; use anyhow::Result; use async_trait::async_trait; @@ -13,6 +13,9 @@ use async_trait::async_trait; /// Describes the functionality of a data source that can provide information from the blockchain. #[async_trait] pub trait ChainProvider { + /// Fetch the L1 [Header] for the given [B256] hash. + async fn header_by_hash(&mut self, hash: B256) -> Result
; + /// Returns the block at the given number, or an error if the block does not exist in the data /// source. async fn block_info_by_number(&mut self, number: u64) -> Result; diff --git a/crates/derive/src/traits/test_utils/data_sources.rs b/crates/derive/src/traits/test_utils/data_sources.rs index 7fb4f55db8..75784652bc 100644 --- a/crates/derive/src/traits/test_utils/data_sources.rs +++ b/crates/derive/src/traits/test_utils/data_sources.rs @@ -5,7 +5,7 @@ use crate::{ types::{BlockInfo, ExecutionPayloadEnvelope, L2BlockInfo}, }; use alloc::{boxed::Box, vec::Vec}; -use alloy_consensus::{Receipt, TxEnvelope}; +use alloy_consensus::{Header, Receipt, TxEnvelope}; use alloy_primitives::B256; use anyhow::Result; use async_trait::async_trait; @@ -50,6 +50,8 @@ impl L2ChainProvider for MockBlockFetcher { pub struct TestChainProvider { /// Maps block numbers to block information using a tuple list. pub blocks: Vec<(u64, BlockInfo)>, + /// Maps block hashes to header information using a tuple list. + pub headers: Vec<(B256, Header)>, /// Maps block hashes to receipts using a tuple list. pub receipts: Vec<(B256, Vec)>, } @@ -84,6 +86,14 @@ impl TestChainProvider { #[async_trait] impl ChainProvider for TestChainProvider { + async fn header_by_hash(&mut self, hash: B256) -> Result
{ + if let Some((_, header)) = self.headers.iter().find(|(_, b)| b.hash_slow() == hash) { + Ok(header.clone()) + } else { + Err(anyhow::anyhow!("Block not found")) + } + } + async fn block_info_by_number(&mut self, _number: u64) -> Result { if let Some((_, block)) = self.blocks.iter().find(|(n, _)| *n == _number) { Ok(*block) diff --git a/crates/derive/src/types/deposits.rs b/crates/derive/src/types/deposits.rs new file mode 100644 index 0000000000..389404794a --- /dev/null +++ b/crates/derive/src/types/deposits.rs @@ -0,0 +1,529 @@ +//! Contains deposit transaction types and helper methods. + +use alloc::{string::String, vec::Vec}; +use alloy_primitives::{keccak256, Address, Bytes, Log, TxKind, B256, U256, U64}; +use alloy_rlp::Encodable; +use op_alloy_consensus::TxDeposit; + +use crate::{ + params::DEPOSIT_EVENT_ABI_HASH, + types::{DepositError, RawTransaction}, +}; + +/// Source domain identifiers for deposit transactions. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[repr(u8)] +pub enum DepositSourceDomainIdentifier { + /// A user deposit source. + User = 0, + /// A L1 info deposit source. + L1Info = 1, + /// An upgrade deposit source. + Upgrade = 2, +} + +/// Source domains for deposit transactions. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum DepositSourceDomain { + /// A user deposit source. + User(UserDepositSource), + /// A L1 info deposit source. + L1Info(L1InfoDepositSource), + /// An upgrade deposit source. + Upgrade(UpgradeDepositSource), +} + +/// A deposit transaction source. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UserDepositSource { + /// The L1 block hash. + pub l1_block_hash: B256, + /// The log index. + pub log_index: u64, +} + +impl UserDepositSource { + /// Creates a new [UserDepositSource]. + pub fn new(l1_block_hash: B256, log_index: u64) -> Self { + Self { l1_block_hash, log_index } + } + + /// Returns the source hash. + pub fn source_hash(&self) -> B256 { + let mut input = [0u8; 32 * 2]; + input[..32].copy_from_slice(&self.l1_block_hash[..]); + input[32 * 2 - 8..].copy_from_slice(&self.log_index.to_be_bytes()); + let deposit_id_hash = keccak256(input); + let mut domain_input = [0u8; 32 * 2]; + let identifier_bytes: [u8; 8] = (DepositSourceDomainIdentifier::User as u64).to_be_bytes(); + domain_input[32 - 8..32].copy_from_slice(&identifier_bytes); + domain_input[32..].copy_from_slice(&deposit_id_hash[..]); + keccak256(domain_input) + } +} + +/// A L1 info deposit transaction source. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct L1InfoDepositSource { + /// The L1 block hash. + pub l1_block_hash: B256, + /// The sequence number. + pub seq_number: u64, +} + +impl L1InfoDepositSource { + /// Creates a new [L1InfoDepositSource]. + pub fn new(l1_block_hash: B256, seq_number: u64) -> Self { + Self { l1_block_hash, seq_number } + } + + /// Returns the source hash. + pub fn source_hash(&self) -> B256 { + let mut input = [0u8; 32 * 2]; + input[..32].copy_from_slice(&self.l1_block_hash[..]); + input[32 * 2 - 8..].copy_from_slice(&self.seq_number.to_be_bytes()); + let deposit_id_hash = keccak256(input); + let mut domain_input = [0u8; 32 * 2]; + let identifier_bytes: [u8; 8] = + (DepositSourceDomainIdentifier::L1Info as u64).to_be_bytes(); + domain_input[32 - 8..32].copy_from_slice(&identifier_bytes); + domain_input[32..].copy_from_slice(&deposit_id_hash[..]); + keccak256(domain_input) + } +} + +/// An upgrade deposit transaction source. +/// This implements the translation of upgrade-tx identity information to a deposit source-hash, +/// which makes the deposit uniquely identifiable. +/// System-upgrade transactions have their own domain for source-hashes, +/// to not conflict with user-deposits or deposited L1 information. +/// The intent identifies the upgrade-tx uniquely, in a human-readable way. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UpgradeDepositSource { + /// The intent. + pub intent: String, +} + +impl UpgradeDepositSource { + /// Creates a new [UpgradeDepositSource]. + pub fn new(intent: String) -> Self { + Self { intent } + } + + /// Returns the source hash. + pub fn source_hash(&self) -> B256 { + let intent_hash = keccak256(self.intent.as_bytes()); + let mut domain_input = [0u8; 32 * 2]; + let identifier_bytes: [u8; 8] = + (DepositSourceDomainIdentifier::Upgrade as u64).to_be_bytes(); + domain_input[32 - 8..32].copy_from_slice(&identifier_bytes); + domain_input[32..].copy_from_slice(&intent_hash[..]); + keccak256(domain_input) + } +} + +/// Derives a deposit transaction from an EVM log event emitted by the deposit contract. +/// +/// The emitted log must be in format: +/// ```solidity +/// event TransactionDeposited( +/// address indexed from, +/// address indexed to, +/// uint256 indexed version, +/// bytes opaqueData +/// ); +/// ``` +pub(crate) fn decode_deposit( + block_hash: B256, + index: usize, + log: &Log, +) -> Result { + let topics = log.data.topics(); + if topics.len() != 4 { + return Err(DepositError::UnexpectedTopicsLen(topics.len())); + } + if topics[0] != DEPOSIT_EVENT_ABI_HASH { + return Err(DepositError::InvalidSelector(DEPOSIT_EVENT_ABI_HASH, topics[0])); + } + if log.data.data.len() < 64 { + return Err(DepositError::IncompleteOpaqueData(log.data.data.len())); + } + if log.data.data.len() % 32 != 0 { + return Err(DepositError::UnalignedData(log.data.data.len())); + } + + let from = Address::try_from(&topics[1].as_slice()[12..]) + .map_err(|_| DepositError::FromDecode(topics[1]))?; + let to = Address::try_from(&topics[2].as_slice()[12..]) + .map_err(|_| DepositError::ToDecode(topics[2]))?; + let version = log.data.topics()[3]; + + // Solidity serializes the event's Data field as follows: + // + // ```solidity + // abi.encode(abi.encodPacked(uint256 mint, uint256 value, uint64 gasLimit, uint8 isCreation, bytes data)) + // ``` + // + // The the opaqueData will be packed as shown below: + // + // ------------------------------------------------------------ + // | offset | 256 byte content | + // ------------------------------------------------------------ + // | 0 | [0; 24] . {U64 big endian, hex encoded offset} | + // ------------------------------------------------------------ + // | 32 | [0; 24] . {U64 big endian, hex encoded length} | + // ------------------------------------------------------------ + + let opaque_content_offset: U64 = U64::try_from_be_slice(&log.data.data[24..32]).ok_or( + DepositError::InvalidOpaqueDataOffset(Bytes::copy_from_slice(&log.data.data[24..32])), + )?; + if opaque_content_offset != U64::from(32) { + return Err(DepositError::InvalidOpaqueDataOffset(Bytes::copy_from_slice( + &log.data.data[24..32], + ))); + } + + // The next 32 bytes indicate the length of the opaqueData content. + let opaque_content_len = + u64::from_be_bytes(log.data.data[56..64].try_into().map_err(|_| { + DepositError::InvalidOpaqueDataLength(Bytes::copy_from_slice(&log.data.data[56..64])) + })?); + if opaque_content_len as usize > log.data.data.len() - 64 { + return Err(DepositError::OpaqueDataOverflow( + opaque_content_len as usize, + log.data.data.len() - 64, + )); + } + let padded_len = opaque_content_len.checked_add(32).ok_or(DepositError::OpaqueDataOverflow( + opaque_content_len as usize, + log.data.data.len() - 64, + ))?; + if padded_len as usize <= log.data.data.len() - 64 { + return Err(DepositError::PaddedOpaqueDataOverflow( + log.data.data.len() - 64, + opaque_content_len as usize, + )); + } + + // The remaining data is the opaqueData which is tightly packed and then padded to 32 bytes by + // the EVM. + let opaque_data = &log.data.data[64..64 + opaque_content_len as usize]; + let source = UserDepositSource::new(block_hash, index as u64); + + let mut deposit_tx = TxDeposit { + from, + is_system_transaction: false, + source_hash: source.source_hash(), + ..Default::default() + }; + + // Can only handle version 0 for now + if !version.is_zero() { + return Err(DepositError::InvalidVersion(version)); + } + + unmarshal_deposit_version0(&mut deposit_tx, to, opaque_data)?; + + // Re-encode the deposit transaction and return as a RawTransaction + let mut buffer = Vec::::new(); + deposit_tx.encode(&mut buffer); + Ok(RawTransaction::from(buffer)) +} + +/// Unmarshals a deposit transaction from the opaque data. +pub(crate) fn unmarshal_deposit_version0( + tx: &mut TxDeposit, + to: Address, + data: &[u8], +) -> Result<(), DepositError> { + if data.len() < 32 + 32 + 8 + 1 { + return Err(DepositError::UnexpectedOpaqueDataLen(data.len())); + } + + let mut offset = 0; + + let raw_mint: [u8; 16] = data[offset + 16..offset + 32].try_into().map_err(|_| { + DepositError::MintDecode(Bytes::copy_from_slice(&data[offset + 16..offset + 32])) + })?; + let mint = u128::from_be_bytes(raw_mint); + + // 0 mint is represented as nil to skip minting code + if mint == 0 { + tx.mint = None; + } else { + tx.mint = Some(mint); + } + offset += 32; + + // uint256 value + tx.value = U256::from_be_slice(&data[offset..offset + 32]); + offset += 32; + + // uint64 gas + let raw_gas: [u8; 8] = data[offset..offset + 8] + .try_into() + .map_err(|_| DepositError::GasDecode(Bytes::copy_from_slice(&data[offset..offset + 8])))?; + tx.gas_limit = u64::from_be_bytes(raw_gas) as u128; + offset += 8; + + // uint8 isCreation + // isCreation: If the boolean byte is 1 then dep.To will stay nil, + // and it will create a contract using L2 account nonce to determine the created address. + if data[offset] == 0 { + tx.to = TxKind::Call(to); + } else { + tx.to = TxKind::Create; + } + offset += 1; + + // The remainder of the opaqueData is the transaction data (without length prefix). + // The data may be padded to a multiple of 32 bytes + let tx_data_len = data.len() - offset; + + // Remaining bytes fill the data + tx.input = Bytes::copy_from_slice(&data[offset..offset + tx_data_len]); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + use alloy_primitives::{address, b256, hex, LogData}; + + #[test] + fn test_decode_deposit_invalid_topic_len() { + let log = Log { + address: Address::default(), + data: LogData::new_unchecked(vec![B256::default()], Bytes::default()), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::UnexpectedTopicsLen(1)); + } + + #[test] + fn test_decode_deposit_invalid_first_topic() { + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![B256::default(), B256::default(), B256::default(), B256::default()], + Bytes::default(), + ), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::InvalidSelector(DEPOSIT_EVENT_ABI_HASH, B256::default())); + } + + #[test] + fn test_decode_deposit_incomplete_data() { + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![DEPOSIT_EVENT_ABI_HASH, B256::default(), B256::default(), B256::default()], + Bytes::from(vec![0u8; 63]), + ), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::IncompleteOpaqueData(63)); + } + + #[test] + fn test_decode_deposit_unaligned_data() { + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![DEPOSIT_EVENT_ABI_HASH, B256::default(), B256::default(), B256::default()], + Bytes::from(vec![0u8; 65]), + ), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::UnalignedData(65)); + } + + #[test] + #[ignore] + fn test_decode_deposit_invalid_from() {} + + #[test] + #[ignore] + fn test_decode_deposit_invalid_to() {} + + #[test] + fn test_decode_deposit_invalid_opaque_data_offset() { + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![DEPOSIT_EVENT_ABI_HASH, B256::default(), B256::default(), B256::default()], + Bytes::from(vec![0u8; 64]), + ), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::InvalidOpaqueDataOffset(Bytes::from(vec![0u8; 8]))); + } + + #[test] + fn test_decode_deposit_opaque_data_overflow() { + let mut data = vec![0u8; 128]; + let offset: [u8; 8] = U64::from(32).to_be_bytes(); + data[24..32].copy_from_slice(&offset); + // The first 64 bytes of the data are identifiers so + // if this test was to be valid, the data length would be 64 not 128. + let len: [u8; 8] = U64::from(128).to_be_bytes(); + data[56..64].copy_from_slice(&len); + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![DEPOSIT_EVENT_ABI_HASH, B256::default(), B256::default(), B256::default()], + Bytes::from(data), + ), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::OpaqueDataOverflow(128, 64)); + } + + #[test] + fn test_decode_deposit_padded_overflow() { + let mut data = vec![0u8; 256]; + let offset: [u8; 8] = U64::from(32).to_be_bytes(); + data[24..32].copy_from_slice(&offset); + let len: [u8; 8] = U64::from(64).to_be_bytes(); + data[56..64].copy_from_slice(&len); + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![DEPOSIT_EVENT_ABI_HASH, B256::default(), B256::default(), B256::default()], + Bytes::from(data), + ), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::PaddedOpaqueDataOverflow(192, 64)); + } + + #[test] + fn test_decode_deposit_invalid_version() { + let mut data = vec![0u8; 128]; + let offset: [u8; 8] = U64::from(32).to_be_bytes(); + data[24..32].copy_from_slice(&offset); + let len: [u8; 8] = U64::from(64).to_be_bytes(); + data[56..64].copy_from_slice(&len); + let version = b256!("0000000000000000000000000000000000000000000000000000000000000001"); + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![DEPOSIT_EVENT_ABI_HASH, B256::default(), B256::default(), version], + Bytes::from(data), + ), + }; + let err = decode_deposit(B256::default(), 0, &log).unwrap_err(); + assert_eq!(err, DepositError::InvalidVersion(version)); + } + + #[test] + fn test_decode_deposit_empty_succeeds() { + let mut data = vec![0u8; 192]; + let offset: [u8; 8] = U64::from(32).to_be_bytes(); + data[24..32].copy_from_slice(&offset); + let len: [u8; 8] = U64::from(128).to_be_bytes(); + data[56..64].copy_from_slice(&len); + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![DEPOSIT_EVENT_ABI_HASH, B256::default(), B256::default(), B256::default()], + Bytes::from(data), + ), + }; + let tx = decode_deposit(B256::default(), 0, &log).unwrap(); + let raw_hex = hex!("f887a0ed428e1c45e1d9561b62834e1a2d3015a0caae3bfdc16b4da059ac885b01a14594000000000000000000000000000000000000000094000000000000000000000000000000000000000080808080b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + let expected = RawTransaction::from(Bytes::from(raw_hex)); + assert_eq!(tx, expected); + } + + #[test] + fn test_decode_deposit_full_succeeds() { + let mut data = vec![0u8; 192]; + let offset: [u8; 8] = U64::from(32).to_be_bytes(); + data[24..32].copy_from_slice(&offset); + let len: [u8; 8] = U64::from(128).to_be_bytes(); + data[56..64].copy_from_slice(&len); + // Copy the u128 mint value + let mint: [u8; 16] = 10_u128.to_be_bytes(); + data[80..96].copy_from_slice(&mint); + // Copy the tx value + let value: [u8; 32] = U256::from(100).to_be_bytes(); + data[96..128].copy_from_slice(&value); + // Copy the gas limit + let gas: [u8; 8] = 1000_u64.to_be_bytes(); + data[128..136].copy_from_slice(&gas); + // Copy the isCreation flag + data[136] = 1; + let from = address!("1111111111111111111111111111111111111111"); + let mut from_bytes = vec![0u8; 32]; + from_bytes[12..32].copy_from_slice(from.as_slice()); + let to = address!("2222222222222222222222222222222222222222"); + let mut to_bytes = vec![0u8; 32]; + to_bytes[12..32].copy_from_slice(to.as_slice()); + let log = Log { + address: Address::default(), + data: LogData::new_unchecked( + vec![ + DEPOSIT_EVENT_ABI_HASH, + B256::from_slice(&from_bytes), + B256::from_slice(&to_bytes), + B256::default(), + ], + Bytes::from(data), + ), + }; + let tx = decode_deposit(B256::default(), 0, &log).unwrap(); + let raw_hex = hex!("f875a0ed428e1c45e1d9561b62834e1a2d3015a0caae3bfdc16b4da059ac885b01a145941111111111111111111111111111111111111111800a648203e880b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + let expected = RawTransaction::from(Bytes::from(raw_hex)); + assert_eq!(tx, expected); + } + + #[test] + fn test_unmarshal_deposit_version0_invalid_len() { + let data = vec![0u8; 72]; + let mut tx = TxDeposit::default(); + let to = address!("5555555555555555555555555555555555555555"); + let err = unmarshal_deposit_version0(&mut tx, to, &data).unwrap_err(); + assert_eq!(err, DepositError::UnexpectedOpaqueDataLen(72)); + + // Data must have at least length 73 + let data = vec![0u8; 73]; + let mut tx = TxDeposit::default(); + let to = address!("5555555555555555555555555555555555555555"); + unmarshal_deposit_version0(&mut tx, to, &data).unwrap(); + } + + #[test] + fn test_unmarshal_deposit_version0() { + let mut data = vec![0u8; 192]; + let offset: [u8; 8] = U64::from(32).to_be_bytes(); + data[24..32].copy_from_slice(&offset); + let len: [u8; 8] = U64::from(128).to_be_bytes(); + data[56..64].copy_from_slice(&len); + // Copy the u128 mint value + let mint: [u8; 16] = 10_u128.to_be_bytes(); + data[80..96].copy_from_slice(&mint); + // Copy the tx value + let value: [u8; 32] = U256::from(100).to_be_bytes(); + data[96..128].copy_from_slice(&value); + // Copy the gas limit + let gas: [u8; 8] = 1000_u64.to_be_bytes(); + data[128..136].copy_from_slice(&gas); + // Copy the isCreation flag + data[136] = 1; + let mut tx = TxDeposit { + from: address!("1111111111111111111111111111111111111111"), + to: TxKind::Call(address!("2222222222222222222222222222222222222222")), + value: U256::from(100), + gas_limit: 1000, + mint: Some(10), + ..Default::default() + }; + let to = address!("5555555555555555555555555555555555555555"); + unmarshal_deposit_version0(&mut tx, to, &data).unwrap(); + assert_eq!(tx.to, TxKind::Call(address!("5555555555555555555555555555555555555555"))); + } +} diff --git a/crates/derive/src/types/ecotone.rs b/crates/derive/src/types/ecotone.rs new file mode 100644 index 0000000000..43a79b38d8 --- /dev/null +++ b/crates/derive/src/types/ecotone.rs @@ -0,0 +1,177 @@ +#![allow(dead_code)] +//! Module containing a [Transaction] builder for the Ecotone network updgrade transactions. + +use crate::types::{RawTransaction, UpgradeDepositSource}; +use alloc::{string::String, vec, vec::Vec}; +use alloy_primitives::{address, bytes, Address, Bytes, TxKind, U256}; +use alloy_rlp::Encodable; +use op_alloy_consensus::{OpTxEnvelope, TxDeposit}; +use spin::Lazy; + +/// The UpdgradeTo Function Signature +pub const UPDGRADE_TO_FUNC_SIGNATURE: &str = "upgradeTo(address)"; + +/// L1 Block Deployer Address +pub const L1_BLOCK_DEPLOYER_ADDRESS: Address = address!("4210000000000000000000000000000000000000"); + +/// The Gas Price Oracle Deployer Address +pub const GAS_PRICE_ORACLE_DEPLOYER_ADDRESS: Address = + address!("4210000000000000000000000000000000000001"); + +/// The new L1 Block Address +/// This is computed by using go-ethereum's `crypto.CreateAddress` function, +/// with the L1 Block Deployer Address and nonce 0. +pub const NEW_L1_BLOCK_ADDRESS: Address = address!("07dbe8500fc591d1852b76fee44d5a05e13097ff"); + +/// The Gas Price Oracle Address +/// This is computed by using go-ethereum's `crypto.CreateAddress` function, +/// with the Gas Price Oracle Deployer Address and nonce 0. +pub const GAS_PRICE_ORACLE_ADDRESS: Address = address!("b528d11cc114e026f138fe568744c6d45ce6da7a"); + +/// The Enable Ecotone Input Method 4Byte Signature +pub const ENABLE_ECOTONE_INPUT: &[u8] = &[0x22, 0xb9, 0x08, 0xb3]; + +/// UpgradeTo Function 4Byte Signature +pub const UPGRADE_TO_FUNC_BYTES_4: &[u8] = &[0x36, 0x59, 0xcf, 0xe6]; + +/// EIP-4788 From Address +pub const EIP4788_FROM: Address = address!("0B799C86a49DEeb90402691F1041aa3AF2d3C875"); + +static DEPLOY_L1_BLOCK_SOURCE: Lazy = + Lazy::new(|| UpgradeDepositSource { intent: String::from("Ecotone: L1 Block Deployment") }); + +static DEPLOY_GAS_PRICE_ORACLE_SOURCE: Lazy = Lazy::new(|| { + UpgradeDepositSource { intent: String::from("Ecotone: Gas Price Oracle Deployment") } +}); + +static UPDATE_L1_BLOCK_PROXY_SOURCE: Lazy = + Lazy::new(|| UpgradeDepositSource { intent: String::from("Ecotone: L1 Block Proxy Update") }); + +static UPDATE_GAS_PRICE_ORACLE_SOURCE: Lazy = Lazy::new(|| { + UpgradeDepositSource { intent: String::from("Ecotone: Gas Price Oracle Proxy Update") } +}); + +static ENABLE_ECOTONE_SOURCE: Lazy = Lazy::new(|| UpgradeDepositSource { + intent: String::from("Ecotone: Gas Price Oracle Set Ecotone"), +}); + +static BEACON_ROOTS_SOURCE: Lazy = Lazy::new(|| UpgradeDepositSource { + intent: String::from("Ecotone: beacon block roots contract deployment"), +}); + +/// Turns the given address into calldata for the `upgradeTo` function. +pub fn upgrade_to_calldata(addr: Address) -> Bytes { + let mut v = UPGRADE_TO_FUNC_BYTES_4.to_vec(); + v.extend_from_slice(addr.as_slice()); + Bytes::from(v) +} + +/// Builder wrapper for the Ecotone network updgrade. +#[derive(Debug, Default)] +pub struct EcotoneTransactionBuilder; + +impl EcotoneTransactionBuilder { + /// Constructs the Ecotone network upgrade transactions. + pub fn build_txs() -> anyhow::Result> { + let mut txs = vec![]; + + let eip4788_creation_data = bytes!("60618060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500"); + + let l1_block_deployment_bytecode = bytes!("608060405234801561001057600080fd5b5061053e806100206000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80638381f58a11610097578063c598591811610066578063c598591814610229578063e591b28214610249578063e81b2c6d14610289578063f82061401461029257600080fd5b80638381f58a146101e35780638b239f73146101f75780639e8c496614610200578063b80777ea1461020957600080fd5b806354fd4d50116100d357806354fd4d50146101335780635cf249691461017c57806364ca23ef1461018557806368d5dca6146101b257600080fd5b8063015d8eb9146100fa57806309bd5a601461010f578063440a5e201461012b575b600080fd5b61010d61010836600461044c565b61029b565b005b61011860025481565b6040519081526020015b60405180910390f35b61010d6103da565b61016f6040518060400160405280600581526020017f312e322e3000000000000000000000000000000000000000000000000000000081525081565b60405161012291906104be565b61011860015481565b6003546101999067ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610122565b6003546101ce9068010000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610122565b6000546101999067ffffffffffffffff1681565b61011860055481565b61011860065481565b6000546101999068010000000000000000900467ffffffffffffffff1681565b6003546101ce906c01000000000000000000000000900463ffffffff1681565b61026473deaddeaddeaddeaddeaddeaddeaddeaddead000181565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610122565b61011860045481565b61011860075481565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610342576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4c31426c6f636b3a206f6e6c7920746865206465706f7369746f72206163636f60448201527f756e742063616e20736574204c3120626c6f636b2076616c7565730000000000606482015260840160405180910390fd5b6000805467ffffffffffffffff98891668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116998916999099179890981790975560019490945560029290925560038054919094167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009190911617909255600491909155600555600655565b3373deaddeaddeaddeaddeaddeaddeaddeaddead00011461040357633cc50b456000526004601cfd5b60043560801c60035560143560801c600055602435600155604435600755606435600255608435600455565b803567ffffffffffffffff8116811461044757600080fd5b919050565b600080600080600080600080610100898b03121561046957600080fd5b6104728961042f565b975061048060208a0161042f565b9650604089013595506060890135945061049c60808a0161042f565b979a969950949793969560a0850135955060c08501359460e001359350915050565b600060208083528351808285015260005b818110156104eb578581018301518582016040015282016104cf565b818111156104fd576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a"); + + let gas_price_oracle_deployment_bytecode = + bytes!("608060405234801561001057600080fd5b50610fb5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806354fd4d5011610097578063de26c4a111610066578063de26c4a1146101da578063f45e65d8146101ed578063f8206140146101f5578063fe173b97146101cc57600080fd5b806354fd4d501461016657806368d5dca6146101af5780636ef25c3a146101cc578063c5985918146101d257600080fd5b8063313ce567116100d3578063313ce5671461012757806349948e0e1461012e5780634ef6e22414610141578063519b4bd31461015e57600080fd5b80630c18c162146100fa57806322b90ab3146101155780632e0f26251461011f575b600080fd5b6101026101fd565b6040519081526020015b60405180910390f35b61011d61031e565b005b610102600681565b6006610102565b61010261013c366004610b73565b610541565b60005461014e9060ff1681565b604051901515815260200161010c565b610102610565565b6101a26040518060400160405280600581526020017f312e322e3000000000000000000000000000000000000000000000000000000081525081565b60405161010c9190610c42565b6101b76105c6565b60405163ffffffff909116815260200161010c565b48610102565b6101b761064b565b6101026101e8366004610b73565b6106ac565b610102610760565b610102610853565b6000805460ff1615610296576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103199190610cb5565b905090565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663e591b2826040518163ffffffff1660e01b8152600401602060405180830381865afa15801561037d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a19190610cce565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610481576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161028d565b60005460ff1615610514576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161028d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805460ff161561055c57610556826108b4565b92915050565b61055682610958565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610627573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103199190610d04565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610627573d6000803e3d6000fd5b6000806106b883610ab4565b60005490915060ff16156106cc5792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074f9190610cb5565b6107599082610d59565b9392505050565b6000805460ff16156107f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f6563617465640000000000000000000000000000000000000000000000000000606482015260840161028d565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b6000806108c083610ab4565b905060006108cc610565565b6108d461064b565b6108df906010610d71565b63ffffffff166108ef9190610d9d565b905060006108fb610853565b6109036105c6565b63ffffffff166109139190610d9d565b905060006109218284610d59565b61092b9085610d9d565b90506109396006600a610efa565b610944906010610d9d565b61094e9082610f06565b9695505050505050565b60008061096483610ab4565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109eb9190610cb5565b6109f3610565565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a769190610cb5565b610a809085610d59565b610a8a9190610d9d565b610a949190610d9d565b9050610aa26006600a610efa565b610aac9082610f06565b949350505050565b80516000908190815b81811015610b3757848181518110610ad757610ad7610f41565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016600003610b1757610b10600484610d59565b9250610b25565b610b22601084610d59565b92505b80610b2f81610f70565b915050610abd565b50610aac82610440610d59565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610b8557600080fd5b813567ffffffffffffffff80821115610b9d57600080fd5b818401915084601f830112610bb157600080fd5b813581811115610bc357610bc3610b44565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610c0957610c09610b44565b81604052828152876020848701011115610c2257600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b81811015610c6f57858101830151858201604001528201610c53565b81811115610c81576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600060208284031215610cc757600080fd5b5051919050565b600060208284031215610ce057600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461075957600080fd5b600060208284031215610d1657600080fd5b815163ffffffff8116811461075957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115610d6c57610d6c610d2a565b500190565b600063ffffffff80831681851681830481118215151615610d9457610d94610d2a565b02949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610dd557610dd5610d2a565b500290565b600181815b80851115610e3357817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610e1957610e19610d2a565b80851615610e2657918102915b93841c9390800290610ddf565b509250929050565b600082610e4a57506001610556565b81610e5757506000610556565b8160018114610e6d5760028114610e7757610e93565b6001915050610556565b60ff841115610e8857610e88610d2a565b50506001821b610556565b5060208310610133831016604e8410600b8410161715610eb6575081810a610556565b610ec08383610dda565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610ef257610ef2610d2a565b029392505050565b60006107598383610e3b565b600082610f3c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610fa157610fa1610d2a565b506001019056fea164736f6c634300080f000a"); + + // Deploy the L1 Block Contract + let mut buffer = Vec::new(); + OpTxEnvelope::Deposit(TxDeposit { + source_hash: DEPLOY_L1_BLOCK_SOURCE.source_hash(), + from: L1_BLOCK_DEPLOYER_ADDRESS, + to: TxKind::Create, + mint: 0.into(), + value: U256::ZERO, + gas_limit: 375_000, + is_system_transaction: false, + input: l1_block_deployment_bytecode, + }) + .encode(&mut buffer); + txs.push(RawTransaction::from(buffer)); + + // Deploy the Gas Price Oracle + buffer = Vec::new(); + OpTxEnvelope::Deposit(TxDeposit { + source_hash: DEPLOY_GAS_PRICE_ORACLE_SOURCE.source_hash(), + from: GAS_PRICE_ORACLE_DEPLOYER_ADDRESS, + to: TxKind::Create, + mint: 0.into(), + value: U256::ZERO, + gas_limit: 1_000_000, + is_system_transaction: false, + input: gas_price_oracle_deployment_bytecode, + }) + .encode(&mut buffer); + txs.push(RawTransaction::from(buffer)); + + // Update the l1 block proxy + buffer = Vec::new(); + OpTxEnvelope::Deposit(TxDeposit { + source_hash: UPDATE_L1_BLOCK_PROXY_SOURCE.source_hash(), + from: Address::default(), + to: TxKind::Call(L1_BLOCK_DEPLOYER_ADDRESS), + mint: 0.into(), + value: U256::ZERO, + gas_limit: 50_000, + is_system_transaction: false, + input: upgrade_to_calldata(NEW_L1_BLOCK_ADDRESS), + }) + .encode(&mut buffer); + txs.push(RawTransaction::from(buffer)); + + // Update gas price oracle proxy + buffer = Vec::new(); + OpTxEnvelope::Deposit(TxDeposit { + source_hash: UPDATE_GAS_PRICE_ORACLE_SOURCE.source_hash(), + from: Address::default(), + to: TxKind::Call(GAS_PRICE_ORACLE_DEPLOYER_ADDRESS), + mint: 0.into(), + value: U256::ZERO, + gas_limit: 50_000, + is_system_transaction: false, + input: upgrade_to_calldata(GAS_PRICE_ORACLE_ADDRESS), + }) + .encode(&mut buffer); + txs.push(RawTransaction::from(buffer)); + + // Enable ecotone + buffer = Vec::new(); + OpTxEnvelope::Deposit(TxDeposit { + source_hash: ENABLE_ECOTONE_SOURCE.source_hash(), + from: L1_BLOCK_DEPLOYER_ADDRESS, + to: TxKind::Call(GAS_PRICE_ORACLE_ADDRESS), + mint: 0.into(), + value: U256::ZERO, + gas_limit: 80_000, + is_system_transaction: false, + input: ENABLE_ECOTONE_INPUT.into(), + }) + .encode(&mut buffer); + txs.push(RawTransaction::from(buffer)); + + // Deploy EIP4788 + buffer = Vec::new(); + OpTxEnvelope::Deposit(TxDeposit { + source_hash: BEACON_ROOTS_SOURCE.source_hash(), + from: EIP4788_FROM, + to: TxKind::Create, + mint: 0.into(), + value: U256::ZERO, + gas_limit: 250_000, + is_system_transaction: false, + input: eip4788_creation_data, + }) + .encode(&mut buffer); + txs.push(RawTransaction::from(buffer)); + + Ok(txs) + } +} diff --git a/crates/derive/src/types/errors.rs b/crates/derive/src/types/errors.rs index d226c559b2..a361b2e95a 100644 --- a/crates/derive/src/types/errors.rs +++ b/crates/derive/src/types/errors.rs @@ -1,7 +1,7 @@ //! This module contains derivation errors thrown within the pipeline. use super::SpanBatchError; -use crate::types::Frame; +use crate::types::{BlockID, Frame}; use alloc::vec::Vec; use alloy_primitives::{Bytes, B256}; use core::fmt::Display; @@ -30,7 +30,7 @@ pub enum StageError { /// Missing L1 origin. MissingOrigin, /// Failed to build the [super::PayloadAttributes] for the next batch. - AttributesBuild(anyhow::Error), + AttributesBuild(BuilderError), /// Reset the pipeline. Reset(ResetError), /// The stage detected a block reorg. @@ -189,3 +189,210 @@ impl Display for DecodeError { } } } + +/// An [AttributeBuilder] Error. +#[derive(Debug)] +pub enum BuilderError { + /// Mismatched blocks. + BlockMismatch(BlockID, BlockID), + /// Mismatched blocks for the start of an Epoch. + BlockMismatchEpochReset(BlockID, BlockID, B256), + /// [SystemConfig] update failed. + SystemConfigUpdate, + /// Broken time invariant between L2 and L1. + BrokenTimeInvariant(BlockID, u64, BlockID, u64), + /// A custom error wrapping [anyhow::Error]. + Custom(anyhow::Error), +} + +impl PartialEq for BuilderError { + fn eq(&self, other: &BuilderError) -> bool { + match (self, other) { + (BuilderError::BlockMismatch(b1, e1), BuilderError::BlockMismatch(b2, e2)) => { + b1 == b2 && e1 == e2 + } + ( + BuilderError::BlockMismatchEpochReset(b1, e1, e2), + BuilderError::BlockMismatchEpochReset(b2, e3, e4), + ) => e1 == e3 && e2 == e4 && b1 == b2, + ( + BuilderError::BrokenTimeInvariant(b1, t1, b2, t2), + BuilderError::BrokenTimeInvariant(b3, t3, b4, t4), + ) => b1 == b3 && t1 == t3 && b2 == b4 && t2 == t4, + (BuilderError::SystemConfigUpdate, BuilderError::SystemConfigUpdate) | + (BuilderError::Custom(_), BuilderError::Custom(_)) => true, + _ => false, + } + } +} + +impl From for BuilderError { + fn from(e: anyhow::Error) -> Self { + BuilderError::Custom(e) + } +} + +impl Display for BuilderError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + BuilderError::BlockMismatch(block_id, parent) => { + write!(f, "Block mismatch with L1 origin {} (parent {})", block_id, parent) + } + BuilderError::BlockMismatchEpochReset(block_id, parent, origin) => { + write!( + f, + "Block mismatch with L1 origin {} (parent {}) on top of L1 origin {}", + block_id, parent, origin + ) + } + BuilderError::SystemConfigUpdate => write!(f, "System config update failed"), + BuilderError::BrokenTimeInvariant(block_id, l2_time, parent, l1_time) => { + write!( + f, + "Cannot build L2 block on top {} (time {}) before L1 origin {} (time {})", + block_id, l2_time, parent, l1_time + ) + } + BuilderError::Custom(e) => write!(f, "Custom error: {}", e), + } + } +} + +/// An [op_alloy_consensus::TxDeposit] validation error. +#[derive(Debug)] +pub enum DepositError { + /// Unexpected number of deposit event log topics. + UnexpectedTopicsLen(usize), + /// Invalid deposit event selector. + /// Expected: [B256] (deposit event selector), Actual: [B256] (event log topic). + InvalidSelector(B256, B256), + /// Incomplete opaqueData slice header (incomplete length). + IncompleteOpaqueData(usize), + /// The log data is not aligned to 32 bytes. + UnalignedData(usize), + /// Failed to decode the `from` field of the deposit event (the second topic). + FromDecode(B256), + /// Failed to decode the `to` field of the deposit event (the third topic). + ToDecode(B256), + /// Invalid opaque data content offset. + InvalidOpaqueDataOffset(Bytes), + /// Invalid opaque data content length. + InvalidOpaqueDataLength(Bytes), + /// Opaque data length exceeds the deposit log event data length. + /// Specified: [usize] (data length), Actual: [usize] (opaque data length). + OpaqueDataOverflow(usize, usize), + /// Opaque data with padding exceeds the specified data length. + PaddedOpaqueDataOverflow(usize, usize), + /// An invalid deposit version. + InvalidVersion(B256), + /// Unexpected opaque data length + UnexpectedOpaqueDataLen(usize), + /// Failed to decode the deposit mint value. + MintDecode(Bytes), + /// Failed to decode the deposit gas value. + GasDecode(Bytes), + /// A custom error wrapping [anyhow::Error]. + Custom(anyhow::Error), +} + +impl PartialEq for DepositError { + fn eq(&self, other: &DepositError) -> bool { + match (self, other) { + (DepositError::UnexpectedTopicsLen(l1), DepositError::UnexpectedTopicsLen(l2)) => { + l1 == l2 + } + (DepositError::InvalidSelector(e1, t1), DepositError::InvalidSelector(e2, t2)) => { + e1 == e2 && t1 == t2 + } + (DepositError::IncompleteOpaqueData(l1), DepositError::IncompleteOpaqueData(l2)) => { + l1 == l2 + } + (DepositError::UnalignedData(d1), DepositError::UnalignedData(d2)) => d1 == d2, + (DepositError::FromDecode(e1), DepositError::FromDecode(e2)) => e1 == e2, + (DepositError::ToDecode(e1), DepositError::ToDecode(e2)) => e1 == e2, + ( + DepositError::InvalidOpaqueDataOffset(o1), + DepositError::InvalidOpaqueDataOffset(o2), + ) => o1 == o2, + ( + DepositError::InvalidOpaqueDataLength(o1), + DepositError::InvalidOpaqueDataLength(o2), + ) => o1 == o2, + ( + DepositError::OpaqueDataOverflow(l1, l2), + DepositError::OpaqueDataOverflow(l3, l4), + ) => l1 == l3 && l2 == l4, + ( + DepositError::PaddedOpaqueDataOverflow(l1, l2), + DepositError::PaddedOpaqueDataOverflow(l3, l4), + ) => l1 == l3 && l2 == l4, + (DepositError::InvalidVersion(v1), DepositError::InvalidVersion(v2)) => v1 == v2, + ( + DepositError::UnexpectedOpaqueDataLen(a), + DepositError::UnexpectedOpaqueDataLen(b), + ) => a == b, + (DepositError::MintDecode(a), DepositError::MintDecode(b)) => a == b, + (DepositError::GasDecode(a), DepositError::GasDecode(b)) => a == b, + (DepositError::Custom(_), DepositError::Custom(_)) => true, + _ => false, + } + } +} + +impl Display for DepositError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + DepositError::UnexpectedTopicsLen(len) => { + write!(f, "Unexpected number of deposit event log topics: {}", len) + } + DepositError::InvalidSelector(expected, actual) => { + write!(f, "Invalid deposit event selector: {}, expected {}", actual, expected) + } + DepositError::IncompleteOpaqueData(len) => { + write!(f, "Incomplete opaqueData slice header (incomplete length): {}", len) + } + DepositError::UnalignedData(data) => { + write!(f, "Unaligned log data, expected multiple of 32 bytes, got: {}", data) + } + DepositError::FromDecode(topic) => { + write!(f, "Failed to decode the `from` address of the deposit log topic: {}", topic) + } + DepositError::ToDecode(topic) => { + write!(f, "Failed to decode the `to` address of the deposit log topic: {}", topic) + } + DepositError::InvalidOpaqueDataOffset(offset) => { + write!(f, "Invalid u64 opaque data content offset: {:?}", offset) + } + DepositError::InvalidOpaqueDataLength(length) => { + write!(f, "Invalid u64 opaque data content length: {:?}", length) + } + DepositError::OpaqueDataOverflow(data_len, opaque_len) => { + write!( + f, + "Specified opaque data length {} exceeds the deposit log event data length {}", + opaque_len, data_len + ) + } + DepositError::PaddedOpaqueDataOverflow(data_len, opaque_len) => { + write!( + f, + "Opaque data with padding exceeds the specified data length: {} > {}", + opaque_len, data_len + ) + } + DepositError::InvalidVersion(version) => { + write!(f, "Invalid deposit version: {}", version) + } + DepositError::UnexpectedOpaqueDataLen(len) => { + write!(f, "Unexpected opaque data length: {}", len) + } + DepositError::MintDecode(data) => { + write!(f, "Failed to decode the u128 deposit mint value: {:?}", data) + } + DepositError::GasDecode(data) => { + write!(f, "Failed to decode the u64 deposit gas value: {:?}", data) + } + DepositError::Custom(e) => write!(f, "Custom error: {}", e), + } + } +} diff --git a/crates/derive/src/types/mod.rs b/crates/derive/src/types/mod.rs index bc6c72a6d9..636553c4e7 100644 --- a/crates/derive/src/types/mod.rs +++ b/crates/derive/src/types/mod.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use alloc::vec::Vec; +pub use alloy_consensus::Receipt; use alloy_primitives::Bytes; use alloy_rlp::{Decodable, Encodable}; @@ -13,6 +14,9 @@ pub use attributes::{AttributesWithParent, PayloadAttributes}; mod system_config; pub use system_config::{SystemAccounts, SystemConfig, SystemConfigUpdateType}; +mod deposits; +pub use deposits::*; + mod rollup_config; pub use rollup_config::RollupConfig; @@ -25,6 +29,9 @@ pub use batch::{ MAX_SPAN_BATCH_SIZE, }; +mod ecotone; +pub use ecotone::*; + mod payload; pub use payload::{ ExecutionPayload, ExecutionPayloadEnvelope, PAYLOAD_MEM_FIXED_COST, PAYLOAD_TX_MEM_OVERHEAD, @@ -65,6 +72,12 @@ impl RawTransaction { } } +impl> From for RawTransaction { + fn from(bytes: T) -> Self { + Self(bytes.into()) + } +} + impl Encodable for RawTransaction { fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { self.0.encode(out)