snowbridge_pallet_ethereum_client/
impls.rs1use super::*;
4use frame_support::ensure;
5use snowbridge_beacon_primitives::ExecutionProof;
6
7use alloy_primitives::Log as AlloyLog;
8use snowbridge_beacon_primitives::merkle_proof::{generalized_index_length, subtree_index};
9use snowbridge_verification_primitives::{
10 receipt::verify_receipt_proof,
11 VerificationError::{self, *},
12 Verifier, *,
13};
14
15impl<T: Config> Verifier for Pallet<T> {
16 fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> {
22 ensure!(!Self::operating_mode().is_halted(), VerificationError::Halted);
29
30 Self::verify_execution_proof(&proof.execution_proof)
31 .map_err(|e| InvalidExecutionProof(e.into()))?;
32
33 Self::verify_receipt_inclusion(
34 proof.execution_proof.execution_header.receipts_root(),
35 event_log.tx_index,
36 &proof.receipt_proof,
37 event_log,
38 )?;
39
40 Ok(())
41 }
42}
43
44impl<T: Config> Pallet<T> {
45 pub fn verify_receipt_inclusion(
48 receipts_root: H256,
49 tx_index: u64,
50 receipt_proof: &[Vec<u8>],
51 log: &Log,
52 ) -> Result<(), VerificationError> {
53 let receipt =
54 verify_receipt_proof(receipts_root, tx_index, receipt_proof).ok_or(InvalidProof)?;
55 if !receipt.logs().iter().any(|l| Self::check_log_match(log, l)) {
56 tracing::error!(
57 target: "ethereum-client",
58 "💫 Event log not found in receipt for transaction",
59 );
60 return Err(LogNotFound);
61 }
62 Ok(())
63 }
64
65 fn check_log_match(log: &Log, receipt_log: &AlloyLog) -> bool {
66 let equal = receipt_log.data.data.0 == log.data &&
67 receipt_log.address.0 == log.address.0 &&
68 receipt_log.topics().len() == log.topics.len();
69 if !equal {
70 return false;
71 }
72 for (_, (topic1, topic2)) in receipt_log.topics().iter().zip(log.topics.iter()).enumerate()
73 {
74 if topic1.0 != topic2.0 {
75 return false;
76 }
77 }
78 true
79 }
80
81 pub(crate) fn verify_execution_proof(execution_proof: &ExecutionProof) -> DispatchResult {
85 let latest_finalized_state =
86 FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get())
87 .ok_or(Error::<T>::NotBootstrapped)?;
88 ensure!(
90 execution_proof.header.slot <= latest_finalized_state.slot,
91 Error::<T>::HeaderNotFinalized
92 );
93
94 let beacon_block_root: H256 = execution_proof
95 .header
96 .hash_tree_root()
97 .map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;
98
99 match &execution_proof.ancestry_proof {
100 Some(proof) => {
101 Self::verify_ancestry_proof(
102 beacon_block_root,
103 execution_proof.header.slot,
104 &proof.header_branch,
105 proof.finalized_block_root,
106 )?;
107 },
108 None => {
109 let state = <FinalizedBeaconState<T>>::get(beacon_block_root)
113 .ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
114 if execution_proof.header.slot != state.slot {
115 return Err(Error::<T>::ExpectedFinalizedHeaderNotStored.into());
116 }
117 },
118 }
119
120 let execution_header_root: H256 = execution_proof
124 .execution_header
125 .hash_tree_root()
126 .map_err(|_| Error::<T>::BlockBodyHashTreeRootFailed)?;
127
128 let execution_header_gindex = Self::execution_header_gindex();
129 ensure!(
130 verify_merkle_branch(
131 execution_header_root,
132 &execution_proof.execution_branch,
133 subtree_index(execution_header_gindex),
134 generalized_index_length(execution_header_gindex),
135 execution_proof.header.body_root
136 ),
137 Error::<T>::InvalidExecutionHeaderProof
138 );
139 Ok(())
140 }
141
142 fn verify_ancestry_proof(
146 block_root: H256,
147 block_slot: u64,
148 block_root_proof: &[H256],
149 finalized_block_root: H256,
150 ) -> DispatchResult {
151 let state = <FinalizedBeaconState<T>>::get(finalized_block_root)
152 .ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
153
154 ensure!(block_slot < state.slot, Error::<T>::HeaderNotFinalized);
155
156 let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64);
157 let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array;
158
159 ensure!(
160 verify_merkle_branch(
161 block_root,
162 block_root_proof,
163 leaf_index as usize,
164 config::BLOCK_ROOT_AT_INDEX_DEPTH,
165 state.block_roots_root
166 ),
167 Error::<T>::InvalidAncestryMerkleProof
168 );
169
170 Ok(())
171 }
172}