Skip to content

Commit 5331a63

Browse files
committed
Epoch 0 completely working from ValidatorSet
1 parent c99729f commit 5331a63

File tree

2 files changed

+76
-183
lines changed

2 files changed

+76
-183
lines changed

lib/lambda_ethereum_consensus/validator/validator.ex

Lines changed: 47 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -111,101 +111,70 @@ defmodule LambdaEthereumConsensus.Validator do
111111
end
112112
end
113113

114-
@spec handle_tick({Types.slot(), atom()}, t(), Types.root()) :: t()
115-
def handle_tick(_logical_time, %{index: nil} = state, _root) do
116-
log_error("-1", "setup validator", "index not present for handle tick")
117-
state
118-
end
119-
120-
def handle_tick({slot, :first_third}, state, root) do
121-
log_debug(state.index, "started first third", slot: slot)
122-
# Here we may:
123-
# 1. propose our blocks
124-
# 2. (TODO) start collecting attestations for aggregation
125-
maybe_propose(state, slot, root)
126-
|> update_state(slot, root)
127-
end
128-
129-
def handle_tick({slot, :second_third}, state, root) do
130-
log_debug(state.index, "started second third", slot: slot)
131-
# Here we may:
132-
# 1. send our attestation for an empty slot
133-
# 2. start building a payload
134-
state
135-
|> maybe_attest(slot, root)
136-
|> maybe_build_payload(slot + 1, root)
137-
end
138-
139-
def handle_tick({slot, :last_third}, state, _root) do
140-
log_debug(state.index, "started last third", slot: slot)
141-
# Here we may publish our attestation aggregate
142-
maybe_publish_aggregate(state, slot)
143-
end
144-
145114
##########################
146115
### Private Functions
147116
##########################
148117

149-
@spec update_state(t(), Types.slot(), Types.root()) :: t()
118+
# @spec update_state(t(), Types.slot(), Types.root()) :: t()
150119

151-
defp update_state(%{slot: slot, root: root} = state, slot, root), do: state
120+
# defp update_state(%{slot: slot, root: root} = state, slot, root), do: state
152121

153-
# Epoch as part of the state now avoids recomputing the duties at every block
154-
defp update_state(%{epoch: last_epoch} = state, slot, head_root) do
155-
epoch = Misc.compute_epoch_at_slot(slot + 1)
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)
156125

157-
if last_epoch == epoch do
158-
state
159-
else
160-
recompute_duties(state, last_epoch, epoch, slot, head_root)
161-
end
162-
end
126+
# if last_epoch == epoch do
127+
# state
128+
# else
129+
# recompute_duties(state, last_epoch, epoch, slot, head_root)
130+
# end
131+
# end
163132

164-
@spec recompute_duties(t(), Types.epoch(), Types.epoch(), Types.slot(), Types.root()) :: t()
165-
defp recompute_duties(state, last_epoch, epoch, _slot, head_root) do
166-
start_slot = Misc.compute_start_slot_at_epoch(epoch)
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)
167136

168-
# TODO: Why is this needed? something here seems wrong, why would i need to move to a different slot if
169-
# I'm calculating this at a new epoch? need to check it
170-
# target_root = if slot == start_slot, do: head_root, else: last_root
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
171140

172-
# Process the start of the new epoch
173-
# new_beacon = fetch_target_state(epoch, target_root) |> go_to_slot(start_slot)
174-
new_beacon = fetch_target_state(epoch, head_root) |> go_to_slot(start_slot)
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)
175144

176-
new_duties =
177-
Duties.shift_duties(state.duties, epoch, last_epoch)
178-
|> Duties.maybe_update_duties(new_beacon, epoch, state.index, state.keystore.privkey)
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)
179148

180-
move_subnets(state.duties, new_duties)
181-
Duties.log_duties(new_duties, state.index)
149+
# move_subnets(state.duties, new_duties)
150+
# Duties.log_duties(new_duties, state.index)
182151

183-
%{state | duties: new_duties, epoch: epoch}
184-
end
152+
# %{state | duties: new_duties, epoch: epoch}
153+
# end
185154

186155
@spec fetch_target_state(Types.epoch(), Types.root()) :: Types.BeaconState.t()
187156
defp fetch_target_state(epoch, root) do
188157
{:ok, state} = CheckpointStates.compute_target_checkpoint_state(epoch, root)
189158
state
190159
end
191160

161+
defp join_subnets_for_duties(%{attester: duties}) do
162+
duties |> get_subnet_ids() |> join()
163+
end
164+
192165
defp get_subnet_ids(duties),
193166
do: duties |> Stream.reject(&(&1 == :not_computed)) |> Enum.map(& &1.subnet_id)
194167

