Skip to content

Commit

Permalink
Merge branch 'main' into optimize-process_operations
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaRedHand committed Nov 30, 2023
2 parents 239c8db + 8b7a60e commit 311b9ae
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 166 deletions.
60 changes: 0 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,66 +167,6 @@ Our aim is to infuse these strengths into the Ethereum consensus client ecosyste

We also have for objective to bootstart an Ethereum Elixir community, and to make Elixir a first-class citizen in the Ethereum ecosystem.

## Roadmap

**1. Block Subscription - Mid September**
- Libp2p discovery and block retrieval
- SSZ + snappy
- `on_block` callback: Save the latest block in fork-choice store, conduct basic checks. GetHead returns the last obtained block.
- Beacon API: Return block root (`GET /beacon/states/{state_id}/root`)

**2. Checkpoint Sync - October**
- Libp2p primitives for sync
- Support checkpoint Sync from a known provider
- Sync from the latest finalized block
- BeaconAPI: Return headers for head block
- EngineAPI: Validate incoming blocks

**3. Attestations - Mid October**
- Libp2p attestation retrieval
- Basic beacon state representation
- Store attestations (last message sent by each validator)
- `on_attestation` callback for attestations sent via Gossip
- Process attestations from blocks
- Beacon API: Return head block root (`GET /beacon/states/head/root`)

**4. Deposits - November**
- BLS signature checks
- Update consensus state view of deposit contract (`process_eth1_data`)
- Process deposit operation to update validator list (`process_deposit`)
- Verify block signatures (`verify_block_signature`)

**5. Slots and Fork-choice - Mid November**
- `on_tick`/`process_slot` in state transition; a GenServer that calls this periodically
- `on_block`: Add slot-related checks and epoch calculations (excluding finalization)
- Get-head uses the messages
- Block header validation
- EngineAPI: Process execution payload
- BeaconAPI: Ensure getting head values point to the heaviest

**6. Finality and Slashing - Mid November**
- Epoch processing
- `on_block`: Prune fork-choice store; reject blocks before finalization
- Add RANDAO mix to the beacon state
- BeaconAPI: Retrieve finality checkpoints, randao mixes
- Process attester slashings and proposer slashings
- EngineAPI: fork-choice updates

**7. Rewards, Shuffling - December**
- Process rewards `on_epoch` for a checkpoint
- Handle Deposits and Withdrawals
- Implement RANDAO
- Calculate committee for a given state
- Conduct shuffling
- Integrate with Grafana
- BeaconAPI: Retrieve randao mix for a given block

**8. Validator Features - Mid December/January 2024**
- Create attestations
- Monitor for slashings
- Create slashing proofs
- BeaconAPI: Post blocks, slashings, voluntary exits, and withdrawals

## Contributor Package

Dream of becoming an Ethereum core developer? Eager to shape the protocol that will underpin tomorrow's world? Want to collaborate with a passionate team, learn, grow, and be a pivotal part of the Ethereum Elixir community?
Expand Down
26 changes: 26 additions & 0 deletions lib/spec/runners/finality.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule FinalityTestRunner do
@moduledoc """
Runner for finality test cases. See: https://github.com/ethereum/consensus-specs/tree/dev/tests/formats/finality
"""

use ExUnit.CaseTemplate
use TestRunner

@disabled_cases [
# "finality_no_updates_at_genesis",
# "finality_rule_1",
# "finality_rule_2",
# "finality_rule_3",
# "finality_rule_4"
]

@impl TestRunner
def skip?(%SpecTestCase{fork: "capella", case: testcase}) do
Enum.member?(@disabled_cases, testcase)
end

@impl TestRunner
def run_test_case(testcase) do
Helpers.ProcessBlocks.process_blocks(testcase)
end
end
57 changes: 57 additions & 0 deletions lib/spec/runners/helpers/process_blocks.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
defmodule Helpers.ProcessBlocks do
@moduledoc """
Helper module for processing blocks.
"""

use ExUnit.CaseTemplate

alias LambdaEthereumConsensus.StateTransition
alias LambdaEthereumConsensus.Utils.Diff

def process_blocks(%SpecTestCase{} = testcase) do
case_dir = SpecTestCase.dir(testcase)

pre =
SpecTestUtils.read_ssz_from_file!(
case_dir <> "/pre.ssz_snappy",
SszTypes.BeaconState
)

post =
SpecTestUtils.read_ssz_from_optional_file!(
case_dir <> "/post.ssz_snappy",
SszTypes.BeaconState
)

meta =
YamlElixir.read_from_file!(case_dir <> "/meta.yaml") |> SpecTestUtils.sanitize_yaml()

