Skip to content

Commit 9f68516

Browse files
committed
Initial sync_committee duty recalculation
1 parent 4d72f18 commit 9f68516

File tree

4 files changed

+111
-79
lines changed

4 files changed

+111
-79
lines changed

lib/lambda_ethereum_consensus/validator/duties.ex

Lines changed: 101 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ defmodule LambdaEthereumConsensus.Validator.Duties do
44
"""
55
alias LambdaEthereumConsensus.StateTransition.Accessors
66
alias LambdaEthereumConsensus.StateTransition.Misc
7+
alias LambdaEthereumConsensus.Validator
78
alias LambdaEthereumConsensus.Validator.Utils
89
alias LambdaEthereumConsensus.ValidatorSet
910
alias Types.BeaconState
@@ -44,69 +45,42 @@ defmodule LambdaEthereumConsensus.Validator.Duties do
4445
}
4546

4647
############################
47-
# Accessors
48-
49-
@spec current_proposer(duties(), Types.epoch(), Types.slot()) :: proposer_duty() | nil
50-
def current_proposer(duties, epoch, slot),
51-
do: get_in(duties, [epoch, :proposers, slot])
48+
# Main Compute functions
5249

53-
@spec current_sync_committee(duties(), Types.epoch(), Types.slot()) ::
54-
sync_committee_duties()
55-
def current_sync_committee(duties, epoch, slot) do
56-
for %{last_slot_broadcasted: last_slot} = duty <- sync_committee(duties, epoch),
57-
last_slot < slot do
58-
duty
59-
end
60-
end
61-
62-
@spec current_attesters(duties(), Types.epoch(), Types.slot()) :: attester_duties()
63-
def current_attesters(duties, epoch, slot) do
64-
for %{attested?: false} = duty <- attesters(duties, epoch, slot) do
65-
duty
66-
end
67-
end
50+
@spec compute_duties_for_epochs(
51+
%{Types.epoch() => duties()},
52+
[{Types.epoch(), Types.slot()}],
53+
Types.root(),
54+
ValidatorSet.validators()
55+
) :: duties()
56+
def compute_duties_for_epochs(duties_map, epochs_and_start_slots, head_root, validators) do
57+
for {epoch, slot} <- epochs_and_start_slots, reduce: duties_map do
58+
duties_map ->
59+
beacon = Validator.fetch_target_state_and_go_to_slot(slot, head_root)
60+
last_epoch = Map.keys(duties_map) |> Enum.max(fn -> 0 end)
61+
62+
new_proposers = compute_proposers_for_epoch(beacon, epoch, validators)
63+
new_attesters = compute_attesters_for_epoch(beacon, epoch, validators)
64+
65+
new_sync_committees =
66+
case sync_committee_compute_check(epoch, {last_epoch, Map.get(duties_map, last_epoch)}) do
67+
{:already_computed, sync_committees} -> sync_committees
68+
:not_computed -> compute_current_sync_committees(beacon, validators)
69+
end
70+
71+
new_duties = %{
72+
proposers: new_proposers,
73+
attesters: new_attesters,
74+
sync_committees: new_sync_committees
75+
}
6876

69-
@spec current_aggregators(duties(), Types.epoch(), Types.slot()) :: attester_duties()
70-
def current_aggregators(duties, epoch, slot) do
71-
for %{should_aggregate?: true} = duty <- attesters(duties, epoch, slot) do
72-
duty
77+
Map.put(duties_map, epoch, new_duties)
7378
end
7479
end
7580

76-
defp sync_committee(duties, epoch), do: get_in(duties, [epoch, :sync_committees]) || []
77-
defp attesters(duties, epoch, slot), do: get_in(duties, [epoch, :attesters, slot]) || []
78-
79-
############################
80-
# Update functions
81-
82-
@spec update_duties!(
83-
duties(),
84-
kind(),
85-
Types.epoch(),
86-
Types.slot(),
87-
attester_duties() | proposer_duties()
88-
) :: duties()
89-
def update_duties!(duties, :sync_committees, epoch, _slot, updated),
90-
do: put_in(duties, [epoch, :sync_committees], updated)
91-
92-
def update_duties!(duties, kind, epoch, slot, updated),
93-
do: put_in(duties, [epoch, kind, slot], updated)
94-
95-
@spec attested(attester_duty()) :: attester_duty()
96-
def attested(duty), do: Map.put(duty, :attested?, true)
97-
98-
@spec aggregated(attester_duty()) :: attester_duty()
99-
def aggregated(duty), do: Map.put(duty, :should_aggregate?, false)
100-
101-
@spec sync_committee_broadcasted(sync_committee_duty(), Types.slot()) :: sync_committee_duty()
102-
def sync_committee_broadcasted(duty, slot), do: Map.put(duty, :last_slot_broadcasted, slot)
103-
104-
############################
105-
# Main functions
106-
10781
@spec compute_proposers_for_epoch(BeaconState.t(), Types.epoch(), ValidatorSet.validators()) ::
10882
proposer_duties_per_slot()
109-
def compute_proposers_for_epoch(%BeaconState{} = state, epoch, validators) do
83+
defp compute_proposers_for_epoch(%BeaconState{} = state, epoch, validators) do
11084
with {:ok, epoch} <- check_valid_epoch(state, epoch),
11185
{start_slot, end_slot} <- boundary_slots(epoch) do
11286
for slot <- start_slot..end_slot,
@@ -120,7 +94,7 @@ defmodule LambdaEthereumConsensus.Validator.Duties do
12094

12195
@spec compute_current_sync_committees(BeaconState.t(), ValidatorSet.validators()) ::
12296
sync_committee_duties()
123-
def compute_current_sync_committees(%BeaconState{} = state, validators) do
97+
defp compute_current_sync_committees(%BeaconState{} = state, validators) do
12498
for validator_index <- Map.keys(validators),
12599
subnet_ids = Utils.compute_subnets_for_sync_committee(state, validator_index) do
126100
%{
@@ -131,9 +105,20 @@ defmodule LambdaEthereumConsensus.Validator.Duties do
131105
end
132106
end
133107

108+
defp sync_committee_compute_check(_epoch, {_last_epoch, nil}), do: :not_computed
109+
110+
defp sync_committee_compute_check(epoch, {last_epoch, last_duties}) do
111+
last_period = Misc.compute_sync_committee_period(last_epoch)
112+
current_period = Misc.compute_sync_committee_period(epoch)
113+
114+
if last_period == current_period,
115+
do: {:already_computed, last_duties.sync_committees},
116+
else: :not_computed
117+
end
118+
134119
@spec compute_attesters_for_epoch(BeaconState.t(), Types.epoch(), ValidatorSet.validators()) ::
135120
attester_duties_per_slot()
136-
def compute_attesters_for_epoch(%BeaconState{} = state, epoch, validators) do
121+
defp compute_attesters_for_epoch(%BeaconState{} = state, epoch, validators) do
137122
with {:ok, epoch} <- check_valid_epoch(state, epoch),
138123
{start_slot, end_slot} <- boundary_slots(epoch) do
139124
committee_count_per_slot = Accessors.get_committee_count_per_slot(state, epoch)
@@ -193,6 +178,64 @@ defmodule LambdaEthereumConsensus.Validator.Duties do
193178
Map.put(duty, :subnet_id, subnet_id)
194179
end
195180

181+
############################
182+
# Accessors
183+
184+
@spec current_proposer(duties(), Types.epoch(), Types.slot()) :: proposer_duty() | nil
185+
def current_proposer(duties, epoch, slot),
186+
do: get_in(duties, [epoch, :proposers, slot])
187+
188+
@spec current_sync_committee(duties(), Types.epoch(), Types.slot()) ::
189+
sync_committee_duties()
190+
def current_sync_committee(duties, epoch, slot) do
191+
for %{last_slot_broadcasted: last_slot} = duty <- sync_committee(duties, epoch),
192+
last_slot < slot do
193+
duty
194+
end
195+
end
196+
197+
@spec current_attesters(duties(), Types.epoch(), Types.slot()) :: attester_duties()
198+
def current_attesters(duties, epoch, slot) do
199+
for %{attested?: false} = duty <- attesters(duties, epoch, slot) do
200+
duty
201+
end
202+
end
203+
204+
@spec current_aggregators(duties(), Types.epoch(), Types.slot()) :: attester_duties()
205+
def current_aggregators(duties, epoch, slot) do
206+
for %{should_aggregate?: true} = duty <- attesters(duties, epoch, slot) do
207+
duty
208+
end
209+
end
210+
211+
defp sync_committee(duties, epoch), do: get_in(duties, [epoch, :sync_committees]) || []
212+
defp attesters(duties, epoch, slot), do: get_in(duties, [epoch, :attesters, slot]) || []
213+
214+
############################
215+
# Update functions
216+
217+
@spec update_duties!(
218+
duties(),
219+
kind(),
220+
Types.epoch(),
221+
Types.slot(),
222+
attester_duties() | proposer_duties()
223+
) :: duties()
224+
def update_duties!(duties, :sync_committees, epoch, _slot, updated),
225+
do: put_in(duties, [epoch, :sync_committees], updated)
226+
227+
def update_duties!(duties, kind, epoch, slot, updated),
228+
do: put_in(duties, [epoch, kind, slot], updated)
229+
230+
@spec attested(attester_duty()) :: attester_duty()
231+
def attested(duty), do: Map.put(duty, :attested?, true)
232+
233+
@spec aggregated(attester_duty()) :: attester_duty()
234+
def aggregated(duty), do: Map.put(duty, :should_aggregate?, false)
235+
236+
@spec sync_committee_broadcasted(sync_committee_duty(), Types.slot()) :: sync_committee_duty()
237+
def sync_committee_broadcasted(duty, slot), do: Map.put(duty, :last_slot_broadcasted, slot)
238+
196239
############################
197240
# Helpers
198241

lib/lambda_ethereum_consensus/validator/validator.ex

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ defmodule LambdaEthereumConsensus.Validator do
3838

3939
@spec new(Keystore.t(), Types.slot(), Types.root()) :: t()
4040
def new(keystore, head_slot, head_root) do
41-
epoch = Misc.compute_epoch_at_slot(head_slot)
42-
beacon = fetch_target_state_and_go_to_slot(epoch, head_slot, head_root)
41+
beacon = fetch_target_state_and_go_to_slot(head_slot, head_root)
4342

4443
state = %__MODULE__{
4544
index: nil,
@@ -86,9 +85,11 @@ defmodule LambdaEthereumConsensus.Validator do
8685
##########################
8786
# Target State
8887

89-
@spec fetch_target_state_and_go_to_slot(Types.epoch(), Types.slot(), Types.root()) ::
88+
@spec fetch_target_state_and_go_to_slot(Types.slot(), Types.root()) ::
9089
Types.BeaconState.t()
91-
def fetch_target_state_and_go_to_slot(epoch, slot, root) do
90+
def fetch_target_state_and_go_to_slot(slot, root) do
91+
epoch = Misc.compute_epoch_at_slot(slot)
92+
9293
epoch |> fetch_target_state(root) |> go_to_slot(slot)
9394
end
9495

lib/lambda_ethereum_consensus/validator/validator_set.ex

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -132,25 +132,11 @@ defmodule LambdaEthereumConsensus.ValidatorSet do
132132
[{epoch, slot}, {epoch + 1, Misc.compute_start_slot_at_epoch(epoch + 1)}]
133133
|> Enum.reject(&Map.has_key?(set.duties, elem(&1, 0)))
134134

135-
epochs_to_calculate
136-
|> Map.new(&compute_duties_for_epoch!(set, &1, head_root))
135+
set.duties
136+
|> Duties.compute_duties_for_epochs(epochs_to_calculate, head_root, set.validators)
137137
|> merge_duties_and_prune(epoch, set)
138138
end
139139

140-
defp compute_duties_for_epoch!(set, {epoch, slot}, head_root) do
141-
beacon = Validator.fetch_target_state_and_go_to_slot(epoch, slot, head_root)
142-
143-
duties = %{
144-
proposers: Duties.compute_proposers_for_epoch(beacon, epoch, set.validators),
145-
attesters: Duties.compute_attesters_for_epoch(beacon, epoch, set.validators),
146-
sync_committees: Duties.compute_current_sync_committees(beacon, set.validators)
147-
}
148-
149-
Duties.log_duties_for_epoch(duties, epoch)
150-
151-
{epoch, duties}
152-
end
153-
154140
defp merge_duties_and_prune(new_duties, current_epoch, set) do
155141
set.duties
156142
# Remove duties from epoch - 2 or older

network_params.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ participants:
88
cl_image: lambda_ethereum_consensus:latest
99
use_separate_vc: false
1010
count: 1
11-
validator_count: 32
11+
validator_count: 15
1212
cl_max_mem: 4096
1313
keymanager_enabled: true
14+
network_params:
15+
preset: minimal

0 commit comments

Comments
 (0)