195-
defp move_subnets(%{attester: old_duties}, %{attester: new_duties}) do
196-
old_subnets = old_duties |> get_subnet_ids() |> MapSet.new()
197-
new_subnets = new_duties |> get_subnet_ids() |> MapSet.new()
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()
198171

199-
# leave old subnets (except for recurring ones)
200-
MapSet.difference(old_subnets, new_subnets) |> leave()
172+
# # leave old subnets (except for recurring ones)
173+
# MapSet.difference(old_subnets, new_subnets) |> leave()
201174

202-
# join new subnets (except for recurring ones)
203-
MapSet.difference(new_subnets, old_subnets) |> join()
204-
end
205-
206-
defp join_subnets_for_duties(%{attester: duties}) do
207-
duties |> get_subnet_ids() |> join()
208-
end
175+
# # join new subnets (except for recurring ones)
176+
# MapSet.difference(new_subnets, old_subnets) |> join()
177+
# end
209178

210179
defp join(subnets) do
211180
if not Enum.empty?(subnets) do
@@ -214,28 +183,12 @@ defmodule LambdaEthereumConsensus.Validator do
214183
end
215184
end
216185

217-
defp leave(subnets) do
218-
if not Enum.empty?(subnets) do
219-
Logger.debug("Leaving subnets: #{Enum.join(subnets, ", ")}")
220-
Enum.each(subnets, &Gossip.Attestation.leave/1)
221-
end
222-
end
223-
224-
@spec maybe_attest(t(), Types.slot(), Types.root()) :: t()
225-
defp maybe_attest(state, slot, head_root) do
226-
case Duties.get_current_attester_duty(state.duties, slot) do
227-
%{attested?: false} = duty ->
228-
attest(state, duty, head_root)
229-
230-
new_duties =
231-
Duties.replace_attester_duty(state.duties, duty, %{duty | attested?: true})
232-
233-
%{state | duties: new_duties}
234-
235-
_ ->
236-
state
237-
end
238-
end
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
239192

240193
@spec attest(t(), Duties.attester_duty(), Types.root()) :: :ok
241194
def attest(%{index: validator_index, keystore: keystore}, current_duty, head_root) do
@@ -262,22 +215,7 @@ defmodule LambdaEthereumConsensus.Validator do
262215
end
263216
end
264217

265-
# We publish our aggregate on the next slot, and when we're an aggregator
266-
defp maybe_publish_aggregate(%{index: validator_index, keystore: keystore} = state, slot) do
267-
case Duties.get_current_attester_duty(state.duties, slot) do
268-
%{should_aggregate?: true} = duty ->
269-
publish_aggregate(duty, validator_index, keystore)
270-
271-
new_duties =
272-
Duties.replace_attester_duty(state.duties, duty, %{duty | should_aggregate?: false})
273-
274-
%{state | duties: new_duties}
275-
276-
_ ->
277-
state
278-
end
279-
end
280-
218+
@spec publish_aggregate(Duties.attester_duty(), non_neg_integer(), Keystore.t()) :: :ok
281219
def publish_aggregate(duty, validator_index, keystore) do
282220
case Gossip.Attestation.stop_collecting(duty.subnet_id) do
283221
{:ok, attestations} ->
@@ -384,17 +322,6 @@ defmodule LambdaEthereumConsensus.Validator do
384322
Enum.find_index(beacon.validators, &(&1.pubkey == pubkey))
385323
end
386324

387-
defp proposer?(%{duties: %{proposer: slots}}, slot), do: Enum.member?(slots, slot)
388-
389-
@spec maybe_build_payload(t(), Types.slot(), Types.root()) :: t()
390-
defp maybe_build_payload(state, proposed_slot, head_root) do
391-
if proposer?(state, proposed_slot) do
392-
start_payload_builder(state, proposed_slot, head_root)
393-
else
394-
state
395-
end
396-
end
397-
398325
@spec start_payload_builder(t(), Types.slot(), Types.root()) :: t()
399326
def start_payload_builder(%{payload_builder: {slot, root, _}} = state, slot, root), do: state
400327

@@ -417,14 +344,7 @@ defmodule LambdaEthereumConsensus.Validator do
417344
end
418345
end
419346

