Skip to content

Commit

Permalink
perf: reduce get_beacon_committee calls (#518)
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaRedHand authored Dec 12, 2023
1 parent d3485bc commit 9de8dec
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 16 deletions.
29 changes: 27 additions & 2 deletions lib/lambda_ethereum_consensus/state_transition/accessors.ex
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,9 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
"""
@spec get_committee_count_per_slot(BeaconState.t(), SszTypes.epoch()) :: SszTypes.uint64()
def get_committee_count_per_slot(%BeaconState{} = state, epoch) do
get_active_validator_indices(state, epoch)
|> length()
state.validators
|> Stream.filter(&Predicates.is_active_validator(&1, epoch))
|> Enum.count()
|> div(ChainSpec.get("SLOTS_PER_EPOCH"))
|> div(ChainSpec.get("TARGET_COMMITTEE_SIZE"))
|> min(ChainSpec.get("MAX_COMMITTEES_PER_SLOT"))
Expand Down Expand Up @@ -444,6 +445,20 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
end
end

@spec get_committee_indexed_attestation([SszTypes.validator_index()], Attestation.t()) ::
IndexedAttestation.t()
def get_committee_indexed_attestation(beacon_committee, attestation) do
get_committee_attesting_indices(beacon_committee, attestation.aggregation_bits)
|> Enum.sort()
|> then(
&%IndexedAttestation{
attesting_indices: &1,
data: attestation.data,
signature: attestation.signature
}
)
end

@doc """
Return the set of attesting indices corresponding to ``data`` and ``bits``.
"""
Expand All @@ -460,6 +475,16 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
end
end

@spec get_committee_attesting_indices([SszTypes.validator_index()], SszTypes.bitlist()) ::
MapSet.t()
def get_committee_attesting_indices(committee, bits) do
committee
|> Stream.with_index()
|> Stream.filter(fn {_value, index} -> participated?(bits, index) end)
|> Stream.map(fn {value, _index} -> value end)
|> MapSet.new()
end

defp participated?(bits, index) do
# The bit order inside the byte is reversed (e.g. bits[0] is the 8th bit).
# Here we keep the byte index the same, but reverse the bit index.
Expand Down
24 changes: 10 additions & 14 deletions lib/lambda_ethereum_consensus/state_transition/operations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -645,29 +645,27 @@ defmodule LambdaEthereumConsensus.StateTransition.Operations do
@spec process_attestation(BeaconState.t(), Attestation.t()) ::
{:ok, BeaconState.t()} | {:error, binary()}
def process_attestation(state, %Attestation{data: data} = attestation) do
# TODO: optimize (takes ~3s)
with :ok <- check_valid_target_epoch(data, state),
:ok <- check_epoch_matches(data),
:ok <- check_valid_slot_range(data, state),
:ok <- check_committee_count(data, state),
{:ok, beacon_committee} <- Accessors.get_beacon_committee(state, data.slot, data.index),
:ok <- check_matching_aggregation_bits_length(attestation, beacon_committee),
{:ok, indexed_attestation} <- Accessors.get_indexed_attestation(state, attestation),
indexed_attestation =
Accessors.get_committee_indexed_attestation(beacon_committee, attestation),
:ok <- check_valid_signature(state, indexed_attestation) do
# TODO: optimize (takes ~1s)
process_attestation(state, data, attestation.aggregation_bits)
inner_process_attestation(state, data, attestation.aggregation_bits, beacon_committee)
end
end

defp process_attestation(state, data, aggregation_bits) do
defp inner_process_attestation(state, data, aggregation_bits, committee) do
slot = state.slot - data.slot

with {:ok, participation_flag_indices} <-
Accessors.get_attestation_participation_flag_indices(
state,
data,
state.slot - data.slot
),
{:ok, attesting_indices} <-
Accessors.get_attesting_indices(state, data, aggregation_bits) do
Accessors.get_attestation_participation_flag_indices(state, data, slot) do
attesting_indices =
Accessors.get_committee_attesting_indices(committee, aggregation_bits)

is_current_epoch = data.target.epoch == Accessors.get_current_epoch(state)
initial_epoch_participation = get_initial_epoch_participation(state, is_current_epoch)

Expand All @@ -687,8 +685,6 @@ defmodule LambdaEthereumConsensus.StateTransition.Operations do
|> Mutators.increase_balance(proposer_index, proposer_reward)
|> update_state(is_current_epoch, updated_epoch_participation)
|> then(&{:ok, &1})
else
{:error, reason} -> {:error, reason}
end
end

Expand Down

0 comments on commit 9de8dec

Please sign in to comment.