%{blocks_count: blocks_count} = meta

blocks =
0..(blocks_count - 1)//1
|> Enum.map(fn index ->
SpecTestUtils.read_ssz_from_file!(
case_dir <> "/blocks_#{index}.ssz_snappy",
SszTypes.SignedBeaconBlock
)
end)

result =
blocks
|> Enum.reduce_while({:ok, pre}, fn block, {:ok, state} ->
case StateTransition.state_transition(state, block, true) do
{:ok, post_state} -> {:cont, {:ok, post_state}}
{:error, error} -> {:halt, {:error, error}}
end
end)

case result do
{:ok, state} ->
assert Diff.diff(state, post) == :unchanged

{:error, error} ->
assert post == nil, "Process block failed, error: #{error}"
end
end
end
37 changes: 37 additions & 0 deletions lib/spec/runners/random.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule RandomTestRunner do
@moduledoc """
Runner for random test cases. See: https://github.com/ethereum/consensus-specs/tree/dev/tests/formats/random
"""

use ExUnit.CaseTemplate
use TestRunner

@disabled_cases [
"randomized_0",
# "randomized_1",
"randomized_2",
"randomized_3",
# "randomized_4",
"randomized_5",
"randomized_6",
"randomized_7",
# "randomized_8",
# "randomized_9",
"randomized_10",
# "randomized_11",
"randomized_12",
"randomized_13",
"randomized_14",
"randomized_15"
]

@impl TestRunner
def skip?(%SpecTestCase{fork: "capella", case: testcase}) do
Enum.member?(@disabled_cases, testcase)
end

@impl TestRunner
def run_test_case(testcase) do
Helpers.ProcessBlocks.process_blocks(testcase)
end
end
169 changes: 63 additions & 106 deletions lib/spec/runners/sanity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,82 +10,83 @@ defmodule SanityTestRunner do
alias LambdaEthereumConsensus.Utils.Diff