420-
defp maybe_propose(state, slot, root) do
421-
if proposer?(state, slot) do
422-
propose(state, slot, root)
423-
else
424-
state
425-
end
426-
end
427-
347+
@spec propose(t(), Types.slot(), Types.root()) :: t()
428348
def propose(
429349
%{
430350
index: validator_index,

lib/lambda_ethereum_consensus/validator/validator_set.ex

Lines changed: 29 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -88,23 +88,9 @@ defmodule LambdaEthereumConsensus.ValidatorSet do
8888
def process_tick(%{head_root: head_root} = set, epoch, {slot, :last_third}) do
8989
set
9090
|> update_state(epoch, head_root)
91-
|> publish_aggregate(epoch, slot, head_root)
91+
|> publish_aggregate(epoch, slot)
9292
end
9393

94-
# def process_tick(%{validators: validators, head_root: head_root} = set, _epoch, slot_data) do
95-
# validators =
96-
# maybe_debug_notify(
97-
# fn ->
98-
# Map.new(validators, fn {k, v} ->
99-
# {k, Validator.handle_tick(slot_data, v, head_root)}
100-
# end)
101-
# end,
102-
# {:on_tick, slot_data}
103-
# )
104-
105-
# %{set | validators: validators}
106-
# end
107-
10894
##############################
10995
# Setup
11096

@@ -190,32 +176,36 @@ defmodule LambdaEthereumConsensus.ValidatorSet do
190176
##############################
191177
# Attestation and proposal
192178

193-
defp attest(set, epoch, slot, root) do
194-
updated_duties =
195-
set
196-
|> current_attesters(epoch, slot)
197-
|> Enum.map(fn {validator, duty} ->
198-
Validator.attest(validator, duty, root)
179+
defp attest(set, epoch, slot, head_root) do
180+
case current_attesters(set, epoch, slot) do
181+
[] ->
182+
set
199183

200-
# Duty.attested(duty)
201-
%{duty | attested?: true}
202-
end)
184+
attesters ->
185+
Enum.map(attesters, fn {validator, duty} ->
186+
Validator.attest(validator, duty, head_root)
203187

204-
%{set | duties: put_in(set.duties, [epoch, :attesters, slot], updated_duties)}
188+
# Duty.attested(duty)
189+
%{duty | attested?: true}
190+
end)
191+
|> then(&%{set | duties: put_in(set.duties, [epoch, :attesters, slot], &1)})
192+
end
205193
end
206194

207-
defp publish_aggregate(set, epoch, slot, head_root) do
208-
updated_duties =
209-
set
210-
|> current_aggregators(epoch, slot)
211-
|> Enum.map(fn {validator, duty} ->
212-
Validator.publish_aggregate(duty, validator.index, validator.keystore)
195+
defp publish_aggregate(set, epoch, slot) do
196+
case current_aggregators(set, epoch, slot) do
197+
[] ->
198+
set
213199

214-
# Duty.aggregated(duty)
215-
%{duty | should_aggregate?: false}
216-
end)
200+
aggregators ->
201+
Enum.map(aggregators, fn {validator, duty} ->
202+
Validator.publish_aggregate(duty, validator.index, validator.keystore)
217203

218-
%{set | duties: put_in(set.duties, [epoch, :attesters, slot], updated_duties)}
204+
# Duty.aggregated(duty)
205+
%{duty | should_aggregate?: false}
206+
end)
207+
|> then(&%{set | duties: put_in(set.duties, [epoch, :attesters, slot], &1)})
208+
end
219209
end
220210

221211
defp build_next_payload(%{validators: validators} = set, epoch, slot, head_root) do
@@ -250,15 +240,17 @@ defmodule LambdaEthereumConsensus.ValidatorSet do
250240
# Helpers
251241

252242
defp current_attesters(set, epoch, slot) do
253-
attesters(set, epoch, slot)
243+
set
244+
|> attesters(epoch, slot)
254245
|> Enum.flat_map(fn
255246
%{attested?: false} = duty -> [{Map.get(set.validators, duty.validator_index), duty}]
256247
_ -> []
257248
end)
258249
end
259250

260251
defp current_aggregators(set, epoch, slot) do
261-
attesters(set, epoch, slot)
252+
set
253+
|> attesters(epoch, slot)
262254
|> Enum.flat_map(fn
263255
%{should_aggregate?: true} = duty -> [{Map.get(set.validators, duty.validator_index), duty}]
264256
_ -> []
@@ -268,25 +260,6 @@ defmodule LambdaEthereumConsensus.ValidatorSet do
268260
defp proposer(set, epoch, slot), do: get_in(set.duties, [epoch, :proposers, slot])
269261
defp attesters(set, epoch, slot), do: get_in(set.duties, [epoch, :attesters, slot]) || []
270262

271-
# defp maybe_debug_notify(fun, data) do
272-
# # :debug do
273-
# if Application.get_env(:logger, :level) == :info do
274-
# Logger.info("[Validator] Notifying all Validators with message: #{inspect(data)}")
275-
276-
# start_time = System.monotonic_time(:millisecond)
277-
# result = fun.()
278-
# end_time = System.monotonic_time(:millisecond)
279-
280-
# Logger.info(
281-
# "[Validator] #{inspect(data)} notified to all Validators after #{end_time - start_time} ms"
282-
# )
283-
284-
# result
285-
# else
286-
# fun.()
287-
# end
288-
# end
289-
290263
@doc """
291264
Get validator keystores from the keystore directory.
292265
This function expects two files for each validator:

0 commit comments

Comments
 (0)