Verify execution block hashes during finalized sync (#3794)

## Issue Addressed

Recent discussions with other client devs about optimistic sync have revealed a conceptual issue with the optimisation implemented in #3738. In designing that feature I failed to consider that the execution node checks the `blockHash` of the execution payload before responding with `SYNCING`, and that omitting this check entirely results in a degradation of the full node's validation. A node omitting the `blockHash` checks could be tricked by a supermajority of validators into following an invalid chain, something which is ordinarily impossible.

## Proposed Changes

I've added verification of the `payload.block_hash` in Lighthouse. In case of failure we log a warning and fall back to verifying the payload with the execution client.

I've used our existing dependency on `ethers_core` for RLP support, and a new dependency on Parity's `triehash` crate for the Merkle patricia trie. Although the `triehash` crate is currently unmaintained it seems like our best option at the moment (it is also used by Reth, and requires vastly less boilerplate than Parity's generic `trie-root` library).

Block hash verification is pretty quick, about 500us per block on my machine (mainnet).

The optimistic finalized sync feature can be disabled using `--disable-optimistic-finalized-sync` which forces full verification with the EL.

## Additional Info

This PR also introduces a new dependency on our [`metastruct`](https://github.com/sigp/metastruct) library, which was perfectly suited to the RLP serialization method. There will likely be changes as `metastruct` grows, but I think this is a good way to start dogfooding it.

I took inspiration from some Parity and Reth code while writing this, and have preserved the relevant license headers on the files containing code that was copied and modified.
This commit is contained in:
Michael Sproul
2023-01-09 03:11:59 +00:00
parent 1d9a2022b4
commit 4bd2b777ec
27 changed files with 561 additions and 257 deletions

403
Cargo.lock generated
View File

@@ -755,7 +755,7 @@ dependencies = [
"eth2_hashing",
"eth2_serde_utils",
"eth2_ssz",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"hex",
"milagro_bls",
"rand 0.7.3",
@@ -804,51 +804,6 @@ dependencies = [
"types",
]
[[package]]
name = "borsh"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa"
dependencies = [
"borsh-derive",
"hashbrown 0.11.2",
]
[[package]]
name = "borsh-derive"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775"
dependencies = [
"borsh-derive-internal",
"borsh-schema-derive-internal",
"proc-macro-crate 0.1.5",
"proc-macro2",
"syn",
]
[[package]]
name = "borsh-derive-internal"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "borsh-schema-derive-internal"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "bs58"
version = "0.4.0"
@@ -900,27 +855,6 @@ version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
[[package]]
name = "bytecheck"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d11cac2c12b5adc6570dad2ee1b87eff4955dac476fe12d81e5fdd352e52406f"
dependencies = [
"bytecheck_derive",
"ptr_meta",
]
[[package]]
name = "bytecheck_derive"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -965,7 +899,7 @@ dependencies = [
"eth2_ssz",
"eth2_ssz_derive",
"eth2_ssz_types",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"quickcheck",
"quickcheck_macros",
"smallvec",
@@ -1102,7 +1036,7 @@ dependencies = [
"dirs",
"eth2_network_config",
"eth2_ssz",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"hex",
"serde",
"serde_json",
@@ -1972,7 +1906,7 @@ dependencies = [
"derivative",
"eth2_ssz",
"eth2_ssz_derive",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"execution_layer",
"fork_choice",
"fs2",
@@ -2273,7 +2207,7 @@ dependencies = [
name = "eth2_serde_utils"
version = "0.1.1"
dependencies = [
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"hex",
"serde",
"serde_derive",
@@ -2285,7 +2219,7 @@ name = "eth2_ssz"
version = "0.4.1"
dependencies = [
"eth2_ssz_derive",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"itertools",
"smallvec",
]
@@ -2359,11 +2293,11 @@ dependencies = [
[[package]]
name = "ethabi"
version = "17.2.0"
version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b"
checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898"
dependencies = [
"ethereum-types 0.13.1",
"ethereum-types 0.14.1",
"hex",
"once_cell",
"regex",
@@ -2381,22 +2315,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8"
dependencies = [
"crunchy",
"fixed-hash",
"fixed-hash 0.7.0",
"impl-rlp",
"impl-serde",
"impl-serde 0.3.2",
"tiny-keccak",
]
[[package]]
name = "ethbloom"
version = "0.12.1"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef"
checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60"
dependencies = [
"crunchy",
"fixed-hash",
"fixed-hash 0.8.0",
"impl-codec 0.6.0",
"impl-rlp",
"impl-serde",
"impl-serde 0.4.0",
"scale-info",
"tiny-keccak",
]
@@ -2429,46 +2365,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf"
dependencies = [
"ethbloom 0.11.1",
"fixed-hash",
"fixed-hash 0.7.0",
"impl-rlp",
"impl-serde",
"impl-serde 0.3.2",
"primitive-types 0.10.1",
"uint",
]
[[package]]
name = "ethereum-types"
version = "0.13.1"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6"
checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee"
dependencies = [
"ethbloom 0.12.1",
"fixed-hash",
"ethbloom 0.13.0",
"fixed-hash 0.8.0",
"impl-codec 0.6.0",
"impl-rlp",
"impl-serde",
"primitive-types 0.11.1",
"impl-serde 0.4.0",
"primitive-types 0.12.1",
"scale-info",
"uint",
]
[[package]]
name = "ethers-core"
version = "0.17.0"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ebdd63c828f58aa067f40f9adcbea5e114fb1f90144b3a1e2858e0c9b1ff4e8"
checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15"
dependencies = [
"arrayvec",
"bytes",
"chrono",
"elliptic-curve",
"ethabi 17.2.0",
"fastrlp",
"ethabi 18.0.0",
"generic-array",
"hex",
"k256",
"open-fastrlp",
"rand 0.8.5",
"rlp",
"rlp-derive",
"rust_decimal",
"serde",
"serde_json",
"strum",
@@ -2479,9 +2416,9 @@ dependencies = [
[[package]]
name = "ethers-providers"
version = "0.17.0"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e46482e4d1e79b20c338fd9db9e166184eb387f0a4e7c05c5b5c0aa2e8c8900c"
checksum = "a1a9e0597aa6b2fdc810ff58bc95e4eeaa2c219b3e615ed025106ecb027407d8"
dependencies = [
"async-trait",
"auto_impl",
@@ -2560,8 +2497,11 @@ dependencies = [
"exit-future",
"fork_choice",
"futures",
"hash-db",
"hash256-std-hasher",
"hex",
"jsonwebtoken",
"keccak-hash",
"lazy_static",
"lighthouse_metrics",
"lru 0.7.8",
@@ -2583,6 +2523,7 @@ dependencies = [
"tokio-stream",
"tree_hash",
"tree_hash_derive",
"triehash",
"types",
"warp",
"zeroize",
@@ -2618,31 +2559,6 @@ dependencies = [
"instant",
]
[[package]]
name = "fastrlp"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "089263294bb1c38ac73649a6ad563dd9a5142c8dc0482be15b8b9acb22a1611e"
dependencies = [
"arrayvec",
"auto_impl",
"bytes",
"ethereum-types 0.13.1",
"fastrlp-derive",
]
[[package]]
name = "fastrlp-derive"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6e454d03710df0cd95ce075d7731ce3fa35fb3779c15270cd491bc5f2ef9355"
dependencies = [
"bytes",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ff"
version = "0.12.1"
@@ -2687,6 +2603,18 @@ dependencies = [
name = "fixed-hash"
version = "0.7.0"
source = "git+https://github.com/paritytech/parity-common?rev=df638ab0885293d21d656dc300d39236b69ce57d#df638ab0885293d21d656dc300d39236b69ce57d"
dependencies = [
"byteorder",
"rand 0.8.5",
"rustc-hex",
"static_assertions",
]
[[package]]
name = "fixed-hash"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534"
dependencies = [
"arbitrary",
"byteorder",
@@ -3057,6 +2985,21 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hash-db"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a"
[[package]]
name = "hash256-std-hasher"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2"
dependencies = [
"crunchy",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
@@ -3525,6 +3468,15 @@ dependencies = [
"serde",
]
[[package]]
name = "impl-serde"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd"
dependencies = [
"serde",
]
[[package]]
name = "impl-trait-for-tuples"
version = "0.2.2"
@@ -3694,6 +3646,16 @@ dependencies = [
"cpufeatures",
]
[[package]]
name = "keccak-hash"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c"
dependencies = [
"primitive-types 0.12.1",
"tiny-keccak",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -4627,13 +4589,36 @@ name = "merkle_proof"
version = "0.2.0"
dependencies = [
"eth2_hashing",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"lazy_static",
"quickcheck",
"quickcheck_macros",
"safe_arith",
]
[[package]]
name = "metastruct"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "734788dec2091fe9afa39530ca2ea7994f4a2c9aff3dbfebb63f2c1945c6f10b"
dependencies = [
"metastruct_macro",
]
[[package]]
name = "metastruct_macro"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ded15e7570c2a507a23e6c3a1c8d74507b779476e43afe93ddfc261d44173d"
dependencies = [
"darling 0.13.4",
"itertools",
"proc-macro2",
"quote",
"smallvec",
"syn",
]
[[package]]
name = "mev-build-rs"
version = "0.2.1"
@@ -4797,7 +4782,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db"
dependencies = [
"proc-macro-crate 1.1.3",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
@@ -4952,7 +4937,7 @@ dependencies = [
"error-chain",
"eth2_ssz",
"eth2_ssz_types",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"exit-future",
"fnv",
"futures",
@@ -5209,6 +5194,31 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "open-fastrlp"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce"
dependencies = [
"arrayvec",
"auto_impl",
"bytes",
"ethereum-types 0.14.1",
"open-fastrlp-derive",
]
[[package]]
name = "open-fastrlp-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c"
dependencies = [
"bytes",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl"
version = "0.10.44"
@@ -5359,7 +5369,7 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27"
dependencies = [
"proc-macro-crate 1.1.3",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
@@ -5371,7 +5381,7 @@ version = "3.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd"
dependencies = [
"proc-macro-crate 1.1.3",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
@@ -5679,35 +5689,27 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373"
dependencies = [
"fixed-hash",
"fixed-hash 0.7.0",
"impl-codec 0.5.1",
"impl-rlp",
"impl-serde",
"impl-serde 0.3.2",
"uint",
]
[[package]]
name = "primitive-types"
version = "0.11.1"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a"
checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66"
dependencies = [
"fixed-hash",
"fixed-hash 0.8.0",
"impl-codec 0.6.0",
"impl-rlp",
"impl-serde",
"impl-serde 0.4.0",
"scale-info",
"uint",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
]
[[package]]
name = "proc-macro-crate"
version = "1.1.3"
@@ -5913,26 +5915,6 @@ dependencies = [
"unescape",
]
[[package]]
name = "ptr_meta"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
dependencies = [
"ptr_meta_derive",
]
[[package]]
name = "ptr_meta_derive"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "quick-error"
version = "1.2.3"
@@ -6215,15 +6197,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "rend"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95"
dependencies = [
"bytecheck",
]
[[package]]
name = "reqwest"
version = "0.11.13"
@@ -6303,31 +6276,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "rkyv"
version = "0.7.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15"
dependencies = [
"bytecheck",
"hashbrown 0.12.3",
"ptr_meta",
"rend",
"rkyv_derive",
"seahash",
]
[[package]]
name = "rkyv_derive"
version = "0.7.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "rle-decode-fast"
version = "1.0.3"
@@ -6420,24 +6368,6 @@ dependencies = [
"smallvec",
]
[[package]]
name = "rust_decimal"
version = "1.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9"
dependencies = [
"arrayvec",
"borsh",
"bytecheck",
"byteorder",
"bytes",
"num-traits",
"rand 0.8.5",
"rkyv",
"serde",
"serde_json",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
@@ -6577,6 +6507,30 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scale-info"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608"
dependencies = [
"cfg-if",
"derive_more",
"parity-scale-codec 3.2.1",
"scale-info-derive",
]
[[package]]
name = "scale-info-derive"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "schannel"
version = "0.1.20"
@@ -6658,12 +6612,6 @@ dependencies = [
"url",
]
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "sec1"
version = "0.3.0"
@@ -7466,7 +7414,7 @@ version = "0.2.0"
dependencies = [
"criterion",
"eth2_hashing",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
]
[[package]]
@@ -8087,7 +8035,7 @@ dependencies = [
"eth2_hashing",
"eth2_ssz",
"eth2_ssz_derive",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"rand 0.8.5",
"smallvec",
"tree_hash_derive",
@@ -8103,6 +8051,16 @@ dependencies = [
"syn",
]
[[package]]
name = "triehash"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1631b201eb031b563d2e85ca18ec8092508e262a3196ce9bd10a67ec87b9f5c"
dependencies = [
"hash-db",
"rlp",
]
[[package]]
name = "trust-dns-proto"
version = "0.22.0"
@@ -8247,7 +8205,7 @@ dependencies = [
"eth2_ssz",
"eth2_ssz_derive",
"eth2_ssz_types",
"ethereum-types 0.12.1",
"ethereum-types 0.14.1",
"hex",
"int_to_bytes",
"itertools",
@@ -8255,6 +8213,7 @@ dependencies = [
"log",
"maplit",
"merkle_proof",
"metastruct",
"parking_lot 0.12.1",
"rand 0.8.5",
"rand_xorshift",