diff --git a/Cargo.lock b/Cargo.lock index df817dc2035..b8d9d00ba33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,7 +135,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.10", + "getrandom", "once_cell", "version_check", ] @@ -153,9 +153,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -203,9 +203,9 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +checksum = "a2e1373abdaa212b704512ec2bd8b26bd0b7d5c3f70117411a5d9a451383c859" dependencies = [ "derive_arbitrary", ] @@ -287,7 +287,7 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.23", + "rustix 0.37.25", "slab", "socket2 0.4.9", "waker-fn", @@ -304,13 +304,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -631,9 +631,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bitvec" @@ -801,9 +801,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -861,9 +861,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" dependencies = [ "serde", ] @@ -1240,7 +1240,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -1252,7 +1252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -1289,9 +1289,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" dependencies = [ "csv-core", "itoa", @@ -1301,9 +1301,9 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" dependencies = [ "memchr", ] @@ -1327,19 +1327,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - [[package]] name = "curve25519-dalek" version = "4.1.1" @@ -1365,7 +1352,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1534,9 +1521,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] [[package]] name = "derivative" @@ -1557,7 +1547,7 @@ checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1575,11 +1565,11 @@ dependencies = [ [[package]] name = "diesel" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c8a2cb22327206568569e5a45bb5a2c946455efdd76e24d15b7e82171af95e" +checksum = "2268a214a6f118fce1838edba3d1561cf0e78d8de785475957a580a7f8c69d33" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "byteorder", "diesel_derives", "itoa", @@ -1596,7 +1586,7 @@ dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1616,7 +1606,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1731,7 +1721,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1766,7 +1756,7 @@ checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ "der 0.7.8", "digest 0.10.7", - "elliptic-curve 0.13.5", + "elliptic-curve 0.13.6", "rfc6979 0.4.0", "signature 2.1.0", "spki 0.7.2", @@ -1774,9 +1764,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8 0.10.2", "signature 2.1.0", @@ -1788,11 +1778,11 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ - "curve25519-dalek 4.1.1", + "curve25519-dalek", "ed25519", - "rand_core 0.6.4", + "rand_core", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "zeroize", ] @@ -1846,7 +1836,7 @@ dependencies = [ "ff 0.12.1", "generic-array", "group 0.12.1", - "rand_core 0.6.4", + "rand_core", "sec1 0.3.0", "subtle", "zeroize", @@ -1854,9 +1844,9 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.13.5" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" dependencies = [ "base16ct 0.2.0", "crypto-bigint 0.5.3", @@ -1866,7 +1856,7 @@ dependencies = [ "group 0.13.0", "pem-rfc7468", "pkcs8 0.10.2", - "rand_core 0.6.4", + "rand_core", "sec1 0.7.3", "subtle", "zeroize", @@ -1965,25 +1955,14 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ - "errno-dragonfly", "libc", "windows-sys 0.48.0", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "error-chain" version = "0.12.4" @@ -2260,7 +2239,7 @@ dependencies = [ "impl-codec 0.6.0", "impl-rlp", "impl-serde 0.4.0", - "primitive-types 0.12.1", + "primitive-types 0.12.2", "scale-info", "uint", ] @@ -2274,7 +2253,7 @@ dependencies = [ "cpufeatures", "lazy_static", "ring", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -2343,7 +2322,7 @@ dependencies = [ "dunce", "ethers-core", "eyre", - "getrandom 0.2.10", + "getrandom", "hex", "proc-macro2", "quote", @@ -2414,7 +2393,7 @@ dependencies = [ "futures-core", "futures-timer", "futures-util", - "getrandom 0.2.10", + "getrandom", "hashers", "hex", "http", @@ -2567,7 +2546,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2577,7 +2556,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2644,9 +2623,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "libz-sys", @@ -2792,7 +2771,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2893,17 +2872,6 @@ dependencies = [ "types", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.10" @@ -2913,7 +2881,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -2968,7 +2936,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff 0.12.1", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2979,7 +2947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -3052,9 +3020,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" dependencies = [ "ahash 0.8.3", "allocator-api2", @@ -3084,7 +3052,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.0", + "hashbrown 0.14.1", ] [[package]] @@ -3365,16 +3333,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.48.0", + "windows-core", ] [[package]] @@ -3446,9 +3414,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9465340214b296cd17a0009acdb890d6160010b8adf8f78a00d0d7ab270f79f" +checksum = "bbb892e5777fe09e16f3d44de7802f4daa7267ecbe8c466f19d94e25bb0c303e" dependencies = [ "async-io", "core-foundation", @@ -3460,7 +3428,7 @@ dependencies = [ "rtnetlink", "system-configuration", "tokio", - "windows 0.34.0", + "windows", ] [[package]] @@ -3550,12 +3518,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", ] [[package]] @@ -3674,9 +3642,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -3713,7 +3681,7 @@ dependencies = [ "cfg-if", "ecdsa 0.14.8", "elliptic-curve 0.12.3", - "sha2 0.10.7", + "sha2 0.10.8", "sha3 0.10.8", ] @@ -3725,9 +3693,9 @@ checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", "ecdsa 0.16.8", - "elliptic-curve 0.13.5", + "elliptic-curve 0.13.6", "once_cell", - "sha2 0.10.7", + "sha2 0.10.8", "signature 2.1.0", ] @@ -3746,7 +3714,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" dependencies = [ - "primitive-types 0.12.1", + "primitive-types 0.12.2", "tiny-keccak", ] @@ -3828,9 +3796,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libflate" @@ -3864,9 +3832,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libmdbx" @@ -3892,7 +3860,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.10", + "getrandom", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -3994,7 +3962,7 @@ dependencies = [ "fnv", "futures", "futures-ticker", - "getrandom 0.2.10", + "getrandom", "hex_fmt", "instant", "libp2p-core", @@ -4006,7 +3974,7 @@ dependencies = [ "quick-protobuf-codec", "rand", "regex", - "sha2 0.10.7", + "sha2 0.10.8", "smallvec", "unsigned-varint 0.7.2", "void", @@ -4036,13 +4004,14 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686e73aff5e23efbb99bc85340ea6fd8686986aa7b283a881ba182cfca535ca9" +checksum = "31e6cc3b46b1183c2de7c452efbc64813389036be632aaae71de2f15f1994fad" dependencies = [ "asn1_der", "bs58 0.5.0", "ed25519-dalek", + "hkdf", "libsecp256k1", "log", "multihash", @@ -4050,7 +4019,7 @@ dependencies = [ "quick-protobuf", "rand", "sec1 0.7.3", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", "void", "zeroize", @@ -4114,12 +4083,12 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.43.1" +version = "0.43.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ce70757f2c0d82e9a3ef738fb10ea0723d16cec37f078f719e2c247704c1bb" +checksum = "d2eeec39ad3ad0677551907dd304b2f13f17208ccebe333bef194076cd2e8921" dependencies = [ "bytes", - "curve25519-dalek 4.1.1", + "curve25519-dalek", "futures", "libp2p-core", "libp2p-identity", @@ -4129,7 +4098,7 @@ dependencies = [ "once_cell", "quick-protobuf", "rand", - "sha2 0.10.7", + "sha2 0.10.8", "snow", "static_assertions", "thiserror", @@ -4178,9 +4147,9 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.43.4" +version = "0.43.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0cf749abdc5ca1dce6296dc8ea0f012464dfcfd3ddd67ffc0cabd8241c4e1da" +checksum = "ab94183f8fc2325817835b57946deb44340c99362cd4606c0a5717299b2ba369" dependencies = [ "either", "fnv", @@ -4209,7 +4178,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -4465,9 +4434,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lmdb-rkv" @@ -4492,9 +4461,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -4650,9 +4619,9 @@ checksum = "8c408dc227d302f1496c84d9dc68c00fec6f56f9228a18f3023f976f3ca7c945" [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -4778,7 +4747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] @@ -5030,7 +4999,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "libc", ] @@ -5115,6 +5084,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -5138,9 +5113,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -5238,7 +5213,7 @@ version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -5255,7 +5230,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -5323,9 +5298,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ "ecdsa 0.16.8", - "elliptic-curve 0.13.5", + "elliptic-curve 0.13.6", "primeorder", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -5404,7 +5379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.9", ] [[package]] @@ -5423,13 +5398,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "smallvec", "windows-targets 0.48.5", ] @@ -5441,7 +5416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -5469,7 +5444,7 @@ dependencies = [ "digest 0.10.7", "hmac 0.12.1", "password-hash", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -5547,7 +5522,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -5681,7 +5656,7 @@ dependencies = [ "md-5", "memchr", "rand", - "sha2 0.10.7", + "sha2 0.10.8", "stringprep", ] @@ -5696,6 +5671,12 @@ dependencies = [ "postgres-protocol", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -5725,7 +5706,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" dependencies = [ - "elliptic-curve 0.13.5", + "elliptic-curve 0.13.6", ] [[package]] @@ -5743,9 +5724,9 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash 0.8.0", "impl-codec 0.6.0", @@ -5757,12 +5738,12 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ - "thiserror", - "toml 0.5.11", + "once_cell", + "toml_edit", ] [[package]] @@ -5803,14 +5784,14 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -5827,7 +5808,7 @@ dependencies = [ "flate2", "hex", "lazy_static", - "rustix 0.36.15", + "rustix 0.36.16", ] [[package]] @@ -5865,7 +5846,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -6055,7 +6036,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -6065,16 +6046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -6083,7 +6055,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom", ] [[package]] @@ -6092,7 +6064,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -6145,27 +6117,36 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.10", + "getrandom", "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.9.5" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.8", - "regex-syntax 0.7.5", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -6179,13 +6160,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", ] [[package]] @@ -6196,15 +6177,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64 0.21.4", "bytes", @@ -6230,6 +6211,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -6394,9 +6376,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.15" +version = "0.36.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" +checksum = "6da3636faa25820d8648e0e31c5d519bbb01f72fdf57131f0f5f7da5fed36eab" dependencies = [ "bitflags 1.3.2", "errno", @@ -6408,9 +6390,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" +version = "0.37.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" dependencies = [ "bitflags 1.3.2", "errno", @@ -6422,14 +6404,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.14" +version = "0.38.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.7", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -6638,9 +6620,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" dependencies = [ "serde", ] @@ -6661,9 +6643,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" dependencies = [ "serde_derive", ] @@ -6690,13 +6672,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -6728,7 +6710,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -6812,9 +6794,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -6845,9 +6827,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -6874,7 +6856,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -6884,7 +6866,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -7131,11 +7113,11 @@ dependencies = [ "aes-gcm", "blake2", "chacha20poly1305", - "curve25519-dalek 4.1.1", - "rand_core 0.6.4", + "curve25519-dalek", + "rand_core", "ring", "rustc_version", - "sha2 0.10.7", + "sha2 0.10.8", "subtle", ] @@ -7188,8 +7170,7 @@ dependencies = [ [[package]] name = "ssz_types" version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382939886cb24ee8ac885d09116a60f6262d827c7a9e36012b4f6d3d0116d0b3" +source = "git+https://github.com/macladson/ssz_types.git?branch=optional#6a187e66213d42c748e477585ec43e79d057f2cf" dependencies = [ "arbitrary", "derivative", @@ -7360,9 +7341,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -7483,7 +7464,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall 0.3.5", - "rustix 0.38.14", + "rustix 0.38.19", "windows-sys 0.48.0", ] @@ -7536,7 +7517,7 @@ dependencies = [ "rand", "serde", "serde_json", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -7550,22 +7531,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -7589,14 +7570,16 @@ dependencies = [ [[package]] name = "time" -version = "0.3.29" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", "libc", + "num-conv", "num_threads", + "powerfmt", "serde", "time-core", "time-macros", @@ -7610,10 +7593,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -7640,7 +7624,7 @@ dependencies = [ "pbkdf2 0.11.0", "rand", "rustc-hash", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -7683,9 +7667,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ "backtrace", "bytes", @@ -7717,7 +7701,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -7845,7 +7829,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.2", "serde", "serde_spanned", "toml_datetime", @@ -7882,11 +7866,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -7895,20 +7878,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -8238,7 +8221,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.10", + "getrandom", "serde", ] @@ -8398,8 +8381,8 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.5" -source = "git+https://github.com/seanmonstar/warp.git#5ad8a9cb155f6485d13d591a564d8c70053a388a" +version = "0.3.6" +source = "git+https://github.com/seanmonstar/warp.git#efe8548a19172e69918396d0fdbc369df9d0eb17" dependencies = [ "bytes", "futures-channel", @@ -8443,12 +8426,6 @@ dependencies = [ "warp", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -8476,7 +8453,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -8510,7 +8487,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8687,23 +8664,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" -dependencies = [ - "windows_aarch64_msvc 0.34.0", - "windows_i686_gnu 0.34.0", - "windows_i686_msvc 0.34.0", - "windows_x86_64_gnu 0.34.0", - "windows_x86_64_msvc 0.34.0", -] - -[[package]] -name = "windows" -version = "0.48.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ + "windows-core", "windows-targets 0.48.5", ] @@ -8719,6 +8684,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -8779,12 +8753,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" -[[package]] -name = "windows_aarch64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -8797,12 +8765,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" -[[package]] -name = "windows_i686_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -8815,12 +8777,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" -[[package]] -name = "windows_i686_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -8833,12 +8789,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" -[[package]] -name = "windows_x86_64_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -8863,12 +8813,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" -[[package]] -name = "windows_x86_64_msvc" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -8883,9 +8827,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" dependencies = [ "memchr", ] @@ -8936,12 +8880,13 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "1.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ - "curve25519-dalek 3.2.0", - "rand_core 0.5.1", + "curve25519-dalek", + "rand_core", + "serde", "zeroize", ] @@ -9027,7 +8972,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -9071,11 +9016,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.9+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index 901ceea68be..faea7b2ebd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -222,6 +222,10 @@ validator_client = { path = "validator_client/" } validator_dir = { path = "common/validator_dir" } warp_utils = { path = "common/warp_utils" } +[patch] +[patch.crates-io] +ssz_types = { git = "https://github.com/macladson/ssz_types.git", branch = "optional" } + [profile.maxperf] inherits = "release" lto = "fat" diff --git a/Makefile b/Makefile index 8f744e03c5a..148f61ee607 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ PROFILE ?= release # List of all hard forks. This list is used to set env variables for several tests so that # they run for different forks. -FORKS=phase0 altair merge capella +FORKS=phase0 altair merge capella electra # Extra flags for Cargo CARGO_INSTALL_EXTRA_FLAGS?= diff --git a/beacon_node/beacon_chain/src/attestation_rewards.rs b/beacon_node/beacon_chain/src/attestation_rewards.rs index 94bd28f98fd..dff9d6759d3 100644 --- a/beacon_node/beacon_chain/src/attestation_rewards.rs +++ b/beacon_node/beacon_chain/src/attestation_rewards.rs @@ -50,9 +50,10 @@ impl BeaconChain { match state { BeaconState::Base(_) => self.compute_attestation_rewards_base(state, validators), - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { - self.compute_attestation_rewards_altair(state, validators) - } + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => self.compute_attestation_rewards_altair(state, validators), } } diff --git a/beacon_node/beacon_chain/src/beacon_block_streamer.rs b/beacon_node/beacon_chain/src/beacon_block_streamer.rs index e43f2a8dd81..3daf3e58195 100644 --- a/beacon_node/beacon_chain/src/beacon_block_streamer.rs +++ b/beacon_node/beacon_chain/src/beacon_block_streamer.rs @@ -15,7 +15,8 @@ use types::{ SignedBlindedBeaconBlock, Slot, }; use types::{ - ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadHeader, ExecutionPayloadMerge, + ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadHeader, + ExecutionPayloadMerge, }; #[derive(PartialEq)] @@ -97,6 +98,7 @@ fn reconstruct_default_header_block( let payload: ExecutionPayload = match fork { ForkName::Merge => ExecutionPayloadMerge::default().into(), ForkName::Capella => ExecutionPayloadCapella::default().into(), + ForkName::Electra => ExecutionPayloadElectra::default().into(), ForkName::Base | ForkName::Altair => { return Err(Error::PayloadReconstruction(format!( "Block with fork variant {} has execution payload", @@ -714,17 +716,19 @@ mod tests { } #[tokio::test] - async fn check_all_blocks_from_altair_to_capella() { + async fn check_all_blocks_from_altair_to_electra() { let slots_per_epoch = MinimalEthSpec::slots_per_epoch() as usize; - let num_epochs = 8; + let num_epochs = 10; let bellatrix_fork_epoch = 2usize; let capella_fork_epoch = 4usize; + let electra_fork_epoch = 6usize; let num_blocks_produced = num_epochs * slots_per_epoch; let mut spec = test_spec::(); spec.altair_fork_epoch = Some(Epoch::new(0)); spec.bellatrix_fork_epoch = Some(Epoch::new(bellatrix_fork_epoch as u64)); spec.capella_fork_epoch = Some(Epoch::new(capella_fork_epoch as u64)); + spec.electra_fork_epoch = Some(Epoch::new(electra_fork_epoch as u64)); let harness = get_harness(VALIDATOR_COUNT, spec); // go to bellatrix fork @@ -833,17 +837,19 @@ mod tests { } #[tokio::test] - async fn check_fallback_altair_to_capella() { + async fn check_fallback_altair_to_electra() { let slots_per_epoch = MinimalEthSpec::slots_per_epoch() as usize; - let num_epochs = 8; + let num_epochs = 10; let bellatrix_fork_epoch = 2usize; let capella_fork_epoch = 4usize; + let electra_fork_epoch = 6usize; let num_blocks_produced = num_epochs * slots_per_epoch; let mut spec = test_spec::(); spec.altair_fork_epoch = Some(Epoch::new(0)); spec.bellatrix_fork_epoch = Some(Epoch::new(bellatrix_fork_epoch as u64)); spec.capella_fork_epoch = Some(Epoch::new(capella_fork_epoch as u64)); + spec.electra_fork_epoch = Some(Epoch::new(electra_fork_epoch as u64)); let harness = get_harness(VALIDATOR_COUNT, spec); diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 9587783508f..fd5225883ba 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -4353,7 +4353,7 @@ impl BeaconChain { // allows it to run concurrently with things like attestation packing. let prepare_payload_handle = match &state { BeaconState::Base(_) | BeaconState::Altair(_) => None, - BeaconState::Merge(_) | BeaconState::Capella(_) => { + BeaconState::Merge(_) | BeaconState::Capella(_) | BeaconState::Electra(_) => { let prepare_payload_handle = get_execution_payload(self.clone(), &state, proposer_index, builder_params)?; Some(prepare_payload_handle) @@ -4643,6 +4643,30 @@ impl BeaconChain { bls_to_execution_changes: bls_to_execution_changes.into(), }, }), + BeaconState::Electra(_) => BeaconBlock::Electra(BeaconBlockElectra { + slot, + proposer_index, + parent_root, + state_root: Hash256::zero(), + body: BeaconBlockBodyElectra { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings: proposer_slashings.into(), + attester_slashings: attester_slashings.into(), + attestations: attestations.into(), + deposits: deposits.into(), + voluntary_exits: voluntary_exits.into(), + sync_aggregate: sync_aggregate + .ok_or(BlockProductionError::MissingSyncAggregate)?, + execution_payload: block_contents + .ok_or(BlockProductionError::MissingExecutionPayload)? + .to_payload() + .try_into() + .map_err(|_| BlockProductionError::InvalidPayloadFork)?, + bls_to_execution_changes: bls_to_execution_changes.into(), + }, + }), }; let block = SignedBeaconBlock::from_block( @@ -4912,7 +4936,7 @@ impl BeaconChain { } else { let withdrawals = match self.spec.fork_name_at_slot::(prepare_slot) { ForkName::Base | ForkName::Altair | ForkName::Merge => None, - ForkName::Capella => { + ForkName::Capella | ForkName::Electra => { let chain = self.clone(); self.spawn_blocking_handle( move || { diff --git a/beacon_node/beacon_chain/src/electra_readiness.rs b/beacon_node/beacon_chain/src/electra_readiness.rs new file mode 100644 index 00000000000..8887d7b346c --- /dev/null +++ b/beacon_node/beacon_chain/src/electra_readiness.rs @@ -0,0 +1,122 @@ +//! Provides tools for checking if a node is ready for the Electra upgrade and following merge +//! transition. + +use crate::{BeaconChain, BeaconChainTypes}; +use execution_layer::http::{ + ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_GET_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V2, +}; +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::time::Duration; +use types::*; + +/// The time before the Electra fork when we will start issuing warnings about preparation. +use super::merge_readiness::SECONDS_IN_A_WEEK; +pub const ELECTRA_READINESS_PREPARATION_SECONDS: u64 = SECONDS_IN_A_WEEK * 2; +pub const ENGINE_CAPABILITIES_REFRESH_INTERVAL: u64 = 300; + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[serde(tag = "type")] +pub enum ElectraReadiness { + /// The execution engine is electra-enabled (as far as we can tell) + Ready, + /// We are connected to an execution engine which doesn't support the V2 engine api methods + V2MethodsNotSupported { error: String }, + /// The transition configuration with the EL failed, there might be a problem with + /// connectivity, authentication or a difference in configuration. + ExchangeCapabilitiesFailed { error: String }, + /// The user has not configured an execution endpoint + NoExecutionEndpoint, +} + +impl fmt::Display for ElectraReadiness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ElectraReadiness::Ready => { + write!(f, "This node appears ready for Electra.") + } + ElectraReadiness::ExchangeCapabilitiesFailed { error } => write!( + f, + "Could not exchange capabilities with the \ + execution endpoint: {}", + error + ), + ElectraReadiness::NoExecutionEndpoint => write!( + f, + "The --execution-endpoint flag is not specified, this is a \ + requirement post-merge" + ), + ElectraReadiness::V2MethodsNotSupported { error } => write!( + f, + "Execution endpoint does not support Electra methods: {}", + error + ), + } + } +} + +impl BeaconChain { + /// Returns `true` if electra epoch is set and Electra fork has occurred or will + /// occur within `ELECTRA_READINESS_PREPARATION_SECONDS` + pub fn is_time_to_prepare_for_electra(&self, current_slot: Slot) -> bool { + if let Some(electra_epoch) = self.spec.electra_fork_epoch { + let electra_slot = electra_epoch.start_slot(T::EthSpec::slots_per_epoch()); + let electra_readiness_preparation_slots = + ELECTRA_READINESS_PREPARATION_SECONDS / self.spec.seconds_per_slot; + // Return `true` if Electra has happened or is within the preparation time. + current_slot + electra_readiness_preparation_slots > electra_slot + } else { + // The Electra fork epoch has not been defined yet, no need to prepare. + false + } + } + + /// Attempts to connect to the EL and confirm that it is ready for electra. + pub async fn check_electra_readiness(&self) -> ElectraReadiness { + if let Some(el) = self.execution_layer.as_ref() { + match el + .get_engine_capabilities(Some(Duration::from_secs( + ENGINE_CAPABILITIES_REFRESH_INTERVAL, + ))) + .await + { + Err(e) => { + // The EL was either unreachable or responded with an error + ElectraReadiness::ExchangeCapabilitiesFailed { + error: format!("{:?}", e), + } + } + Ok(capabilities) => { + let mut missing_methods = String::from("Required Methods Unsupported:"); + let mut all_good = true; + if !capabilities.get_payload_v2 { + missing_methods.push(' '); + missing_methods.push_str(ENGINE_GET_PAYLOAD_V2); + all_good = false; + } + if !capabilities.forkchoice_updated_v2 { + missing_methods.push(' '); + missing_methods.push_str(ENGINE_FORKCHOICE_UPDATED_V2); + all_good = false; + } + if !capabilities.new_payload_v2 { + missing_methods.push(' '); + missing_methods.push_str(ENGINE_NEW_PAYLOAD_V2); + all_good = false; + } + + if all_good { + ElectraReadiness::Ready + } else { + ElectraReadiness::V2MethodsNotSupported { + error: missing_methods, + } + } + } + } + } else { + ElectraReadiness::NoExecutionEndpoint + } + } +} diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index 1ac7229cc6d..5844bf6f079 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -419,7 +419,9 @@ pub fn get_execution_payload< let latest_execution_payload_header_block_hash = state.latest_execution_payload_header()?.block_hash(); let withdrawals = match state { - &BeaconState::Capella(_) => Some(get_expected_withdrawals(state, spec)?.into()), + &BeaconState::Capella(_) | &BeaconState::Electra(_) => { + Some(get_expected_withdrawals(state, spec)?.into()) + } &BeaconState::Merge(_) => None, // These shouldn't happen but they're here to make the pattern irrefutable &BeaconState::Base(_) | &BeaconState::Altair(_) => None, diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 4ea1eeee011..c448395f1e2 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -15,6 +15,7 @@ pub mod canonical_head; pub mod capella_readiness; pub mod chain_config; mod early_attester_cache; +pub mod electra_readiness; mod errors; pub mod eth1_chain; mod eth1_finalization_cache; diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 5de697764e6..89d542f1b8c 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -440,10 +440,14 @@ where let shanghai_time = spec.capella_fork_epoch.map(|epoch| { HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() }); + let prague_time = spec.electra_fork_epoch.map(|epoch| { + HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() + }); let mock = MockExecutionLayer::new( self.runtime.task_executor.clone(), DEFAULT_TERMINAL_BLOCK, shanghai_time, + prague_time, builder_threshold, Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), spec, diff --git a/beacon_node/beacon_chain/tests/store_tests.rs b/beacon_node/beacon_chain/tests/store_tests.rs index ab54af42c78..3b04e1de123 100644 --- a/beacon_node/beacon_chain/tests/store_tests.rs +++ b/beacon_node/beacon_chain/tests/store_tests.rs @@ -1893,9 +1893,9 @@ async fn pruning_test( }; let start_slot = Slot::new(1); - let divergence_slot = start_slot + num_initial_blocks; + let dielectrance_slot = start_slot + num_initial_blocks; let (state, state_root) = harness.get_current_state_and_root(); - let (_, _, _, divergence_state) = harness + let (_, _, _, dielectrance_state) = harness .add_attested_blocks_at_slots( state, state_root, @@ -1908,17 +1908,17 @@ async fn pruning_test( .add_blocks_on_multiple_chains(vec![ // Canonical chain ( - divergence_state.clone(), + dielectrance_state.clone(), slots( - divergence_slot + num_canonical_skips, + dielectrance_slot + num_canonical_skips, num_canonical_middle_blocks, ), honest_validators.clone(), ), // Fork chain ( - divergence_state.clone(), - slots(divergence_slot + num_fork_skips, num_fork_blocks), + dielectrance_state.clone(), + slots(dielectrance_slot + num_fork_skips, num_fork_blocks), faulty_validators, ), ]) @@ -1926,7 +1926,7 @@ async fn pruning_test( let (_, _, _, mut canonical_state) = chains.remove(0); let (stray_blocks, stray_states, _, stray_head_state) = chains.remove(0); - let stray_head_slot = divergence_slot + num_fork_skips + num_fork_blocks - 1; + let stray_head_slot = dielectrance_slot + num_fork_skips + num_fork_blocks - 1; let stray_head_state_root = stray_states[&stray_head_slot]; let stray_states = harness .chain @@ -1946,7 +1946,7 @@ async fn pruning_test( // Trigger finalization let num_finalization_blocks = 4 * E::slots_per_epoch(); - let canonical_slot = divergence_slot + num_canonical_skips + num_canonical_middle_blocks; + let canonical_slot = dielectrance_slot + num_canonical_skips + num_canonical_middle_blocks; let canonical_state_root = canonical_state.update_tree_hash_cache().unwrap(); harness .add_attested_blocks_at_slots( @@ -1957,13 +1957,13 @@ async fn pruning_test( ) .await; - // Check that finalization has advanced past the divergence slot. + // Check that finalization has advanced past the dielectrance slot. assert!( harness .finalized_checkpoint() .epoch .start_slot(E::slots_per_epoch()) - > divergence_slot + > dielectrance_slot ); check_chain_dump( &harness, diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 2c7738e8fab..d38c6465a55 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -1,6 +1,7 @@ use crate::metrics; use beacon_chain::{ capella_readiness::CapellaReadiness, + electra_readiness::ElectraReadiness, merge_readiness::{GenesisExecutionPayloadStatus, MergeConfig, MergeReadiness}, BeaconChain, BeaconChainTypes, ExecutionStatus, }; @@ -319,6 +320,7 @@ pub fn spawn_notifier( eth1_logging(&beacon_chain, &log); merge_readiness_logging(current_slot, &beacon_chain, &log).await; capella_readiness_logging(current_slot, &beacon_chain, &log).await; + electra_readiness_logging(current_slot, &beacon_chain, &log).await; } }; @@ -445,12 +447,15 @@ async fn capella_readiness_logging( } if capella_completed && !has_execution_layer { - error!( - log, - "Execution endpoint required"; - "info" => "you need a Capella enabled execution engine to validate blocks, see: \ - https://lighthouse-book.sigmaprime.io/merge-migration.html" - ); + if !beacon_chain.is_time_to_prepare_for_electra(current_slot) { + // logging of the EE being offline is handled in `electra_readiness_logging()` + error!( + log, + "Execution endpoint required"; + "info" => "you need a Capella enabled execution engine to validate blocks, see: \ + https://lighthouse-book.sigmaprime.io/merge-migration.html" + ); + } return; } @@ -479,6 +484,66 @@ async fn capella_readiness_logging( } } +/// Provides some helpful logging to users to indicate if their node is ready for Electra. +async fn electra_readiness_logging( + current_slot: Slot, + beacon_chain: &BeaconChain, + log: &Logger, +) { + let electra_completed = beacon_chain + .canonical_head + .cached_head() + .snapshot + .beacon_block + .message() + .body() + .execution_payload() + .map_or(false, |payload| payload.execution_witness_root().is_ok()); + + let has_execution_layer = beacon_chain.execution_layer.is_some(); + + if electra_completed && has_execution_layer + || !beacon_chain.is_time_to_prepare_for_electra(current_slot) + { + return; + } + + if electra_completed && !has_execution_layer { + // When adding a new fork, add a check for the next fork readiness here. + error!( + log, + "Execution endpoint required"; + "info" => "you need a Electra enabled execution engine to validate blocks, see: \ + https://lighthouse-book.sigmaprime.io/merge-migration.html" + ); + return; + } + + match beacon_chain.check_electra_readiness().await { + ElectraReadiness::Ready => { + info!( + log, + "Ready for Electra"; + "info" => "ensure the execution endpoint is updated to the latest Electra/Prague release" + ) + } + readiness @ ElectraReadiness::ExchangeCapabilitiesFailed { error: _ } => { + error!( + log, + "Not ready for Electra"; + "hint" => "the execution endpoint may be offline", + "info" => %readiness, + ) + } + readiness => warn!( + log, + "Not ready for Electra"; + "hint" => "try updating the execution endpoint", + "info" => %readiness, + ), + } +} + async fn genesis_execution_payload_logging( beacon_chain: &BeaconChain, log: &Logger, diff --git a/beacon_node/execution_layer/src/block_hash.rs b/beacon_node/execution_layer/src/block_hash.rs index c889fead0a0..07ac24c37a6 100644 --- a/beacon_node/execution_layer/src/block_hash.rs +++ b/beacon_node/execution_layer/src/block_hash.rs @@ -37,12 +37,22 @@ impl ExecutionLayer { None }; + // TODO(mac): Calculate the execution witness root (post-Electra). + let rlp_execution_witness_root = None; + //let rlp_execution_witness_root = if let Ok(execution_witness) = payload.execution_witness() { + // Some(keccak_hash::keccak(execution_witness.)) + // Some(trie_root::(execution_witness)) + //} else { + // None + //}; + // Construct the block header. let exec_block_header = ExecutionBlockHeader::from_payload( payload, KECCAK_EMPTY_LIST_RLP.as_fixed_bytes().into(), rlp_transactions_root, rlp_withdrawals_root, + rlp_execution_witness_root, ); // Hash the RLP encoding of the block header. @@ -140,6 +150,7 @@ mod test { nonce: Hash64::zero(), base_fee_per_gas: 0x036b_u64.into(), withdrawals_root: None, + execution_witness_root: None, }; let expected_rlp = "f90200a0e0a94a7a3c9617401586b1a27025d2d9671332d22d540e0af72b069170380f2aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ba5e000000000000000000000000000000000000a0ec3c94b18b8a1cff7d60f8d258ec723312932928626b4c9355eb4ab3568ec7f7a050f738580ed699f0469702c7ccc63ed2e51bc034be9479b7bff4e68dee84accfa029b0562f7140574dd0d50dee8a271b22e1a0a7b78fca58f7c60370d8317ba2a9b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000188016345785d8a00008301553482079e42a0000000000000000000000000000000000000000000000000000000000000000088000000000000000082036b"; let expected_hash = @@ -168,6 +179,7 @@ mod test { nonce: Hash64::zero(), base_fee_per_gas: 0x036b_u64.into(), withdrawals_root: None, + execution_witness_root: None, }; let expected_rlp = "f901fda0927ca537f06c783a3a2635b8805eef1c8c2124f7444ad4a3389898dd832f2dbea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ba5e000000000000000000000000000000000000a0e97859b065bd8dbbb4519c7cb935024de2484c2b7f881181b4360492f0b06b82a050f738580ed699f0469702c7ccc63ed2e51bc034be9479b7bff4e68dee84accfa029b0562f7140574dd0d50dee8a271b22e1a0a7b78fca58f7c60370d8317ba2a9b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a00008301553482079e42a0000000000000000000000000000000000000000000000000000000000002000088000000000000000082036b"; let expected_hash = @@ -197,6 +209,7 @@ mod test { nonce: Hash64::zero(), base_fee_per_gas: 0x34187b238_u64.into(), withdrawals_root: None, + execution_witness_root: None, }; let expected_hash = Hash256::from_str("6da69709cd5a34079b6604d29cd78fc01dacd7c6268980057ad92a2bede87351") diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 359dcb52239..93a6e9abc22 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -8,7 +8,7 @@ use eth2::types::{SsePayloadAttributes, SsePayloadAttributesV1, SsePayloadAttrib pub use ethers_core::types::Transaction; use ethers_core::utils::rlp::{self, Decodable, Rlp}; use http::deposit_methods::RpcError; -pub use json_structures::{JsonWithdrawal, TransitionConfigurationV1}; +pub use json_structures::{JsonExecutionWitness, JsonWithdrawal, TransitionConfigurationV1}; use pretty_reqwest_error::PrettyReqwestError; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; @@ -17,10 +17,10 @@ use strum::IntoStaticStr; use superstruct::superstruct; pub use types::{ Address, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadHeader, - ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transactions, Uint256, VariableList, - Withdrawal, Withdrawals, + ExecutionPayloadRef, ExecutionWitness, FixedVector, ForkName, Hash256, Transactions, Uint256, + VariableList, Withdrawal, Withdrawals, }; -use types::{ExecutionPayloadCapella, ExecutionPayloadMerge}; +use types::{ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadMerge}; pub mod auth; pub mod http; @@ -137,7 +137,7 @@ pub struct ExecutionBlock { /// Representation of an execution block with enough detail to reconstruct a payload. #[superstruct( - variants(Merge, Capella), + variants(Merge, Capella, Electra), variant_attributes( derive(Clone, Debug, PartialEq, Serialize, Deserialize,), serde(bound = "T: EthSpec", rename_all = "camelCase"), @@ -171,8 +171,10 @@ pub struct ExecutionBlockWithTransactions { #[serde(rename = "hash")] pub block_hash: ExecutionBlockHash, pub transactions: Vec, - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] pub withdrawals: Vec, + #[superstruct(only(Electra))] + pub execution_witness: JsonExecutionWitness, } impl TryFrom> for ExecutionBlockWithTransactions { @@ -226,6 +228,33 @@ impl TryFrom> for ExecutionBlockWithTransactions .collect(), }) } + ExecutionPayload::Electra(block) => { + Self::Electra(ExecutionBlockWithTransactionsElectra { + parent_hash: block.parent_hash, + fee_recipient: block.fee_recipient, + state_root: block.state_root, + receipts_root: block.receipts_root, + logs_bloom: block.logs_bloom, + prev_randao: block.prev_randao, + block_number: block.block_number, + gas_limit: block.gas_limit, + gas_used: block.gas_used, + timestamp: block.timestamp, + extra_data: block.extra_data, + base_fee_per_gas: block.base_fee_per_gas, + block_hash: block.block_hash, + transactions: block + .transactions + .iter() + .map(|tx| Transaction::decode(&Rlp::new(tx))) + .collect::, _>>()?, + withdrawals: Vec::from(block.withdrawals) + .into_iter() + .map(|withdrawal| withdrawal.into()) + .collect(), + execution_witness: block.execution_witness.into(), + }) + } }; Ok(json_payload) } @@ -320,7 +349,7 @@ pub struct ProposeBlindedBlockResponse { } #[superstruct( - variants(Merge, Capella), + variants(Merge, Capella, Electra), variant_attributes(derive(Clone, Debug, PartialEq),), map_into(ExecutionPayload), map_ref_into(ExecutionPayloadRef), @@ -333,6 +362,8 @@ pub struct GetPayloadResponse { pub execution_payload: ExecutionPayloadMerge, #[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))] pub execution_payload: ExecutionPayloadCapella, + #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] + pub execution_payload: ExecutionPayloadElectra, pub block_value: Uint256, } @@ -363,6 +394,10 @@ impl From> for (ExecutionPayload, Uint256) ExecutionPayload::Capella(inner.execution_payload), inner.block_value, ), + GetPayloadResponse::Electra(inner) => ( + ExecutionPayload::Electra(inner.execution_payload), + inner.block_value, + ), } } } @@ -377,6 +412,7 @@ impl GetPayloadResponse { pub struct ExecutionPayloadBodyV1 { pub transactions: Transactions, pub withdrawals: Option>, + pub execution_witness: Option>, } impl ExecutionPayloadBodyV1 { @@ -435,6 +471,40 @@ impl ExecutionPayloadBodyV1 { )) } } + ExecutionPayloadHeader::Electra(header) => { + if let Some(withdrawals) = self.withdrawals { + if let Some(execution_witness) = self.execution_witness { + Ok(ExecutionPayload::Electra(ExecutionPayloadElectra { + parent_hash: header.parent_hash, + fee_recipient: header.fee_recipient, + state_root: header.state_root, + receipts_root: header.receipts_root, + logs_bloom: header.logs_bloom, + prev_randao: header.prev_randao, + block_number: header.block_number, + gas_limit: header.gas_limit, + gas_used: header.gas_used, + timestamp: header.timestamp, + extra_data: header.extra_data, + base_fee_per_gas: header.base_fee_per_gas, + block_hash: header.block_hash, + transactions: self.transactions, + withdrawals, + execution_witness, + })) + } else { + Err(format!( + "block {} is post electra but payload body doesn't have the execution witness", + header.block_hash + )) + } + } else { + Err(format!( + "block {} is post capella but payload body doesn't have withdrawals", + header.block_hash + )) + } + } } } } diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index 0ce03e60294..a423a724cd3 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -741,6 +741,14 @@ impl HttpJsonRpc { ) .await?, ), + ForkName::Electra => ExecutionBlockWithTransactions::Electra( + self.rpc_request( + ETH_GET_BLOCK_BY_HASH, + params, + ETH_GET_BLOCK_BY_HASH_TIMEOUT * self.execution_timeout_multiplier, + ) + .await?, + ), ForkName::Base | ForkName::Altair => { return Err(Error::UnsupportedForkVariant(format!( "called get_block_by_hash_with_txns with fork {:?}", @@ -835,6 +843,16 @@ impl HttpJsonRpc { .await?; Ok(JsonGetPayloadResponse::V2(response).into()) } + ForkName::Electra => { + let response: JsonGetPayloadResponseV4 = self + .rpc_request( + ENGINE_GET_PAYLOAD_V2, + params, + ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier, + ) + .await?; + Ok(JsonGetPayloadResponse::V4(response).into()) + } ForkName::Base | ForkName::Altair => Err(Error::UnsupportedForkVariant(format!( "called get_payload_v2 with {}", fork_name @@ -1662,7 +1680,7 @@ mod test { "extraData":"0x", "baseFeePerGas":"0x7", "blockHash":"0x6359b8381a370e2f54072a5784ddd78b6ed024991558c511d4452eb4f6ac898c", - "transactions":[] + "transactions":[], } })], |client| async move { @@ -1686,7 +1704,7 @@ mod test { extra_data: vec![].into(), base_fee_per_gas: Uint256::from(7), block_hash: ExecutionBlockHash::from_str("0x6359b8381a370e2f54072a5784ddd78b6ed024991558c511d4452eb4f6ac898c").unwrap(), - transactions: vec![].into(), + transactions: vec![].into(), }); assert_eq!(payload, expected); @@ -1733,7 +1751,7 @@ mod test { "extraData":"0x", "baseFeePerGas":"0x7", "blockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858", - "transactions":[] + "transactions":[], }], }) ) diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index d85d294c836..2cb03d99626 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -3,9 +3,17 @@ use serde::{Deserialize, Serialize}; use strum::EnumString; use superstruct::superstruct; use types::{ - EthSpec, ExecutionBlockHash, FixedVector, Transactions, Unsigned, VariableList, Withdrawal, + execution_witness::{ + BanderwagonFieldElement, BanderwagonGroupElement, IpaProof, StateDiff, StateDiffValue, + Stem, StemStateDiff, StemValue, SuffixStateDiff, VerkleProof, + }, + ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadMerge, + ExecutionWitness, +}; +use types::{ + EthSpec, ExecutionBlockHash, FixedVector, Optional, Transactions, Unsigned, VariableList, + Withdrawal, }; -use types::{ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadMerge}; #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -61,7 +69,7 @@ pub struct JsonPayloadIdResponse { } #[superstruct( - variants(V1, V2), + variants(V1, V2, V4), variant_attributes( derive(Debug, PartialEq, Default, Serialize, Deserialize,), serde(bound = "T: EthSpec", rename_all = "camelCase"), @@ -94,8 +102,11 @@ pub struct JsonExecutionPayload { pub block_hash: ExecutionBlockHash, #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, - #[superstruct(only(V2))] + #[superstruct(only(V2, V4))] pub withdrawals: VariableList, + #[superstruct(only(V4))] + #[serde(deserialize_with = "serde_execution_witness")] + pub execution_witness: JsonExecutionWitness, } impl From> for JsonExecutionPayloadV1 { @@ -144,12 +155,40 @@ impl From> for JsonExecutionPayloadV2 } } } +impl From> for JsonExecutionPayloadV4 { + fn from(payload: ExecutionPayloadElectra) -> Self { + JsonExecutionPayloadV4 { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom, + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data, + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions: payload.transactions, + withdrawals: payload + .withdrawals + .into_iter() + .map(Into::into) + .collect::>() + .into(), + execution_witness: payload.execution_witness.into(), + } + } +} impl From> for JsonExecutionPayload { fn from(execution_payload: ExecutionPayload) -> Self { match execution_payload { ExecutionPayload::Merge(payload) => JsonExecutionPayload::V1(payload.into()), ExecutionPayload::Capella(payload) => JsonExecutionPayload::V2(payload.into()), + ExecutionPayload::Electra(payload) => JsonExecutionPayload::V4(payload.into()), } } } @@ -200,18 +239,46 @@ impl From> for ExecutionPayloadCapella } } } +impl From> for ExecutionPayloadElectra { + fn from(payload: JsonExecutionPayloadV4) -> Self { + ExecutionPayloadElectra { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom, + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data, + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions: payload.transactions, + withdrawals: payload + .withdrawals + .into_iter() + .map(Into::into) + .collect::>() + .into(), + execution_witness: payload.execution_witness.into(), + } + } +} impl From> for ExecutionPayload { fn from(json_execution_payload: JsonExecutionPayload) -> Self { match json_execution_payload { JsonExecutionPayload::V1(payload) => ExecutionPayload::Merge(payload.into()), JsonExecutionPayload::V2(payload) => ExecutionPayload::Capella(payload.into()), + JsonExecutionPayload::V4(payload) => ExecutionPayload::Electra(payload.into()), } } } #[superstruct( - variants(V1, V2), + variants(V1, V2, V4), variant_attributes( derive(Debug, PartialEq, Serialize, Deserialize), serde(bound = "T: EthSpec", rename_all = "camelCase") @@ -226,6 +293,8 @@ pub struct JsonGetPayloadResponse { pub execution_payload: JsonExecutionPayloadV1, #[superstruct(only(V2), partial_getter(rename = "execution_payload_v2"))] pub execution_payload: JsonExecutionPayloadV2, + #[superstruct(only(V4), partial_getter(rename = "execution_payload_v4"))] + pub execution_payload: JsonExecutionPayloadV4, #[serde(with = "serde_utils::u256_hex_be")] pub block_value: Uint256, } @@ -245,6 +314,12 @@ impl From> for GetPayloadResponse { block_value: response.block_value, }) } + JsonGetPayloadResponse::V4(response) => { + GetPayloadResponse::Electra(GetPayloadResponseElectra { + execution_payload: response.execution_payload.into(), + block_value: response.block_value, + }) + } } } } @@ -499,6 +574,7 @@ pub struct JsonExecutionPayloadBodyV1 { #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, pub withdrawals: Option>, + pub execution_witness: Option>, } impl From> for ExecutionPayloadBodyV1 { @@ -513,6 +589,7 @@ impl From> for ExecutionPayloadBodyV1< .collect::>(), ) }), + execution_witness: value.execution_witness.map(Into::into), } } } @@ -555,3 +632,202 @@ pub mod serde_logs_bloom { .map_err(|e| serde::de::Error::custom(format!("invalid logs bloom: {:?}", e))) } } + +pub fn serde_execution_witness<'de, D, T>(deserializer: D) -> Result +where + T: Default + Deserialize<'de>, + D: serde::Deserializer<'de>, +{ + let opt = Option::deserialize(deserializer)?; + Ok(opt.unwrap_or_default()) +} + +/// Execution Witness JSON types. +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonSuffixStateDiff { + //#[serde(with = "eth2_serde_utils::quoted_u8")] + suffix: u8, + // `None` means not currently present. + current_value: Optional>, + // `None` means value is not updated. + new_value: Optional>, +} + +impl From> for SuffixStateDiff { + fn from(value: JsonSuffixStateDiff) -> Self { + Self { + suffix: value.suffix, + current_value: value.current_value, + new_value: value.new_value, + } + } +} + +impl From> for JsonSuffixStateDiff { + fn from(value: SuffixStateDiff) -> Self { + Self { + suffix: value.suffix, + current_value: value.current_value, + new_value: value.new_value, + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonStemStateDiff { + stem: Stem, + suffix_diffs: VariableList, E::MaxVerkleWidth>, +} + +impl From> for StemStateDiff { + fn from(value: JsonStemStateDiff) -> Self { + Self { + stem: value.stem, + suffix_diffs: value + .suffix_diffs + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +impl From> for JsonStemStateDiff { + fn from(value: StemStateDiff) -> Self { + Self { + stem: value.stem, + suffix_diffs: value + .suffix_diffs + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonIpaProof { + cl: FixedVector, E::IpaProofDepth>, + cr: FixedVector, E::IpaProofDepth>, + final_evaluation: BanderwagonFieldElement, +} + +impl From> for IpaProof { + fn from(value: JsonIpaProof) -> Self { + Self { + cl: value.cl, + cr: value.cr, + final_evaluation: value.final_evaluation, + } + } +} + +impl From> for JsonIpaProof { + fn from(value: IpaProof) -> Self { + Self { + cl: value.cl, + cr: value.cr, + final_evaluation: value.final_evaluation, + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonVerkleProof { + other_stems: VariableList, E::MaxStems>, + #[serde(with = "ssz_types::serde_utils::hex_var_list")] + depth_extension_present: VariableList, + commitments_by_path: VariableList, E::MaxCommittments>, + d: BanderwagonGroupElement, + ipa_proof: JsonIpaProof, +} + +impl From> for VerkleProof { + fn from(value: JsonVerkleProof) -> Self { + Self { + other_stems: value.other_stems, + depth_extension_present: value.depth_extension_present, + commitments_by_path: value.commitments_by_path, + d: value.d, + ipa_proof: IpaProof::::from(value.ipa_proof), + } + } +} + +impl From> for JsonVerkleProof { + fn from(value: VerkleProof) -> Self { + Self { + other_stems: value.other_stems, + depth_extension_present: value.depth_extension_present, + commitments_by_path: value.commitments_by_path, + d: value.d, + ipa_proof: JsonIpaProof::::from(value.ipa_proof), + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", transparent)] +pub struct JsonStateDiff { + inner: VariableList, E::MaxStems>, +} + +impl From> for StateDiff { + fn from(value: JsonStateDiff) -> Self { + Self { + inner: value + .inner + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +impl From> for JsonStateDiff { + fn from(value: StateDiff) -> Self { + Self { + inner: value + .inner + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonExecutionWitness { + state_diff: JsonStateDiff, + verkle_proof: JsonVerkleProof, + parent_state_root: Hash256, +} + +impl From> for ExecutionWitness { + fn from(value: JsonExecutionWitness) -> Self { + Self { + state_diff: StateDiff::::from(value.state_diff), + verkle_proof: VerkleProof::::from(value.verkle_proof), + parent_state_root: value.parent_state_root, + } + } +} + +impl From> for JsonExecutionWitness { + fn from(value: ExecutionWitness) -> Self { + Self { + state_diff: JsonStateDiff::::from(value.state_diff), + verkle_proof: JsonVerkleProof::::from(value.verkle_proof), + parent_state_root: value.parent_state_root, + } + } +} diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 32e255a166b..0be2c771575 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -41,9 +41,9 @@ use tokio_stream::wrappers::WatchStream; use tree_hash::TreeHash; use types::{AbstractExecPayload, BeaconStateError, ExecPayload}; use types::{ - BlindedPayload, BlockType, ChainSpec, Epoch, ExecutionPayloadCapella, ExecutionPayloadMerge, - ForkVersionedResponse, ProposerPreparationData, PublicKeyBytes, Signature, SignedBeaconBlock, - Slot, + BlindedPayload, BlockType, ChainSpec, Epoch, ExecutionPayloadCapella, ExecutionPayloadElectra, + ExecutionPayloadMerge, ForkVersionedResponse, ProposerPreparationData, PublicKeyBytes, + Signature, SignedBeaconBlock, Slot, }; mod block_hash; @@ -158,13 +158,15 @@ impl> BlockProposalContents Result { Ok(match fork_name { - ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => { - BlockProposalContents::Payload { - payload: Payload::default_at_fork(fork_name)?, - block_value: Uint256::zero(), - _phantom: PhantomData, - } - } + ForkName::Base + | ForkName::Altair + | ForkName::Merge + | ForkName::Capella + | ForkName::Electra => BlockProposalContents::Payload { + payload: Payload::default_at_fork(fork_name)?, + block_value: Uint256::zero(), + _phantom: PhantomData, + }, }) } } @@ -1576,6 +1578,7 @@ impl ExecutionLayer { let payload = match fork { ForkName::Merge => ExecutionPayloadMerge::default().into(), ForkName::Capella => ExecutionPayloadCapella::default().into(), + ForkName::Electra => ExecutionPayloadElectra::default().into(), ForkName::Base | ForkName::Altair => { return Err(Error::InvalidForkForPayload); } @@ -1643,6 +1646,7 @@ impl ExecutionLayer { return match fork { ForkName::Merge => Ok(Some(ExecutionPayloadMerge::default().into())), ForkName::Capella => Ok(Some(ExecutionPayloadCapella::default().into())), + ForkName::Electra => Ok(Some(ExecutionPayloadElectra::default().into())), ForkName::Base | ForkName::Altair => Err(ApiError::UnsupportedForkVariant( format!("called get_payload_by_hash_from_engine with {}", fork), )), @@ -1715,6 +1719,34 @@ impl ExecutionLayer { withdrawals, }) } + ExecutionBlockWithTransactions::Electra(electra_block) => { + let withdrawals = VariableList::new( + electra_block + .withdrawals + .into_iter() + .map(Into::into) + .collect(), + ) + .map_err(ApiError::DeserializeWithdrawals)?; + ExecutionPayload::Electra(ExecutionPayloadElectra { + parent_hash: electra_block.parent_hash, + fee_recipient: electra_block.fee_recipient, + state_root: electra_block.state_root, + receipts_root: electra_block.receipts_root, + logs_bloom: electra_block.logs_bloom, + prev_randao: electra_block.prev_randao, + block_number: electra_block.block_number, + gas_limit: electra_block.gas_limit, + gas_used: electra_block.gas_used, + timestamp: electra_block.timestamp, + extra_data: electra_block.extra_data, + base_fee_per_gas: electra_block.base_fee_per_gas, + block_hash: electra_block.block_hash, + transactions, + withdrawals, + execution_witness: electra_block.execution_witness.into(), + }) + } }; Ok(Some(payload)) diff --git a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs index d76d54bc7dc..c0c8e25112d 100644 --- a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs +++ b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs @@ -13,8 +13,8 @@ use std::collections::HashMap; use tree_hash::TreeHash; use tree_hash_derive::TreeHash; use types::{ - EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadMerge, - ForkName, Hash256, Uint256, + EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, + ExecutionPayloadElectra, ExecutionPayloadMerge, ExecutionWitness, ForkName, Hash256, Uint256, }; const GAS_LIMIT: u64 = 16384; @@ -118,6 +118,7 @@ pub struct ExecutionBlockGenerator { * Post-merge fork triggers */ pub shanghai_time: Option, // withdrawals + pub prague_time: Option, // verkle trees } impl ExecutionBlockGenerator { @@ -126,6 +127,7 @@ impl ExecutionBlockGenerator { terminal_block_number: u64, terminal_block_hash: ExecutionBlockHash, shanghai_time: Option, + prague_time: Option, ) -> Self { let mut gen = Self { head_block: <_>::default(), @@ -139,6 +141,7 @@ impl ExecutionBlockGenerator { next_payload_id: 0, payload_ids: <_>::default(), shanghai_time, + prague_time, }; gen.insert_pow_block(0).unwrap(); @@ -171,9 +174,12 @@ impl ExecutionBlockGenerator { } pub fn get_fork_at_timestamp(&self, timestamp: u64) -> ForkName { - match self.shanghai_time { - Some(fork_time) if timestamp >= fork_time => ForkName::Capella, - _ => ForkName::Merge, + match self.prague_time { + Some(fork_time) if timestamp >= fork_time => ForkName::Electra, + _ => match self.shanghai_time { + Some(fork_time) if timestamp >= fork_time => ForkName::Capella, + _ => ForkName::Merge, + }, } } @@ -526,6 +532,24 @@ impl ExecutionBlockGenerator { transactions: vec![].into(), withdrawals: pa.withdrawals.clone().into(), }), + ForkName::Electra => ExecutionPayload::Electra(ExecutionPayloadElectra { + parent_hash: forkchoice_state.head_block_hash, + fee_recipient: pa.suggested_fee_recipient, + receipts_root: Hash256::repeat_byte(42), + state_root: Hash256::repeat_byte(43), + logs_bloom: vec![0; 256].into(), + prev_randao: pa.prev_randao, + block_number: parent.block_number() + 1, + gas_limit: GAS_LIMIT, + gas_used: GAS_USED, + timestamp: pa.timestamp, + extra_data: "block gen was here".as_bytes().to_vec().into(), + base_fee_per_gas: Uint256::one(), + block_hash: ExecutionBlockHash::zero(), + transactions: vec![].into(), + withdrawals: pa.withdrawals.clone().into(), + execution_witness: ExecutionWitness::default(), + }), _ => unreachable!(), }, }; @@ -618,6 +642,7 @@ mod test { TERMINAL_BLOCK, ExecutionBlockHash::zero(), None, + None, ); for i in 0..=TERMINAL_BLOCK { diff --git a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs index 62cab5ad285..1dc75f566d4 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -99,11 +99,15 @@ pub async fn handle_rpc( get_param::>(params, 0) .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?, ), - ENGINE_NEW_PAYLOAD_V2 => get_param::>(params, 0) - .map(|jep| JsonExecutionPayload::V2(jep)) + ENGINE_NEW_PAYLOAD_V2 => get_param::>(params, 0) + .map(|jep| JsonExecutionPayload::V4(jep)) .or_else(|_| { - get_param::>(params, 0) - .map(|jep| JsonExecutionPayload::V1(jep)) + get_param::>(params, 0) + .map(|jep| JsonExecutionPayload::V2(jep)) + .or_else(|_| { + get_param::>(params, 0) + .map(|jep| JsonExecutionPayload::V1(jep)) + }) }) .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?, // TODO(4844) add that here.. @@ -114,7 +118,7 @@ pub async fn handle_rpc( .execution_block_generator .read() .get_fork_at_timestamp(*request.timestamp()); - // validate method called correctly according to shanghai fork time + // validate method called correctly according to fork time match fork { ForkName::Merge => { if matches!(request, JsonExecutionPayload::V2(_)) { @@ -145,6 +149,32 @@ pub async fn handle_rpc( } } // TODO(4844) add 4844 error checking here + ForkName::Electra => { + if method == ENGINE_NEW_PAYLOAD_V1 { + return Err(( + format!("{} called after Electra fork!", method), + GENERIC_ERROR_CODE, + )); + } + if matches!(request, JsonExecutionPayload::V1(_)) { + return Err(( + format!( + "{} called with `ExecutionPayloadV1` after Electra fork!", + method + ), + GENERIC_ERROR_CODE, + )); + } + if matches!(request, JsonExecutionPayload::V2(_)) { + return Err(( + format!( + "{} called with `ExecutionPayloadV2` after Electra fork!", + method + ), + GENERIC_ERROR_CODE, + )); + } + } _ => unreachable!(), }; @@ -210,6 +240,19 @@ pub async fn handle_rpc( )); } // TODO(4844) add 4844 error checking here + // validate method called correctly according to electra fork time + if ctx + .execution_block_generator + .read() + .get_fork_at_timestamp(response.timestamp()) + == ForkName::Electra + && method == ENGINE_GET_PAYLOAD_V1 + { + return Err(( + format!("{} called after Electra fork!", method), + FORK_REQUEST_MISMATCH_ERROR_CODE, + )); + } match method { ENGINE_GET_PAYLOAD_V1 => { @@ -230,6 +273,13 @@ pub async fn handle_rpc( }) .unwrap() } + JsonExecutionPayload::V4(execution_payload) => { + serde_json::to_value(JsonGetPayloadResponseV4 { + execution_payload, + block_value: DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI.into(), + }) + .unwrap() + } }), _ => unreachable!(), } @@ -260,7 +310,7 @@ pub async fn handle_rpc( .map(|opt| opt.map(JsonPayloadAttributes::V1)) .transpose() } - ForkName::Capella => { + ForkName::Capella | ForkName::Electra => { get_param::>(params, 1) .map(|opt| opt.map(JsonPayloadAttributes::V2)) .transpose() @@ -293,7 +343,7 @@ pub async fn handle_rpc( )); } } - ForkName::Capella => { + ForkName::Capella | ForkName::Electra => { if method == ENGINE_FORKCHOICE_UPDATED_V1 { return Err(( format!("{} called after Capella fork!", method), @@ -408,6 +458,7 @@ pub async fn handle_rpc( .withdrawals() .ok() .map(|withdrawals| VariableList::from(withdrawals.clone())), + execution_witness: block.execution_witness().ok().cloned(), })); } None => response.push(None), diff --git a/beacon_node/execution_layer/src/test_utils/mock_builder.rs b/beacon_node/execution_layer/src/test_utils/mock_builder.rs index 2d3cc27eb1d..f78470eaef9 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -81,6 +81,9 @@ impl BidStuff for BuilderBid> { BlindedPayloadRefMut::Capella(payload) => { payload.execution_payload_header.fee_recipient = fee_recipient; } + BlindedPayloadRefMut::Electra(payload) => { + payload.execution_payload_header.fee_recipient = fee_recipient; + } } } fn set_gas_limit(&mut self, gas_limit: u64) { @@ -91,6 +94,9 @@ impl BidStuff for BuilderBid> { BlindedPayloadRefMut::Capella(payload) => { payload.execution_payload_header.gas_limit = gas_limit; } + BlindedPayloadRefMut::Electra(payload) => { + payload.execution_payload_header.gas_limit = gas_limit; + } } } fn set_value(&mut self, value: Uint256) { @@ -106,6 +112,10 @@ impl BidStuff for BuilderBid> { payload.execution_payload_header.parent_hash = ExecutionBlockHash::from_root(parent_hash); } + BlindedPayloadRefMut::Electra(payload) => { + payload.execution_payload_header.parent_hash = + ExecutionBlockHash::from_root(parent_hash); + } } } fn set_prev_randao(&mut self, prev_randao: Hash256) { @@ -116,6 +126,9 @@ impl BidStuff for BuilderBid> { BlindedPayloadRefMut::Capella(payload) => { payload.execution_payload_header.prev_randao = prev_randao; } + BlindedPayloadRefMut::Electra(payload) => { + payload.execution_payload_header.prev_randao = prev_randao; + } } } fn set_block_number(&mut self, block_number: u64) { @@ -126,6 +139,9 @@ impl BidStuff for BuilderBid> { BlindedPayloadRefMut::Capella(payload) => { payload.execution_payload_header.block_number = block_number; } + BlindedPayloadRefMut::Electra(payload) => { + payload.execution_payload_header.block_number = block_number; + } } } fn set_timestamp(&mut self, timestamp: u64) { @@ -136,6 +152,9 @@ impl BidStuff for BuilderBid> { BlindedPayloadRefMut::Capella(payload) => { payload.execution_payload_header.timestamp = timestamp; } + BlindedPayloadRefMut::Electra(payload) => { + payload.execution_payload_header.timestamp = timestamp; + } } } fn set_withdrawals_root(&mut self, withdrawals_root: Hash256) { @@ -146,6 +165,9 @@ impl BidStuff for BuilderBid> { BlindedPayloadRefMut::Capella(payload) => { payload.execution_payload_header.withdrawals_root = withdrawals_root; } + BlindedPayloadRefMut::Electra(payload) => { + payload.execution_payload_header.withdrawals_root = withdrawals_root; + } } } @@ -297,6 +319,9 @@ pub fn serve( SignedBlindedBeaconBlock::Capella(block) => { block.message.body.execution_payload.tree_hash_root() } + SignedBlindedBeaconBlock::Electra(block) => { + block.message.body.execution_payload.tree_hash_root() + } }; let fork_name = builder.spec.fork_name_at_slot::(slot); @@ -438,6 +463,9 @@ pub fn serve( ForkName::Capella => { PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, Some(vec![])) } + ForkName::Electra => { + PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, Some(vec![])) + } ForkName::Base | ForkName::Altair => { return Err(reject("invalid fork")); } diff --git a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs index 05f6c137e86..9718b59b6dc 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs @@ -29,6 +29,7 @@ impl MockExecutionLayer { DEFAULT_TERMINAL_BLOCK, None, None, + None, Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), spec, ) @@ -39,6 +40,7 @@ impl MockExecutionLayer { executor: TaskExecutor, terminal_block: u64, shanghai_time: Option, + prague_time: Option, builder_threshold: Option, jwt_key: Option, spec: ChainSpec, @@ -53,6 +55,7 @@ impl MockExecutionLayer { terminal_block, spec.terminal_block_hash, shanghai_time, + prague_time, ); let url = SensitiveUrl::parse(&server.url()).unwrap(); diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index f7f82781228..c9b6137cd72 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -59,6 +59,7 @@ pub struct MockExecutionConfig { pub terminal_block: u64, pub terminal_block_hash: ExecutionBlockHash, pub shanghai_time: Option, + pub prague_time: Option, } impl Default for MockExecutionConfig { @@ -70,6 +71,7 @@ impl Default for MockExecutionConfig { terminal_block_hash: ExecutionBlockHash::zero(), server_config: Config::default(), shanghai_time: None, + prague_time: None, } } } @@ -90,6 +92,7 @@ impl MockServer { DEFAULT_TERMINAL_BLOCK, ExecutionBlockHash::zero(), None, // FIXME(capella): should this be the default? + None, // FIXME(electra): should this be the default? ) } @@ -101,6 +104,7 @@ impl MockServer { terminal_block_hash, server_config, shanghai_time, + prague_time, } = config; let last_echo_request = Arc::new(RwLock::new(None)); let preloaded_responses = Arc::new(Mutex::new(vec![])); @@ -109,6 +113,7 @@ impl MockServer { terminal_block, terminal_block_hash, shanghai_time, + prague_time, ); let ctx: Arc> = Arc::new(Context { @@ -168,6 +173,7 @@ impl MockServer { terminal_block: u64, terminal_block_hash: ExecutionBlockHash, shanghai_time: Option, + prague_time: Option, ) -> Self { Self::new_with_config( handle, @@ -178,6 +184,7 @@ impl MockServer { terminal_block, terminal_block_hash, shanghai_time, + prague_time, }, ) } diff --git a/beacon_node/lighthouse_network/src/config.rs b/beacon_node/lighthouse_network/src/config.rs index 42260463961..799ae4b299a 100644 --- a/beacon_node/lighthouse_network/src/config.rs +++ b/beacon_node/lighthouse_network/src/config.rs @@ -468,7 +468,7 @@ pub fn gossipsub_config( ) -> Vec { let topic_bytes = message.topic.as_str().as_bytes(); match fork_context.current_fork() { - ForkName::Altair | ForkName::Merge | ForkName::Capella => { + ForkName::Altair | ForkName::Merge | ForkName::Capella | ForkName::Electra => { let topic_len_bytes = topic_bytes.len().to_le_bytes(); let mut vec = Vec::with_capacity( prefix.len() + topic_len_bytes.len() + topic_bytes.len() + message.data.len(), diff --git a/beacon_node/lighthouse_network/src/peer_manager/mod.rs b/beacon_node/lighthouse_network/src/peer_manager/mod.rs index 03e17ed255b..dfcaeba6305 100644 --- a/beacon_node/lighthouse_network/src/peer_manager/mod.rs +++ b/beacon_node/lighthouse_network/src/peer_manager/mod.rs @@ -1549,7 +1549,7 @@ mod tests { "/ip4/0.0.0.0".parse().unwrap(), None, ); - // Have one peer be on the verge of disconnection. + // Have one peer be on the electra of disconnection. peer_manager.inject_connect_ingoing( &inbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap(), diff --git a/beacon_node/lighthouse_network/src/rpc/codec/base.rs b/beacon_node/lighthouse_network/src/rpc/codec/base.rs index 943d4a3bce2..a3a9e1dcb93 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec/base.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec/base.rs @@ -194,16 +194,19 @@ mod tests { let altair_fork_epoch = Epoch::new(1); let merge_fork_epoch = Epoch::new(2); let capella_fork_epoch = Epoch::new(3); + let electra_fork_epoch = Epoch::new(4); chain_spec.altair_fork_epoch = Some(altair_fork_epoch); chain_spec.bellatrix_fork_epoch = Some(merge_fork_epoch); chain_spec.capella_fork_epoch = Some(capella_fork_epoch); + chain_spec.electra_fork_epoch = Some(electra_fork_epoch); let current_slot = match fork_name { ForkName::Base => Slot::new(0), ForkName::Altair => altair_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Merge => merge_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Capella => capella_fork_epoch.start_slot(Spec::slots_per_epoch()), + ForkName::Electra => electra_fork_epoch.start_slot(Spec::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) } diff --git a/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs b/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs index f1d94da7ece..d009089cb0c 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs @@ -18,7 +18,8 @@ use tokio_util::codec::{Decoder, Encoder}; use types::light_client_bootstrap::LightClientBootstrap; use types::{ EthSpec, ForkContext, ForkName, Hash256, SignedBeaconBlock, SignedBeaconBlockAltair, - SignedBeaconBlockBase, SignedBeaconBlockCapella, SignedBeaconBlockMerge, + SignedBeaconBlockBase, SignedBeaconBlockCapella, SignedBeaconBlockElectra, + SignedBeaconBlockMerge, }; use unsigned_varint::codec::Uvi; @@ -396,6 +397,10 @@ fn context_bytes( return match **ref_box_block { // NOTE: If you are adding another fork type here, be sure to modify the // `fork_context.to_context_bytes()` function to support it as well! + SignedBeaconBlock::Electra { .. } => { + // Electra context being `None` implies that "merge never happened". + fork_context.to_context_bytes(ForkName::Electra) + } SignedBeaconBlock::Capella { .. } => { // Capella context being `None` implies that "merge never happened". fork_context.to_context_bytes(ForkName::Capella) @@ -555,6 +560,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::Electra) => Ok(Some(RPCResponse::BlocksByRange(Arc::new( + SignedBeaconBlock::Electra(SignedBeaconBlockElectra::from_ssz_bytes( + decoded_buffer, + )?), + )))), None => Err(RPCError::ErrorResponse( RPCResponseErrorCode::InvalidRequest, format!( @@ -578,6 +588,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::Electra) => Ok(Some(RPCResponse::BlocksByRoot(Arc::new( + SignedBeaconBlock::Electra(SignedBeaconBlockElectra::from_ssz_bytes( + decoded_buffer, + )?), + )))), None => Err(RPCError::ErrorResponse( RPCResponseErrorCode::InvalidRequest, format!( @@ -630,16 +645,19 @@ mod tests { let altair_fork_epoch = Epoch::new(1); let merge_fork_epoch = Epoch::new(2); let capella_fork_epoch = Epoch::new(3); + let electra_fork_epoch = Epoch::new(4); chain_spec.altair_fork_epoch = Some(altair_fork_epoch); chain_spec.bellatrix_fork_epoch = Some(merge_fork_epoch); chain_spec.capella_fork_epoch = Some(capella_fork_epoch); + chain_spec.electra_fork_epoch = Some(electra_fork_epoch); let current_slot = match fork_name { ForkName::Base => Slot::new(0), ForkName::Altair => altair_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Merge => merge_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Capella => capella_fork_epoch.start_slot(Spec::slots_per_epoch()), + ForkName::Electra => electra_fork_epoch.start_slot(Spec::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) } diff --git a/beacon_node/lighthouse_network/src/rpc/protocol.rs b/beacon_node/lighthouse_network/src/rpc/protocol.rs index f2a39470b94..59d48c98168 100644 --- a/beacon_node/lighthouse_network/src/rpc/protocol.rs +++ b/beacon_node/lighthouse_network/src/rpc/protocol.rs @@ -21,9 +21,9 @@ use tokio_util::{ compat::{Compat, FuturesAsyncReadCompatExt}, }; use types::{ - BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockMerge, - EmptyBlock, EthSpec, ForkContext, ForkName, Hash256, MainnetEthSpec, Signature, - SignedBeaconBlock, + BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockElectra, + BeaconBlockMerge, EmptyBlock, EthSpec, ForkContext, ForkName, Hash256, MainnetEthSpec, + Signature, SignedBeaconBlock, }; lazy_static! { @@ -69,6 +69,13 @@ lazy_static! { .as_ssz_bytes() .len(); + pub static ref SIGNED_BEACON_BLOCK_ELECTRA_MAX_WITHOUT_PAYLOAD: usize = SignedBeaconBlock::::from_block( + BeaconBlock::Electra(BeaconBlockElectra::full(&MainnetEthSpec::default_spec())), + Signature::empty(), + ) + .as_ssz_bytes() + .len(); + /// The `BeaconBlockMerge` block has an `ExecutionPayload` field which has a max size ~16 GiB for future proofing. /// We calculate the value from its fields instead of constructing the block and checking the length. /// Note: This is only the theoretical upper bound. We further bound the max size we receive over the network @@ -81,6 +88,10 @@ lazy_static! { pub static ref SIGNED_BEACON_BLOCK_CAPELLA_MAX: usize = *SIGNED_BEACON_BLOCK_CAPELLA_MAX_WITHOUT_PAYLOAD + types::ExecutionPayload::::max_execution_payload_capella_size() // adding max size of execution payload (~16gb) + + ssz::BYTES_PER_LENGTH_OFFSET; // Adding the additional ssz offset for the `ExecutionPayload` field + // + pub static ref SIGNED_BEACON_BLOCK_ELECTRA_MAX: usize = *SIGNED_BEACON_BLOCK_ELECTRA_MAX_WITHOUT_PAYLOAD + + types::ExecutionPayload::::max_execution_payload_electra_size() // adding max size of execution payload (~16gb) + ssz::BYTES_PER_LENGTH_OFFSET; // Adding the additional ssz offset for the `ExecutionPayload` field pub static ref BLOCKS_BY_ROOT_REQUEST_MIN: usize = @@ -121,6 +132,7 @@ pub fn max_rpc_size(fork_context: &ForkContext, max_chunk_size: usize) -> usize ForkName::Altair | ForkName::Base => max_chunk_size / 10, ForkName::Merge => max_chunk_size, ForkName::Capella => max_chunk_size, + ForkName::Electra => max_chunk_size, } } @@ -145,6 +157,11 @@ pub fn rpc_block_limits_by_fork(current_fork: ForkName) -> RpcLimits { *SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and merge blocks *SIGNED_BEACON_BLOCK_CAPELLA_MAX, // Capella block is larger than base, altair and merge blocks ), + ForkName::Electra => RpcLimits::new( + *SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and merge blocks + *SIGNED_BEACON_BLOCK_ELECTRA_MAX, // Electra block is larger than base, altair, merge and + // capella blocks + ), } } diff --git a/beacon_node/lighthouse_network/src/service/gossipsub_scoring_parameters.rs b/beacon_node/lighthouse_network/src/service/gossipsub_scoring_parameters.rs index b058fc0ff13..d87f63e1cf9 100644 --- a/beacon_node/lighthouse_network/src/service/gossipsub_scoring_parameters.rs +++ b/beacon_node/lighthouse_network/src/service/gossipsub_scoring_parameters.rs @@ -99,7 +99,7 @@ impl PeerScoreSettings { ..Default::default() }; - let target_value = Self::decay_convergence( + let target_value = Self::decay_conelectrance( params.behaviour_penalty_decay, 10.0 / TSpec::slots_per_epoch() as f64, ) - params.behaviour_penalty_threshold; @@ -245,12 +245,12 @@ impl PeerScoreSettings { decay_to_zero.powf(1.0 / ticks) } - fn decay_convergence(decay: f64, rate: f64) -> f64 { + fn decay_conelectrance(decay: f64, rate: f64) -> f64 { rate / (1.0 - decay) } fn threshold(decay: f64, rate: f64) -> f64 { - Self::decay_convergence(decay, rate) * decay + Self::decay_conelectrance(decay, rate) * decay } fn expected_aggregator_count_per_slot( @@ -310,7 +310,7 @@ impl PeerScoreSettings { t_params.first_message_deliveries_decay = self.score_parameter_decay(first_message_decay_time); - t_params.first_message_deliveries_cap = Self::decay_convergence( + t_params.first_message_deliveries_cap = Self::decay_conelectrance( t_params.first_message_deliveries_decay, 2.0 * expected_message_rate / self.mesh_n as f64, ); diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index 06732ac99fd..6d25e4e0070 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -12,8 +12,8 @@ use types::{ Attestation, AttesterSlashing, EthSpec, ForkContext, ForkName, LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing, SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockCapella, - SignedBeaconBlockMerge, SignedBlsToExecutionChange, SignedContributionAndProof, - SignedVoluntaryExit, SubnetId, SyncCommitteeMessage, SyncSubnetId, + SignedBeaconBlockElectra, SignedBeaconBlockMerge, SignedBlsToExecutionChange, + SignedContributionAndProof, SignedVoluntaryExit, SubnetId, SyncCommitteeMessage, SyncSubnetId, }; #[derive(Debug, Clone, PartialEq)] @@ -183,6 +183,10 @@ impl PubsubMessage { SignedBeaconBlockCapella::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, ), + Some(ForkName::Electra) => SignedBeaconBlock::::Electra( + SignedBeaconBlockElectra::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?, + ), None => { return Err(format!( "Unknown gossipsub fork digest: {:?}", diff --git a/beacon_node/lighthouse_network/src/types/topics.rs b/beacon_node/lighthouse_network/src/types/topics.rs index 0e4aefbb5c1..0a479ae2b55 100644 --- a/beacon_node/lighthouse_network/src/types/topics.rs +++ b/beacon_node/lighthouse_network/src/types/topics.rs @@ -46,6 +46,7 @@ pub fn fork_core_topics(fork_name: &ForkName) -> Vec { ForkName::Altair => ALTAIR_CORE_TOPICS.to_vec(), ForkName::Merge => vec![], ForkName::Capella => CAPELLA_CORE_TOPICS.to_vec(), + ForkName::Electra => vec![], } } diff --git a/beacon_node/lighthouse_network/tests/common.rs b/beacon_node/lighthouse_network/tests/common.rs index 7b437fe7a68..ed6c71ef376 100644 --- a/beacon_node/lighthouse_network/tests/common.rs +++ b/beacon_node/lighthouse_network/tests/common.rs @@ -25,16 +25,19 @@ pub fn fork_context(fork_name: ForkName) -> ForkContext { let altair_fork_epoch = Epoch::new(1); let merge_fork_epoch = Epoch::new(2); let capella_fork_epoch = Epoch::new(3); + let electra_fork_epoch = Epoch::new(4); chain_spec.altair_fork_epoch = Some(altair_fork_epoch); chain_spec.bellatrix_fork_epoch = Some(merge_fork_epoch); chain_spec.capella_fork_epoch = Some(capella_fork_epoch); + chain_spec.electra_fork_epoch = Some(electra_fork_epoch); let current_slot = match fork_name { ForkName::Base => Slot::new(0), ForkName::Altair => altair_fork_epoch.start_slot(E::slots_per_epoch()), ForkName::Merge => merge_fork_epoch.start_slot(E::slots_per_epoch()), ForkName::Capella => capella_fork_epoch.start_slot(E::slots_per_epoch()), + ForkName::Electra => electra_fork_epoch.start_slot(E::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) } diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 48b4a8f0d85..e9c297ca96c 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -814,8 +814,9 @@ pub fn get_config( } // Optimistic finalized sync. - client_config.chain.optimistic_finalized_sync = - !cli_args.is_present("disable-optimistic-finalized-sync"); + client_config.chain.optimistic_finalized_sync = false; + // TODO(mac) remove this once optimistic finalized sync is working. + // !cli_args.is_present("disable-optimistic-finalized-sync"); if cli_args.is_present("genesis-backfill") { client_config.chain.genesis_backfill = true; diff --git a/beacon_node/store/src/impls/execution_payload.rs b/beacon_node/store/src/impls/execution_payload.rs index b5753f3797e..d677ad59bb1 100644 --- a/beacon_node/store/src/impls/execution_payload.rs +++ b/beacon_node/store/src/impls/execution_payload.rs @@ -1,6 +1,9 @@ use crate::{DBColumn, Error, StoreItem}; use ssz::{Decode, Encode}; -use types::{EthSpec, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadMerge}; +use types::{ + EthSpec, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadElectra, + ExecutionPayloadMerge, +}; macro_rules! impl_store_item { ($ty_name:ident) => { @@ -21,6 +24,7 @@ macro_rules! impl_store_item { } impl_store_item!(ExecutionPayloadMerge); impl_store_item!(ExecutionPayloadCapella); +impl_store_item!(ExecutionPayloadElectra); /// This fork-agnostic implementation should be only used for writing. /// @@ -36,8 +40,9 @@ impl StoreItem for ExecutionPayload { } fn from_store_bytes(bytes: &[u8]) -> Result { - ExecutionPayloadCapella::from_ssz_bytes(bytes) - .map(Self::Capella) + ExecutionPayloadElectra::from_ssz_bytes(bytes) + .map(Self::Electra) + .or_else(|_| ExecutionPayloadCapella::from_ssz_bytes(bytes).map(Self::Capella)) .or_else(|_| ExecutionPayloadMerge::from_ssz_bytes(bytes).map(Self::Merge)) .map_err(Into::into) } diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index 9f2532d0a75..c54e4080812 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -15,7 +15,7 @@ use types::*; /// /// Utilises lazy-loading from separate storage for its vector fields. #[superstruct( - variants(Base, Altair, Merge, Capella), + variants(Base, Altair, Merge, Capella, Electra), variant_attributes(derive(Debug, PartialEq, Clone, Encode, Decode)) )] #[derive(Debug, PartialEq, Clone, Encode)] @@ -67,9 +67,9 @@ where pub current_epoch_attestations: VariableList, T::MaxPendingAttestations>, // Participation (Altair and later) - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub previous_epoch_participation: VariableList, - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub current_epoch_participation: VariableList, // Finality @@ -79,13 +79,13 @@ where pub finalized_checkpoint: Checkpoint, // Inactivity - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub inactivity_scores: VariableList, // Light-client sync committees - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub next_sync_committee: Arc>, // Execution @@ -99,15 +99,20 @@ where partial_getter(rename = "latest_execution_payload_header_capella") )] pub latest_execution_payload_header: ExecutionPayloadHeaderCapella, + #[superstruct( + only(Electra), + partial_getter(rename = "latest_execution_payload_header_electra") + )] + pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, // Capella - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] pub next_withdrawal_validator_index: u64, #[ssz(skip_serializing, skip_deserializing)] - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] pub historical_summaries: Option>, } @@ -222,6 +227,23 @@ impl PartialBeaconState { ], [historical_summaries] ), + BeaconState::Electra(s) => impl_from_state_forgetful!( + s, + outer, + Electra, + PartialBeaconStateElectra, + [ + previous_epoch_participation, + current_epoch_participation, + current_sync_committee, + next_sync_committee, + inactivity_scores, + latest_execution_payload_header, + next_withdrawal_index, + next_withdrawal_validator_index + ], + [historical_summaries] + ), } } @@ -451,6 +473,22 @@ impl TryInto> for PartialBeaconState { ], [historical_summaries] ), + PartialBeaconState::Electra(inner) => impl_try_into_beacon_state!( + inner, + Electra, + BeaconStateElectra, + [ + previous_epoch_participation, + current_epoch_participation, + current_sync_committee, + next_sync_committee, + inactivity_scores, + latest_execution_payload_header, + next_withdrawal_index, + next_withdrawal_validator_index + ], + [historical_summaries] + ), }; Ok(state) } diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index 822f8817991..7a2fd2d863b 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -967,6 +967,9 @@ impl ForkVersionDeserialize for SsePayloadAttributes { ForkName::Capella => serde_json::from_value(value) .map(Self::V2) .map_err(serde::de::Error::custom), + ForkName::Electra => serde_json::from_value(value) + .map(Self::V2) + .map_err(serde::de::Error::custom), ForkName::Base | ForkName::Altair => Err(serde::de::Error::custom(format!( "SsePayloadAttributes deserialization for {fork_name} not implemented" ))), diff --git a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml index 98984f3b7db..25cce158358 100644 --- a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml @@ -99,4 +99,4 @@ MESSAGE_DOMAIN_INVALID_SNAPPY: 0x00000000 MESSAGE_DOMAIN_VALID_SNAPPY: 0x01000000 ATTESTATION_SUBNET_COUNT: 64 ATTESTATION_SUBNET_EXTRA_BITS: 0 -ATTESTATION_SUBNET_PREFIX_BITS: 6 +ATTESTATION_SUBNET_PREFIX_BITS: 6 \ No newline at end of file diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index ea3a58127b2..ecb2300ce01 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -762,7 +762,8 @@ where (parent_justified, parent_finalized) } else { let justification_and_finalization_state = match block { - BeaconBlockRef::Capella(_) + BeaconBlockRef::Electra(_) + | BeaconBlockRef::Capella(_) | BeaconBlockRef::Merge(_) | BeaconBlockRef::Altair(_) => match progressive_balances_mode { ProgressiveBalancesMode::Disabled => { diff --git a/consensus/state_processing/src/common/slash_validator.rs b/consensus/state_processing/src/common/slash_validator.rs index d54da43a04b..39dd249e583 100644 --- a/consensus/state_processing/src/common/slash_validator.rs +++ b/consensus/state_processing/src/common/slash_validator.rs @@ -53,11 +53,12 @@ pub fn slash_validator( validator_effective_balance.safe_div(spec.whistleblower_reward_quotient)?; let proposer_reward = match state { BeaconState::Base(_) => whistleblower_reward.safe_div(spec.proposer_reward_quotient)?, - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { - whistleblower_reward - .safe_mul(PROPOSER_WEIGHT)? - .safe_div(WEIGHT_DENOMINATOR)? - } + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => whistleblower_reward + .safe_mul(PROPOSER_WEIGHT)? + .safe_div(WEIGHT_DENOMINATOR)?, }; // Ensure the whistleblower index is in the validator registry. diff --git a/consensus/state_processing/src/genesis.rs b/consensus/state_processing/src/genesis.rs index ebbc8f9f31e..a4f4ea226a6 100644 --- a/consensus/state_processing/src/genesis.rs +++ b/consensus/state_processing/src/genesis.rs @@ -2,7 +2,9 @@ use super::per_block_processing::{ errors::BlockProcessingError, process_operations::process_deposit, }; use crate::common::DepositDataTree; -use crate::upgrade::{upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella}; +use crate::upgrade::{ + upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_electra, +}; use safe_arith::{ArithError, SafeArith}; use tree_hash::TreeHash; use types::DEPOSIT_TREE_DEPTH; @@ -91,6 +93,23 @@ pub fn initialize_beacon_state_from_eth1( } } + // Upgrade to electra if configured from genesis. + if spec + .electra_fork_epoch + .map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch()) + { + upgrade_to_electra(&mut state, spec)?; + + // Remove intermediate Bellatrix fork from `state.fork`. + state.fork_mut().previous_version = spec.electra_fork_version; + + // Override latest execution payload header. + // See https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#testing + if let Some(ExecutionPayloadHeader::Electra(ref header)) = execution_payload_header { + *state.latest_execution_payload_header_electra_mut()? = header.clone(); + } + } + // Now that we have our validators, initialize the caches (including the committees) state.build_caches(spec)?; diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index b8b76a499d3..9a033724c91 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -414,6 +414,12 @@ pub fn process_execution_payload>( _ => return Err(BlockProcessingError::IncorrectStateType), } } + ExecutionPayloadHeaderRefMut::Electra(header_mut) => { + match payload.to_execution_payload_header() { + ExecutionPayloadHeader::Electra(header) => *header_mut = header, + _ => return Err(BlockProcessingError::IncorrectStateType), + } + } } Ok(()) @@ -526,7 +532,7 @@ pub fn process_withdrawals>( ) -> Result<(), BlockProcessingError> { match state { BeaconState::Merge(_) => Ok(()), - BeaconState::Capella(_) => { + BeaconState::Capella(_) | BeaconState::Electra(_) => { let expected_withdrawals = get_expected_withdrawals(state, spec)?; let expected_root = expected_withdrawals.tree_hash_root(); let withdrawals_root = payload.withdrawals_root()?; diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index 1dbcb7fb8fe..195846cbef2 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -267,7 +267,8 @@ pub fn process_attestations>( } BeaconBlockBodyRef::Altair(_) | BeaconBlockBodyRef::Merge(_) - | BeaconBlockBodyRef::Capella(_) => { + | BeaconBlockBodyRef::Capella(_) + | BeaconBlockBodyRef::Electra(_) => { altair::process_attestations( state, block_body.attestations(), diff --git a/consensus/state_processing/src/per_epoch_processing.rs b/consensus/state_processing/src/per_epoch_processing.rs index 6350685f822..c8ebd7ee72a 100644 --- a/consensus/state_processing/src/per_epoch_processing.rs +++ b/consensus/state_processing/src/per_epoch_processing.rs @@ -40,7 +40,7 @@ pub fn process_epoch( match state { BeaconState::Base(_) => base::process_epoch(state, spec), BeaconState::Altair(_) | BeaconState::Merge(_) => altair::process_epoch(state, spec), - BeaconState::Capella(_) => capella::process_epoch(state, spec), + BeaconState::Capella(_) | BeaconState::Electra(_) => capella::process_epoch(state, spec), } } diff --git a/consensus/state_processing/src/per_slot_processing.rs b/consensus/state_processing/src/per_slot_processing.rs index e16fb4a7b11..d5c8d4cfada 100644 --- a/consensus/state_processing/src/per_slot_processing.rs +++ b/consensus/state_processing/src/per_slot_processing.rs @@ -1,4 +1,6 @@ -use crate::upgrade::{upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella}; +use crate::upgrade::{ + upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_electra, +}; use crate::{per_epoch_processing::EpochProcessingSummary, *}; use safe_arith::{ArithError, SafeArith}; use types::*; @@ -59,6 +61,10 @@ pub fn per_slot_processing( if spec.capella_fork_epoch == Some(state.current_epoch()) { upgrade_to_capella(state, spec)?; } + // Electra. + if spec.electra_fork_epoch == Some(state.current_epoch()) { + upgrade_to_electra(state, spec)?; + } } Ok(summary) diff --git a/consensus/state_processing/src/upgrade.rs b/consensus/state_processing/src/upgrade.rs index a57d5923f86..58f8ef28033 100644 --- a/consensus/state_processing/src/upgrade.rs +++ b/consensus/state_processing/src/upgrade.rs @@ -1,7 +1,9 @@ pub mod altair; pub mod capella; +pub mod electra; pub mod merge; pub use altair::upgrade_to_altair; pub use capella::upgrade_to_capella; +pub use electra::upgrade_to_electra; pub use merge::upgrade_to_bellatrix; diff --git a/consensus/state_processing/src/upgrade/electra.rs b/consensus/state_processing/src/upgrade/electra.rs new file mode 100644 index 00000000000..20f66e2f6e9 --- /dev/null +++ b/consensus/state_processing/src/upgrade/electra.rs @@ -0,0 +1,74 @@ +use std::mem; +use types::{BeaconState, BeaconStateElectra, BeaconStateError as Error, ChainSpec, EthSpec, Fork}; + +/// Transform a `Capella` state into an `Electra` state. +pub fn upgrade_to_electra( + pre_state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { + let epoch = pre_state.current_epoch(); + let pre = pre_state.as_capella_mut()?; + + // Where possible, use something like `mem::take` to move fields from behind the &mut + // reference. For other fields that don't have a good default value, use `clone`. + // + // Fixed size vectors get cloned because replacing them would require the same size + // allocation as cloning. + let post = BeaconState::Electra(BeaconStateElectra { + // Versioning + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork: Fork { + previous_version: pre.fork.current_version, + current_version: spec.electra_fork_version, + epoch, + }, + // History + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: mem::take(&mut pre.historical_roots), + // Eth1 + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: mem::take(&mut pre.eth1_data_votes), + eth1_deposit_index: pre.eth1_deposit_index, + // Registry + validators: mem::take(&mut pre.validators), + balances: mem::take(&mut pre.balances), + // Randomness + randao_mixes: pre.randao_mixes.clone(), + // Slashings + slashings: pre.slashings.clone(), + // `Participation + previous_epoch_participation: mem::take(&mut pre.previous_epoch_participation), + current_epoch_participation: mem::take(&mut pre.current_epoch_participation), + // Finality + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + // Inactivity + inactivity_scores: mem::take(&mut pre.inactivity_scores), + // Sync committees + current_sync_committee: pre.current_sync_committee.clone(), + next_sync_committee: pre.next_sync_committee.clone(), + // Execution + latest_execution_payload_header: pre.latest_execution_payload_header.upgrade_to_electra(), + // Capella + next_withdrawal_index: pre.next_withdrawal_index, + next_withdrawal_validator_index: pre.next_withdrawal_validator_index, + historical_summaries: pre.historical_summaries.clone(), + // Caches + total_active_balance: pre.total_active_balance, + progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache), + committee_caches: mem::take(&mut pre.committee_caches), + pubkey_cache: mem::take(&mut pre.pubkey_cache), + exit_cache: mem::take(&mut pre.exit_cache), + tree_hash_cache: mem::take(&mut pre.tree_hash_cache), + }); + + *pre_state = post; + + Ok(()) +} diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 1b40fe76d4d..dd480ac1de4 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -17,7 +17,7 @@ use tree_hash_derive::TreeHash; /// A block of the `BeaconChain`. #[superstruct( - variants(Base, Altair, Merge, Capella), + variants(Base, Altair, Merge, Capella, Electra), variant_attributes( derive( Debug, @@ -72,6 +72,8 @@ pub struct BeaconBlock = FullPayload pub body: BeaconBlockBodyMerge, #[superstruct(only(Capella), partial_getter(rename = "body_capella"))] pub body: BeaconBlockBodyCapella, + #[superstruct(only(Electra), partial_getter(rename = "body_electra"))] + pub body: BeaconBlockBodyElectra, } pub type BlindedBeaconBlock = BeaconBlock>; @@ -124,8 +126,9 @@ impl> BeaconBlock { /// Usually it's better to prefer `from_ssz_bytes` which will decode the correct variant based /// on the fork slot. pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result { - BeaconBlockCapella::from_ssz_bytes(bytes) - .map(BeaconBlock::Capella) + BeaconBlockElectra::from_ssz_bytes(bytes) + .map(BeaconBlock::Electra) + .or_else(|_| BeaconBlockCapella::from_ssz_bytes(bytes).map(BeaconBlock::Capella)) .or_else(|_| BeaconBlockMerge::from_ssz_bytes(bytes).map(BeaconBlock::Merge)) .or_else(|_| BeaconBlockAltair::from_ssz_bytes(bytes).map(BeaconBlock::Altair)) .or_else(|_| BeaconBlockBase::from_ssz_bytes(bytes).map(BeaconBlock::Base)) @@ -203,6 +206,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload> BeaconBlockRef<'a, T, Payl BeaconBlockRef::Altair { .. } => ForkName::Altair, BeaconBlockRef::Merge { .. } => ForkName::Merge, BeaconBlockRef::Capella { .. } => ForkName::Capella, + BeaconBlockRef::Electra { .. } => ForkName::Electra, }; if fork_at_slot == object_fork { @@ -556,6 +560,81 @@ impl> EmptyBlock for BeaconBlockCape } } +impl> BeaconBlockElectra { + /// Return a Electra block where the block has maximum size. + pub fn full(spec: &ChainSpec) -> Self { + let base_block: BeaconBlockBase<_, Payload> = BeaconBlockBase::full(spec); + let bls_to_execution_changes = vec![ + SignedBlsToExecutionChange { + message: BlsToExecutionChange { + validator_index: 0, + from_bls_pubkey: PublicKeyBytes::empty(), + to_execution_address: Address::zero(), + }, + signature: Signature::empty() + }; + T::max_bls_to_execution_changes() + ] + .into(); + let sync_aggregate = SyncAggregate { + sync_committee_signature: AggregateSignature::empty(), + sync_committee_bits: BitVector::default(), + }; + BeaconBlockElectra { + slot: spec.genesis_slot, + proposer_index: 0, + parent_root: Hash256::zero(), + state_root: Hash256::zero(), + body: BeaconBlockBodyElectra { + proposer_slashings: base_block.body.proposer_slashings, + attester_slashings: base_block.body.attester_slashings, + attestations: base_block.body.attestations, + deposits: base_block.body.deposits, + voluntary_exits: base_block.body.voluntary_exits, + bls_to_execution_changes, + sync_aggregate, + randao_reveal: Signature::empty(), + eth1_data: Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + deposit_count: 0, + }, + graffiti: Graffiti::default(), + execution_payload: Payload::Electra::default(), + }, + } + } +} + +impl> EmptyBlock for BeaconBlockElectra { + /// Returns an empty Electra block to be used during genesis. + fn empty(spec: &ChainSpec) -> Self { + BeaconBlockElectra { + slot: spec.genesis_slot, + proposer_index: 0, + parent_root: Hash256::zero(), + state_root: Hash256::zero(), + body: BeaconBlockBodyElectra { + randao_reveal: Signature::empty(), + eth1_data: Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + deposit_count: 0, + }, + graffiti: Graffiti::default(), + proposer_slashings: VariableList::empty(), + attester_slashings: VariableList::empty(), + attestations: VariableList::empty(), + deposits: VariableList::empty(), + voluntary_exits: VariableList::empty(), + sync_aggregate: SyncAggregate::empty(), + execution_payload: Payload::Electra::default(), + bls_to_execution_changes: VariableList::empty(), + }, + } + } +} + // We can convert pre-Bellatrix blocks without payloads into blocks "with" payloads. impl From>> for BeaconBlockBase> @@ -635,6 +714,7 @@ impl_from!(BeaconBlockBase, >, >, |body: impl_from!(BeaconBlockAltair, >, >, |body: BeaconBlockBodyAltair<_, _>| body.into()); impl_from!(BeaconBlockMerge, >, >, |body: BeaconBlockBodyMerge<_, _>| body.into()); impl_from!(BeaconBlockCapella, >, >, |body: BeaconBlockBodyCapella<_, _>| body.into()); +impl_from!(BeaconBlockElectra, >, >, |body: BeaconBlockBodyElectra<_, _>| body.into()); // We can clone blocks with payloads to blocks without payloads, without cloning the payload. macro_rules! impl_clone_as_blinded { @@ -666,6 +746,7 @@ impl_clone_as_blinded!(BeaconBlockBase, >, >, >); impl_clone_as_blinded!(BeaconBlockMerge, >, >); impl_clone_as_blinded!(BeaconBlockCapella, >, >); +impl_clone_as_blinded!(BeaconBlockElectra, >, >); // A reference to a full beacon block can be cloned into a blinded beacon block, without cloning the // execution payload. @@ -781,6 +862,25 @@ mod tests { }); } + #[test] + fn roundtrip_electra_block() { + let rng = &mut XorShiftRng::from_seed([42; 16]); + let spec = &ForkName::Electra.make_genesis_spec(MainnetEthSpec::default_spec()); + + let inner_block = BeaconBlockElectra { + slot: Slot::random_for_test(rng), + proposer_index: u64::random_for_test(rng), + parent_root: Hash256::random_for_test(rng), + state_root: Hash256::random_for_test(rng), + body: BeaconBlockBodyElectra::random_for_test(rng), + }; + let block = BeaconBlock::Electra(inner_block.clone()); + + test_ssz_tree_hash_pair_with(&block, &inner_block, |bytes| { + BeaconBlock::from_ssz_bytes(bytes, spec) + }); + } + #[test] fn decode_base_and_altair() { type E = MainnetEthSpec; @@ -796,9 +896,12 @@ mod tests { let altair_slot = altair_epoch.start_slot(E::slots_per_epoch()); let capella_epoch = altair_fork_epoch + 1; let capella_slot = capella_epoch.start_slot(E::slots_per_epoch()); + let electra_epoch = capella_epoch + 1; + let electra_slot = electra_epoch.start_slot(E::slots_per_epoch()); spec.altair_fork_epoch = Some(altair_epoch); spec.capella_fork_epoch = Some(capella_epoch); + spec.electra_fork_epoch = Some(electra_epoch); // BeaconBlockBase { @@ -865,5 +968,27 @@ mod tests { BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec) .expect_err("bad capella block cannot be decoded"); } + + // BeaconBlockElectra + { + let good_block = BeaconBlock::Electra(BeaconBlockElectra { + slot: electra_slot, + ..<_>::random_for_test(rng) + }); + // It's invalid to have an Electra block with a epoch lower than the fork epoch. + let bad_block = { + let mut bad = good_block.clone(); + *bad.slot_mut() = electra_slot; + bad + }; + + assert_eq!( + BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec) + .expect("good electra block can be decoded"), + good_block + ); + BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec) + .expect_err("bad electra block cannot be decoded"); + } } } diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index dce1be742ff..1cfa05f9a0e 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -13,7 +13,7 @@ use tree_hash_derive::TreeHash; /// /// This *superstruct* abstracts over the hard-fork. #[superstruct( - variants(Base, Altair, Merge, Capella), + variants(Base, Altair, Merge, Capella, Electra), variant_attributes( derive( Debug, @@ -51,7 +51,7 @@ pub struct BeaconBlockBody = FullPay pub attestations: VariableList, T::MaxAttestations>, pub deposits: VariableList, pub voluntary_exits: VariableList, - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub sync_aggregate: SyncAggregate, // We flatten the execution payload so that serde can use the name of the inner type, // either `execution_payload` for full payloads, or `execution_payload_header` for blinded @@ -62,7 +62,10 @@ pub struct BeaconBlockBody = FullPay #[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))] #[serde(flatten)] pub execution_payload: Payload::Capella, - #[superstruct(only(Capella))] + #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] + #[serde(flatten)] + pub execution_payload: Payload::Electra, + #[superstruct(only(Capella, Electra))] pub bls_to_execution_changes: VariableList, #[superstruct(only(Base, Altair))] @@ -85,6 +88,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, T, Self::Base(_) | Self::Altair(_) => Err(Error::IncorrectStateVariant), Self::Merge(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Capella(body) => Ok(Payload::Ref::from(&body.execution_payload)), + Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)), } } } @@ -97,6 +101,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, T, BeaconBlockBodyRef::Altair { .. } => ForkName::Altair, BeaconBlockBodyRef::Merge { .. } => ForkName::Merge, BeaconBlockBodyRef::Capella { .. } => ForkName::Capella, + BeaconBlockBodyRef::Electra { .. } => ForkName::Electra, } } } @@ -321,6 +326,48 @@ impl From>> } } +impl From>> + for ( + BeaconBlockBodyElectra>, + Option>, + ) +{ + fn from(body: BeaconBlockBodyElectra>) -> Self { + let BeaconBlockBodyElectra { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadElectra { execution_payload }, + bls_to_execution_changes, + } = body; + + ( + BeaconBlockBodyElectra { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: BlindedPayloadElectra { + execution_payload_header: From::from(&execution_payload), + }, + bls_to_execution_changes, + }, + Some(execution_payload), + ) + } +} + // We can clone a full block into a blinded block, without cloning the payload. impl BeaconBlockBodyBase> { pub fn clone_as_blinded(&self) -> BeaconBlockBodyBase> { @@ -402,6 +449,40 @@ impl BeaconBlockBodyCapella> { } } +impl BeaconBlockBodyElectra> { + pub fn clone_as_blinded(&self) -> BeaconBlockBodyElectra> { + let BeaconBlockBodyElectra { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadElectra { execution_payload }, + bls_to_execution_changes, + } = self; + + BeaconBlockBodyElectra { + randao_reveal: randao_reveal.clone(), + eth1_data: eth1_data.clone(), + graffiti: *graffiti, + proposer_slashings: proposer_slashings.clone(), + attester_slashings: attester_slashings.clone(), + attestations: attestations.clone(), + deposits: deposits.clone(), + voluntary_exits: voluntary_exits.clone(), + sync_aggregate: sync_aggregate.clone(), + execution_payload: BlindedPayloadElectra { + execution_payload_header: execution_payload.into(), + }, + bls_to_execution_changes: bls_to_execution_changes.clone(), + } + } +} + impl From>> for ( BeaconBlockBody>, diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 6a205e307ad..aadfe8445e6 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -183,7 +183,7 @@ impl From for Hash256 { /// The state of the `BeaconChain` at some slot. #[superstruct( - variants(Base, Altair, Merge, Capella), + variants(Base, Altair, Merge, Capella, Electra), variant_attributes( derive( Derivative, @@ -263,9 +263,9 @@ where pub current_epoch_attestations: VariableList, T::MaxPendingAttestations>, // Participation (Altair and later) - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub previous_epoch_participation: VariableList, - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub current_epoch_participation: VariableList, // Finality @@ -280,13 +280,13 @@ where // Inactivity #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub inactivity_scores: VariableList, // Light-client sync committees - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Merge, Capella))] + #[superstruct(only(Altair, Merge, Capella, Electra))] pub next_sync_committee: Arc>, // Execution @@ -300,16 +300,21 @@ where partial_getter(rename = "latest_execution_payload_header_capella") )] pub latest_execution_payload_header: ExecutionPayloadHeaderCapella, + #[superstruct( + only(Electra), + partial_getter(rename = "latest_execution_payload_header_electra") + )] + pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, // Capella - #[superstruct(only(Capella), partial_getter(copy))] + #[superstruct(only(Capella, Electra), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub next_withdrawal_index: u64, - #[superstruct(only(Capella), partial_getter(copy))] + #[superstruct(only(Capella, Electra), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub next_withdrawal_validator_index: u64, // Deep history valid from Capella onwards. - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] pub historical_summaries: VariableList, // Caching (not in the spec) @@ -429,6 +434,7 @@ impl BeaconState { BeaconState::Altair { .. } => ForkName::Altair, BeaconState::Merge { .. } => ForkName::Merge, BeaconState::Capella { .. } => ForkName::Capella, + BeaconState::Electra { .. } => ForkName::Electra, }; if fork_at_slot == object_fork { @@ -728,6 +734,9 @@ impl BeaconState { BeaconState::Capella(state) => Ok(ExecutionPayloadHeaderRef::Capella( &state.latest_execution_payload_header, )), + BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRef::Electra( + &state.latest_execution_payload_header, + )), } } @@ -742,6 +751,9 @@ impl BeaconState { BeaconState::Capella(state) => Ok(ExecutionPayloadHeaderRefMut::Capella( &mut state.latest_execution_payload_header, )), + BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRefMut::Electra( + &mut state.latest_execution_payload_header, + )), } } @@ -1188,6 +1200,11 @@ impl BeaconState { &mut state.balances, &mut state.progressive_balances_cache, ), + BeaconState::Electra(state) => ( + &mut state.validators, + &mut state.balances, + &mut state.progressive_balances_cache, + ), } } @@ -1385,6 +1402,7 @@ impl BeaconState { BeaconState::Altair(state) => Ok(&mut state.current_epoch_participation), BeaconState::Merge(state) => Ok(&mut state.current_epoch_participation), BeaconState::Capella(state) => Ok(&mut state.current_epoch_participation), + BeaconState::Electra(state) => Ok(&mut state.current_epoch_participation), } } else if epoch == self.previous_epoch() { match self { @@ -1392,6 +1410,7 @@ impl BeaconState { BeaconState::Altair(state) => Ok(&mut state.previous_epoch_participation), BeaconState::Merge(state) => Ok(&mut state.previous_epoch_participation), BeaconState::Capella(state) => Ok(&mut state.previous_epoch_participation), + BeaconState::Electra(state) => Ok(&mut state.previous_epoch_participation), } } else { Err(BeaconStateError::EpochOutOfBounds) @@ -1703,6 +1722,7 @@ impl BeaconState { BeaconState::Altair(inner) => BeaconState::Altair(inner.clone()), BeaconState::Merge(inner) => BeaconState::Merge(inner.clone()), BeaconState::Capella(inner) => BeaconState::Capella(inner.clone()), + BeaconState::Electra(inner) => BeaconState::Electra(inner.clone()), }; if config.committee_caches { *res.committee_caches_mut() = self.committee_caches().clone(); @@ -1879,7 +1899,7 @@ impl CompareFields for BeaconState { (BeaconState::Base(x), BeaconState::Base(y)) => x.compare_fields(y), (BeaconState::Altair(x), BeaconState::Altair(y)) => x.compare_fields(y), (BeaconState::Merge(x), BeaconState::Merge(y)) => x.compare_fields(y), - (BeaconState::Capella(x), BeaconState::Capella(y)) => x.compare_fields(y), + (BeaconState::Electra(x), BeaconState::Electra(y)) => x.compare_fields(y), _ => panic!("compare_fields: mismatched state variants",), } } diff --git a/consensus/types/src/beacon_state/progressive_balances_cache.rs b/consensus/types/src/beacon_state/progressive_balances_cache.rs index 9f5c223d573..0428c05b94d 100644 --- a/consensus/types/src/beacon_state/progressive_balances_cache.rs +++ b/consensus/types/src/beacon_state/progressive_balances_cache.rs @@ -179,6 +179,9 @@ impl ProgressiveBalancesMode { pub fn is_progressive_balances_enabled(state: &BeaconState) -> bool { match state { BeaconState::Base(_) => false, - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => true, + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => true, } } diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index a13d3116d8b..c3d9cf190c5 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -160,6 +160,13 @@ pub struct ChainSpec { pub capella_fork_epoch: Option, pub max_validators_per_withdrawals_sweep: u64, + /* + * Electra hard fork params + */ + pub electra_fork_version: [u8; 4], + /// The Electra fork epoch is optional, with `None` representing "Electra never happens". + pub electra_fork_epoch: Option, + /* * Networking */ @@ -254,13 +261,16 @@ impl ChainSpec { /// Returns the name of the fork which is active at `epoch`. pub fn fork_name_at_epoch(&self, epoch: Epoch) -> ForkName { - match self.capella_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Capella, - _ => match self.bellatrix_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Merge, - _ => match self.altair_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair, - _ => ForkName::Base, + match self.electra_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Electra, + _ => match self.capella_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Capella, + _ => match self.bellatrix_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Merge, + _ => match self.altair_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair, + _ => ForkName::Base, + }, }, }, } @@ -273,6 +283,7 @@ impl ChainSpec { ForkName::Altair => self.altair_fork_version, ForkName::Merge => self.bellatrix_fork_version, ForkName::Capella => self.capella_fork_version, + ForkName::Electra => self.electra_fork_version, } } @@ -283,6 +294,7 @@ impl ChainSpec { ForkName::Altair => self.altair_fork_epoch, ForkName::Merge => self.bellatrix_fork_epoch, ForkName::Capella => self.capella_fork_epoch, + ForkName::Electra => self.electra_fork_epoch, } } @@ -293,6 +305,7 @@ impl ChainSpec { BeaconState::Altair(_) => self.inactivity_penalty_quotient_altair, BeaconState::Merge(_) => self.inactivity_penalty_quotient_bellatrix, BeaconState::Capella(_) => self.inactivity_penalty_quotient_bellatrix, + BeaconState::Electra(_) => self.inactivity_penalty_quotient_bellatrix, } } @@ -306,6 +319,7 @@ impl ChainSpec { BeaconState::Altair(_) => self.proportional_slashing_multiplier_altair, BeaconState::Merge(_) => self.proportional_slashing_multiplier_bellatrix, BeaconState::Capella(_) => self.proportional_slashing_multiplier_bellatrix, + BeaconState::Electra(_) => self.proportional_slashing_multiplier_bellatrix, } } @@ -319,6 +333,7 @@ impl ChainSpec { BeaconState::Altair(_) => self.min_slashing_penalty_quotient_altair, BeaconState::Merge(_) => self.min_slashing_penalty_quotient_bellatrix, BeaconState::Capella(_) => self.min_slashing_penalty_quotient_bellatrix, + BeaconState::Electra(_) => self.min_slashing_penalty_quotient_bellatrix, } } @@ -621,6 +636,12 @@ impl ChainSpec { capella_fork_epoch: Some(Epoch::new(194048)), max_validators_per_withdrawals_sweep: 16384, + /* + * Electra hard fork params + */ + electra_fork_version: [0x04, 00, 00, 00], + electra_fork_epoch: Some(Epoch::new(194049)), + /* * Network specific */ @@ -693,6 +714,9 @@ impl ChainSpec { capella_fork_version: [0x03, 0x00, 0x00, 0x01], capella_fork_epoch: None, max_validators_per_withdrawals_sweep: 16, + // Electra + electra_fork_version: [0x04, 0x00, 0x00, 0x01], + electra_fork_epoch: None, // Other network_id: 2, // lighthouse testnet network id deposit_chain_id: 5, @@ -853,6 +877,12 @@ impl ChainSpec { capella_fork_epoch: Some(Epoch::new(648704)), max_validators_per_withdrawals_sweep: 8192, + /* + * Electra hard fork params + */ + electra_fork_version: [0x04, 0x00, 0x00, 0x64], + electra_fork_epoch: Some(Epoch::new(648705)), + /* * Network specific */ @@ -950,6 +980,14 @@ pub struct Config { #[serde(deserialize_with = "deserialize_fork_epoch")] pub capella_fork_epoch: Option>, + #[serde(default = "default_electra_fork_version")] + #[serde(with = "serde_utils::bytes_4_hex")] + electra_fork_version: [u8; 4], + #[serde(default)] + #[serde(serialize_with = "serialize_fork_epoch")] + #[serde(deserialize_with = "deserialize_fork_epoch")] + pub electra_fork_epoch: Option>, + #[serde(with = "serde_utils::quoted_u64")] seconds_per_slot: u64, #[serde(with = "serde_utils::quoted_u64")] @@ -1023,6 +1061,11 @@ fn default_capella_fork_version() -> [u8; 4] { [0xff, 0xff, 0xff, 0xff] } +fn default_electra_fork_version() -> [u8; 4] { + // TODO: determine if the bellatrix example should be copied like this + [0xff, 0xff, 0xff, 0xff] +} + /// Placeholder value: 2^256-2^10 (115792089237316195423570985008687907853269984665640564039457584007913129638912). /// /// Taken from https://github.com/ethereum/consensus-specs/blob/d5e4828aecafaf1c57ef67a5f23c4ae7b08c5137/configs/mainnet.yaml#L15-L16 @@ -1163,6 +1206,10 @@ impl Config { capella_fork_epoch: spec .capella_fork_epoch .map(|epoch| MaybeQuoted { value: epoch }), + electra_fork_version: spec.electra_fork_version, + electra_fork_epoch: spec + .electra_fork_epoch + .map(|epoch| MaybeQuoted { value: epoch }), seconds_per_slot: spec.seconds_per_slot, seconds_per_eth1_block: spec.seconds_per_eth1_block, @@ -1221,6 +1268,8 @@ impl Config { bellatrix_fork_version, capella_fork_epoch, capella_fork_version, + electra_fork_epoch, + electra_fork_version, seconds_per_slot, seconds_per_eth1_block, min_validator_withdrawability_delay, @@ -1263,6 +1312,8 @@ impl Config { bellatrix_fork_version, capella_fork_epoch: capella_fork_epoch.map(|q| q.value), capella_fork_version, + electra_fork_epoch: electra_fork_epoch.map(|q| q.value), + electra_fork_version, seconds_per_slot, seconds_per_eth1_block, min_validator_withdrawability_delay, diff --git a/consensus/types/src/config_and_preset.rs b/consensus/types/src/config_and_preset.rs index 01f86d3480a..54d67f7e61d 100644 --- a/consensus/types/src/config_and_preset.rs +++ b/consensus/types/src/config_and_preset.rs @@ -1,6 +1,6 @@ use crate::{ consts::altair, AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ChainSpec, Config, - EthSpec, ForkName, + ElectraPreset, EthSpec, ForkName, }; use maplit::hashmap; use serde_derive::{Deserialize, Serialize}; @@ -12,7 +12,7 @@ use superstruct::superstruct; /// /// Mostly useful for the API. #[superstruct( - variants(Bellatrix, Capella), + variants(Bellatrix, Capella, Electra), variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone)) )] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -27,9 +27,12 @@ pub struct ConfigAndPreset { pub altair_preset: AltairPreset, #[serde(flatten)] pub bellatrix_preset: BellatrixPreset, - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] #[serde(flatten)] pub capella_preset: CapellaPreset, + #[superstruct(only(Electra))] + #[serde(flatten)] + pub electra_preset: ElectraPreset, /// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks. #[serde(flatten)] pub extra_fields: HashMap, @@ -43,7 +46,23 @@ impl ConfigAndPreset { let bellatrix_preset = BellatrixPreset::from_chain_spec::(spec); let extra_fields = get_extra_fields(spec); - if spec.capella_fork_epoch.is_some() + if spec.electra_fork_epoch.is_some() + || fork_name.is_none() + || fork_name == Some(ForkName::Electra) + { + let capella_preset = CapellaPreset::from_chain_spec::(spec); + let electra_preset = ElectraPreset::from_chain_spec::(spec); + + ConfigAndPreset::Electra(ConfigAndPresetElectra { + config, + base_preset, + altair_preset, + bellatrix_preset, + capella_preset, + electra_preset, + extra_fields, + }) + } else if spec.capella_fork_epoch.is_some() || fork_name.is_none() || fork_name == Some(ForkName::Capella) { diff --git a/consensus/types/src/eth_spec.rs b/consensus/types/src/eth_spec.rs index 64bfb8da0b2..1af5a40c425 100644 --- a/consensus/types/src/eth_spec.rs +++ b/consensus/types/src/eth_spec.rs @@ -3,8 +3,8 @@ use crate::*; use safe_arith::SafeArith; use serde_derive::{Deserialize, Serialize}; use ssz_types::typenum::{ - bit::B0, UInt, Unsigned, U0, U1024, U1048576, U1073741824, U1099511627776, U128, U16, - U16777216, U2, U2048, U256, U32, U4, U4096, U512, U625, U64, U65536, U8, U8192, + bit::B0, Prod, UInt, Unsigned, U0, U1024, U1048576, U1073741824, U1099511627776, U128, U16, + U16777216, U2, U2048, U256, U31, U32, U33, U4, U4096, U512, U625, U64, U65536, U8, U8192, }; use std::fmt::{self, Debug}; use std::str::FromStr; @@ -120,6 +120,18 @@ pub trait EthSpec: /// Must be set to `SyncCommitteeSize / SyncCommitteeSubnetCount`. type SyncSubcommitteeSize: Unsigned + Clone + Sync + Send + Debug + PartialEq; + /* + * New in Electra + */ + type BytesPerBanderwagonElement: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxStems: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxStemLength: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxCommittmentsPerStem: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxCommittments: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type BytesPerSuffixStateDiffValue: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxVerkleWidth: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type IpaProofDepth: Unsigned + Clone + Sync + Send + Debug + PartialEq; + fn default_spec() -> ChainSpec; fn spec_name() -> EthSpecId; @@ -239,6 +251,38 @@ pub trait EthSpec: fn max_withdrawals_per_payload() -> usize { Self::MaxWithdrawalsPerPayload::to_usize() } + + fn bytes_per_banderwagon_element() -> usize { + Self::BytesPerBanderwagonElement::to_usize() + } + + fn max_stems() -> usize { + Self::MaxStems::to_usize() + } + + fn max_stem_length() -> usize { + Self::MaxStemLength::to_usize() + } + + fn max_committments_per_stem() -> usize { + Self::MaxCommittmentsPerStem::to_usize() + } + + fn max_committments() -> usize { + Self::MaxCommittments::to_usize() + } + + fn bytes_per_suffix_state_diff_value() -> usize { + Self::BytesPerSuffixStateDiffValue::to_usize() + } + + fn max_verkle_width() -> usize { + Self::MaxVerkleWidth::to_usize() + } + + fn ipa_proof_depth() -> usize { + Self::IpaProofDepth::to_usize() + } } /// Macro to inherit some type values from another EthSpec. @@ -283,6 +327,14 @@ impl EthSpec for MainnetEthSpec { type SlotsPerEth1VotingPeriod = U2048; // 64 epochs * 32 slots per epoch type MaxBlsToExecutionChanges = U16; type MaxWithdrawalsPerPayload = U16; + type BytesPerBanderwagonElement = U32; + type MaxStems = U65536; + type MaxStemLength = U31; + type MaxCommittmentsPerStem = U33; + type MaxCommittments = Prod; + type BytesPerSuffixStateDiffValue = U32; + type MaxVerkleWidth = U256; + type IpaProofDepth = U8; fn default_spec() -> ChainSpec { ChainSpec::mainnet() @@ -328,7 +380,15 @@ impl EthSpec for MinimalEthSpec { GasLimitDenominator, MinGasLimit, MaxExtraDataBytes, - MaxBlsToExecutionChanges + MaxBlsToExecutionChanges, + BytesPerBanderwagonElement, + MaxStems, + MaxStemLength, + MaxCommittmentsPerStem, + MaxCommittments, + BytesPerSuffixStateDiffValue, + MaxVerkleWidth, + IpaProofDepth }); fn default_spec() -> ChainSpec { @@ -374,6 +434,14 @@ impl EthSpec for GnosisEthSpec { type SlotsPerEth1VotingPeriod = U1024; // 64 epochs * 16 slots per epoch type MaxBlsToExecutionChanges = U16; type MaxWithdrawalsPerPayload = U8; + type BytesPerBanderwagonElement = U32; + type MaxStems = U65536; + type MaxStemLength = U31; + type MaxCommittmentsPerStem = U33; + type MaxCommittments = Prod; + type BytesPerSuffixStateDiffValue = U32; + type MaxVerkleWidth = U256; + type IpaProofDepth = U8; fn default_spec() -> ChainSpec { ChainSpec::gnosis() diff --git a/consensus/types/src/execution_block_header.rs b/consensus/types/src/execution_block_header.rs index b19988ff7df..297a4446d3b 100644 --- a/consensus/types/src/execution_block_header.rs +++ b/consensus/types/src/execution_block_header.rs @@ -45,6 +45,7 @@ pub struct ExecutionBlockHeader { pub nonce: Hash64, pub base_fee_per_gas: Uint256, pub withdrawals_root: Option, + pub execution_witness_root: Option, } impl ExecutionBlockHeader { @@ -53,6 +54,7 @@ impl ExecutionBlockHeader { rlp_empty_list_root: Hash256, rlp_transactions_root: Hash256, rlp_withdrawals_root: Option, + rlp_execution_witness_root: Option, ) -> Self { // Most of these field mappings are defined in EIP-3675 except for `mixHash`, which is // defined in EIP-4399. @@ -74,6 +76,7 @@ impl ExecutionBlockHeader { nonce: Hash64::zero(), base_fee_per_gas: payload.base_fee_per_gas(), withdrawals_root: rlp_withdrawals_root, + execution_witness_root: rlp_execution_witness_root, } } } diff --git a/consensus/types/src/execution_payload.rs b/consensus/types/src/execution_payload.rs index 690138da674..def2703fe4b 100644 --- a/consensus/types/src/execution_payload.rs +++ b/consensus/types/src/execution_payload.rs @@ -15,7 +15,7 @@ pub type Transactions = VariableList< pub type Withdrawals = VariableList::MaxWithdrawalsPerPayload>; #[superstruct( - variants(Merge, Capella), + variants(Merge, Capella, Electra), variant_attributes( derive( Default, @@ -81,8 +81,11 @@ pub struct ExecutionPayload { pub block_hash: ExecutionBlockHash, #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] pub withdrawals: Withdrawals, + // Fields for Verkle testing. + #[superstruct(only(Electra))] + pub execution_witness: ExecutionWitness, } impl<'a, T: EthSpec> ExecutionPayloadRef<'a, T> { @@ -103,6 +106,7 @@ impl ExecutionPayload { ))), ForkName::Merge => ExecutionPayloadMerge::from_ssz_bytes(bytes).map(Self::Merge), ForkName::Capella => ExecutionPayloadCapella::from_ssz_bytes(bytes).map(Self::Capella), + ForkName::Electra => ExecutionPayloadElectra::from_ssz_bytes(bytes).map(Self::Electra), } } @@ -129,6 +133,20 @@ impl ExecutionPayload { // Max size of variable length `withdrawals` field + (T::max_withdrawals_per_payload() * ::ssz_fixed_len()) } + + #[allow(clippy::arithmetic_side_effects)] + /// Returns the maximum size of an execution payload. + pub fn max_execution_payload_electra_size() -> usize { + // Fixed part + ExecutionPayloadElectra::::default().as_ssz_bytes().len() + // Max size of variable length `extra_data` field + + (T::max_extra_data_bytes() * ::ssz_fixed_len()) + // Max size of variable length `transactions` field + + (T::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + T::max_bytes_per_transaction())) + // Max size of variable length `withdrawals` field + + (T::max_withdrawals_per_payload() * ::ssz_fixed_len()) + + 999999999 // TODO(mac) get actual size of payload. + } } impl ForkVersionDeserialize for ExecutionPayload { @@ -143,6 +161,7 @@ impl ForkVersionDeserialize for ExecutionPayload { Ok(match fork_name { ForkName::Merge => Self::Merge(serde_json::from_value(value).map_err(convert_err)?), ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?), + ForkName::Electra => Self::Electra(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( "ExecutionPayload failed to deserialize: unsupported fork '{}'", @@ -158,6 +177,7 @@ impl ExecutionPayload { match self { ExecutionPayload::Merge(_) => ForkName::Merge, ExecutionPayload::Capella(_) => ForkName::Capella, + ExecutionPayload::Electra(_) => ForkName::Electra, } } } diff --git a/consensus/types/src/execution_payload_header.rs b/consensus/types/src/execution_payload_header.rs index 77bea03dbff..c315353ca99 100644 --- a/consensus/types/src/execution_payload_header.rs +++ b/consensus/types/src/execution_payload_header.rs @@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash; use BeaconStateError; #[superstruct( - variants(Merge, Capella), + variants(Merge, Capella, Electra), variant_attributes( derive( Default, @@ -77,9 +77,12 @@ pub struct ExecutionPayloadHeader { pub block_hash: ExecutionBlockHash, #[superstruct(getter(copy))] pub transactions_root: Hash256, - #[superstruct(only(Capella))] + #[superstruct(only(Capella, Electra))] #[superstruct(getter(copy))] pub withdrawals_root: Hash256, + #[superstruct(only(Electra))] + #[superstruct(getter(copy))] + pub execution_witness_root: Hash256, } impl ExecutionPayloadHeader { @@ -96,6 +99,9 @@ impl ExecutionPayloadHeader { ForkName::Capella => { ExecutionPayloadHeaderCapella::from_ssz_bytes(bytes).map(Self::Capella) } + ForkName::Electra => { + ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra) + } } } } @@ -131,6 +137,29 @@ impl ExecutionPayloadHeaderMerge { } } +impl ExecutionPayloadHeaderCapella { + pub fn upgrade_to_electra(&self) -> ExecutionPayloadHeaderElectra { + ExecutionPayloadHeaderElectra { + parent_hash: self.parent_hash, + fee_recipient: self.fee_recipient, + state_root: self.state_root, + receipts_root: self.receipts_root, + logs_bloom: self.logs_bloom.clone(), + prev_randao: self.prev_randao, + block_number: self.block_number, + gas_limit: self.gas_limit, + gas_used: self.gas_used, + timestamp: self.timestamp, + extra_data: self.extra_data.clone(), + base_fee_per_gas: self.base_fee_per_gas, + block_hash: self.block_hash, + transactions_root: self.transactions_root, + withdrawals_root: self.withdrawals_root, + execution_witness_root: Hash256::zero(), + } + } +} + impl<'a, T: EthSpec> From<&'a ExecutionPayloadMerge> for ExecutionPayloadHeaderMerge { fn from(payload: &'a ExecutionPayloadMerge) -> Self { Self { @@ -172,6 +201,28 @@ impl<'a, T: EthSpec> From<&'a ExecutionPayloadCapella> for ExecutionPayloadHe } } } +impl<'a, T: EthSpec> From<&'a ExecutionPayloadElectra> for ExecutionPayloadHeaderElectra { + fn from(payload: &'a ExecutionPayloadElectra) -> Self { + Self { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions_root: payload.transactions.tree_hash_root(), + withdrawals_root: payload.withdrawals.tree_hash_root(), + execution_witness_root: payload.execution_witness.tree_hash_root(), + } + } +} // These impls are required to work around an inelegance in `to_execution_payload_header`. // They only clone headers so they should be relatively cheap. @@ -187,6 +238,12 @@ impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderCapella { } } +impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderElectra { + fn from(payload: &'a Self) -> Self { + payload.clone() + } +} + impl<'a, T: EthSpec> From> for ExecutionPayloadHeader { fn from(payload: ExecutionPayloadRef<'a, T>) -> Self { map_execution_payload_ref_into_execution_payload_header!( @@ -217,6 +274,17 @@ impl TryFrom> for ExecutionPayloadHeaderCa } } } +impl TryFrom> for ExecutionPayloadHeaderElectra { + type Error = BeaconStateError; + fn try_from(header: ExecutionPayloadHeader) -> Result { + match header { + ExecutionPayloadHeader::Electra(execution_payload_header) => { + Ok(execution_payload_header) + } + _ => Err(BeaconStateError::IncorrectStateVariant), + } + } +} impl ForkVersionDeserialize for ExecutionPayloadHeader { fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>( @@ -233,6 +301,7 @@ impl ForkVersionDeserialize for ExecutionPayloadHeader { Ok(match fork_name { ForkName::Merge => Self::Merge(serde_json::from_value(value).map_err(convert_err)?), ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?), + ForkName::Electra => Self::Electra(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( "ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'", diff --git a/consensus/types/src/execution_witness.rs b/consensus/types/src/execution_witness.rs new file mode 100644 index 00000000000..af84cc56ad9 --- /dev/null +++ b/consensus/types/src/execution_witness.rs @@ -0,0 +1,258 @@ +use crate::{test_utils::TestRandom, *}; +use derivative::Derivative; +use serde_derive::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +#[ssz(struct_behaviour = "transparent")] +#[serde(transparent)] +pub struct BanderwagonGroupElement { + #[serde(with = "ssz_types::serde_utils::hex_fixed_vec")] + inner: FixedVector, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +#[ssz(struct_behaviour = "transparent")] +#[serde(transparent)] +pub struct BanderwagonFieldElement { + #[serde(with = "ssz_types::serde_utils::hex_fixed_vec")] + inner: FixedVector, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +#[ssz(struct_behaviour = "transparent")] +#[serde(transparent)] +pub struct Stem { + #[serde(with = "ssz_types::serde_utils::hex_fixed_vec")] + inner: FixedVector, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +#[ssz(struct_behaviour = "transparent")] +#[serde(transparent)] +pub struct StateDiffValue { + #[serde(with = "ssz_types::serde_utils::hex_fixed_vec")] + inner: FixedVector, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +pub struct SuffixStateDiff { + //#[serde(with = "eth2_serde_utils::quoted_u8")] + pub suffix: u8, + // `None` means not currently present. + pub current_value: Optional>, + // `None` means value is not updated. + pub new_value: Optional>, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +pub struct StemStateDiff { + pub stem: Stem, + pub suffix_diffs: VariableList, T::MaxVerkleWidth>, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +#[ssz(struct_behaviour = "transparent")] +#[serde(transparent)] +pub struct StateDiff { + pub inner: VariableList, T::MaxStems>, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +pub struct IpaProof { + pub cl: FixedVector, T::IpaProofDepth>, + pub cr: FixedVector, T::IpaProofDepth>, + pub final_evaluation: BanderwagonFieldElement, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +#[ssz(struct_behaviour = "transparent")] +#[serde(transparent)] +pub struct StemValue { + #[serde(with = "ssz_types::serde_utils::hex_fixed_vec")] + inner: FixedVector, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +pub struct VerkleProof { + pub other_stems: VariableList, T::MaxStems>, + #[serde(with = "ssz_types::serde_utils::hex_var_list")] + pub depth_extension_present: VariableList, + pub commitments_by_path: VariableList, T::MaxCommittments>, + pub d: BanderwagonGroupElement, + pub ipa_proof: IpaProof, +} + +#[derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Derivative, + arbitrary::Arbitrary, +)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[arbitrary(bound = "T: EthSpec")] +#[serde(bound = "T: EthSpec")] +pub struct ExecutionWitness { + pub state_diff: StateDiff, + pub verkle_proof: VerkleProof, + pub parent_state_root: Hash256, +} diff --git a/consensus/types/src/fork_context.rs b/consensus/types/src/fork_context.rs index 90d1fbc6864..5c619cda048 100644 --- a/consensus/types/src/fork_context.rs +++ b/consensus/types/src/fork_context.rs @@ -54,6 +54,13 @@ impl ForkContext { )); } + if spec.electra_fork_epoch.is_some() { + fork_to_digest.push(( + ForkName::Electra, + ChainSpec::compute_fork_digest(spec.electra_fork_version, genesis_validators_root), + )); + } + let fork_to_digest: HashMap = fork_to_digest.into_iter().collect(); let digest_to_fork = fork_to_digest diff --git a/consensus/types/src/fork_name.rs b/consensus/types/src/fork_name.rs index 85144a61377..535cfdfc628 100644 --- a/consensus/types/src/fork_name.rs +++ b/consensus/types/src/fork_name.rs @@ -12,6 +12,7 @@ pub enum ForkName { Altair, Merge, Capella, + Electra, } impl ForkName { @@ -21,6 +22,7 @@ impl ForkName { ForkName::Altair, ForkName::Merge, ForkName::Capella, + ForkName::Electra, ] } @@ -38,24 +40,35 @@ impl ForkName { spec.altair_fork_epoch = None; spec.bellatrix_fork_epoch = None; spec.capella_fork_epoch = None; + spec.electra_fork_epoch = None; spec } ForkName::Altair => { spec.altair_fork_epoch = Some(Epoch::new(0)); spec.bellatrix_fork_epoch = None; spec.capella_fork_epoch = None; + spec.electra_fork_epoch = None; spec } ForkName::Merge => { spec.altair_fork_epoch = Some(Epoch::new(0)); spec.bellatrix_fork_epoch = Some(Epoch::new(0)); spec.capella_fork_epoch = None; + spec.electra_fork_epoch = None; spec } ForkName::Capella => { spec.altair_fork_epoch = Some(Epoch::new(0)); spec.bellatrix_fork_epoch = Some(Epoch::new(0)); spec.capella_fork_epoch = Some(Epoch::new(0)); + spec.electra_fork_epoch = None; + spec + } + ForkName::Electra => { + spec.altair_fork_epoch = Some(Epoch::new(0)); + spec.bellatrix_fork_epoch = Some(Epoch::new(0)); + spec.capella_fork_epoch = Some(Epoch::new(0)); + spec.electra_fork_epoch = Some(Epoch::new(0)); spec } } @@ -70,6 +83,7 @@ impl ForkName { ForkName::Altair => Some(ForkName::Base), ForkName::Merge => Some(ForkName::Altair), ForkName::Capella => Some(ForkName::Merge), + ForkName::Electra => Some(ForkName::Capella), } } @@ -81,7 +95,8 @@ impl ForkName { ForkName::Base => Some(ForkName::Altair), ForkName::Altair => Some(ForkName::Merge), ForkName::Merge => Some(ForkName::Capella), - ForkName::Capella => None, + ForkName::Capella => Some(ForkName::Electra), + ForkName::Electra => None, } } } @@ -127,6 +142,10 @@ macro_rules! map_fork_name_with { let (value, extra_data) = $body; ($t::Capella(value), extra_data) } + ForkName::Electra => { + let (value, extra_data) = $body; + ($t::Electra(value), extra_data) + } } }; } @@ -140,6 +159,7 @@ impl FromStr for ForkName { "altair" => ForkName::Altair, "bellatrix" | "merge" => ForkName::Merge, "capella" => ForkName::Capella, + "electra" => ForkName::Electra, _ => return Err(format!("unknown fork name: {}", fork_name)), }) } @@ -152,6 +172,7 @@ impl Display for ForkName { ForkName::Altair => "altair".fmt(f), ForkName::Merge => "bellatrix".fmt(f), ForkName::Capella => "capella".fmt(f), + ForkName::Electra => "electra".fmt(f), } } } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index 85ce351766f..d1ffd750a5a 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -41,6 +41,7 @@ pub mod eth_spec; pub mod execution_block_hash; pub mod execution_payload; pub mod execution_payload_header; +pub mod execution_witness; pub mod fork; pub mod fork_data; pub mod fork_name; @@ -106,12 +107,12 @@ pub use crate::attestation_data::AttestationData; pub use crate::attestation_duty::AttestationDuty; pub use crate::attester_slashing::AttesterSlashing; pub use crate::beacon_block::{ - BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockMerge, - BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock, + BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockElectra, + BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock, }; pub use crate::beacon_block_body::{ BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyCapella, - BeaconBlockBodyMerge, BeaconBlockBodyRef, BeaconBlockBodyRefMut, + BeaconBlockBodyElectra, BeaconBlockBodyMerge, BeaconBlockBodyRef, BeaconBlockBodyRefMut, }; pub use crate::beacon_block_header::BeaconBlockHeader; pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee}; @@ -120,7 +121,7 @@ pub use crate::bls_to_execution_change::BlsToExecutionChange; pub use crate::chain_spec::{ChainSpec, Config, Domain}; pub use crate::checkpoint::Checkpoint; pub use crate::config_and_preset::{ - ConfigAndPreset, ConfigAndPresetBellatrix, ConfigAndPresetCapella, + ConfigAndPreset, ConfigAndPresetBellatrix, ConfigAndPresetCapella, ConfigAndPresetElectra, }; pub use crate::contribution_and_proof::ContributionAndProof; pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH}; @@ -133,13 +134,14 @@ pub use crate::eth_spec::EthSpecId; pub use crate::execution_block_hash::ExecutionBlockHash; pub use crate::execution_block_header::ExecutionBlockHeader; pub use crate::execution_payload::{ - ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadMerge, ExecutionPayloadRef, - Transaction, Transactions, Withdrawals, + ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadMerge, + ExecutionPayloadRef, Transaction, Transactions, Withdrawals, }; pub use crate::execution_payload_header::{ - ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderMerge, - ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, + ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderElectra, + ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, }; +pub use crate::execution_witness::ExecutionWitness; pub use crate::fork::Fork; pub use crate::fork_context::ForkContext; pub use crate::fork_data::ForkData; @@ -153,12 +155,12 @@ pub use crate::light_client_optimistic_update::LightClientOptimisticUpdate; pub use crate::participation_flags::ParticipationFlags; pub use crate::participation_list::ParticipationList; pub use crate::payload::{ - AbstractExecPayload, BlindedPayload, BlindedPayloadCapella, BlindedPayloadMerge, - BlindedPayloadRef, BlockType, ExecPayload, FullPayload, FullPayloadCapella, FullPayloadMerge, - FullPayloadRef, OwnedExecPayload, + AbstractExecPayload, BlindedPayload, BlindedPayloadCapella, BlindedPayloadElectra, + BlindedPayloadMerge, BlindedPayloadRef, BlockType, ExecPayload, FullPayload, + FullPayloadCapella, FullPayloadElectra, FullPayloadMerge, FullPayloadRef, OwnedExecPayload, }; pub use crate::pending_attestation::PendingAttestation; -pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset, CapellaPreset}; +pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ElectraPreset}; pub use crate::proposer_preparation_data::ProposerPreparationData; pub use crate::proposer_slashing::ProposerSlashing; pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch}; @@ -167,7 +169,8 @@ pub use crate::shuffling_id::AttestationShufflingId; pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof; pub use crate::signed_beacon_block::{ SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockCapella, - SignedBeaconBlockHash, SignedBeaconBlockMerge, SignedBlindedBeaconBlock, + SignedBeaconBlockElectra, SignedBeaconBlockHash, SignedBeaconBlockMerge, + SignedBlindedBeaconBlock, }; pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader; pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange; @@ -205,5 +208,7 @@ pub use bls::{ AggregatePublicKey, AggregateSignature, Keypair, PublicKey, PublicKeyBytes, SecretKey, Signature, SignatureBytes, }; -pub use ssz_types::{typenum, typenum::Unsigned, BitList, BitVector, FixedVector, VariableList}; +pub use ssz_types::{ + typenum, typenum::Unsigned, BitList, BitVector, FixedVector, Optional, VariableList, +}; pub use superstruct::superstruct; diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index 2795c7f1092..ce41ebb7245 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -39,6 +39,7 @@ pub trait ExecPayload: Debug + Clone + PartialEq + Hash + TreeHash + fn transactions(&self) -> Option<&Transactions>; /// fork-specific fields fn withdrawals_root(&self) -> Result; + fn execution_witness_root(&self) -> Result; /// Is this a default payload with 0x0 roots for transactions and withdrawals? fn is_default_with_zero_roots(&self) -> bool; @@ -81,8 +82,13 @@ pub trait AbstractExecPayload: + TryFrom> + TryInto + TryInto + + TryInto { - type Ref<'a>: ExecPayload + Copy + From<&'a Self::Merge> + From<&'a Self::Capella>; + type Ref<'a>: ExecPayload + + Copy + + From<&'a Self::Merge> + + From<&'a Self::Capella> + + From<&'a Self::Electra>; type Merge: OwnedExecPayload + Into @@ -92,12 +98,16 @@ pub trait AbstractExecPayload: + Into + for<'a> From>> + TryFrom>; + type Electra: OwnedExecPayload + + Into + + for<'a> From>> + + TryFrom>; fn default_at_fork(fork_name: ForkName) -> Result; } #[superstruct( - variants(Merge, Capella), + variants(Merge, Capella, Electra), variant_attributes( derive( Debug, @@ -136,6 +146,8 @@ pub struct FullPayload { pub execution_payload: ExecutionPayloadMerge, #[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))] pub execution_payload: ExecutionPayloadCapella, + #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] + pub execution_payload: ExecutionPayloadElectra, } impl From> for ExecutionPayload { @@ -239,6 +251,19 @@ impl ExecPayload for FullPayload { FullPayload::Capella(ref inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } + FullPayload::Electra(ref inner) => { + Ok(inner.execution_payload.withdrawals.tree_hash_root()) + } + } + } + + fn execution_witness_root(&self) -> Result { + match self { + FullPayload::Merge(_) => Err(Error::IncorrectStateVariant), + FullPayload::Capella(_) => Err(Error::IncorrectStateVariant), + FullPayload::Electra(ref inner) => { + Ok(inner.execution_payload.execution_witness.tree_hash_root()) + } } } @@ -345,6 +370,19 @@ impl<'b, T: EthSpec> ExecPayload for FullPayloadRef<'b, T> { FullPayloadRef::Capella(inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } + FullPayloadRef::Electra(inner) => { + Ok(inner.execution_payload.withdrawals.tree_hash_root()) + } + } + } + + fn execution_witness_root(&self) -> Result { + match self { + FullPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant), + FullPayloadRef::Capella(_) => Err(Error::IncorrectStateVariant), + FullPayloadRef::Electra(inner) => { + Ok(inner.execution_payload.execution_witness.tree_hash_root()) + } } } @@ -365,12 +403,14 @@ impl AbstractExecPayload for FullPayload { type Ref<'a> = FullPayloadRef<'a, T>; type Merge = FullPayloadMerge; type Capella = FullPayloadCapella; + type Electra = FullPayloadElectra; fn default_at_fork(fork_name: ForkName) -> Result { match fork_name { ForkName::Base | ForkName::Altair => Err(Error::IncorrectStateVariant), ForkName::Merge => Ok(FullPayloadMerge::default().into()), ForkName::Capella => Ok(FullPayloadCapella::default().into()), + ForkName::Electra => Ok(FullPayloadElectra::default().into()), } } } @@ -391,7 +431,7 @@ impl TryFrom> for FullPayload { } #[superstruct( - variants(Merge, Capella), + variants(Merge, Capella, Electra), variant_attributes( derive( Debug, @@ -429,6 +469,8 @@ pub struct BlindedPayload { pub execution_payload_header: ExecutionPayloadHeaderMerge, #[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))] pub execution_payload_header: ExecutionPayloadHeaderCapella, + #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] + pub execution_payload_header: ExecutionPayloadHeaderElectra, } impl<'a, T: EthSpec> From> for BlindedPayload { @@ -510,6 +552,19 @@ impl ExecPayload for BlindedPayload { BlindedPayload::Capella(ref inner) => { Ok(inner.execution_payload_header.withdrawals_root) } + BlindedPayload::Electra(ref inner) => { + Ok(inner.execution_payload_header.withdrawals_root) + } + } + } + + fn execution_witness_root(&self) -> Result { + match self { + BlindedPayload::Merge(_) => Err(Error::IncorrectStateVariant), + BlindedPayload::Capella(_) => Err(Error::IncorrectStateVariant), + BlindedPayload::Electra(ref inner) => { + Ok(inner.execution_payload_header.execution_witness_root) + } } } @@ -597,6 +652,19 @@ impl<'b, T: EthSpec> ExecPayload for BlindedPayloadRef<'b, T> { BlindedPayloadRef::Capella(inner) => { Ok(inner.execution_payload_header.withdrawals_root) } + BlindedPayloadRef::Electra(inner) => { + Ok(inner.execution_payload_header.withdrawals_root) + } + } + } + + fn execution_witness_root(&self) -> Result { + match self { + BlindedPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant), + BlindedPayloadRef::Capella(_) => Err(Error::IncorrectStateVariant), + BlindedPayloadRef::Electra(inner) => { + Ok(inner.execution_payload_header.execution_witness_root) + } } } @@ -625,7 +693,8 @@ macro_rules! impl_exec_payload_common { $block_type_variant:ident, // Blinded | Full $is_default_with_empty_roots:block, $f:block, - $g:block) => { + $g:block, + $h:block) => { impl ExecPayload for $wrapper_type { fn block_type() -> BlockType { BlockType::$block_type_variant @@ -683,6 +752,11 @@ macro_rules! impl_exec_payload_common { let g = $g; g(self) } + + fn execution_witness_root(&self) -> Result { + let h = $h; + h(self) + } } impl From<$wrapped_type> for $wrapper_type { @@ -720,6 +794,14 @@ macro_rules! impl_exec_payload_for_fork { wrapper_ref_type.withdrawals_root() }; c + }, + { + let c: for<'a> fn(&'a $wrapper_type_header) -> Result = + |payload: &$wrapper_type_header| { + let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload); + wrapper_ref_type.execution_witness_root() + }; + c } ); @@ -799,6 +881,14 @@ macro_rules! impl_exec_payload_for_fork { wrapper_ref_type.withdrawals_root() }; c + }, + { + let c: for<'a> fn(&'a $wrapper_type_full) -> Result = + |payload: &$wrapper_type_full| { + let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload); + wrapper_ref_type.execution_witness_root() + }; + c } ); @@ -860,17 +950,26 @@ impl_exec_payload_for_fork!( ExecutionPayloadCapella, Capella ); +impl_exec_payload_for_fork!( + BlindedPayloadElectra, + FullPayloadElectra, + ExecutionPayloadHeaderElectra, + ExecutionPayloadElectra, + Electra +); impl AbstractExecPayload for BlindedPayload { type Ref<'a> = BlindedPayloadRef<'a, T>; type Merge = BlindedPayloadMerge; type Capella = BlindedPayloadCapella; + type Electra = BlindedPayloadElectra; fn default_at_fork(fork_name: ForkName) -> Result { match fork_name { ForkName::Base | ForkName::Altair => Err(Error::IncorrectStateVariant), ForkName::Merge => Ok(BlindedPayloadMerge::default().into()), ForkName::Capella => Ok(BlindedPayloadCapella::default().into()), + ForkName::Electra => Ok(BlindedPayloadElectra::default().into()), } } } @@ -899,6 +998,11 @@ impl From> for BlindedPayload { execution_payload_header, }) } + ExecutionPayloadHeader::Electra(execution_payload_header) => { + Self::Electra(BlindedPayloadElectra { + execution_payload_header, + }) + } } } } @@ -912,6 +1016,9 @@ impl From> for ExecutionPayloadHeader { BlindedPayload::Capella(blinded_payload) => { ExecutionPayloadHeader::Capella(blinded_payload.execution_payload_header) } + BlindedPayload::Electra(blinded_payload) => { + ExecutionPayloadHeader::Electra(blinded_payload.execution_payload_header) + } } } } diff --git a/consensus/types/src/preset.rs b/consensus/types/src/preset.rs index e65dd8f60de..d0b51a3d37d 100644 --- a/consensus/types/src/preset.rs +++ b/consensus/types/src/preset.rs @@ -205,6 +205,42 @@ impl CapellaPreset { } } +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub struct ElectraPreset { + #[serde(with = "serde_utils::quoted_u64")] + pub bytes_per_banderwagon_element: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_stems: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_stem_length: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_committments_per_stem: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_committments: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub bytes_per_suffix_state_diff_value: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_verkle_width: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub ipa_proof_depth: u64, +} + +impl ElectraPreset { + pub fn from_chain_spec(_spec: &ChainSpec) -> Self { + Self { + bytes_per_banderwagon_element: T::bytes_per_banderwagon_element() as u64, + max_stems: T::max_stems() as u64, + max_stem_length: T::max_stem_length() as u64, + max_committments_per_stem: T::max_committments_per_stem() as u64, + max_committments: T::max_committments() as u64, + bytes_per_suffix_state_diff_value: T::bytes_per_suffix_state_diff_value() as u64, + max_verkle_width: T::max_verkle_width() as u64, + ipa_proof_depth: T::ipa_proof_depth() as u64, + } + } +} + #[cfg(test)] mod test { use super::*; @@ -243,6 +279,9 @@ mod test { let capella: CapellaPreset = preset_from_file(&preset_name, "capella.yaml"); assert_eq!(capella, CapellaPreset::from_chain_spec::(&spec)); + + let electra: ElectraPreset = preset_from_file(&preset_name, "electra.yaml"); + assert_eq!(electra, ElectraPreset::from_chain_spec::(&spec)); } #[test] diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index 5f623cf07a6..dc3bbfb94cd 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -37,7 +37,7 @@ impl From for Hash256 { /// A `BeaconBlock` and a signature from its proposer. #[superstruct( - variants(Base, Altair, Merge, Capella), + variants(Base, Altair, Merge, Capella, Electra), variant_attributes( derive( Debug, @@ -76,6 +76,8 @@ pub struct SignedBeaconBlock = FullP pub message: BeaconBlockMerge, #[superstruct(only(Capella), partial_getter(rename = "message_capella"))] pub message: BeaconBlockCapella, + #[superstruct(only(Electra), partial_getter(rename = "message_electra"))] + pub message: BeaconBlockElectra, pub signature: Signature, } @@ -136,6 +138,9 @@ impl> SignedBeaconBlock BeaconBlock::Capella(message) => { SignedBeaconBlock::Capella(SignedBeaconBlockCapella { message, signature }) } + BeaconBlock::Electra(message) => { + SignedBeaconBlock::Electra(SignedBeaconBlockElectra { message, signature }) + } } } @@ -367,6 +372,59 @@ impl SignedBeaconBlockCapella> { } } } +impl SignedBeaconBlockElectra> { + pub fn into_full_block( + self, + execution_payload: ExecutionPayloadElectra, + ) -> SignedBeaconBlockElectra> { + let SignedBeaconBlockElectra { + message: + BeaconBlockElectra { + slot, + proposer_index, + parent_root, + state_root, + body: + BeaconBlockBodyElectra { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: BlindedPayloadElectra { .. }, + bls_to_execution_changes, + }, + }, + signature, + } = self; + SignedBeaconBlockElectra { + message: BeaconBlockElectra { + slot, + proposer_index, + parent_root, + state_root, + body: BeaconBlockBodyElectra { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadElectra { execution_payload }, + bls_to_execution_changes, + }, + }, + signature, + } + } +} impl SignedBeaconBlock> { pub fn try_into_full_block( @@ -382,10 +440,14 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Capella(block), Some(ExecutionPayload::Capella(payload))) => { SignedBeaconBlock::Capella(block.into_full_block(payload)) } + (SignedBeaconBlock::Electra(block), Some(ExecutionPayload::Electra(payload))) => { + SignedBeaconBlock::Electra(block.into_full_block(payload)) + } // avoid wildcard matching forks so that compiler will // direct us here when a new fork has been added (SignedBeaconBlock::Merge(_), _) => return None, (SignedBeaconBlock::Capella(_), _) => return None, + (SignedBeaconBlock::Electra(_), _) => return None, }; Some(full_block) } diff --git a/consensus/types/src/test_utils/test_random.rs b/consensus/types/src/test_utils/test_random.rs index 51b79d8d531..f1bcb2c05a0 100644 --- a/consensus/types/src/test_utils/test_random.rs +++ b/consensus/types/src/test_utils/test_random.rs @@ -86,6 +86,18 @@ where } } +impl TestRandom for Option +where + T: TestRandom, +{ + fn random_for_test(rng: &mut impl RngCore) -> Self { + match bool::random_for_test(rng) { + false => None, + true => Some(T::random_for_test(rng)), + } + } +} + impl TestRandom for FixedVector where T: TestRandom, @@ -117,6 +129,13 @@ where } } +// TODO(mac) Dummy impl +impl TestRandom for Optional { + fn random_for_test(_rng: &mut impl RngCore) -> Self { + Self::from(None) + } +} + macro_rules! impl_test_random_for_u8_array { ($len: expr) => { impl TestRandom for [u8; $len] { diff --git a/lcli/src/create_payload_header.rs b/lcli/src/create_payload_header.rs index 6c0e8dcecf8..70ef0fa30ef 100644 --- a/lcli/src/create_payload_header.rs +++ b/lcli/src/create_payload_header.rs @@ -5,8 +5,8 @@ use std::fs::File; use std::io::Write; use std::time::{SystemTime, UNIX_EPOCH}; use types::{ - EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderMerge, - ForkName, + EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderElectra, + ExecutionPayloadHeaderMerge, ForkName, }; pub fn run(matches: &ArgMatches) -> Result<(), String> { @@ -40,6 +40,14 @@ pub fn run(matches: &ArgMatches) -> Result<(), String> { prev_randao: eth1_block_hash.into_root(), ..ExecutionPayloadHeaderCapella::default() }), + ForkName::Electra => ExecutionPayloadHeader::Electra(ExecutionPayloadHeaderElectra { + gas_limit, + base_fee_per_gas, + timestamp: genesis_time, + block_hash: eth1_block_hash, + prev_randao: eth1_block_hash.into_root(), + ..ExecutionPayloadHeaderElectra::default() + }), }; let mut file = File::create(file_name).map_err(|_| "Unable to create file".to_string())?; diff --git a/lcli/src/generate_ssz.rs b/lcli/src/generate_ssz.rs new file mode 100644 index 00000000000..32951ed3c43 --- /dev/null +++ b/lcli/src/generate_ssz.rs @@ -0,0 +1,54 @@ +use clap::ArgMatches; +use serde::{Deserialize, Serialize}; +use ssz::Encode; +use std::fs; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use types::*; + +#[derive(Serialize, Deserialize)] +#[serde(bound = "T: EthSpec")] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +enum SszType { + BaseState(BeaconStateBase), + AltairState(BeaconStateAltair), + BellatrixState(BeaconStateMerge), + BaseBlock(BeaconBlockBase), + AltairBlock(BeaconBlockAltair), + BellatrixBlock(BeaconBlockMerge), +} + +pub fn run_parse_json(matches: &ArgMatches) -> Result<(), String> { + let file_path = Path::new(matches.value_of("file").ok_or("No file supplied")?); + let output_path = Path::new( + matches + .value_of("output") + .ok_or("No output file supplied")?, + ); + + let data = fs::read_to_string(file_path).expect("Unable to read file"); + + let ssz_type: SszType = serde_json::from_str(&data).unwrap_or_else(|_| { + serde_yaml::from_str(&data) + .map_err(|_| "Unable to parse as either JSON or YAML".to_string()) + })?; + + let bytes = match ssz_type { + SszType::BaseState(bases) => bases.as_ssz_bytes(), + SszType::AltairState(altairs) => altairs.as_ssz_bytes(), + SszType::BellatrixState(bellatrixs) => bellatrixs.as_ssz_bytes(), + SszType::BaseBlock(baseb) => baseb.as_ssz_bytes(), + SszType::AltairBlock(altairb) => altairb.as_ssz_bytes(), + SszType::BellatrixBlock(bellatrixb) => bellatrixb.as_ssz_bytes(), + }; + + let mut output = + File::create(output_path).map_err(|e| format!("Error creating output file: {}", e))?; + output + .write_all(&bytes) + .map_err(|e| format!("Error writing to output to file: {}", e))?; + + Ok(()) +} diff --git a/lcli/src/main.rs b/lcli/src/main.rs index 38fec2ebb48..e57e5054ebf 100644 --- a/lcli/src/main.rs +++ b/lcli/src/main.rs @@ -7,6 +7,7 @@ mod create_payload_header; mod deploy_deposit_contract; mod eth1_genesis; mod generate_bootnode_enr; +mod generate_ssz; mod indexed_attestations; mod insecure_validators; mod interop_genesis; @@ -22,6 +23,7 @@ use clap::{App, Arg, ArgMatches, SubCommand}; use clap_utils::parse_optional; use environment::{EnvironmentBuilder, LoggerConfig}; use eth2_network_config::Eth2NetworkConfig; +use generate_ssz::run_parse_json; use parse_ssz::run_parse_ssz; use std::path::PathBuf; use std::process; @@ -212,6 +214,28 @@ fn main() { the block."), ) ) + .subcommand( + SubCommand::with_name("generate-ssz") + .about("Generates the corresponding SSZ from JSON-encoded data in a file") + .arg( + Arg::with_name("file") + .short("f") + .long("file") + .value_name("FILE") + .takes_value(true) + .required(true) + .help("Path of the file containing the JSON-encoded data") + ) + .arg( + Arg::with_name("output") + .short("o") + .long("output") + .value_name("FILE") + .takes_value(true) + .required(true) + .help("Path of the file to write the SSZ to") + ) + ) .subcommand( SubCommand::with_name("pretty-ssz") .about("Parses SSZ-encoded data from a file") @@ -432,7 +456,7 @@ fn main() { .takes_value(true) .default_value("bellatrix") .help("The fork for which the execution payload header should be created.") - .possible_values(&["merge", "bellatrix", "capella"]) + .possible_values(&["merge", "bellatrix", "capella", "electra"]) ) ) .subcommand( @@ -608,6 +632,15 @@ fn main() { "The epoch at which to enable the Capella hard fork", ), ) + .arg( + Arg::with_name("electra-fork-epoch") + .long("electra-fork-epoch") + .value_name("EPOCH") + .takes_value(true) + .help( + "The epoch at which to enable the Electra hard fork", + ), + ) .arg( Arg::with_name("ttd") .long("ttd") @@ -967,6 +1000,9 @@ fn run( skip_slots::run::(env, network_config, matches) .map_err(|e| format!("Failed to skip slots: {}", e)) } + ("generate-ssz", Some(matches)) => { + run_parse_json::(matches).map_err(|e| format!("Failed to generate ssz: {}", e)) + } ("pretty-ssz", Some(matches)) => { let network_config = get_network_config()?; run_parse_ssz::(network_config, matches) diff --git a/lcli/src/new_testnet.rs b/lcli/src/new_testnet.rs index 973993f9790..4519cee71b9 100644 --- a/lcli/src/new_testnet.rs +++ b/lcli/src/new_testnet.rs @@ -9,7 +9,9 @@ use ethereum_hashing::hash; use ssz::Decode; use ssz::Encode; use state_processing::process_activations; -use state_processing::upgrade::{upgrade_to_altair, upgrade_to_bellatrix}; +use state_processing::upgrade::{ + upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_electra, +}; use std::fs::File; use std::io::Read; use std::path::PathBuf; @@ -19,8 +21,8 @@ use types::ExecutionBlockHash; use types::{ test_utils::generate_deterministic_keypairs, Address, BeaconState, ChainSpec, Config, Epoch, Eth1Data, EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, - ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRefMut, ForkName, Hash256, Keypair, - PublicKey, Validator, + ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRefMut, + ForkName, Hash256, Keypair, PublicKey, Validator, }; pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> { @@ -85,6 +87,10 @@ pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Resul spec.capella_fork_epoch = Some(fork_epoch); } + if let Some(fork_epoch) = parse_optional(matches, "electra-fork-epoch")? { + spec.electra_fork_epoch = Some(fork_epoch); + } + if let Some(ttd) = parse_optional(matches, "ttd")? { spec.terminal_total_difficulty = ttd; } @@ -111,6 +117,10 @@ pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Resul ExecutionPayloadHeaderCapella::::from_ssz_bytes(bytes.as_slice()) .map(ExecutionPayloadHeader::Capella) } + ForkName::Electra => { + ExecutionPayloadHeaderElectra::::from_ssz_bytes(bytes.as_slice()) + .map(ExecutionPayloadHeader::Electra) + } } .map_err(|e| format!("SSZ decode failed: {:?}", e)) }) @@ -214,14 +224,29 @@ fn initialize_state_with_validators( execution_payload_header: Option>, spec: &ChainSpec, ) -> Result, String> { - // If no header is provided, then start from a Bellatrix state by default - let default_header: ExecutionPayloadHeader = + // If no header is provided, then start from a default state. + let default_header = if spec.electra_fork_epoch == Some(T::genesis_epoch()) { + ExecutionPayloadHeader::Electra(ExecutionPayloadHeaderElectra { + block_hash: ExecutionBlockHash::from_root(eth1_block_hash), + parent_hash: ExecutionBlockHash::zero(), + ..ExecutionPayloadHeaderElectra::default() + }) + } else if spec.capella_fork_epoch == Some(T::genesis_epoch()) { + ExecutionPayloadHeader::Capella(ExecutionPayloadHeaderCapella { + block_hash: ExecutionBlockHash::from_root(eth1_block_hash), + parent_hash: ExecutionBlockHash::zero(), + ..ExecutionPayloadHeaderCapella::default() + }) + } else { ExecutionPayloadHeader::Merge(ExecutionPayloadHeaderMerge { block_hash: ExecutionBlockHash::from_root(eth1_block_hash), parent_hash: ExecutionBlockHash::zero(), ..ExecutionPayloadHeaderMerge::default() - }); + }) + }; + let execution_payload_header = execution_payload_header.unwrap_or(default_header); + // Empty eth1 data let eth1_data = Eth1Data { block_hash: eth1_block_hash, @@ -263,6 +288,8 @@ fn initialize_state_with_validators( process_activations(&mut state, spec).unwrap(); + let mut post_merge = false; + if spec .altair_fork_epoch .map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch()) @@ -272,7 +299,7 @@ fn initialize_state_with_validators( state.fork_mut().previous_version = spec.altair_fork_version; } - // Similarly, perform an upgrade to the merge if configured from genesis. + // Similarly, perform an upgrade to Bellatrix if configured from genesis. if spec .bellatrix_fork_epoch .map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch()) @@ -282,6 +309,37 @@ fn initialize_state_with_validators( // Remove intermediate Altair fork from `state.fork`. state.fork_mut().previous_version = spec.bellatrix_fork_version; + post_merge = true; + } + + // Similarly, perform an upgrade to Capella if configured from genesis. + if spec + .capella_fork_epoch + .map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch()) + { + upgrade_to_capella(&mut state, spec).unwrap(); + + // Remove intermediate Bellatrix fork from `state.fork`. + state.fork_mut().previous_version = spec.capella_fork_version; + + post_merge = true; + } + + // Similarly, perform an upgrade to Electra if configured from genesis. + if spec + .electra_fork_epoch + .map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch()) + { + upgrade_to_electra(&mut state, spec).unwrap(); + + // Remove intermediate Capella fork from `state.fork`. + state.fork_mut().previous_version = spec.electra_fork_version; + + post_merge = true; + } + + // If fork is post_merge. + if post_merge { // Override latest execution payload header. // See https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/merge/beacon-chain.md#testing @@ -297,8 +355,19 @@ fn initialize_state_with_validators( return Err("Execution payload header must be a bellatrix header".to_string()); } } - ExecutionPayloadHeaderRefMut::Capella(_) => { - return Err("Cannot start genesis from a capella state".to_string()) + ExecutionPayloadHeaderRefMut::Capella(header_mut) => { + if let ExecutionPayloadHeader::Capella(eph) = execution_payload_header { + *header_mut = eph; + } else { + return Err("Execution payload header must be a capella header".to_string()); + } + } + ExecutionPayloadHeaderRefMut::Electra(header_mut) => { + if let ExecutionPayloadHeader::Electra(eph) = execution_payload_header { + *header_mut = eph; + } else { + return Err("Execution payload header must be a electra header".to_string()); + } } } } diff --git a/lcli/src/parse_ssz.rs b/lcli/src/parse_ssz.rs index 5c306f4fdc1..620c624d197 100644 --- a/lcli/src/parse_ssz.rs +++ b/lcli/src/parse_ssz.rs @@ -78,6 +78,11 @@ pub fn run_parse_ssz( SignedBeaconBlockCapella::::from_ssz_bytes, format, )?, + "SignedBeaconBlockElectra" => decode_and_print( + &bytes, + SignedBeaconBlockElectra::::from_ssz_bytes, + format, + )?, "BeaconState" => decode_and_print::>( &bytes, |bytes| BeaconState::from_ssz_bytes(bytes, spec), @@ -95,6 +100,9 @@ pub fn run_parse_ssz( "BeaconStateCapella" => { decode_and_print(&bytes, BeaconStateCapella::::from_ssz_bytes, format)? } + "BeaconStateElectra" => { + decode_and_print(&bytes, BeaconStateElectra::::from_ssz_bytes, format)? + } other => return Err(format!("Unknown type: {}", other)), }; diff --git a/scripts/local_testnet/genesis.json b/scripts/local_testnet/genesis.json index 3ac553e55b8..56d2d1682ec 100644 --- a/scripts/local_testnet/genesis.json +++ b/scripts/local_testnet/genesis.json @@ -12,7 +12,9 @@ "berlinBlock": 0, "londonBlock": 0, "mergeNetsplitBlock": 0, + "mergeForkBlock": 0, "shanghaiTime": 0, + "pragueTime": 0, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true }, @@ -26,6 +28,9 @@ "0xdA2DD7560DB7e212B945fC72cEB54B7D8C886D77": { "balance": "10000000000000000000000000" }, + "0xf3c4A483ca812fE2e6ABFBd5d74b4b6a1Fb6B21C": { + "balance": "1000000000000000000000000000" + }, "0x0000000000000000000000000000000000000000": { "balance": "1" }, @@ -858,4 +863,4 @@ "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp": "1662465600" -} \ No newline at end of file +} diff --git a/scripts/local_testnet/geth.sh b/scripts/local_testnet/geth.sh index d3923cdd89b..c1f9fc364a7 100755 --- a/scripts/local_testnet/geth.sh +++ b/scripts/local_testnet/geth.sh @@ -39,11 +39,17 @@ $GETH_BINARY init \ --datadir $data_dir \ $genesis_file +cp ./keystore/f3c4a483ca812fe2e6abfbd5d74b4b6a1fb6b21c $1/keystore/ + echo "Completed init" exec $GETH_BINARY \ --datadir $data_dir \ --ipcdisable \ + --log.vmodule=5 \ + --allow-insecure-unlock \ + --unlock=f3c4a483ca812fe2e6abfbd5d74b4b6a1fb6b21c \ + --password=./keystore/password \ --http \ --http.api="engine,eth,web3,net,debug" \ --networkid=$CHAIN_ID \ diff --git a/scripts/local_testnet/json_rpc_snoop b/scripts/local_testnet/json_rpc_snoop new file mode 100755 index 00000000000..91d611787b2 Binary files /dev/null and b/scripts/local_testnet/json_rpc_snoop differ diff --git a/scripts/local_testnet/keystore/f3c4a483ca812fe2e6abfbd5d74b4b6a1fb6b21c b/scripts/local_testnet/keystore/f3c4a483ca812fe2e6abfbd5d74b4b6a1fb6b21c new file mode 100644 index 00000000000..57815017782 --- /dev/null +++ b/scripts/local_testnet/keystore/f3c4a483ca812fe2e6abfbd5d74b4b6a1fb6b21c @@ -0,0 +1 @@ +{"address":"f3c4a483ca812fe2e6abfbd5d74b4b6a1fb6b21c","crypto":{"cipher":"aes-128-ctr","ciphertext":"53dd14e5bb092c4dc040446ae732df281ee4cb7afd1e940ebc72b597c936c6e9","cipherparams":{"iv":"2e988d89df5df27430c1e4012f3cb729"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"bd20a76c732bf8cd6038f29e1fd4d3f4a11320adbc40c8838937638b4c7b906d"},"mac":"25ae88a52cb1b776cef32c37f3f43b20723cb6802513bb75a2dbed438042f6bb"},"id":"f51d72fe-e41b-45c2-8d2f-59ad067b1f4f","version":3} \ No newline at end of file diff --git a/scripts/local_testnet/keystore/password b/scripts/local_testnet/keystore/password new file mode 100644 index 00000000000..e69de29bb2d diff --git a/scripts/local_testnet/setup.sh b/scripts/local_testnet/setup.sh index e026ba1c020..fdcce2fbf00 100755 --- a/scripts/local_testnet/setup.sh +++ b/scripts/local_testnet/setup.sh @@ -16,7 +16,7 @@ source ./vars.env NOW=`date +%s` GENESIS_TIME=`expr $NOW + $GENESIS_DELAY` -lcli \ +RUST_BACKTRACE=1 lcli \ new-testnet \ --spec $SPEC_PRESET \ --deposit-contract-address $DEPOSIT_CONTRACT_ADDRESS \ @@ -28,6 +28,7 @@ lcli \ --altair-fork-epoch $ALTAIR_FORK_EPOCH \ --bellatrix-fork-epoch $BELLATRIX_FORK_EPOCH \ --capella-fork-epoch $CAPELLA_FORK_EPOCH \ + --electra-fork-epoch $ELECTRA_FORK_EPOCH \ --ttd $TTD \ --eth1-block-hash $ETH1_BLOCK_HASH \ --eth1-id $CHAIN_ID \ @@ -48,4 +49,4 @@ lcli \ --base-dir $DATADIR \ --node-count $VC_COUNT -echo Validators generated with keystore passwords at $DATADIR. +echo Validators generated with keystore passwords at $DATADIR. \ No newline at end of file diff --git a/scripts/local_testnet/start_local_testnet.sh b/scripts/local_testnet/start_local_testnet.sh index fdf9ae17243..81b7f1b6e85 100755 --- a/scripts/local_testnet/start_local_testnet.sh +++ b/scripts/local_testnet/start_local_testnet.sh @@ -108,6 +108,9 @@ echo $GENESIS_TIME CAPELLA_TIME=$((GENESIS_TIME + (CAPELLA_FORK_EPOCH * 32 * SECONDS_PER_SLOT))) echo $CAPELLA_TIME sed -i 's/"shanghaiTime".*$/"shanghaiTime": '"$CAPELLA_TIME"',/g' $genesis_file +PRAGUE_TIME=$((GENESIS_TIME + (ELECTRA_FORK_EPOCH * 32 * SECONDS_PER_SLOT))) +echo $PRAGUE_TIME +sed -i 's/"pragueTime".*$/"pragueTime": '"$PRAGUE_TIME"',/g' $genesis_file cat $genesis_file # Delay to let boot_enr.yaml to be created @@ -117,6 +120,14 @@ sleeping 1 execute_command_add_PID el_bootnode.log ./el_bootnode.sh sleeping 1 +# Start json_rpc_snoop +SNOOP_PORT=8646 +SNOOP_LISTEN=8999 +snoop() { + exec ./json_rpc_snoop -p $SNOOP_PORT http://localhost:$SNOOP_LISTEN +} +execute_command_add_PID snoop.log snoop + # Start beacon nodes BN_udp_tcp_base=9000 BN_http_port_base=8000 @@ -127,21 +138,29 @@ EL_base_auth_http=5000 (( $VC_COUNT < $BN_COUNT )) && SAS=-s || SAS= -for (( el=1; el<=$BN_COUNT; el++ )); do +# Reset the `genesis.json` config file fork times. +sed -i 's/"shanghaiTime".*$/"shanghaiTime": 0,/g' $genesis_file +sed -i 's/"pragueTime".*$/"pragueTime": 0,/g' $genesis_file + +for (( el=2; el<=$BN_COUNT; el++ )); do execute_command_add_PID geth_$el.log ./geth.sh $DATADIR/geth_datadir$el $((EL_base_network + $el)) $((EL_base_http + $el)) $((EL_base_auth_http + $el)) $genesis_file done -sleeping 20 +# Start geth which is connected to json_rpc_snoop +execute_command_add_PID geth_1.log ./geth.sh $DATADIR/geth_datadir1 $((EL_base_network + 1)) $((EL_base_http + 1)) $SNOOP_LISTEN $genesis_file -# Reset the `genesis.json` config file fork times. -sed -i 's/"shanghaiTime".*$/"shanghaiTime": 0,/g' $genesis_file -for (( bn=1; bn<=$BN_COUNT; bn++ )); do +sleeping 20 + +for (( bn=2; bn<=$BN_COUNT; bn++ )); do secret=$DATADIR/geth_datadir$bn/geth/jwtsecret echo $secret execute_command_add_PID beacon_node_$bn.log ./beacon_node.sh $SAS -d $DEBUG_LEVEL $DATADIR/node_$bn $((BN_udp_tcp_base + $bn)) $((BN_udp_tcp_base + $bn + 100)) $((BN_http_port_base + $bn)) http://localhost:$((EL_base_auth_http + $bn)) $secret done +# Start beacon node which is connected to json_rpc_snoop +execute_command_add_PID beacon_node_1.log ./beacon_node.sh $SAS -d $DEBUG_LEVEL $DATADIR/node_1 $((BN_udp_tcp_base + 1)) $((BN_http_port_base + 1)) http://localhost:$SNOOP_PORT $DATADIR/geth_datadir1/geth/jwtsecret + # Start requested number of validator clients for (( vc=1; vc<=$VC_COUNT; vc++ )); do execute_command_add_PID validator_node_$vc.log ./validator_client.sh $BUILDER_PROPOSALS -d $DEBUG_LEVEL $DATADIR/node_$vc http://localhost:$((BN_http_port_base + $vc)) diff --git a/scripts/local_testnet/vars.env b/scripts/local_testnet/vars.env index 6e05f0c411a..c97d8df641b 100644 --- a/scripts/local_testnet/vars.env +++ b/scripts/local_testnet/vars.env @@ -19,7 +19,8 @@ DEPOSIT_CONTRACT_ADDRESS=4242424242424242424242424242424242424242 GENESIS_FORK_VERSION=0x42424242 # Block hash generated from genesis.json in directory -ETH1_BLOCK_HASH=4b0e17cf5c04616d64526d292b80a1f2720cf2195d990006e4ea6950c5bbcb9f +#ETH1_BLOCK_HASH=4b0e17cf5c04616d64526d292b80a1f2720cf2195d990006e4ea6950c5bbcb9f +ETH1_BLOCK_HASH=fb0bad079a84b88fd9f6ec8eb0854f7bad71d34a866076c83a966efceb244405 VALIDATOR_COUNT=80 GENESIS_VALIDATOR_COUNT=80 @@ -36,7 +37,7 @@ VC_COUNT=$BN_COUNT GENESIS_DELAY=0 # Port for P2P communication with bootnode -BOOTNODE_PORT=4242 +BOOTNODE_PORT=4249 # Network ID and Chain ID of local eth1 test network CHAIN_ID=4242 @@ -44,7 +45,8 @@ CHAIN_ID=4242 # Hard fork configuration ALTAIR_FORK_EPOCH=0 BELLATRIX_FORK_EPOCH=0 -CAPELLA_FORK_EPOCH=1 +CAPELLA_FORK_EPOCH=0 +ELECTRA_FORK_EPOCH=0 TTD=0 @@ -61,4 +63,4 @@ SECONDS_PER_ETH1_BLOCK=1 PROPOSER_SCORE_BOOST=40 # Command line arguments for validator client -VC_ARGS="" +VC_ARGS="" \ No newline at end of file diff --git a/testing/ef_tests/src/cases/common.rs b/testing/ef_tests/src/cases/common.rs index a59ccb34adf..e7486fe58f1 100644 --- a/testing/ef_tests/src/cases/common.rs +++ b/testing/ef_tests/src/cases/common.rs @@ -66,6 +66,7 @@ pub fn previous_fork(fork_name: ForkName) -> ForkName { ForkName::Altair => ForkName::Base, ForkName::Merge => ForkName::Altair, // TODO: Check this when tests are released.. ForkName::Capella => ForkName::Merge, // TODO: Check this when tests are released.. + ForkName::Electra => ForkName::Capella, // TODO: Check this when tests are released.. } } diff --git a/testing/ef_tests/src/cases/epoch_processing.rs b/testing/ef_tests/src/cases/epoch_processing.rs index 5e711871560..f2e316aa435 100644 --- a/testing/ef_tests/src/cases/epoch_processing.rs +++ b/testing/ef_tests/src/cases/epoch_processing.rs @@ -101,7 +101,10 @@ impl EpochTransition for JustificationAndFinalization { justification_and_finalization_state.apply_changes_to_state(state); Ok(()) } - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => { let justification_and_finalization_state = altair::process_justification_and_finalization( state, @@ -122,13 +125,14 @@ impl EpochTransition for RewardsAndPenalties { validator_statuses.process_attestations(state)?; base::process_rewards_and_penalties(state, &validator_statuses, spec) } - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { - altair::process_rewards_and_penalties( - state, - &altair::ParticipationCache::new(state, spec).unwrap(), - spec, - ) - } + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => altair::process_rewards_and_penalties( + state, + &altair::ParticipationCache::new(state, spec).unwrap(), + spec, + ), } } } @@ -151,7 +155,10 @@ impl EpochTransition for Slashings { spec, )?; } - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => { process_slashings( state, altair::ParticipationCache::new(state, spec) @@ -203,7 +210,9 @@ impl EpochTransition for HistoricalRootsUpdate { impl EpochTransition for HistoricalSummariesUpdate { fn run(state: &mut BeaconState, _spec: &ChainSpec) -> Result<(), EpochProcessingError> { match state { - BeaconState::Capella(_) => process_historical_summaries_update(state), + BeaconState::Capella(_) | BeaconState::Electra(_) => { + process_historical_summaries_update(state) + } _ => Ok(()), } } @@ -223,9 +232,10 @@ impl EpochTransition for SyncCommitteeUpdates { fn run(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), EpochProcessingError> { match state { BeaconState::Base(_) => Ok(()), - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { - altair::process_sync_committee_updates(state, spec) - } + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => altair::process_sync_committee_updates(state, spec), } } } @@ -234,13 +244,14 @@ impl EpochTransition for InactivityUpdates { fn run(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), EpochProcessingError> { match state { BeaconState::Base(_) => Ok(()), - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { - altair::process_inactivity_updates( - state, - &altair::ParticipationCache::new(state, spec).unwrap(), - spec, - ) - } + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => altair::process_inactivity_updates( + state, + &altair::ParticipationCache::new(state, spec).unwrap(), + spec, + ), } } } @@ -249,9 +260,10 @@ impl EpochTransition for ParticipationFlagUpdates { fn run(state: &mut BeaconState, _: &ChainSpec) -> Result<(), EpochProcessingError> { match state { BeaconState::Base(_) => Ok(()), - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { - altair::process_participation_flag_updates(state) - } + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => altair::process_participation_flag_updates(state), } } } @@ -302,7 +314,7 @@ impl> Case for EpochProcessing { T::name() != "participation_record_updates" && T::name() != "historical_summaries_update" } - ForkName::Capella => { + ForkName::Capella | ForkName::Electra => { T::name() != "participation_record_updates" && T::name() != "historical_roots_update" } diff --git a/testing/ef_tests/src/cases/fork.rs b/testing/ef_tests/src/cases/fork.rs index 52157d32f8e..440ae2b887f 100644 --- a/testing/ef_tests/src/cases/fork.rs +++ b/testing/ef_tests/src/cases/fork.rs @@ -3,7 +3,9 @@ use crate::case_result::compare_beacon_state_results_without_caches; use crate::cases::common::previous_fork; use crate::decode::{ssz_decode_state, yaml_decode_file}; use serde_derive::Deserialize; -use state_processing::upgrade::{upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella}; +use state_processing::upgrade::{ + upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_electra, +}; use types::{BeaconState, ForkName}; #[derive(Debug, Clone, Default, Deserialize)] @@ -62,6 +64,7 @@ impl Case for ForkTest { ForkName::Altair => upgrade_to_altair(&mut result_state, spec).map(|_| result_state), ForkName::Merge => upgrade_to_bellatrix(&mut result_state, spec).map(|_| result_state), ForkName::Capella => upgrade_to_capella(&mut result_state, spec).map(|_| result_state), + ForkName::Electra => upgrade_to_electra(&mut result_state, spec).map(|_| result_state), }; compare_beacon_state_results_without_caches(&mut result, &mut expected) diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index 21a56dcf2a7..9d9a25f45d4 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -96,7 +96,10 @@ impl Operation for Attestation { &mut ctxt, spec, ), - BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Capella(_) => { + BeaconState::Altair(_) + | BeaconState::Merge(_) + | BeaconState::Capella(_) + | BeaconState::Electra(_) => { initialize_progressive_balances_cache(state, None, spec)?; altair::process_attestation(state, self, 0, &mut ctxt, VerifySignatures::True, spec) } diff --git a/testing/ef_tests/src/cases/transition.rs b/testing/ef_tests/src/cases/transition.rs index bb4efdb6de9..d796bb7d4d8 100644 --- a/testing/ef_tests/src/cases/transition.rs +++ b/testing/ef_tests/src/cases/transition.rs @@ -47,6 +47,12 @@ impl LoadCase for TransitionTest { spec.bellatrix_fork_epoch = Some(Epoch::new(0)); spec.capella_fork_epoch = Some(metadata.fork_epoch); } + ForkName::Electra => { + spec.altair_fork_epoch = Some(Epoch::new(0)); + spec.bellatrix_fork_epoch = Some(Epoch::new(0)); + spec.capella_fork_epoch = Some(Epoch::new(0)); + spec.electra_fork_epoch = Some(metadata.fork_epoch); + } } // Load blocks diff --git a/validator_client/src/beacon_node_fallback.rs b/validator_client/src/beacon_node_fallback.rs index 531cec08ac5..58ee4708518 100644 --- a/validator_client/src/beacon_node_fallback.rs +++ b/validator_client/src/beacon_node_fallback.rs @@ -296,6 +296,14 @@ impl CandidateBeaconNode { "endpoint_capella_fork_epoch" => ?beacon_node_spec.capella_fork_epoch, "hint" => UPDATE_REQUIRED_LOG_HINT, ); + } else if beacon_node_spec.electra_fork_epoch != spec.electra_fork_epoch { + warn!( + log, + "Beacon node has mismatched Electra fork epoch"; + "endpoint" => %self.beacon_node, + "endpoint_electra_fork_epoch" => ?beacon_node_spec.electra_fork_epoch, + "hint" => UPDATE_REQUIRED_LOG_HINT, + ); } Ok(()) diff --git a/validator_client/src/signing_method/web3signer.rs b/validator_client/src/signing_method/web3signer.rs index 2c1f0cb3fc6..9a902f46a26 100644 --- a/validator_client/src/signing_method/web3signer.rs +++ b/validator_client/src/signing_method/web3signer.rs @@ -27,6 +27,7 @@ pub enum ForkName { Altair, Bellatrix, Capella, + Electra, } #[derive(Debug, PartialEq, Serialize)] @@ -95,6 +96,11 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload> Web3SignerObject<'a, T, Pa block: None, block_header: Some(block.block_header()), }), + BeaconBlock::Electra(_) => Ok(Web3SignerObject::BeaconBlock { + version: ForkName::Electra, + block: None, + block_header: Some(block.block_header()), + }), } }