snowbridge_pallet_ethereum_client/
impls.rs1use super::*;
4use frame_support::ensure;
5use snowbridge_beacon_primitives::ExecutionProof;
6
7use snowbridge_beacon_primitives::merkle_proof::{generalized_index_length, subtree_index};
8use snowbridge_ethereum::Receipt;
9use snowbridge_verification_primitives::{
10 VerificationError::{self, *},
11 Verifier, *,
12};
13
14impl<T: Config> Verifier for Pallet<T> {
15 fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> {
21 Self::verify_execution_proof(&proof.execution_proof)
22 .map_err(|e| InvalidExecutionProof(e.into()))?;
23
24 let receipt = Self::verify_receipt_inclusion(
25 proof.execution_proof.execution_header.receipts_root(),
26 &proof.receipt_proof.1,
27 )?;
28
29 event_log.validate().map_err(|_| InvalidLog)?;
30
31 let event_log = snowbridge_ethereum::Log {
33 address: event_log.address,
34 topics: event_log.topics.clone(),
35 data: event_log.data.clone(),
36 };
37
38 if !receipt.contains_log(&event_log) {
39 log::error!(
40 target: "ethereum-client",
41 "💫 Event log not found in receipt for transaction",
42 );
43 return Err(LogNotFound)
44 }
45
46 Ok(())
47 }
48}
49
50impl<T: Config> Pallet<T> {
51 pub fn verify_receipt_inclusion(
54 receipts_root: H256,
55 receipt_proof: &[Vec<u8>],
56 ) -> Result<Receipt, VerificationError> {
57 let result = verify_receipt_proof(receipts_root, receipt_proof).ok_or(InvalidProof)?;
58
59 match result {
60 Ok(receipt) => Ok(receipt),
61 Err(err) => {
62 log::trace!(
63 target: "ethereum-client",
64 "💫 Failed to decode transaction receipt: {}",
65 err
66 );
67 Err(InvalidProof)
68 },
69 }
70 }
71
72 pub(crate) fn verify_execution_proof(execution_proof: &ExecutionProof) -> DispatchResult {
76 let latest_finalized_state =
77 FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get())
78 .ok_or(Error::<T>::NotBootstrapped)?;
79 ensure!(
81 execution_proof.header.slot <= latest_finalized_state.slot,
82 Error::<T>::HeaderNotFinalized
83 );
84
85 let beacon_block_root: H256 = execution_proof
86 .header
87 .hash_tree_root()
88 .map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;
89
90 match &execution_proof.ancestry_proof {
91 Some(proof) => {
92 Self::verify_ancestry_proof(
93 beacon_block_root,
94 execution_proof.header.slot,
95 &proof.header_branch,
96 proof.finalized_block_root,
97 )?;
98 },
99 None => {
100 let state = <FinalizedBeaconState<T>>::get(beacon_block_root)
104 .ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
105 if execution_proof.header.slot != state.slot {
106 return Err(Error::<T>::ExpectedFinalizedHeaderNotStored.into())
107 }
108 },
109 }
110
111 let execution_header_root: H256 = execution_proof
115 .execution_header
116 .hash_tree_root()
117 .map_err(|_| Error::<T>::BlockBodyHashTreeRootFailed)?;
118
119 let execution_header_gindex = Self::execution_header_gindex();
120 ensure!(
121 verify_merkle_branch(
122 execution_header_root,
123 &execution_proof.execution_branch,
124 subtree_index(execution_header_gindex),
125 generalized_index_length(execution_header_gindex),
126 execution_proof.header.body_root
127 ),
128 Error::<T>::InvalidExecutionHeaderProof
129 );
130 Ok(())
131 }
132
133 fn verify_ancestry_proof(
137 block_root: H256,
138 block_slot: u64,
139 block_root_proof: &[H256],
140 finalized_block_root: H256,
141 ) -> DispatchResult {
142 let state = <FinalizedBeaconState<T>>::get(finalized_block_root)
143 .ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
144
145 ensure!(block_slot < state.slot, Error::<T>::HeaderNotFinalized);
146
147 let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64);
148 let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array;
149
150 ensure!(
151 verify_merkle_branch(
152 block_root,
153 block_root_proof,
154 leaf_index as usize,
155 config::BLOCK_ROOT_AT_INDEX_DEPTH,
156 state.block_roots_root
157 ),
158 Error::<T>::InvalidAncestryMerkleProof
159 );
160
161 Ok(())
162 }
163}