@@ -11,27 +11,38 @@ defmodule LambdaEthereumConsensus.ForkChoice.Head do
1111 @ spec get_head ( Store . t ( ) ) :: { :ok , Types . root ( ) } | { :error , any }
1212 def get_head ( % Store { } = store ) do
1313 # Get filtered block tree that only includes viable branches
14- blocks = get_filtered_block_tree ( store )
14+ filtered_blocks = get_filtered_block_tree ( store )
1515 # Execute the LMD-GHOST fork choice
1616 head = store . justified_checkpoint . root
1717
1818 { _store , % BeaconState { } = justified_state } =
1919 Store . get_checkpoint_state ( store , store . justified_checkpoint )
2020
21- # PERF: return just the parent root and the block root in `get_filtered_block_tree`
22- Stream . cycle ( [ nil ] )
23- |> Enum . reduce_while ( head , fn nil , head ->
24- blocks
25- |> Stream . filter ( fn { _ , block } -> block . parent_root == head end )
26- |> Stream . map ( fn { root , _ } -> root end )
27- # Ties broken by favoring block with lexicographically higher root
28- |> Enum . sort ( :desc )
29- |> then ( fn
30- [ ] -> { :halt , head }
31- c -> { :cont , Enum . max_by ( c , & get_weight ( store , & 1 , justified_state ) ) }
32- end )
33- end )
34- |> then ( & { :ok , & 1 } )
21+ head = compute_head ( store , filtered_blocks , head , justified_state )
22+ { :ok , head }
23+ end
24+
25+ defp compute_head ( store , blocks , current_root , justified_state ) do
26+ children = for { root , parent_root } <- blocks , parent_root == current_root , do: root
27+
28+ case children do
29+ [ ] ->
30+ current_root
31+
32+ [ only_child ] ->
33+ # Directly continue without a max_by call
34+ compute_head ( store , blocks , only_child , justified_state )
35+
36+ candidates ->
37+ # Choose the candidate with the maximal weight according to get_weight/3
38+ best_child =
39+ candidates
40+ # Ties broken by favoring block with lexicographically higher root
41+ |> Enum . sort ( :desc )
42+ |> Enum . max_by ( & get_weight ( store , & 1 , justified_state ) )
43+
44+ compute_head ( store , blocks , best_child , justified_state )
45+ end
3546 end
3647
3748 defp get_weight ( % Store { } = store , root , state ) do
@@ -79,11 +90,12 @@ defmodule LambdaEthereumConsensus.ForkChoice.Head do
7990
8091 # Retrieve a filtered block tree from ``store``, only returning branches
8192 # whose leaf state's justified/finalized info agrees with that in ``store``.
93+ # Only return the roots and their parent roots.
8294 defp get_filtered_block_tree ( % Store { } = store ) do
8395 base = store . justified_checkpoint . root
8496 block = Blocks . get_block! ( base )
8597 { _ , blocks } = filter_block_tree ( store , base , block , % { } )
86- blocks
98+ Enum . map ( blocks , fn { root , block } -> { root , block . parent_root } end )
8799 end
88100
89101 defp filter_block_tree ( % Store { } = store , block_root , block , blocks ) do
0 commit comments