@@ -138,7 +138,7 @@ defmodule LambdaEthereumConsensus.Execution.ExecutionChain do
138
138
139
139
if has_majority? ( eth1_data_votes , eth1_data ) do
140
140
case update_deposit_tree ( new_state , eth1_data ) do
141
- { :ok , new_tree } -> % { state | deposit_tree: new_tree , current_eth1_data: eth1_data }
141
+ { :ok , new_tree } -> % { new_state | deposit_tree: new_tree , current_eth1_data: eth1_data }
142
142
_ -> new_state
143
143
end
144
144
else
@@ -193,16 +193,16 @@ defmodule LambdaEthereumConsensus.Execution.ExecutionChain do
193
193
% {
194
194
eth1_chain: eth1_chain ,
195
195
eth1_data_votes: seen_votes ,
196
- deposit_tree: deposit_tree
196
+ deposit_tree: deposit_tree ,
197
+ current_eth1_data: default
197
198
} ,
198
199
slot
199
200
) do
200
201
period_start = voting_period_start_time ( slot )
201
- follow_time = ChainSpec . get ( "SECONDS_PER_ETH1_BLOCK" ) * ChainSpec . get ( "ETH1_FOLLOW_DISTANCE" )
202
202
203
203
blocks_to_consider =
204
204
eth1_chain
205
- |> Enum . filter ( & candidate_block? ( & 1 . timestamp , period_start , follow_time ) )
205
+ |> Enum . filter ( & candidate_block? ( & 1 . timestamp , period_start ) )
206
206
|> Enum . reverse ( )
207
207
208
208
# TODO: backfill chain
@@ -217,54 +217,79 @@ defmodule LambdaEthereumConsensus.Execution.ExecutionChain do
217
217
# TODO: fetch asynchronously
218
218
with { :ok , new_deposits } <-
219
219
ExecutionClient . get_deposit_logs ( block_number_min .. block_number_max ) do
220
- get_first_valid_vote ( blocks_to_consider , seen_votes , deposit_tree , new_deposits )
220
+ get_first_valid_vote ( blocks_to_consider , seen_votes , deposit_tree , new_deposits , default )
221
221
end
222
222
end
223
223
end
224
224
225
- defp get_first_valid_vote ( blocks_to_consider , seen_votes , deposit_tree , new_deposits ) do
226
- grouped_deposits = Enum . group_by ( new_deposits , & Map . fetch! ( & 1 , :block_number ) )
227
-
228
- { valid_votes , _last_tree } =
229
- blocks_to_consider
230
- |> Enum . reduce ( { MapSet . new ( ) , deposit_tree } , fn block , { set , tree } ->
231
- new_tree =
232
- case grouped_deposits [ block . block_number ] do
233
- nil -> tree
234
- deposits -> update_tree_with_deposits ( tree , deposits )
235
- end
225
+ defp get_first_valid_vote ( blocks_to_consider , seen_votes , deposit_tree , new_deposits , default ) do
226
+ Logger . debug (
227
+ "Processing new deposits: #{ inspect ( new_deposits ) } and get first valid vote, with default: #{ inspect ( default ) } "
228
+ )
236
229
237
- data = % Eth1Data {
238
- deposit_root: DepositTree . get_root ( new_tree ) ,
239
- deposit_count: DepositTree . get_deposit_count ( new_tree ) ,
240
- block_hash: block . block_hash
241
- }
230
+ { valid_votes , last_eth1_data } =
231
+ get_valid_votes ( blocks_to_consider , deposit_tree , new_deposits , default )
242
232
243
- { MapSet . put ( set , data ) , new_tree }
244
- end )
233
+ # Default vote on latest eth1 block data in the period range unless eth1 chain is not live
234
+ default_vote = last_eth1_data || default
245
235
246
- # Tiebreak by smallest distance to period start
236
+ # Tiebreak by smallest distance to period start seen_votes is a %{eth1_data -> {count, dist}}
247
237
result =
248
238
seen_votes
249
- |> Stream . filter ( & MapSet . member? ( valid_votes , & 1 ) )
250
- |> Enum . max ( fn { _ , count1 } , { _ , count2 } -> count1 >= count2 end , fn -> nil end )
239
+ |> Stream . filter ( fn { eth1_data , _ } -> MapSet . member? ( valid_votes , eth1_data ) end )
240
+ |> Enum . max (
241
+ fn { _ , { count1 , dist1 } } , { _ , { count2 , dist2 } } ->
242
+ cond do
243
+ count1 > count2 -> true
244
+ count1 == count2 && dist1 > dist2 -> true
245
+ true -> false
246
+ end
247
+ end ,
248
+ fn -> nil end
249
+ )
251
250
252
251
case result do
253
- # Use the first vote if there is a tie
254
- nil -> { :ok , List . last ( valid_votes ) }
252
+ nil -> { :ok , default_vote }
255
253
{ eth1_data , _ } -> { :ok , eth1_data }
256
254
end
257
255
end
258
256
257
+ defp get_valid_votes ( blocks_to_consider , deposit_tree , new_deposits , default ) do
258
+ grouped_deposits = Enum . group_by ( new_deposits , & Map . fetch! ( & 1 , :block_number ) )
259
+
260
+ blocks_to_consider
261
+ |> Enum . reduce ( { MapSet . new ( ) , deposit_tree , nil } , fn block , { set , tree , last_eth1_data } ->
262
+ new_tree =
263
+ case grouped_deposits [ block . block_number ] do
264
+ nil -> tree
265
+ deposits -> update_tree_with_deposits ( tree , deposits )
266
+ end
267
+
268
+ data = get_eth1_data ( block , new_tree )
269
+
270
+ if data . deposit_count >= default . deposit_count ,
271
+ do: { MapSet . put ( set , data ) , new_tree , data } ,
272
+ else: { set , new_tree , last_eth1_data }
273
+ end )
274
+ end
275
+
276
+ defp get_eth1_data ( block , tree ) do
277
+ % Eth1Data {
278
+ deposit_root: DepositTree . get_root ( tree ) ,
279
+ deposit_count: DepositTree . get_deposit_count ( tree ) ,
280
+ block_hash: block . block_hash
281
+ }
282
+ end
283
+
259
284
defp update_tree_with_deposits ( tree , [ ] ) , do: tree
260
285
261
286
defp update_tree_with_deposits ( tree , [ deposit | rest ] ) do
262
287
DepositTree . push_leaf ( tree , deposit . data ) |> update_tree_with_deposits ( rest )
263
288
end
264
289
265
- defp candidate_block? ( timestamp , period_start , follow_time ) do
266
- # follow_time = SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE
267
- timestamp in ( period_start - follow_time * 2 ) .. ( period_start - follow_time )
290
+ defp candidate_block? ( timestamp , period_start ) do
291
+ follow_time = ChainSpec . get ( " SECONDS_PER_ETH1_BLOCK" ) * ChainSpec . get ( " ETH1_FOLLOW_DISTANCE" )
292
+ timestamp + follow_time <= period_start and timestamp + follow_time * 2 >= period_start
268
293
end
269
294
270
295
defp voting_period_start_time ( slot ) do
0 commit comments