Snowbridge: Synchronize from Snowfork repository (#3761)

This PR includes the following 2 improvements:

## Ethereum Client

Author: @yrong 
### Original Upstream PRs
- https://github.com/Snowfork/polkadot-sdk/pull/123
- https://github.com/Snowfork/polkadot-sdk/pull/125

### Description
The Ethereum client syncs beacon headers as they are finalized, and
imports every execution header. When a message is received, it is
verified against the import execution header. This is unnecessary, since
the execution header can be sent with the message as proof. The recent
Deneb Ethereum upgrade made it easier to locate the relevant beacon
header from an execution header, and so this improvement was made
possible. This resolves a concern @svyatonik had in our initial Rococo
PR:
https://github.com/paritytech/polkadot-sdk/pull/2522#discussion_r1431270691

## Inbound Queue

Author: @yrong 
### Original Upstream PR
- https://github.com/Snowfork/polkadot-sdk/pull/118

### Description
When the AH sovereign account (who pays relayer rewards) is depleted,
the inbound message will not fail. The relayer just will not receive
rewards.

Both these changes were done by @yrong, many thanks. ❤️

---------

Co-authored-by: claravanstaden <Cats 4 life!>
Co-authored-by: Ron <yrong1997@gmail.com>
Co-authored-by: Vincent Geddes <vincent@snowfork.com>
Co-authored-by: Svyatoslav Nikolsky <svyatonik@gmail.com>
This commit is contained in:
Clara van Staden
2024-04-02 15:53:05 +02:00
committed by GitHub
parent e54279699b
commit 5d9826c262
35 changed files with 1123 additions and 1307 deletions
@@ -6,9 +6,10 @@
use hex_literal::hex;
use snowbridge_beacon_primitives::{
types::deneb, updates::AncestryProof, BeaconHeader, ExecutionHeaderUpdate,
NextSyncCommitteeUpdate, SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader,
types::deneb, AncestryProof, BeaconHeader, ExecutionProof, NextSyncCommitteeUpdate,
SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader,
};
use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof};
use sp_core::U256;
use sp_std::{boxed::Box, vec};
@@ -20,11 +21,11 @@ type Update = snowbridge_beacon_primitives::Update<SC_SIZE, SC_BITS_SIZE>;
pub fn make_checkpoint() -> Box<CheckpointUpdate> {
Box::new(CheckpointUpdate {
header: BeaconHeader {
slot: 2496,
proposer_index: 2,
parent_root: hex!("c99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622").into(),
state_root: hex!("fbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde").into(),
body_root: hex!("a2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0").into(),
slot: 864,
proposer_index: 4,
parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(),
state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(),
body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(),
},
current_sync_committee: SyncCommittee {
pubkeys: [
@@ -544,20 +545,20 @@ pub fn make_checkpoint() -> Box<CheckpointUpdate> {
aggregate_pubkey: hex!("8fbd66eeec2ff69ef0b836f04b1d67d88bcd4dfd495061964ad757c77abe822a39fa1cd8ed0d4d9bc9276cea73fd745c").into(),
},
current_sync_committee_branch: vec![
hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(),
hex!("93880225bf99a0c5ec22b266ff829837754e9c5edf37a68c05b8f803fd82fa45").into(),
hex!("4c60656ec9a95fcf11030ad309c716b5b15beb7f60a0bcfc7c9d4eff505472ff").into(),
hex!("22d1645fceb4bf9a695043dda19a53e784ec70df6a6b1bd66ea30eba1cca5f2f").into(),
hex!("a8fc6cad84ceefc633ec56c2d031d525e1cb4b51c70eb252919fce5bba9a1fde").into(),
hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(),
hex!("a9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e").into(),
hex!("bd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75").into(),
hex!("07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7").into(),
hex!("94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0").into(),
],
validators_root: hex!("270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69").into(),
block_roots_root: hex!("d160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe").into(),
block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(),
block_roots_branch: vec![
hex!("105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135").into(),
hex!("9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99").into(),
hex!("ecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5").into(),
hex!("b2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2").into(),
hex!("cd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf").into(),
hex!("733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f").into(),
hex!("9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa").into(),
hex!("bcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf").into(),
hex!("3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5").into(),
hex!("c2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4").into(),
],
})
}
@@ -567,13 +568,13 @@ pub fn make_sync_committee_update() -> Box<Update> {
attested_header: BeaconHeader {
slot: 129,
proposer_index: 5,
parent_root: hex!("e32b6c18f029e755b0273dc1c4fa2bc4979794c8286ad40276c1b8a8e36049d8").into(),
state_root: hex!("5ec9dacf25a5f09f20be0c59246b3d8dcfe64bd085b4bac5cec180690339801e").into(),
body_root: hex!("4080cf2412d6ff77fc3164ad6155423a7112f207f173145ec16371a93f481f87").into(),
parent_root: hex!("c2def03fe44a2802130ca1a6d8406e4ccf4f344fec7075d4d84431cd4a8b0904").into(),
state_root: hex!("fa62cde6666add7353d7aedcb61ebe3c6c84b5361e34f814825b1250affb5be4").into(),
body_root: hex!("0f9c69f243fe7b5fa5860396c66c720a9e8b1e526e7914188930497cc4a9134c").into(),
},
sync_aggregate: SyncAggregate{
sync_committee_bits: hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
sync_committee_signature: hex!("a761c3333fbb3d36bc8f65454f898da38001499dcd37494cf3d86940a995399ae649216ba4c985af154f83f72c8b1856079b7636a7a8d7d3f7602df2cbf699edb72b65253e82de4d9cc4db7377eafb22f799129f63f094a21c00675bdd5cc243").into(),
sync_committee_signature: hex!("810cfde2afea3e276256c09bdf1cd321c33dcadeefddcfd24f488e6f756d917cfda90b5b437b3a4b4ef880985afa28a40cf565ec0a82877ddee36adc01d55d9d4a911ae3e22556e4c2636f1c707366fba019fb49450440fcd263d0b054b04bf0").into(),
},
signature_slot: 130,
next_sync_committee_update: Some(NextSyncCommitteeUpdate {
@@ -1096,34 +1097,34 @@ pub fn make_sync_committee_update() -> Box<Update> {
},
next_sync_committee_branch: vec![
hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(),
hex!("fd1e5ff5d4a15081efe3ff17857b1f95984c9a271b1c41c2f81f43e60c2cc541").into(),
hex!("e1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d").into(),
hex!("77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61").into(),
hex!("e97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68").into(),
hex!("43276bee17fc9fba3f4866e902f0e5b5b308d79db91154bb8bf819973837a7d9").into(),
hex!("5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd").into(),
hex!("2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221").into(),
hex!("7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f").into(),
],
}),
finalized_header: BeaconHeader{
slot: 64,
proposer_index: 4,
parent_root: hex!("0f7bc2353778c14c7f6dba0fc5fe6eec87228b0d3a5447b61dce67b4d9338de3").into(),
state_root: hex!("feb990de653ce494c0a263f820eaf05a9300dbdc30cb6065ede602827bfccde4").into(),
body_root: hex!("f5235cd8c24f2695fc5b7989926305c10ad8cf5a87d62a739f675f5543df2ec1").into(),
parent_root: hex!("a876486aaad7ddb897f369fd22d0a9903cd61d00c9e0dfe7998dd68d1008c678").into(),
state_root: hex!("818e21c3388575f8ccc9ff17ec79d5a57915bcd31bccf47770f65a18e068416b").into(),
body_root: hex!("1d1f73b864b3bb7e11ff91b56ca1381e0f9ca8122b2c542db88243604c763019").into(),
},
finality_branch: vec![
hex!("0200000000000000000000000000000000000000000000000000000000000000").into(),
hex!("10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7").into(),
hex!("98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d").into(),
hex!("e1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d").into(),
hex!("77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61").into(),
hex!("e97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68").into(),
hex!("5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd").into(),
hex!("2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221").into(),
hex!("7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f").into(),
],
block_roots_root: hex!("6fcdfd1c3fb1bdd421fe59dddfff3855b5ed5e30373887991a0059d019ad12bc").into(),
block_roots_root: hex!("715b08694bef183a6d94b3113d16a7129f89fc3edec85a7e0eaf6ef9153552ef").into(),
block_roots_branch: vec![
hex!("94b59531f172bc24f914bc0c10104ccb158676850f8cc3b47b6ddb7f096ebdd7").into(),
hex!("22470ed9155a938587d44d5fa19217c0f939d8862e504e67cd8cb4d1b960795e").into(),
hex!("feec3ef1a68f93849e71e84f90b99602cccc31868137b6887ca8244a4b979e8e").into(),
hex!("4028c72c71b6ce80ea7d18b2c9471f4e4fa39746261a9921e832a4a2f9bdf7bb").into(),
hex!("75f98062661785d3290b7bd998b64446582baa49210733fd4603e1a97cd45a44").into(),
hex!("6fb757f44052f30c464810f01b0132adfa1a5446d8715b41e9af88eee1ee3e65").into(),
hex!("5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82").into(),
hex!("f5ff4b0c6190005015889879568f5f0d9c40134c7ec4ffdda47950dcd92395ad").into(),
hex!("f2b3cb56753939a728ccad399a434ca490f018f2f331529ec0d8b2d59c509271").into(),
],
})
}
@@ -1131,95 +1132,180 @@ pub fn make_sync_committee_update() -> Box<Update> {
pub fn make_finalized_header_update() -> Box<Update> {
Box::new(Update {
attested_header: BeaconHeader {
slot: 2566,
proposer_index: 6,
parent_root: hex!("6eb9f13a2c496318ce1ab3087bbd872f5c9519a1a7ca8231a2453e3cb523af00").into(),
state_root: hex!("c8cb12766113dff7e46d2917267bf33d0626d99dd47715fcdbc5c65fad3c04b4").into(),
body_root: hex!("d8cfd0d7bc9bc3724417a1655bb0a67c0765ca36197320f4d834150b52ef1420").into(),
slot: 933,
proposer_index: 1,
parent_root: hex!("f5fc63e2780ca302b97aea73fc95d74d702b5afe9a772c2b68f695026337b620").into(),
state_root: hex!("d856d11636bc4d866e78be9e747b222b0977556a367ab42e4085277301438050").into(),
body_root: hex!("5689091ab4eb76c2e876271add4924e1c66ce987c300c24aac2ad8c703e9a33f").into(),
},
sync_aggregate: SyncAggregate{
sync_committee_bits: hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
sync_committee_signature: hex!("9296f9a0387f2cac47008e22ad7c3cd3d49d35384c13e6aa1eacca7dca7c3d2ca81515e50eb3396b9550ed20ef7d8fa2049a186598feb2c00e93728045fcff917733d1827481b8fc95f3913e27fc70112c2490496eb57bb7181f02c3f9fd471f").into(),
sync_committee_signature: hex!("93a3d482fe2a2f7fd2b634169752a8fddf1dc28b23a020b398be8526faf37a74ca0f6db1bed78a9c7256c09a6115235e108e0e8a7ce09287317b0856c4b77dfa5adba6cf4c3ebea5bfa4cd2fcde80fd0a532f2defe65d530201d5d2258796559").into(),
},
signature_slot: 2567,
signature_slot: 934,
next_sync_committee_update: None,
finalized_header: BeaconHeader {
slot: 2496,
proposer_index: 2,
parent_root: hex!("c99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622").into(),
state_root: hex!("fbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde").into(),
body_root: hex!("a2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0").into(),
slot: 864,
proposer_index: 4,
parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(),
state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(),
body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(),
},
finality_branch: vec![
hex!("4e00000000000000000000000000000000000000000000000000000000000000").into(),
hex!("1b00000000000000000000000000000000000000000000000000000000000000").into(),
hex!("10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7").into(),
hex!("98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d").into(),
hex!("958b8e43347f6df6fa5eb3d62d06a862381a6585aa40640dd1c0de11f1cf89c1").into(),
hex!("f107dce04faa86a28fc5d4a618be9cb8d4fc3c23d6c42c3624f3ff4bf6586a03").into(),
hex!("a501cdc02e86969ac3e4d0c5a36f4f049efaa1ab8cb6693f51d130eb52a80f30").into(),
hex!("f12d9aededc72724e417b518fe6f847684f26f81616243dedf8c551cc7d504f5").into(),
hex!("89a85d0907ab3fd6e00ae385f61d456c6191646404ae7b8d23d0e60440cf4d00").into(),
hex!("9fc943b6020eb61d780d78bcc6f6102a81d2c868d58f36e61c6e286a2dc4d8c2").into(),
],
block_roots_root: hex!("d160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe").into(),
block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(),
block_roots_branch: vec![
hex!("105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135").into(),
hex!("9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99").into(),
hex!("ecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5").into(),
hex!("b2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2").into(),
hex!("cd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf").into(),
hex!("733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f").into(),
hex!("9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa").into(),
hex!("bcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf").into(),
hex!("3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5").into(),
hex!("c2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4").into(),
]
})
}
pub fn make_execution_header_update() -> Box<ExecutionHeaderUpdate> {
Box::new(ExecutionHeaderUpdate {
pub fn make_execution_proof() -> Box<ExecutionProof> {
Box::new(ExecutionProof {
header: BeaconHeader {
slot: 215,
proposer_index: 2,
parent_root: hex!("97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45").into(),
state_root: hex!("b088b5a3a8c90d6dc919a695cd7bb0267c6f983ea2e675c559ceb8f46cb90b67").into(),
body_root: hex!("0ba23c8224fdd01531d5ad51486353bd524a0b4c20bca704e26d3210616f829b").into(),
slot: 393,
proposer_index: 4,
parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(),
state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(),
body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(),
},
ancestry_proof: Some(AncestryProof {
header_branch: vec![
hex!("97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45").into(),
hex!("5ce0db996bd499c2b4f7a93263d5aafd052f420efb617cce6fdd54e25516aa45").into(),
hex!("84f0e373b66011ce774c7061440c0a50a51cce2b4b335395eee3e563d605597f").into(),
hex!("48f9ccc5f9594142c18c3b5c39a99f0549329c6ab3ba06c9a50030eadca87770").into(),
hex!("f89d6e311e05bc75a6f63ce118bccce254551f1a88d54c3b4f773f81f946bd99").into(),
hex!("2edd6d893c22636675147c07dfcdb541a146e87c3f15b51c388be4868246dc9b").into(),
hex!("d76b7de5f856e3208a91a42c9c398a7f4fab35e667bf916346050ae742514a2d").into(),
hex!("83a2e233e76385953ca41de4c3afe60471a61f0cc1b3846b4a0670e3e563b747").into(),
hex!("e783a5a109c2ad74e4eb53e8f6b11b31266a92a9e16c1fd5873109c5d41b282c").into(),
hex!("d4ea1ef3869ee6a0fd0b19d7d70027d144eecd4f1d32cbf47632a0a9069164b9").into(),
hex!("f8179564b58eb93a850d35e4156a04db651106442ad891c3e85155c1762792f1").into(),
hex!("4cbb1edb48cf1e32fb30db60aaaeaf6190ffe4d0c8dbc96cec307daecb78be12").into(),
hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(),
hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(),
hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(),
hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(),
hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(),
hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(),
hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(),
hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(),
hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(),
hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(),
hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(),
hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(),
hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(),
],
finalized_block_root: hex!("890a7f23b9ed2160901654be9efc575d6830ca860e2a97866ae3423fb7bd7231").into(),
finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(),
}),
execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
parent_hash: hex!("d82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a").into(),
parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(),
fee_recipient: hex!("0000000000000000000000000000000000000000").into(),
state_root: hex!("8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3").into(),
receipts_root: hex!("7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095").into(),
logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010").into(),
prev_randao: hex!("6d9e2a012d82b1b6cb0a2c1c1ed24cc16dbb56e6e39ae545371e0666ab057862").into(),
block_number: 215,
gas_limit: 64842908,
gas_used: 119301,
timestamp: 1705859527,
extra_data: hex!("d983010d0a846765746888676f312e32312e358664617277696e").into(),
state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(),
receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(),
logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(),
prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(),
block_number: 393,
gas_limit: 54492273,
gas_used: 199644,
timestamp: 1710552813,
extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(),
base_fee_per_gas: U256::from(7u64),
block_hash: hex!("48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98").into(),
transactions_root: hex!("5ebc1347fe3df0611d4f66b19bd8e1c6f4eaed0371d850f14c83b1c77ea234e6").into(),
block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(),
transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(),
withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(),
blob_gas_used: 0,
excess_blob_gas: 0,
}),
execution_branch: vec![
hex!("f8c69d3830406d668619bcccc13c8dddde41e863326f7418b241d5924c4ad34a").into(),
hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(),
hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(),
hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(),
hex!("f4d6b5cf9c6e212615c3674fa625d04eb1114153fb221ef5ad02aa433fc67cfb").into(),
hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(),
],
})
}
pub fn make_inbound_fixture() -> InboundQueueFixture {
InboundQueueFixture {
message: Message {
event_log: Log {
address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(),
],
data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(),
},
proof: Proof {
receipt_proof: (vec![
hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").to_vec(),
hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(),
], vec![
hex!("f851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080").to_vec(),
hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(),
]),
execution_proof: ExecutionProof {
header: BeaconHeader {
slot: 393,
proposer_index: 4,
parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(),
state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(),
body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(),
},
ancestry_proof: Some(AncestryProof {
header_branch: vec![
hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(),
hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(),
hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(),
hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(),
hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(),
hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(),
hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(),
hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(),
hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(),
hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(),
hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(),
hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(),
hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(),
],
finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(),
}),
execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(),
fee_recipient: hex!("0000000000000000000000000000000000000000").into(),
state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(),
receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(),
logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(),
prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(),
block_number: 393,
gas_limit: 54492273,
gas_used: 199644,
timestamp: 1710552813,
extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(),
base_fee_per_gas: U256::from(7u64),
block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(),
transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(),
withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(),
blob_gas_used: 0,
excess_blob_gas: 0,
}),
execution_branch: vec![
hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(),
hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(),
hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(),
hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(),
],
}
},
},
finalized_header: BeaconHeader {
slot: 864,
proposer_index: 4,
parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(),
state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(),
body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(),
},
block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(),
}
}
@@ -65,24 +65,6 @@ mod benchmarks {
Ok(())
}
#[benchmark]
fn submit_execution_header() -> Result<(), BenchmarkError> {
let caller: T::AccountId = whitelisted_caller();
let checkpoint_update = make_checkpoint();
let finalized_header_update = make_finalized_header_update();
let execution_header_update = make_execution_header_update();
let execution_header_hash = execution_header_update.execution_header.block_hash();
EthereumBeaconClient::<T>::process_checkpoint_update(&checkpoint_update)?;
EthereumBeaconClient::<T>::process_update(&finalized_header_update)?;
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), Box::new(*execution_header_update));
assert!(<ExecutionHeaders<T>>::contains_key(execution_header_hash));
Ok(())
}
#[benchmark(extra)]
fn bls_fast_aggregate_verify_pre_aggregated() -> Result<(), BenchmarkError> {
EthereumBeaconClient::<T>::process_checkpoint_update(&make_checkpoint())?;
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use super::*;
use frame_support::ensure;
use primitives::ExecutionProof;
use snowbridge_core::inbound::{
VerificationError::{self, *},
@@ -14,32 +16,13 @@ impl<T: Config> Verifier for Pallet<T> {
/// the log should be in the beacon client storage, meaning it has been verified and is an
/// ancestor of a finalized beacon block.
fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> {
log::info!(
target: "ethereum-client",
"💫 Verifying message with block hash {}",
proof.block_hash,
);
Self::verify_execution_proof(&proof.execution_proof)
.map_err(|e| InvalidExecutionProof(e.into()))?;
let header = <ExecutionHeaderBuffer<T>>::get(proof.block_hash).ok_or(HeaderNotFound)?;
let receipt = match Self::verify_receipt_inclusion(header.receipts_root, proof) {
Ok(receipt) => receipt,
Err(err) => {
log::error!(
target: "ethereum-client",
"💫 Verification of receipt inclusion failed for block {}: {:?}",
proof.block_hash,
err
);
return Err(err)
},
};
log::trace!(
target: "ethereum-client",
"💫 Verified receipt inclusion for transaction at index {} in block {}",
proof.tx_index, proof.block_hash,
);
let receipt = Self::verify_receipt_inclusion(
proof.execution_proof.execution_header.receipts_root(),
&proof.receipt_proof.1,
)?;
event_log.validate().map_err(|_| InvalidLog)?;
@@ -53,18 +36,11 @@ impl<T: Config> Verifier for Pallet<T> {
if !receipt.contains_log(&event_log) {
log::error!(
target: "ethereum-client",
"💫 Event log not found in receipt for transaction at index {} in block {}",
proof.tx_index, proof.block_hash,
"💫 Event log not found in receipt for transaction",
);
return Err(LogNotFound)
}
log::info!(
target: "ethereum-client",
"💫 Receipt verification successful for {}",
proof.block_hash,
);
Ok(())
}
}
@@ -74,9 +50,9 @@ impl<T: Config> Pallet<T> {
/// `proof.block_hash`.
pub fn verify_receipt_inclusion(
receipts_root: H256,
proof: &Proof,
receipt_proof: &[Vec<u8>],
) -> Result<Receipt, VerificationError> {
let result = verify_receipt_proof(receipts_root, &proof.data.1).ok_or(InvalidProof)?;
let result = verify_receipt_proof(receipts_root, receipt_proof).ok_or(InvalidProof)?;
match result {
Ok(receipt) => Ok(receipt),
@@ -90,4 +66,96 @@ impl<T: Config> Pallet<T> {
},
}
}
/// Validates an execution header with ancestry_proof against a finalized checkpoint on
/// chain.The beacon header containing the execution header is sent, plus the execution header,
/// along with a proof that the execution header is rooted in the beacon header body.
pub(crate) fn verify_execution_proof(execution_proof: &ExecutionProof) -> DispatchResult {
let latest_finalized_state =
FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get())
.ok_or(Error::<T>::NotBootstrapped)?;
// Checks that the header is an ancestor of a finalized header, using slot number.
ensure!(
execution_proof.header.slot <= latest_finalized_state.slot,
Error::<T>::HeaderNotFinalized
);
// Gets the hash tree root of the execution header, in preparation for the execution
// header proof (used to check that the execution header is rooted in the beacon
// header body.
let execution_header_root: H256 = execution_proof
.execution_header
.hash_tree_root()
.map_err(|_| Error::<T>::BlockBodyHashTreeRootFailed)?;
ensure!(
verify_merkle_branch(
execution_header_root,
&execution_proof.execution_branch,
config::EXECUTION_HEADER_SUBTREE_INDEX,
config::EXECUTION_HEADER_DEPTH,
execution_proof.header.body_root
),
Error::<T>::InvalidExecutionHeaderProof
);
let beacon_block_root: H256 = execution_proof
.header
.hash_tree_root()
.map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;
match &execution_proof.ancestry_proof {
Some(proof) => {
Self::verify_ancestry_proof(
beacon_block_root,
execution_proof.header.slot,
&proof.header_branch,
proof.finalized_block_root,
)?;
},
None => {
// If the ancestry proof is not provided, we expect this beacon header to be a
// finalized beacon header. We need to check that the header hash matches the
// finalized header root at the expected slot.
let state = <FinalizedBeaconState<T>>::get(beacon_block_root)
.ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
if execution_proof.header.slot != state.slot {
return Err(Error::<T>::ExpectedFinalizedHeaderNotStored.into())
}
},
}
Ok(())
}
/// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that
/// an execution header is an ancestor of a finalized header (i.e. the blocks are
/// on the same chain).
fn verify_ancestry_proof(
block_root: H256,
block_slot: u64,
block_root_proof: &[H256],
finalized_block_root: H256,
) -> DispatchResult {
let state = <FinalizedBeaconState<T>>::get(finalized_block_root)
.ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
ensure!(block_slot < state.slot, Error::<T>::HeaderNotFinalized);
let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64);
let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array;
ensure!(
verify_merkle_branch(
block_root,
block_root_proof,
leaf_index as usize,
config::BLOCK_ROOT_AT_INDEX_DEPTH,
state.block_roots_root
),
Error::<T>::InvalidAncestryMerkleProof
);
Ok(())
}
}
@@ -15,8 +15,6 @@
//! ## Consensus Updates
//!
//! * [`Call::submit`]: Submit a finalized beacon header with an optional sync committee update
//! * [`Call::submit_execution_header`]: Submit an execution header together with an ancestry proof
//! that can be verified against an already imported finalized beacon header.
#![cfg_attr(not(feature = "std"), no_std)]
pub mod config;
@@ -40,8 +38,7 @@ use frame_support::{
use frame_system::ensure_signed;
use primitives::{
fast_aggregate_verify, verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError,
CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState, ForkData, ForkVersion,
ForkVersions, PublicKeyPrepared, SigningData,
CompactBeaconState, ForkData, ForkVersion, ForkVersions, PublicKeyPrepared, SigningData,
};
use snowbridge_core::{BasicOperatingMode, RingBufferMap};
use sp_core::H256;
@@ -51,11 +48,7 @@ pub use weights::WeightInfo;
use functions::{
compute_epoch, compute_period, decompress_sync_committee_bits, sync_committee_sum,
};
pub use types::ExecutionHeaderBuffer;
use types::{
CheckpointUpdate, ExecutionHeaderUpdate, FinalizedBeaconStateBuffer, SyncCommitteePrepared,
Update,
};
use types::{CheckpointUpdate, FinalizedBeaconStateBuffer, SyncCommitteePrepared, Update};
pub use pallet::*;
@@ -76,10 +69,7 @@ pub mod pallet {
pub struct MaxFinalizedHeadersToKeep<T: Config>(PhantomData<T>);
impl<T: Config> Get<u32> for MaxFinalizedHeadersToKeep<T> {
fn get() -> u32 {
// Consider max latency allowed between LatestFinalizedState and LatestExecutionState is
// the total slots in one sync_committee_period so 1 should be fine we keep 2 periods
// here for redundancy.
const MAX_REDUNDANCY: u32 = 2;
const MAX_REDUNDANCY: u32 = 20;
config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD as u32 * MAX_REDUNDANCY
}
}
@@ -92,9 +82,6 @@ pub mod pallet {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
#[pallet::constant]
type ForkVersions: Get<ForkVersions>;
/// Maximum number of execution headers to keep
#[pallet::constant]
type MaxExecutionHeadersToKeep: Get<u32>;
type WeightInfo: WeightInfo;
}
@@ -105,10 +92,6 @@ pub mod pallet {
block_hash: H256,
slot: u64,
},
ExecutionHeaderImported {
block_hash: H256,
block_number: u64,
},
SyncCommitteeUpdated {
period: u64,
},
@@ -191,25 +174,6 @@ pub mod pallet {
pub(super) type NextSyncCommittee<T: Config> =
StorageValue<_, SyncCommitteePrepared, ValueQuery>;
/// Latest imported execution header
#[pallet::storage]
#[pallet::getter(fn latest_execution_state)]
pub(super) type LatestExecutionState<T: Config> =
StorageValue<_, ExecutionHeaderState, ValueQuery>;
/// Execution Headers
#[pallet::storage]
pub type ExecutionHeaders<T: Config> =
StorageMap<_, Identity, H256, CompactExecutionHeader, OptionQuery>;
/// Execution Headers: Current position in ring buffer
#[pallet::storage]
pub type ExecutionHeaderIndex<T: Config> = StorageValue<_, u32, ValueQuery>;
/// Execution Headers: Mapping of ring buffer index to a pruning candidate
#[pallet::storage]
pub type ExecutionHeaderMapping<T: Config> = StorageMap<_, Identity, u32, H256, ValueQuery>;
/// The current operating mode of the pallet.
#[pallet::storage]
#[pallet::getter(fn operating_mode)]
@@ -248,21 +212,6 @@ pub mod pallet {
Ok(())
}
#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::submit_execution_header())]
#[transactional]
/// Submits a new execution header update. The relevant related beacon header
/// is also included to prove the execution header, as well as ancestry proof data.
pub fn submit_execution_header(
origin: OriginFor<T>,
update: Box<ExecutionHeaderUpdate>,
) -> DispatchResult {
ensure_signed(origin)?;
ensure!(!Self::operating_mode().is_halted(), Error::<T>::Halted);
Self::process_execution_header_update(&update)?;
Ok(())
}
/// Halt or resume all pallet operations. May only be called by root.
#[pallet::call_index(3)]
#[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))]
@@ -325,41 +274,19 @@ pub mod pallet {
<CurrentSyncCommittee<T>>::set(sync_committee_prepared);
<NextSyncCommittee<T>>::kill();
InitialCheckpointRoot::<T>::set(header_root);
<LatestExecutionState<T>>::kill();
Self::store_validators_root(update.validators_root);
Self::store_finalized_header(header_root, update.header, update.block_roots_root)?;
Self::store_finalized_header(update.header, update.block_roots_root)?;
Ok(())
}
pub(crate) fn process_update(update: &Update) -> DispatchResult {
Self::cross_check_execution_state()?;
Self::verify_update(update)?;
Self::apply_update(update)?;
Ok(())
}
/// Cross check to make sure that execution header import does not fall too far behind
/// finalised beacon header import. If that happens just return an error and pause
/// processing until execution header processing has caught up.
pub(crate) fn cross_check_execution_state() -> DispatchResult {
let latest_finalized_state =
FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get())
.ok_or(Error::<T>::NotBootstrapped)?;
let latest_execution_state = Self::latest_execution_state();
// The execution header import should be at least within the slot range of a sync
// committee period.
let max_latency = config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD * config::SLOTS_PER_EPOCH;
ensure!(
latest_execution_state.beacon_slot == 0 ||
latest_finalized_state.slot <
latest_execution_state.beacon_slot + max_latency as u64,
Error::<T>::ExecutionHeaderTooFarBehind
);
Ok(())
}
/// References and strictly follows <https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#validate_light_client_update>
/// Verifies that provided next sync committee is valid through a series of checks
/// (including checking that a sync committee period isn't skipped and that the header is
@@ -534,130 +461,12 @@ pub mod pallet {
};
if update.finalized_header.slot > latest_finalized_state.slot {
let finalized_block_root: H256 = update
.finalized_header
.hash_tree_root()
.map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;
Self::store_finalized_header(
finalized_block_root,
update.finalized_header,
update.block_roots_root,
)?;
Self::store_finalized_header(update.finalized_header, update.block_roots_root)?;
}
Ok(())
}
/// Validates an execution header for import. The beacon header containing the execution
/// header is sent, plus the execution header, along with a proof that the execution header
/// is rooted in the beacon header body.
pub(crate) fn process_execution_header_update(
update: &ExecutionHeaderUpdate,
) -> DispatchResult {
let latest_finalized_state =
FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get())
.ok_or(Error::<T>::NotBootstrapped)?;
// Checks that the header is an ancestor of a finalized header, using slot number.
ensure!(
update.header.slot <= latest_finalized_state.slot,
Error::<T>::HeaderNotFinalized
);
// Checks that we don't skip execution headers, they need to be imported sequentially.
let latest_execution_state: ExecutionHeaderState = Self::latest_execution_state();
ensure!(
latest_execution_state.block_number == 0 ||
update.execution_header.block_number() ==
latest_execution_state.block_number + 1,
Error::<T>::ExecutionHeaderSkippedBlock
);
// Gets the hash tree root of the execution header, in preparation for the execution
// header proof (used to check that the execution header is rooted in the beacon
// header body.
let execution_header_root: H256 = update
.execution_header
.hash_tree_root()
.map_err(|_| Error::<T>::BlockBodyHashTreeRootFailed)?;
ensure!(
verify_merkle_branch(
execution_header_root,
&update.execution_branch,
config::EXECUTION_HEADER_SUBTREE_INDEX,
config::EXECUTION_HEADER_DEPTH,
update.header.body_root
),
Error::<T>::InvalidExecutionHeaderProof
);
let block_root: H256 = update
.header
.hash_tree_root()
.map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;
match &update.ancestry_proof {
Some(proof) => {
Self::verify_ancestry_proof(
block_root,
update.header.slot,
&proof.header_branch,
proof.finalized_block_root,
)?;
},
None => {
// If the ancestry proof is not provided, we expect this header to be a
// finalized header. We need to check that the header hash matches the finalized
// header root at the expected slot.
let state = <FinalizedBeaconState<T>>::get(block_root)
.ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
if update.header.slot != state.slot {
return Err(Error::<T>::ExpectedFinalizedHeaderNotStored.into())
}
},
}
Self::store_execution_header(
update.execution_header.block_hash(),
update.execution_header.clone().into(),
update.header.slot,
block_root,
);
Ok(())
}
/// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that
/// an execution header is an ancestor of a finalized header (i.e. the blocks are
/// on the same chain).
fn verify_ancestry_proof(
block_root: H256,
block_slot: u64,
block_root_proof: &[H256],
finalized_block_root: H256,
) -> DispatchResult {
let state = <FinalizedBeaconState<T>>::get(finalized_block_root)
.ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
ensure!(block_slot < state.slot, Error::<T>::HeaderNotFinalized);
let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64);
let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array;
ensure!(
verify_merkle_branch(
block_root,
block_root_proof,
leaf_index as usize,
config::BLOCK_ROOT_AT_INDEX_DEPTH,
state.block_roots_root
),
Error::<T>::InvalidAncestryMerkleProof
);
Ok(())
}
/// Computes the signing root for a given beacon header and domain. The hash tree root
/// of the beacon header is computed, and then the combination of the beacon header hash
/// and the domain makes up the signing root.
@@ -679,13 +488,15 @@ pub mod pallet {
/// Stores a compacted (slot and block roots root (hash of the `block_roots` beacon state
/// field, used for ancestry proof)) beacon state in a ring buffer map, with the header root
/// as map key.
fn store_finalized_header(
header_root: H256,
pub fn store_finalized_header(
header: BeaconHeader,
block_roots_root: H256,
) -> DispatchResult {
let slot = header.slot;
let header_root: H256 =
header.hash_tree_root().map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;
<FinalizedBeaconStateBuffer<T>>::insert(
header_root,
CompactBeaconState { slot: header.slot, block_roots_root },
@@ -704,36 +515,6 @@ pub mod pallet {
Ok(())
}
/// Stores the provided execution header in pallet storage. The header is stored
/// in a ring buffer map, with the block hash as map key. The last imported execution
/// header is also kept in storage, for the relayer to check import progress.
pub fn store_execution_header(
block_hash: H256,
header: CompactExecutionHeader,
beacon_slot: u64,
beacon_block_root: H256,
) {
let block_number = header.block_number;
<ExecutionHeaderBuffer<T>>::insert(block_hash, header);
log::trace!(
target: LOG_TARGET,
"💫 Updated latest execution block at {} to number {}.",
block_hash,
block_number
);
LatestExecutionState::<T>::mutate(|s| {
s.beacon_block_root = beacon_block_root;
s.beacon_slot = beacon_slot;
s.block_hash = block_hash;
s.block_number = block_number;
});
Self::deposit_event(Event::ExecutionHeaderImported { block_hash, block_number });
}
/// Stores the validators root in storage. Validators root is the hash tree root of all the
/// validators at genesis and is used to used to identify the chain that we are on
/// (used in conjunction with the fork version).
@@ -2,12 +2,13 @@
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use crate as ethereum_beacon_client;
use crate::config;
use frame_support::{derive_impl, parameter_types};
use hex_literal::hex;
use frame_support::{derive_impl, dispatch::DispatchResult, parameter_types};
use pallet_timestamp;
use primitives::{CompactExecutionHeader, Fork, ForkVersions};
use primitives::{Fork, ForkVersions};
use snowbridge_core::inbound::{Log, Proof};
use sp_std::default::Default;
use std::{fs::File, path::PathBuf};
type Block = frame_system::mocking::MockBlock<Test>;
use sp_runtime::BuildStorage;
@@ -20,8 +21,8 @@ where
serde_json::from_reader(File::open(filepath).unwrap())
}
pub fn load_execution_header_update_fixture() -> primitives::ExecutionHeaderUpdate {
load_fixture("execution-header-update.json".to_string()).unwrap()
pub fn load_execution_proof_fixture() -> primitives::ExecutionProof {
load_fixture("execution-proof.json".to_string()).unwrap()
}
pub fn load_checkpoint_update_fixture(
@@ -50,41 +51,8 @@ pub fn load_next_finalized_header_update_fixture(
}
pub fn get_message_verification_payload() -> (Log, Proof) {
(
Log {
address: hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into(),
topics: vec![
hex!("1b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ad").into(),
hex!("00000000000000000000000000000000000000000000000000000000000003e8").into(),
hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
],
data: hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000").into(),
},
Proof {
block_hash: hex!("05aaa60b0f27cce9e71909508527264b77ee14da7b5bf915fcc4e32715333213").into(),
tx_index: 0,
data: (vec![
hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb").to_vec(),
hex!("d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c185510").to_vec(),
hex!("b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646").to_vec(),
], vec![
hex!("f90131a0b601337b3aa10a671caa724eba641e759399979856141d3aea6b6b4ac59b889ba00c7d5dd48be9060221a02fb8fa213860b4c50d47046c8fa65ffaba5737d569e0a094601b62a1086cd9c9cb71a7ebff9e718f3217fd6e837efe4246733c0a196f63a06a4b0dd0aefc37b3c77828c8f07d1b7a2455ceb5dbfd3c77d7d6aeeddc2f7e8ca0d6e8e23142cdd8ec219e1f5d8b56aa18e456702b195deeaa210327284d42ade4a08a313d4c87023005d1ab631bbfe3f5de1e405d0e66d0bef3e033f1e5711b5521a0bf09a5d9a48b10ade82b8d6a5362a15921c8b5228a3487479b467db97411d82fa0f95cccae2a7c572ef3c566503e30bac2b2feb2d2f26eebf6d870dcf7f8cf59cea0d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c1855108080808080808080").to_vec(),
hex!("f851a0b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646a060a634b9280e3a23fb63375e7bbdd9ab07fd379ab6a67e2312bbc112195fa358808080808080808080808080808080").to_vec(),
hex!("f9030820b9030402f90300018301d6e2b9010000000000000800000000000020040008000000000000000000000000400000008000000000000000000000000000000000000000000000000000000000042010000000001000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000002000000000000000000000000200000000000000200000000000100000000040000001000200008000000000000200000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000f901f5f87a942ffa5ecdbe006d30397c7636d3e015eee251369ff842a0c965575a00553e094ca7c5d14f02e107c258dda06867cbf9e0e69f80e71bbcc1a000000000000000000000000000000000000000000000000000000000000003e8a000000000000000000000000000000000000000000000000000000000000003e8f9011c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000001b8a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000f858948cf6147918a5cbb672703f879f385036f8793a24e1a01449abf21e49fd025f33495e77f7b1461caefdd3d4bb646424a3f445c4576a5ba0000000000000000000000000440edffa1352b13227e8ee646f3ea37456dec701").to_vec(),
]),
}
)
}
pub fn get_message_verification_header() -> CompactExecutionHeader {
CompactExecutionHeader {
parent_hash: hex!("04a7f6ab8282203562c62f38b0ab41d32aaebe2c7ea687702b463148a6429e04")
.into(),
block_number: 55,
state_root: hex!("894d968712976d613519f973a317cb0781c7b039c89f27ea2b7ca193f7befdb3").into(),
receipts_root: hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb")
.into(),
}
let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture();
(inbound_fixture.message.event_log, inbound_fixture.message.proof)
}
frame_support::construct_runtime!(
@@ -130,20 +98,25 @@ parameter_types! {
epoch: 0,
}
};
pub const ExecutionHeadersPruneThreshold: u32 = 8192;
}
impl ethereum_beacon_client::Config for Test {
type RuntimeEvent = RuntimeEvent;
type ForkVersions = ChainForkVersions;
type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold;
type WeightInfo = ();
}
// Build genesis storage according to the mock runtime.
pub fn new_tester() -> sp_io::TestExternalities {
let t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
let mut ext = sp_io::TestExternalities::new(t);
let _ = ext.execute_with(|| Timestamp::set(RuntimeOrigin::signed(1), 30_000));
let ext = sp_io::TestExternalities::new(t);
ext
}
pub fn initialize_storage() -> DispatchResult {
let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture();
EthereumBeaconClient::store_finalized_header(
inbound_fixture.finalized_header,
inbound_fixture.block_roots_root,
)
}
@@ -1,14 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use crate::{
functions::compute_period, pallet::ExecutionHeaders, sync_committee_sum, verify_merkle_branch,
BeaconHeader, CompactBeaconState, Error, ExecutionHeaderBuffer, FinalizedBeaconState,
LatestExecutionState, LatestFinalizedBlockRoot, NextSyncCommittee, SyncCommitteePrepared,
functions::compute_period, sync_committee_sum, verify_merkle_branch, BeaconHeader,
CompactBeaconState, Error, FinalizedBeaconState, LatestFinalizedBlockRoot, NextSyncCommittee,
SyncCommitteePrepared,
};
use crate::mock::{
get_message_verification_header, get_message_verification_payload,
load_checkpoint_update_fixture, load_execution_header_update_fixture,
get_message_verification_payload, load_checkpoint_update_fixture,
load_finalized_header_update_fixture, load_next_finalized_header_update_fixture,
load_next_sync_committee_update_fixture, load_sync_committee_update_fixture,
};
@@ -19,14 +18,9 @@ use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER
use frame_support::{assert_err, assert_noop, assert_ok};
use hex_literal::hex;
use primitives::{
CompactExecutionHeader, ExecutionHeaderState, Fork, ForkVersions, NextSyncCommitteeUpdate,
VersionedExecutionPayloadHeader,
};
use rand::{thread_rng, Rng};
use snowbridge_core::{
inbound::{VerificationError, Verifier},
RingBufferMap,
types::deneb, Fork, ForkVersions, NextSyncCommitteeUpdate, VersionedExecutionPayloadHeader,
};
use snowbridge_core::inbound::{VerificationError, Verifier};
use sp_core::H256;
use sp_runtime::DispatchError;
@@ -212,61 +206,6 @@ pub fn sync_committee_participation_is_supermajority_errors_when_not_supermajori
});
}
#[test]
pub fn execution_header_pruning() {
new_tester().execute_with(|| {
let execution_header_prune_threshold = ExecutionHeadersPruneThreshold::get();
let to_be_deleted = execution_header_prune_threshold / 2;
let mut stored_hashes = vec![];
for i in 0..execution_header_prune_threshold {
let mut hash = H256::default();
thread_rng().try_fill(&mut hash.0[..]).unwrap();
EthereumBeaconClient::store_execution_header(
hash,
CompactExecutionHeader::default(),
i as u64,
hash,
);
stored_hashes.push(hash);
}
// We should have stored everything until now
assert_eq!({ ExecutionHeaders::<Test>::iter().count() }, stored_hashes.len());
// Let's push extra entries so that some of the previous entries are deleted.
for i in 0..to_be_deleted {
let mut hash = H256::default();
thread_rng().try_fill(&mut hash.0[..]).unwrap();
EthereumBeaconClient::store_execution_header(
hash,
CompactExecutionHeader::default(),
(i + execution_header_prune_threshold) as u64,
hash,
);
stored_hashes.push(hash);
}
// We should have only stored up to `execution_header_prune_threshold`
assert_eq!(
ExecutionHeaders::<Test>::iter().count() as u32,
execution_header_prune_threshold
);
// First `to_be_deleted` items must be deleted
for i in 0..to_be_deleted {
assert!(!ExecutionHeaders::<Test>::contains_key(stored_hashes[i as usize]));
}
// Other entries should be part of data
for i in to_be_deleted..(to_be_deleted + execution_header_prune_threshold) {
assert!(ExecutionHeaders::<Test>::contains_key(stored_hashes[i as usize]));
}
});
}
#[test]
fn compute_fork_version() {
let mock_fork_versions = ForkVersions {
@@ -348,34 +287,6 @@ fn find_present_keys() {
});
}
#[test]
fn cross_check_execution_state() {
new_tester().execute_with(|| {
let header_root: H256 = TEST_HASH.into();
<FinalizedBeaconState<Test>>::insert(
header_root,
CompactBeaconState {
// set slot to period 5
slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 5) as u64,
block_roots_root: Default::default(),
},
);
LatestFinalizedBlockRoot::<Test>::set(header_root);
<LatestExecutionState<Test>>::set(ExecutionHeaderState {
beacon_block_root: Default::default(),
// set slot to period 2
beacon_slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 2) as u64,
block_hash: Default::default(),
block_number: 0,
});
assert_err!(
EthereumBeaconClient::cross_check_execution_state(),
Error::<Test>::ExecutionHeaderTooFarBehind
);
});
}
/* SYNC PROCESS TESTS */
#[test]
@@ -608,40 +519,6 @@ fn submit_update_with_skipped_sync_committee_period() {
});
}
#[test]
fn submit_update_execution_headers_too_far_behind() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let execution_header_update = Box::new(load_execution_header_update_fixture());
let next_update = Box::new(load_next_sync_committee_update_fixture());
new_tester().execute_with(|| {
let far_ahead_finalized_header_slot = finalized_header_update.finalized_header.slot +
(EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH * 2) as u64;
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_ok!(EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update
));
let header_root: H256 = TEST_HASH.into();
<FinalizedBeaconState<Test>>::insert(
header_root,
CompactBeaconState {
slot: far_ahead_finalized_header_slot,
block_roots_root: Default::default(),
},
);
LatestFinalizedBlockRoot::<Test>::set(header_root);
assert_err!(
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update),
Error::<Test>::ExecutionHeaderTooFarBehind
);
});
}
#[test]
fn submit_irrelevant_update() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
@@ -703,187 +580,6 @@ fn submit_update_with_invalid_sync_committee_update() {
});
}
#[test]
fn submit_execution_header_update() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let execution_header_update = Box::new(load_execution_header_update_fixture());
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_ok!(EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update.clone()
));
assert!(<ExecutionHeaders<Test>>::contains_key(
execution_header_update.execution_header.block_hash()
));
});
}
#[test]
fn submit_execution_header_update_invalid_ancestry_proof() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_header_update_fixture());
if let Some(ref mut ancestry_proof) = execution_header_update.ancestry_proof {
ancestry_proof.header_branch[0] = TEST_HASH.into()
}
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_err!(
EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update
),
Error::<Test>::InvalidAncestryMerkleProof
);
});
}
#[test]
fn submit_execution_header_update_invalid_execution_header_proof() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_header_update_fixture());
execution_header_update.execution_branch[0] = TEST_HASH.into();
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_err!(
EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update
),
Error::<Test>::InvalidExecutionHeaderProof
);
});
}
#[test]
fn submit_execution_header_update_that_skips_block() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let execution_header_update = Box::new(load_execution_header_update_fixture());
let mut skipped_block_execution_header_update =
Box::new(load_execution_header_update_fixture());
let mut skipped_execution_header =
skipped_block_execution_header_update.execution_header.clone();
skipped_execution_header = match skipped_execution_header {
VersionedExecutionPayloadHeader::Capella(execution_payload_header) => {
let mut mut_execution_payload_header = execution_payload_header.clone();
mut_execution_payload_header.block_number = execution_payload_header.block_number + 2;
VersionedExecutionPayloadHeader::Capella(mut_execution_payload_header)
},
VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => {
let mut mut_execution_payload_header = execution_payload_header.clone();
mut_execution_payload_header.block_number = execution_payload_header.block_number + 2;
VersionedExecutionPayloadHeader::Deneb(mut_execution_payload_header)
},
};
skipped_block_execution_header_update.execution_header = skipped_execution_header;
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_ok!(EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update.clone()
));
assert!(<ExecutionHeaders<Test>>::contains_key(
execution_header_update.execution_header.block_hash()
));
assert_err!(
EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
skipped_block_execution_header_update
),
Error::<Test>::ExecutionHeaderSkippedBlock
);
});
}
#[test]
fn submit_execution_header_update_that_is_also_finalized_header_which_is_not_stored() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_header_update_fixture());
execution_header_update.ancestry_proof = None;
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_err!(
EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update
),
Error::<Test>::ExpectedFinalizedHeaderNotStored
);
});
}
#[test]
fn submit_execution_header_update_that_is_also_finalized_header_which_is_stored_but_slots_dont_match(
) {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_header_update_fixture());
execution_header_update.ancestry_proof = None;
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
let block_root: H256 = execution_header_update.header.hash_tree_root().unwrap();
<FinalizedBeaconState<Test>>::insert(
block_root,
CompactBeaconState {
slot: execution_header_update.header.slot + 1,
block_roots_root: Default::default(),
},
);
LatestFinalizedBlockRoot::<Test>::set(block_root);
assert_err!(
EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update
),
Error::<Test>::ExpectedFinalizedHeaderNotStored
);
});
}
#[test]
fn submit_execution_header_not_finalized() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let update = Box::new(load_execution_header_update_fixture());
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
<FinalizedBeaconState<Test>>::mutate(<LatestFinalizedBlockRoot<Test>>::get(), |x| {
let prev = x.unwrap();
*x = Some(CompactBeaconState { slot: update.header.slot - 1, ..prev });
});
assert_err!(
EthereumBeaconClient::submit_execution_header(RuntimeOrigin::signed(1), update),
Error::<Test>::HeaderNotFinalized
);
});
}
/// Check that a gap of more than 8192 slots between finalized headers is not allowed.
#[test]
fn submit_finalized_header_update_with_too_large_gap() {
@@ -943,37 +639,21 @@ fn submit_finalized_header_update_with_gap_at_limit() {
#[test]
fn verify_message() {
let header = get_message_verification_header();
let (event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;
new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_ok!(initialize_storage());
assert_ok!(EthereumBeaconClient::verify(&event_log, &proof));
});
}
#[test]
fn verify_message_missing_header() {
let (event_log, proof) = get_message_verification_payload();
new_tester().execute_with(|| {
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::HeaderNotFound
);
});
}
#[test]
fn verify_message_invalid_proof() {
let header = get_message_verification_header();
let (event_log, mut proof) = get_message_verification_payload();
proof.data.1[0] = TEST_HASH.into();
let block_hash = proof.block_hash;
proof.receipt_proof.1[0] = TEST_HASH.into();
new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_ok!(initialize_storage());
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::InvalidProof
@@ -983,29 +663,28 @@ fn verify_message_invalid_proof() {
#[test]
fn verify_message_invalid_receipts_root() {
let mut header = get_message_verification_header();
let (event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;
header.receipts_root = TEST_HASH.into();
let (event_log, mut proof) = get_message_verification_payload();
let mut payload = deneb::ExecutionPayloadHeader::default();
payload.receipts_root = TEST_HASH.into();
proof.execution_proof.execution_header = VersionedExecutionPayloadHeader::Deneb(payload);
new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_ok!(initialize_storage());
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::InvalidProof
VerificationError::InvalidExecutionProof(
Error::<Test>::BlockBodyHashTreeRootFailed.into()
)
);
});
}
#[test]
fn verify_message_invalid_log() {
let header = get_message_verification_header();
let (mut event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;
event_log.topics = vec![H256::zero(); 10];
new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_ok!(initialize_storage());
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::InvalidLog
@@ -1015,13 +694,11 @@ fn verify_message_invalid_log() {
#[test]
fn verify_message_receipt_does_not_contain_log() {
let header = get_message_verification_header();
let (mut event_log, proof) = get_message_verification_payload();
let block_hash = proof.block_hash;
event_log.data = hex!("f9013c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000002b8c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000068000f000000000000000101d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec70100000101001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0000e8890423c78a0000000000000000000000000000000000000000000000000000000000000000").to_vec();
new_tester().execute_with(|| {
<ExecutionHeaderBuffer<Test>>::insert(block_hash, header);
assert_ok!(initialize_storage());
assert_err!(
EthereumBeaconClient::verify(&event_log, &proof),
VerificationError::LogNotFound
@@ -1033,7 +710,6 @@ fn verify_message_receipt_does_not_contain_log() {
fn set_operating_mode() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let update = Box::new(load_finalized_header_update_fixture());
let execution_header_update = Box::new(load_execution_header_update_fixture());
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
@@ -1047,14 +723,6 @@ fn set_operating_mode() {
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update),
Error::<Test>::Halted
);
assert_noop!(
EthereumBeaconClient::submit_execution_header(
RuntimeOrigin::signed(1),
execution_header_update
),
Error::<Test>::Halted
);
});
}
@@ -1070,3 +738,107 @@ fn set_operating_mode_root_only() {
);
});
}
#[test]
fn verify_execution_proof_invalid_ancestry_proof() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_proof_fixture());
if let Some(ref mut ancestry_proof) = execution_header_update.ancestry_proof {
ancestry_proof.header_branch[0] = TEST_HASH.into()
}
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_err!(
EthereumBeaconClient::verify_execution_proof(&execution_header_update),
Error::<Test>::InvalidAncestryMerkleProof
);
});
}
#[test]
fn verify_execution_proof_invalid_execution_header_proof() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_proof_fixture());
execution_header_update.execution_branch[0] = TEST_HASH.into();
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_err!(
EthereumBeaconClient::verify_execution_proof(&execution_header_update),
Error::<Test>::InvalidExecutionHeaderProof
);
});
}
#[test]
fn verify_execution_proof_that_is_also_finalized_header_which_is_not_stored() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_proof_fixture());
execution_header_update.ancestry_proof = None;
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
assert_err!(
EthereumBeaconClient::verify_execution_proof(&execution_header_update),
Error::<Test>::ExpectedFinalizedHeaderNotStored
);
});
}
#[test]
fn submit_execution_proof_that_is_also_finalized_header_which_is_stored_but_slots_dont_match() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let mut execution_header_update = Box::new(load_execution_proof_fixture());
execution_header_update.ancestry_proof = None;
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
let block_root: H256 = execution_header_update.header.hash_tree_root().unwrap();
<FinalizedBeaconState<Test>>::insert(
block_root,
CompactBeaconState {
slot: execution_header_update.header.slot + 1,
block_roots_root: Default::default(),
},
);
LatestFinalizedBlockRoot::<Test>::set(block_root);
assert_err!(
EthereumBeaconClient::verify_execution_proof(&execution_header_update),
Error::<Test>::ExpectedFinalizedHeaderNotStored
);
});
}
#[test]
fn verify_execution_proof_not_finalized() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let finalized_header_update = Box::new(load_finalized_header_update_fixture());
let update = Box::new(load_execution_proof_fixture());
new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update));
<FinalizedBeaconState<Test>>::mutate(<LatestFinalizedBlockRoot<Test>>::get(), |x| {
let prev = x.unwrap();
*x = Some(CompactBeaconState { slot: update.header.slot - 1, ..prev });
});
assert_err!(
EthereumBeaconClient::verify_execution_proof(&update),
Error::<Test>::HeaderNotFinalized
);
});
}
@@ -15,17 +15,7 @@ pub type CheckpointUpdate = primitives::CheckpointUpdate<SC_SIZE>;
pub type Update = primitives::Update<SC_SIZE, SC_BITS_SIZE>;
pub type NextSyncCommitteeUpdate = primitives::NextSyncCommitteeUpdate<SC_SIZE>;
pub use primitives::ExecutionHeaderUpdate;
/// ExecutionHeader ring buffer implementation
pub type ExecutionHeaderBuffer<T> = RingBufferMapImpl<
u32,
<T as crate::Config>::MaxExecutionHeadersToKeep,
crate::ExecutionHeaderIndex<T>,
crate::ExecutionHeaderMapping<T>,
crate::ExecutionHeaders<T>,
OptionQuery,
>;
pub use primitives::{AncestryProof, ExecutionProof};
/// FinalizedState ring buffer implementation
pub(crate) type FinalizedBeaconStateBuffer<T> = RingBufferMapImpl<
@@ -36,7 +36,6 @@ pub trait WeightInfo {
fn force_checkpoint() -> Weight;
fn submit() -> Weight;
fn submit_with_sync_committee() -> Weight;
fn submit_execution_header() -> Weight;
}
// For backwards compatibility and tests
@@ -59,10 +58,4 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(1))
}
fn submit_execution_header() -> Weight {
Weight::from_parts(113_158_000_u64, 0)
.saturating_add(Weight::from_parts(0, 3537))
.saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(4))
}
}
@@ -1,54 +0,0 @@
{
"header": {
"slot": 215,
"proposer_index": 2,
"parent_root": "0x97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45",
"state_root": "0xb088b5a3a8c90d6dc919a695cd7bb0267c6f983ea2e675c559ceb8f46cb90b67",
"body_root": "0x0ba23c8224fdd01531d5ad51486353bd524a0b4c20bca704e26d3210616f829b"
},
"ancestry_proof": {
"header_branch": [
"0x97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45",
"0x5ce0db996bd499c2b4f7a93263d5aafd052f420efb617cce6fdd54e25516aa45",
"0x84f0e373b66011ce774c7061440c0a50a51cce2b4b335395eee3e563d605597f",
"0x48f9ccc5f9594142c18c3b5c39a99f0549329c6ab3ba06c9a50030eadca87770",
"0xf89d6e311e05bc75a6f63ce118bccce254551f1a88d54c3b4f773f81f946bd99",
"0x2edd6d893c22636675147c07dfcdb541a146e87c3f15b51c388be4868246dc9b",
"0xd76b7de5f856e3208a91a42c9c398a7f4fab35e667bf916346050ae742514a2d",
"0x83a2e233e76385953ca41de4c3afe60471a61f0cc1b3846b4a0670e3e563b747",
"0xe783a5a109c2ad74e4eb53e8f6b11b31266a92a9e16c1fd5873109c5d41b282c",
"0xd4ea1ef3869ee6a0fd0b19d7d70027d144eecd4f1d32cbf47632a0a9069164b9",
"0xf8179564b58eb93a850d35e4156a04db651106442ad891c3e85155c1762792f1",
"0x4cbb1edb48cf1e32fb30db60aaaeaf6190ffe4d0c8dbc96cec307daecb78be12",
"0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f"
],
"finalized_block_root": "0x890a7f23b9ed2160901654be9efc575d6830ca860e2a97866ae3423fb7bd7231"
},
"execution_header": {
"Deneb": {
"parent_hash": "0xd82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a",
"fee_recipient": "0x0000000000000000000000000000000000000000",
"state_root": "0x8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3",
"receipts_root": "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095",
"logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010",
"prev_randao": "0x6d9e2a012d82b1b6cb0a2c1c1ed24cc16dbb56e6e39ae545371e0666ab057862",
"block_number": 215,
"gas_limit": 64842908,
"gas_used": 119301,
"timestamp": 1705859527,
"extra_data": "0xd983010d0a846765746888676f312e32312e358664617277696e",
"base_fee_per_gas": 7,
"block_hash": "0x48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98",
"transactions_root": "0x5ebc1347fe3df0611d4f66b19bd8e1c6f4eaed0371d850f14c83b1c77ea234e6",
"withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535",
"blob_gas_used": 0,
"excess_blob_gas": 0
}
},
"execution_branch": [
"0xf8c69d3830406d668619bcccc13c8dddde41e863326f7418b241d5924c4ad34a",
"0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb",
"0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71",
"0xf4d6b5cf9c6e212615c3674fa625d04eb1114153fb221ef5ad02aa433fc67cfb"
]
}
@@ -0,0 +1,54 @@
{
"header": {
"slot": 393,
"proposer_index": 4,
"parent_root": "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef",
"state_root": "0xb62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434",
"body_root": "0x04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db"
},
"ancestry_proof": {
"header_branch": [
"0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef",
"0xfa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3",
"0xcadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d",
"0x33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c",
"0x2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf",
"0xe1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1",
"0xaa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97",
"0x160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f",
"0xf68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535",
"0x1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc",
"0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b",
"0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220",
"0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f"
],
"finalized_block_root": "0x751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46"
},
"execution_header": {
"Deneb": {
"parent_hash": "0x8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2",
"fee_recipient": "0x0000000000000000000000000000000000000000",
"state_root": "0x96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b",
"receipts_root": "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284",
"logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010",
"prev_randao": "0x62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67",
"block_number": 393,
"gas_limit": 54492273,
"gas_used": 199644,
"timestamp": 1710552813,
"extra_data": "0xd983010d0b846765746888676f312e32312e368664617277696e",
"base_fee_per_gas": 7,
"block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131",
"transactions_root": "0x2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d",
"withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535",
"blob_gas_used": 0,
"excess_blob_gas": 0
}
},
"execution_branch": [
"0xa6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d",
"0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb",
"0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71",
"0xd3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da"
]
}
@@ -1,38 +1,40 @@
{
"attested_header": {
"slot": 2566,
"proposer_index": 6,
"parent_root": "0x6eb9f13a2c496318ce1ab3087bbd872f5c9519a1a7ca8231a2453e3cb523af00",
"state_root": "0xc8cb12766113dff7e46d2917267bf33d0626d99dd47715fcdbc5c65fad3c04b4",
"body_root": "0xd8cfd0d7bc9bc3724417a1655bb0a67c0765ca36197320f4d834150b52ef1420"
"slot": 933,
"proposer_index": 1,
"parent_root": "0xf5fc63e2780ca302b97aea73fc95d74d702b5afe9a772c2b68f695026337b620",
"state_root": "0xd856d11636bc4d866e78be9e747b222b0977556a367ab42e4085277301438050",
"body_root": "0x5689091ab4eb76c2e876271add4924e1c66ce987c300c24aac2ad8c703e9a33f"
},
"sync_aggregate": {
"sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"sync_committee_signature": "0x9296f9a0387f2cac47008e22ad7c3cd3d49d35384c13e6aa1eacca7dca7c3d2ca81515e50eb3396b9550ed20ef7d8fa2049a186598feb2c00e93728045fcff917733d1827481b8fc95f3913e27fc70112c2490496eb57bb7181f02c3f9fd471f"
"sync_committee_signature": "0x93a3d482fe2a2f7fd2b634169752a8fddf1dc28b23a020b398be8526faf37a74ca0f6db1bed78a9c7256c09a6115235e108e0e8a7ce09287317b0856c4b77dfa5adba6cf4c3ebea5bfa4cd2fcde80fd0a532f2defe65d530201d5d2258796559"
},
"signature_slot": 2567,
"signature_slot": 934,
"next_sync_committee_update": null,
"finalized_header": {
"slot": 2496,
"proposer_index": 2,
"parent_root": "0xc99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622",
"state_root": "0xfbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde",
"body_root": "0xa2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0"
"slot": 864,
"proposer_index": 4,
"parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614",
"state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a",
"body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e"
},
"finality_branch": [
"0x4e00000000000000000000000000000000000000000000000000000000000000",
"0x1b00000000000000000000000000000000000000000000000000000000000000",
"0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7",
"0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d",
"0x958b8e43347f6df6fa5eb3d62d06a862381a6585aa40640dd1c0de11f1cf89c1",
"0xf107dce04faa86a28fc5d4a618be9cb8d4fc3c23d6c42c3624f3ff4bf6586a03",
"0xa501cdc02e86969ac3e4d0c5a36f4f049efaa1ab8cb6693f51d130eb52a80f30"
"0xf12d9aededc72724e417b518fe6f847684f26f81616243dedf8c551cc7d504f5",
"0x89a85d0907ab3fd6e00ae385f61d456c6191646404ae7b8d23d0e60440cf4d00",
"0x9fc943b6020eb61d780d78bcc6f6102a81d2c868d58f36e61c6e286a2dc4d8c2"
],
"block_roots_root": "0xd160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe",
"block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10",
"block_roots_branch": [
"0x105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135",
"0x9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99",
"0xecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5",
"0xb2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2",
"0xcd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf"
]
"0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f",
"0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa",
"0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf",
"0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5",
"0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4"
],
"execution_header": null,
"execution_branch": null
}
@@ -1,31 +1,79 @@
{
"execution_header": {
"parent_hash": "0xd82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a",
"state_root": "0x8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3",
"receipts_root": "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095",
"block_number": 215
"event_log": {
"address": "0xeda338e4dc46038493b885327842fd3e301cab39",
"topics": [
"0x7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f",
"0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539",
"0x5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0"
],
"data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000"
},
"message": {
"event_log": {
"address": "0xeda338e4dc46038493b885327842fd3e301cab39",
"topics": [
"0x7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f",
"0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539",
"0x5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0"
"proof": {
"block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131",
"tx_index": 0,
"receipt_proof": {
"keys": [
"0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284",
"0x4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f"
],
"data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000"
"values": [
"0xf851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080",
"0xf9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000"
]
},
"Proof": {
"block_hash": "0x48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98",
"tx_index": 0,
"data": {
"keys": [
"0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095"
"execution_proof": {
"header": {
"slot": 393,
"proposer_index": 4,
"parent_root": "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef",
"state_root": "0xb62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434",
"body_root": "0x04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db"
},
"ancestry_proof": {
"header_branch": [
"0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef",
"0xfa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3",
"0xcadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d",
"0x33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c",
"0x2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf",
"0xe1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1",
"0xaa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97",
"0x160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f",
"0xf68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535",
"0x1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc",
"0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b",
"0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220",
"0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f"
],
"values": [
"0xf9028e822080b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000"
]
}
"finalized_block_root": "0x751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46"
},
"execution_header": {
"Deneb": {
"parent_hash": "0x8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2",
"fee_recipient": "0x0000000000000000000000000000000000000000",
"state_root": "0x96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b",
"receipts_root": "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284",
"logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010",
"prev_randao": "0x62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67",
"block_number": 393,
"gas_limit": 54492273,
"gas_used": 199644,
"timestamp": 1710552813,
"extra_data": "0xd983010d0b846765746888676f312e32312e368664617277696e",
"base_fee_per_gas": 7,
"block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131",
"transactions_root": "0x2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d",
"withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535",
"blob_gas_used": 0,
"excess_blob_gas": 0
}
},
"execution_branch": [
"0xa6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d",
"0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb",
"0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71",
"0xd3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da"
]
}
}
}
@@ -1,10 +1,10 @@
{
"header": {
"slot": 2496,
"proposer_index": 2,
"parent_root": "0xc99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622",
"state_root": "0xfbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde",
"body_root": "0xa2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0"
"slot": 864,
"proposer_index": 4,
"parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614",
"state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a",
"body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e"
},
"current_sync_committee": {
"pubkeys": [
@@ -525,18 +525,18 @@
},
"current_sync_committee_branch": [
"0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59",
"0x93880225bf99a0c5ec22b266ff829837754e9c5edf37a68c05b8f803fd82fa45",
"0x4c60656ec9a95fcf11030ad309c716b5b15beb7f60a0bcfc7c9d4eff505472ff",
"0x22d1645fceb4bf9a695043dda19a53e784ec70df6a6b1bd66ea30eba1cca5f2f",
"0xa8fc6cad84ceefc633ec56c2d031d525e1cb4b51c70eb252919fce5bba9a1fde"
"0xa9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e",
"0xbd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75",
"0x07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7",
"0x94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0"
],
"validators_root": "0x270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69",
"block_roots_root": "0xd160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe",
"block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10",
"block_roots_branch": [
"0x105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135",
"0x9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99",
"0xecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5",
"0xb2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2",
"0xcd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf"
"0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f",
"0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa",
"0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf",
"0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5",
"0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4"
]
}
@@ -2,13 +2,13 @@
"attested_header": {
"slot": 129,
"proposer_index": 5,
"parent_root": "0xe32b6c18f029e755b0273dc1c4fa2bc4979794c8286ad40276c1b8a8e36049d8",
"state_root": "0x5ec9dacf25a5f09f20be0c59246b3d8dcfe64bd085b4bac5cec180690339801e",
"body_root": "0x4080cf2412d6ff77fc3164ad6155423a7112f207f173145ec16371a93f481f87"
"parent_root": "0xc2def03fe44a2802130ca1a6d8406e4ccf4f344fec7075d4d84431cd4a8b0904",
"state_root": "0xfa62cde6666add7353d7aedcb61ebe3c6c84b5361e34f814825b1250affb5be4",
"body_root": "0x0f9c69f243fe7b5fa5860396c66c720a9e8b1e526e7914188930497cc4a9134c"
},
"sync_aggregate": {
"sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"sync_committee_signature": "0xa761c3333fbb3d36bc8f65454f898da38001499dcd37494cf3d86940a995399ae649216ba4c985af154f83f72c8b1856079b7636a7a8d7d3f7602df2cbf699edb72b65253e82de4d9cc4db7377eafb22f799129f63f094a21c00675bdd5cc243"
"sync_committee_signature": "0x810cfde2afea3e276256c09bdf1cd321c33dcadeefddcfd24f488e6f756d917cfda90b5b437b3a4b4ef880985afa28a40cf565ec0a82877ddee36adc01d55d9d4a911ae3e22556e4c2636f1c707366fba019fb49450440fcd263d0b054b04bf0"
},
"signature_slot": 130,
"next_sync_committee_update": {
@@ -531,33 +531,35 @@
},
"next_sync_committee_branch": [
"0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59",
"0xfd1e5ff5d4a15081efe3ff17857b1f95984c9a271b1c41c2f81f43e60c2cc541",
"0xe1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d",
"0x77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61",
"0xe97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68"
"0x43276bee17fc9fba3f4866e902f0e5b5b308d79db91154bb8bf819973837a7d9",
"0x5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd",
"0x2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221",
"0x7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f"
]
},
"finalized_header": {
"slot": 64,
"proposer_index": 4,
"parent_root": "0x0f7bc2353778c14c7f6dba0fc5fe6eec87228b0d3a5447b61dce67b4d9338de3",
"state_root": "0xfeb990de653ce494c0a263f820eaf05a9300dbdc30cb6065ede602827bfccde4",
"body_root": "0xf5235cd8c24f2695fc5b7989926305c10ad8cf5a87d62a739f675f5543df2ec1"
"parent_root": "0xa876486aaad7ddb897f369fd22d0a9903cd61d00c9e0dfe7998dd68d1008c678",
"state_root": "0x818e21c3388575f8ccc9ff17ec79d5a57915bcd31bccf47770f65a18e068416b",
"body_root": "0x1d1f73b864b3bb7e11ff91b56ca1381e0f9ca8122b2c542db88243604c763019"
},
"finality_branch": [
"0x0200000000000000000000000000000000000000000000000000000000000000",
"0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7",
"0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d",
"0xe1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d",
"0x77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61",
"0xe97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68"
"0x5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd",
"0x2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221",
"0x7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f"
],
"block_roots_root": "0x6fcdfd1c3fb1bdd421fe59dddfff3855b5ed5e30373887991a0059d019ad12bc",
"block_roots_root": "0x715b08694bef183a6d94b3113d16a7129f89fc3edec85a7e0eaf6ef9153552ef",
"block_roots_branch": [
"0x94b59531f172bc24f914bc0c10104ccb158676850f8cc3b47b6ddb7f096ebdd7",
"0x22470ed9155a938587d44d5fa19217c0f939d8862e504e67cd8cb4d1b960795e",
"0xfeec3ef1a68f93849e71e84f90b99602cccc31868137b6887ca8244a4b979e8e",
"0x4028c72c71b6ce80ea7d18b2c9471f4e4fa39746261a9921e832a4a2f9bdf7bb",
"0x75f98062661785d3290b7bd998b64446582baa49210733fd4603e1a97cd45a44",
"0x6fb757f44052f30c464810f01b0132adfa1a5446d8715b41e9af88eee1ee3e65",
"0x5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82",
"0xf5ff4b0c6190005015889879568f5f0d9c40134c7ec4ffdda47950dcd92395ad"
]
"0xf2b3cb56753939a728ccad399a434ca490f018f2f331529ec0d8b2d59c509271"
],
"execution_header": null,
"execution_branch": null
}