@@ -20,15 +20,15 @@ defmodule LambdaEthereumConsensus.Beacon.StoreSetup do
2020 @ doc """
2121 Args: at least one can be nil.
2222 - testnet_dir: directory of a testnet configuration, including ssz and yaml config.
23- - checkpoint_sync_url: a url where checkpoint sync can be performed.
23+ - checkpoint_sync_url: list of urls where checkpoint sync can be performed.
2424
2525 Return value: a store setup strategy, which is one of the following:
2626 - {:file, anchor_state}: path of an ssz file to get the genesis state from.
27- - {:checkpoint_sync_url, url}: url to get the genesis state from if performing checkpoint sync.
27+ - {:checkpoint_sync_url, url}: list of urls to get the genesis state from if performing checkpoint sync.
2828 - :db : the genesis state and store can only be recovered from the db.
2929 """
3030 def make_strategy! ( nil , nil ) , do: :db
31- def make_strategy! ( nil , url ) when is_binary ( url ) , do: { :checkpoint_sync_url , url }
31+ def make_strategy! ( nil , urls ) when is_list ( urls ) , do: { :checkpoint_sync_url , urls }
3232
3333 def make_strategy! ( dir , nil ) when is_binary ( dir ) do
3434 Path . join ( dir , "genesis.ssz" )
@@ -55,14 +55,14 @@ defmodule LambdaEthereumConsensus.Beacon.StoreSetup do
5555 store
5656 end
5757
58- def setup! ( { :checkpoint_sync_url , checkpoint_url } ) do
58+ def setup! ( { :checkpoint_sync_url , checkpoint_urls } ) do
5959 case restore_state_from_db ( ) do
6060 { :ok , store } ->
6161 Logger . warning ( "[Checkpoint sync] Recent state found. Ignoring the checkpoint URL." )
6262 store
6363
6464 _ ->
65- fetch_state_from_url ( checkpoint_url )
65+ fetch_and_compare_state_from_urls ( checkpoint_urls )
6666 end
6767 end
6868
@@ -87,8 +87,12 @@ defmodule LambdaEthereumConsensus.Beacon.StoreSetup do
8787 @ spec get_deposit_snapshot! ( ) :: DepositTreeSnapshot . t ( ) | nil
8888 def get_deposit_snapshot! ( ) , do: get_deposit_snapshot! ( get_strategy! ( ) )
8989
90+ # The endpoint for deposit snapshots is deprecated in electra and will be removed in Fulu
91+ # https://github.com/ethereum/beacon-APIs/pull/494
92+ # For this reason we don't compare the deposits from the urls as most checkpoints are returning error 500
9093 @ spec get_deposit_snapshot! ( store_setup_strategy ( ) ) :: DepositTreeSnapshot . t ( ) | nil
91- def get_deposit_snapshot! ( { :checkpoint_sync_url , url } ) , do: fetch_deposit_snapshot ( url )
94+ def get_deposit_snapshot! ( { :checkpoint_sync_url , urls } ) ,
95+ do: fetch_deposit_snapshot ( List . first ( urls ) )
9296
9397 def get_deposit_snapshot! ( :db ) do
9498 case StoreDb . fetch_deposits_snapshot ( ) do
@@ -129,28 +133,65 @@ defmodule LambdaEthereumConsensus.Beacon.StoreSetup do
129133 end
130134 end
131135
132- defp fetch_state_from_url ( url ) do
136+ defp fetch_and_compare_state_from_urls ( urls ) do
133137 Logger . info ( "[Checkpoint sync] Initiating checkpoint sync" )
134138
139+ # Fetch last finalized block for all urls
140+ blocks = for { :ok , res } <- Enum . map ( urls , & CheckpointSync . get_block / 1 ) , do: res
141+
142+ case Enum . uniq ( blocks ) do
143+ [ _ ] ->
144+ Logger . info (
145+ "[Checkpoin sync] Received the same last finalized block from #{ length ( blocks ) } checkpoint nodes"
146+ )
147+
148+ _ ->
149+ Logger . error (
150+ "[Checkpoint sync] Received inconsistent last finalized block from #{ length ( blocks ) } checkpoint nodes"
151+ )
152+
153+ Logger . flush ( )
154+ System . halt ( 1 )
155+ end
156+
135157 genesis_validators_root = ChainSpec . get_genesis_validators_root ( )
136158
159+ # All urls returned the same last finalized block, we will trust the first to get the state
160+ { anchor_state , anchor_block } = fetch_state_from_url ( genesis_validators_root , List . first ( urls ) )
161+
162+ first_block = List . first ( blocks )
163+
164+ if anchor_state . latest_block_header . parent_root == first_block . message . parent_root do
165+ { :ok , store } = Store . get_forkchoice_store ( anchor_state , anchor_block )
166+
167+ # Save store in DB
168+ StoreDb . persist_store ( store )
169+
170+ store
171+ else
172+ Logger . error (
173+ "[Checkpoint sync] Root mismatch when comparing latest finalized block with downloaded state"
174+ )
175+
176+ Logger . flush ( )
177+ System . halt ( 1 )
178+ end
179+ end
180+
181+ defp fetch_state_from_url ( genesis_validators_root , url ) do
137182 case CheckpointSync . get_finalized_block_and_state ( url , genesis_validators_root ) do
138183 { :ok , { anchor_state , anchor_block } } ->
139184 Logger . info (
140- "[Checkpoint sync] Received beacon state and block" ,
185+ "[Checkpoint sync] Received beacon state and block from URL #{ url } " ,
141186 slot: anchor_state . slot
142187 )
143188
144- # We already checked block and state match
145- { :ok , store } = Store . get_forkchoice_store ( anchor_state , anchor_block )
146-
147- # Save store in DB
148- StoreDb . persist_store ( store )
149-
150- store
189+ { anchor_state , anchor_block }
151190
152191 _ ->
153- Logger . error ( "[Checkpoint sync] Failed to fetch the latest finalized state and block" )
192+ Logger . error (
193+ "[Checkpoint sync] Failed to fetch the latest finalized state and block for URL: #{ url } "
194+ )
154195
155196 Logger . flush ( )
156197 System . halt ( 1 )
0 commit comments