@disabled_block_cases [
"activate_and_partial_withdrawal_max_effective_balance",
"activate_and_partial_withdrawal_overdeposit",
"attestation",
"attester_slashing",
"balance_driven_status_transitions",
"bls_change",
"deposit_and_bls_change",
"deposit_in_block",
"deposit_top_up",
"duplicate_attestation_same_block",
"empty_block_transition",
"empty_block_transition_large_validator_set",
"empty_block_transition_no_tx",
"empty_block_transition_randomized_payload",
"empty_epoch_transition",
"empty_epoch_transition_large_validator_set",
"empty_epoch_transition_not_finalizing",
"eth1_data_votes_consensus",
"eth1_data_votes_no_consensus",
"exit_and_bls_change",
"full_random_operations_0",
"full_random_operations_1",
"full_random_operations_2",
"full_random_operations_3",
"full_withdrawal_in_epoch_transition",
"high_proposer_index",
"historical_batch",
"inactivity_scores_full_participation_leaking",
"inactivity_scores_leaking",
# "activate_and_partial_withdrawal_max_effective_balance",
# "activate_and_partial_withdrawal_overdeposit",
# "attestation",
# "attester_slashing",
# "balance_driven_status_transitions",
# "bls_change",
# "deposit_and_bls_change",
# "deposit_in_block",
# "deposit_top_up",
# "duplicate_attestation_same_block",
# "invalid_is_execution_enabled_false",
# "empty_block_transition",
# "empty_block_transition_large_validator_set",
# "empty_block_transition_no_tx",
# "empty_block_transition_randomized_payload",
# "empty_epoch_transition",
# "empty_epoch_transition_large_validator_set",
# "empty_epoch_transition_not_finalizing",
# "eth1_data_votes_consensus",
# "eth1_data_votes_no_consensus",
# "exit_and_bls_change",
# "full_random_operations_0",
# "full_random_operations_1",
# "full_random_operations_2",
# "full_random_operations_3",
# "full_withdrawal_in_epoch_transition",
# "high_proposer_index",
# "historical_batch",
# "inactivity_scores_full_participation_leaking",
# "inactivity_scores_leaking",
"invalid_all_zeroed_sig",
"invalid_duplicate_attester_slashing_same_block",
"invalid_duplicate_bls_changes_same_block",
"invalid_duplicate_deposit_same_block",
# "invalid_duplicate_deposit_same_block",
"invalid_duplicate_proposer_slashings_same_block",
"invalid_duplicate_validator_exit_same_block",
"invalid_incorrect_block_sig",
"invalid_incorrect_proposer_index_sig_from_expected_proposer",
"invalid_incorrect_proposer_index_sig_from_proposer_index",
# "invalid_incorrect_proposer_index_sig_from_expected_proposer",
# "invalid_incorrect_proposer_index_sig_from_proposer_index",
"invalid_incorrect_state_root",
"invalid_only_increase_deposit_count",
"invalid_parent_from_same_slot",
"invalid_prev_slot_block_transition",
"invalid_same_slot_block_transition",
# "invalid_only_increase_deposit_count",
# "invalid_parent_from_same_slot",
# "invalid_prev_slot_block_transition",
# "invalid_same_slot_block_transition",
"invalid_similar_proposer_slashings_same_block",
"invalid_two_bls_changes_of_different_addresses_same_validator_same_block",
"invalid_withdrawal_fail_second_block_payload_isnt_compatible",
"is_execution_enabled_false",
"many_partial_withdrawals_in_epoch_transition",
"multiple_attester_slashings_no_overlap",
"multiple_attester_slashings_partial_overlap",
"multiple_different_proposer_slashings_same_block",
"multiple_different_validator_exits_same_block",
"partial_withdrawal_in_epoch_transition",
"proposer_after_inactive_index",
"proposer_self_slashing",
"proposer_slashing",
"skipped_slots",
"slash_and_exit_diff_index",
"slash_and_exit_same_index",
"sync_committee_committee__empty",
"sync_committee_committee__full",
"sync_committee_committee__half",
"sync_committee_committee_genesis__empty",
"sync_committee_committee_genesis__full",
"sync_committee_committee_genesis__half",
"top_up_and_partial_withdrawable_validator",
"top_up_to_fully_withdrawn_validator",
"voluntary_exit",
"withdrawal_success_two_blocks"
# "invalid_withdrawal_fail_second_block_payload_isnt_compatible",
# "is_execution_enabled_false",
# "many_partial_withdrawals_in_epoch_transition",
# "multiple_attester_slashings_no_overlap",
# "multiple_attester_slashings_partial_overlap",
# "multiple_different_proposer_slashings_same_block",
# "multiple_different_validator_exits_same_block",
# "partial_withdrawal_in_epoch_transition",
# "proposer_after_inactive_index",
# "proposer_self_slashing",
# "proposer_slashing",
# "skipped_slots",
# "slash_and_exit_diff_index",
"slash_and_exit_same_index"
# "sync_committee_committee__empty",
# "sync_committee_committee__full",
# "sync_committee_committee__half",
# "sync_committee_committee_genesis__empty",
# "sync_committee_committee_genesis__full",
# "sync_committee_committee_genesis__half",
# "top_up_and_partial_withdrawable_validator",
# "top_up_to_fully_withdrawn_validator",
# "voluntary_exit",
# "withdrawal_success_two_blocks"
]

@disabled_slot_cases [
# "empty_epoch",
# "slots_1",
# "slots_2",
"over_epoch_boundary",
# "over_epoch_boundary",
"historical_accumulator",
"double_empty_epoch"
]
Expand Down Expand Up @@ -135,50 +136,6 @@ defmodule SanityTestRunner do
@impl TestRunner
def run_test_case(%SpecTestCase{handler: "blocks"} = testcase) do
# TODO process meta.yaml
case_dir = SpecTestCase.dir(testcase)

pre =
SpecTestUtils.read_ssz_from_file!(
case_dir <> "/pre.ssz_snappy",
SszTypes.BeaconState
)

post =
SpecTestUtils.read_ssz_from_optional_file!(
case_dir <> "/post.ssz_snappy",
SszTypes.BeaconState
)

meta =
YamlElixir.read_from_file!(case_dir <> "/meta.yaml") |> SpecTestUtils.sanitize_yaml()

%{blocks_count: blocks_count} = meta

blocks =
0..(blocks_count - 1)//1
|> Enum.map(fn index ->
SpecTestUtils.read_ssz_from_file!(
case_dir <> "/blocks_#{index}.ssz_snappy",
SszTypes.SignedBeaconBlock
)
end)
|> Enum.map(& &1.message)

result =
blocks
|> Enum.reduce_while({:ok, pre}, fn block, {:ok, state} ->
case StateTransition.process_block(state, block) do
{:ok, post_state} -> {:cont, {:ok, post_state}}
{:error, error} -> {:halt, {:error, error}}
end
end)

case result do
{:ok, state} ->
assert Diff.diff(state, post) == :unchanged

{:error, error} ->
assert post == nil, "Process block failed, error: #{error}"
end
Helpers.ProcessBlocks.process_blocks(testcase)
end
end
Loading

0 comments on commit 311b9ae

Please sign in to comment.