@@ -5,8 +5,6 @@ defmodule LambdaEthereumConsensus.Validator do
5
5
require Logger
6
6
7
7
defstruct [
8
- :epoch ,
9
- :duties ,
10
8
:index ,
11
9
:keystore ,
12
10
:payload_builder
@@ -33,162 +31,64 @@ defmodule LambdaEthereumConsensus.Validator do
33
31
# TODO: Slot and Root are redundant, we should also have the duties separated and calculated
34
32
# just at the begining of every epoch, and then just update them as needed.
35
33
@ type t :: % __MODULE__ {
36
- epoch: Types . epoch ( ) ,
37
- duties: Duties . duties ( ) ,
38
34
index: non_neg_integer ( ) | nil ,
39
35
keystore: Keystore . t ( ) ,
40
36
payload_builder: { Types . slot ( ) , Types . root ( ) , BlockBuilder . payload_id ( ) } | nil
41
37
}
42
38
43
- @ spec new (
44
- Keystore . t ( ) ,
45
- Types . slot ( ) ,
46
- Types . root ( )
47
- ) :: t ( )
39
+ @ spec new ( Keystore . t ( ) , Types . slot ( ) , Types . root ( ) ) :: t ( )
48
40
def new ( keystore , head_slot , head_root ) do
49
41
epoch = Misc . compute_epoch_at_slot ( head_slot )
50
- beacon = fetch_target_state ( epoch , head_root ) |> go_to_slot ( head_slot )
42
+ beacon = fetch_target_state_and_go_to_slot ( epoch , head_slot , head_root )
51
43
52
- new ( keystore , epoch , head_slot , head_root , beacon )
44
+ new ( keystore , beacon )
53
45
end
54
46
55
- @ spec new (
56
- Keystore . t ( ) ,
57
- Types . epoch ( ) ,
58
- Types . slot ( ) ,
59
- Types . root ( ) ,
60
- Types.BeaconState . t ( )
61
- ) :: t ( )
62
- def new ( keystore , epoch , head_slot , head_root , beacon ) do
47
+ @ spec new ( Keystore . t ( ) , Types.BeaconState . t ( ) ) :: t ( )
48
+ def new ( keystore , beacon ) do
63
49
state = % __MODULE__ {
64
- epoch: epoch ,
65
- duties: Duties . empty_duties ( ) ,
66
50
index: nil ,
67
51
keystore: keystore ,
68
52
payload_builder: nil
69
53
}
70
54
71
- case try_setup_validator ( state , epoch , head_slot , head_root , beacon ) do
72
- nil ->
73
- # TODO: Previously this was handled by the validator continously trying to setup itself,
74
- # but now that they are processed syncronously, we should handle this case different.
75
- # Right now it's just omitted and logged.
76
- Logger . error ( "[Validator] Public key not found in the validator set" )
77
- state
78
-
79
- new_state ->
80
- new_state
81
- end
82
- end
83
-
84
- @ spec try_setup_validator (
85
- t ( ) ,
86
- Types . epoch ( ) ,
87
- Types . slot ( ) ,
88
- Types . root ( ) ,
89
- Types.BeaconState . t ( )
90
- ) :: t ( ) | nil
91
- defp try_setup_validator ( state , epoch , slot , root , beacon ) do
92
55
case fetch_validator_index ( beacon , state . keystore . pubkey ) do
93
56
nil ->
94
- nil
57
+ Logger . warning (
58
+ "[Validator] Public key #{ state . keystore . pubkey } not found in the validator set"
59
+ )
60
+
61
+ state
95
62
96
63
validator_index ->
97
- log_info ( validator_index , "setup validator" , slot: slot , root: root )
98
-
99
- duties =
100
- Duties . maybe_update_duties (
101
- state . duties ,
102
- beacon ,
103
- epoch ,
104
- validator_index ,
105
- state . keystore . privkey
106
- )
107
-
108
- join_subnets_for_duties ( duties )
109
- Duties . log_duties ( duties , validator_index )
110
- % { state | duties: duties , index: validator_index }
64
+ log_debug ( validator_index , "Setup completed" )
65
+ % { state | index: validator_index }
111
66
end
112
67
end
113
68
114
69
##########################
115
- ### Private Functions
116
- ##########################
70
+ # Target State
117
71
118
- # @spec update_state(t(), Types.slot(), Types.root()) :: t()
119
-
120
- # defp update_state(%{slot: slot, root: root} = state, slot, root), do: state
121
-
122
- # # Epoch as part of the state now avoids recomputing the duties at every block
123
- # defp update_state(%{epoch: last_epoch} = state, slot, head_root) do
124
- # epoch = Misc.compute_epoch_at_slot(slot + 1)
125
-
126
- # if last_epoch == epoch do
127
- # state
128
- # else
129
- # recompute_duties(state, last_epoch, epoch, slot, head_root)
130
- # end
131
- # end
132
-
133
- # @spec recompute_duties(t(), Types.epoch(), Types.epoch(), Types.slot(), Types.root()) :: t()
134
- # defp recompute_duties(state, last_epoch, epoch, _slot, head_root) do
135
- # start_slot = Misc.compute_start_slot_at_epoch(epoch)
136
-
137
- # # TODO: Why is this needed? something here seems wrong, why would i need to move to a different slot if
138
- # # I'm calculating this at a new epoch? need to check it
139
- # # target_root = if slot == start_slot, do: head_root, else: last_root
140
-
141
- # # Process the start of the new epoch
142
- # # new_beacon = fetch_target_state(epoch, target_root) |> go_to_slot(start_slot)
143
- # new_beacon = fetch_target_state(epoch, head_root) |> go_to_slot(start_slot)
144
-
145
- # new_duties =
146
- # Duties.shift_duties(state.duties, epoch, last_epoch)
147
- # |> Duties.maybe_update_duties(new_beacon, epoch, state.index, state.keystore.privkey)
148
-
149
- # move_subnets(state.duties, new_duties)
150
- # Duties.log_duties(new_duties, state.index)
151
-
152
- # %{state | duties: new_duties, epoch: epoch}
153
- # end
72
+ @ spec fetch_target_state_and_go_to_slot ( Types . epoch ( ) , Types . slot ( ) , Types . root ( ) ) ::
73
+ Types.BeaconState . t ( )
74
+ def fetch_target_state_and_go_to_slot ( epoch , slot , root ) do
75
+ epoch |> fetch_target_state ( root ) |> go_to_slot ( slot )
76
+ end
154
77
155
- @ spec fetch_target_state ( Types . epoch ( ) , Types . root ( ) ) :: Types.BeaconState . t ( )
156
78
defp fetch_target_state ( epoch , root ) do
157
79
{ :ok , state } = CheckpointStates . compute_target_checkpoint_state ( epoch , root )
158
80
state
159
81
end
160
82
161
- defp join_subnets_for_duties ( % { attester: duties } ) do
162
- duties |> get_subnet_ids ( ) |> join ( )
163
- end
164
-
165
- defp get_subnet_ids ( duties ) ,
166
- do: duties |> Stream . reject ( & ( & 1 == :not_computed ) ) |> Enum . map ( & & 1 . subnet_id )
167
-
168
- # defp move_subnets(%{attester: old_duties}, %{attester: new_duties}) do
169
- # old_subnets = old_duties |> get_subnet_ids() |> MapSet.new()
170
- # new_subnets = new_duties |> get_subnet_ids() |> MapSet.new()
171
-
172
- # # leave old subnets (except for recurring ones)
173
- # MapSet.difference(old_subnets, new_subnets) |> leave()
174
-
175
- # # join new subnets (except for recurring ones)
176
- # MapSet.difference(new_subnets, old_subnets) |> join()
177
- # end
83
+ defp go_to_slot ( % { slot: old_slot } = state , slot ) when old_slot == slot , do: state
178
84
179
- defp join ( subnets ) do
180
- if not Enum . empty? ( subnets ) do
181
- Logger . debug ( "Joining subnets: #{ Enum . join ( subnets , ", " ) } " )
182
- Enum . each ( subnets , & Gossip.Attestation . join / 1 )
183
- end
85
+ defp go_to_slot ( % { slot: old_slot } = state , slot ) when old_slot < slot do
86
+ { :ok , st } = StateTransition . process_slots ( state , slot )
87
+ st
184
88
end
185
89
186
- # defp leave(subnets) do
187
- # if not Enum.empty?(subnets) do
188
- # Logger.debug("Leaving subnets: #{Enum.join(subnets, ", ")}")
189
- # Enum.each(subnets, &Gossip.Attestation.leave/1)
190
- # end
191
- # end
90
+ ##########################
91
+ # Attestations
192
92
193
93
@ spec attest ( t ( ) , Duties . attester_duty ( ) , Types . root ( ) ) :: :ok
194
94
def attest ( % { index: validator_index , keystore: keystore } , current_duty , head_root ) do
@@ -202,7 +102,7 @@ defmodule LambdaEthereumConsensus.Validator do
202
102
debug_log_msg =
203
103
"publishing attestation on committee index: #{ current_duty . committee_index } | as #{ current_duty . index_in_committee } /#{ current_duty . committee_length - 1 } and pubkey: #{ LambdaEthereumConsensus.Utils . format_shorten_binary ( keystore . pubkey ) } "
204
104
205
- log_debug ( validator_index , debug_log_msg , log_md )
105
+ log_info ( validator_index , debug_log_msg , log_md )
206
106
207
107
Gossip.Attestation . publish ( subnet_id , attestation )
208
108
|> log_info_result ( validator_index , "published attestation" , log_md )
@@ -305,23 +205,15 @@ defmodule LambdaEthereumConsensus.Validator do
305
205
}
306
206
end
307
207
308
- defp go_to_slot ( % { slot: old_slot } = state , slot ) when old_slot == slot , do: state
309
-
310
- defp go_to_slot ( % { slot: old_slot } = state , slot ) when old_slot < slot do
311
- { :ok , st } = StateTransition . process_slots ( state , slot )
312
- st
313
- end
314
-
315
- defp go_to_slot ( % { latest_block_header: % { parent_root: parent_root } } , slot ) do
316
- BlockStates . get_state_info! ( parent_root ) . beacon_state |> go_to_slot ( slot )
317
- end
318
-
319
208
@ spec fetch_validator_index ( Types.BeaconState . t ( ) , Bls . pubkey ( ) ) ::
320
209
non_neg_integer ( ) | nil
321
210
defp fetch_validator_index ( beacon , pubkey ) do
322
211
Enum . find_index ( beacon . validators , & ( & 1 . pubkey == pubkey ) )
323
212
end
324
213
214
+ ################################
215
+ # Payload building and proposing
216
+
325
217
@ spec start_payload_builder ( t ( ) , Types . slot ( ) , Types . root ( ) ) :: t ( )
326
218
def start_payload_builder ( % { payload_builder: { slot , root , _ } } = state , slot , root ) , do: state
327
219
@@ -380,7 +272,6 @@ defmodule LambdaEthereumConsensus.Validator do
380
272
% { state | payload_builder: nil }
381
273
end
382
274
383
- # TODO: at least in kurtosis there are blocks that are proposed without a payload apparently, must investigate.
384
275
def propose ( % { payload_builder: nil } = state , _proposed_slot , _head_root ) do
385
276
log_error ( state . index , "propose block" , "lack of execution payload" )
386
277
state
@@ -426,7 +317,8 @@ defmodule LambdaEthereumConsensus.Validator do
426
317
rem ( blob_index , ChainSpec . get ( "BLOB_SIDECAR_SUBNET_COUNT" ) )
427
318
end
428
319
429
- # Some Log Helpers to avoid repetition
320
+ ################################
321
+ # Log Helpers
430
322
431
323
defp log_info_result ( result , index , message , metadata ) ,
432
324
do: log_result ( result , :info , index , message , metadata )
@@ -440,7 +332,7 @@ defmodule LambdaEthereumConsensus.Validator do
440
332
defp log_info ( index , message , metadata \\ [ ] ) ,
441
333
do: Logger . info ( "[Validator] #{ index } #{ message } " , metadata )
442
334
443
- defp log_debug ( index , message , metadata ) ,
335
+ defp log_debug ( index , message , metadata \\ [ ] ) ,
444
336
do: Logger . debug ( "[Validator] #{ index } #{ message } " , metadata )
445
337
446
338
defp log_error ( index , message , reason , metadata \\ [ ] ) ,
0 commit comments