Skip to content

Commit af5d0d9

Browse files
test(spec): implement sync spec tests. (#700)
Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com>
1 parent d846b69 commit af5d0d9

File tree

5 files changed

+124
-21
lines changed

5 files changed

+124
-21
lines changed

lib/lambda_ethereum_consensus/execution/engine_api/mocked.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ defmodule LambdaEthereumConsensus.Execution.EngineApi.Mocked do
2020

2121
@spec forkchoice_updated(map, map | any) :: {:ok, any} | {:error, any}
2222
def forkchoice_updated(_forkchoice_state, _payload_attributes) do
23-
{:ok, %{"payload_id" => nil, payload_status: %{"status" => "SYNCING"}}}
23+
{:ok, %{"payload_id" => nil, "payload_status" => %{"status" => "SYNCING"}}}
2424
end
2525
end

lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ defmodule LambdaEthereumConsensus.ForkChoice do
77
require Logger
88

99
alias LambdaEthereumConsensus.Beacon.BeaconChain
10-
alias LambdaEthereumConsensus.Execution.ExecutionClient
1110
alias LambdaEthereumConsensus.ForkChoice.{Handlers, Helpers}
1211
alias LambdaEthereumConsensus.Store.Blocks
1312
alias Types.Attestation
@@ -180,21 +179,11 @@ defmodule LambdaEthereumConsensus.ForkChoice do
180179
@spec recompute_head(Store.t()) :: :ok
181180
def recompute_head(store) do
182181
{:ok, head_root} = Helpers.get_head(store)
183-
184182
head_block = Blocks.get_block!(head_root)
185-
head_execution_hash = head_block.body.execution_payload.block_hash
183+
184+
Handlers.notify_forkchoice_update(store, head_block)
186185

187186
finalized_checkpoint = store.finalized_checkpoint
188-
finalized_block = Blocks.get_block!(store.finalized_checkpoint.root)
189-
finalized_execution_hash = finalized_block.body.execution_payload.block_hash
190-
191-
# TODO: do someting with the result from the execution client
192-
# TODO: compute safe block hash
193-
ExecutionClient.notify_forkchoice_updated(
194-
head_execution_hash,
195-
finalized_execution_hash,
196-
finalized_execution_hash
197-
)
198187

199188
BeaconChain.update_fork_choice_cache(
200189
head_root,

lib/lambda_ethereum_consensus/fork_choice/handlers.ex

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule LambdaEthereumConsensus.ForkChoice.Handlers do
33
Handlers that update the fork choice store.
44
"""
55

6+
alias LambdaEthereumConsensus.Execution.ExecutionClient
67
alias LambdaEthereumConsensus.StateTransition
78
alias LambdaEthereumConsensus.StateTransition.{Accessors, EpochProcessing, Misc, Predicates}
89
alias LambdaEthereumConsensus.Store.Blocks
@@ -184,6 +185,21 @@ defmodule LambdaEthereumConsensus.ForkChoice.Handlers do
184185
end
185186
end
186187

188+
def notify_forkchoice_update(store, head_block) do
189+
head_execution_hash = head_block.body.execution_payload.block_hash
190+
191+
finalized_block = Blocks.get_block!(store.finalized_checkpoint.root)
192+
finalized_execution_hash = finalized_block.body.execution_payload.block_hash
193+
194+
# TODO: do someting with the result from the execution client
195+
# TODO: compute safe block hash
196+
ExecutionClient.notify_forkchoice_updated(
197+
head_execution_hash,
198+
finalized_execution_hash,
199+
finalized_execution_hash
200+
)
201+
end
202+
187203
### Private functions ###
188204

189205
# Update checkpoints in store if necessary

test/spec/runners/fork_choice.ex

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,18 @@ defmodule ForkChoiceTestRunner do
151151

152152
assert Ssz.hash_tree_root!(block) == Base.decode16!(hash, case: :mixed)
153153

154-
with {:ok, new_store} <- Handlers.on_block(store, block) do
155-
block.message.body.attestations
156-
|> Enum.reduce_while({:ok, new_store}, fn
157-
x, {:ok, st} -> {:cont, Handlers.on_attestation(st, x, true)}
158-
_, {:error, _} = err -> {:halt, err}
159-
end)
154+
with {:ok, new_store} <- Handlers.on_block(store, block),
155+
{:ok, new_store} <-
156+
block.message.body.attestations
157+
|> Enum.reduce_while({:ok, new_store}, fn
158+
x, {:ok, st} -> {:cont, Handlers.on_attestation(st, x, true)}
159+
_, {:error, _} = err -> {:halt, err}
160+
end) do
161+
{:ok, head_root} = Helpers.get_head(new_store)
162+
head_block = Blocks.get_block!(head_root)
163+
164+
{:ok, _} = Handlers.notify_forkchoice_update(new_store, head_block)
165+
{:ok, new_store}
160166
end
161167
end
162168

@@ -182,6 +188,28 @@ defmodule ForkChoiceTestRunner do
182188
Handlers.on_attester_slashing(store, attester_slashing)
183189
end
184190

191+
defp apply_step(_case_dir, store, %{block_hash: block_hash, payload_status: payload_status}) do
192+
# Convert keys to strings
193+
normalized_payload_status =
194+
Enum.reduce(payload_status, %{}, fn {k, v}, acc ->
195+
Map.put(acc, Atom.to_string(k), v)
196+
end)
197+
198+
:ok =
199+
SyncTestRunner.EngineApiMock.add_new_payload_response(
200+
block_hash,
201+
normalized_payload_status
202+
)
203+
204+
:ok =
205+
SyncTestRunner.EngineApiMock.add_forkchoice_updated_response(
206+
block_hash,
207+
normalized_payload_status
208+
)
209+
210+
{:ok, store}
211+
end
212+
185213
defp apply_step(_case_dir, store, %{checks: checks}) do
186214
if Map.has_key?(checks, :head) do
187215
{:ok, head_root} = Helpers.get_head(store)

test/spec/runners/sync.ex

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ defmodule SyncTestRunner do
66
use ExUnit.CaseTemplate
77
use TestRunner
88

9+
alias LambdaEthereumConsensus.Execution.EngineApi
10+
911
@disabled_cases [
1012
# TODO: we have to support https://github.com/ethereum/consensus-specs/blob/dev/tests/formats/fork_choice/README.md#on_payload_info-execution-step
11-
"from_syncing_to_invalid"
13+
# "from_syncing_to_invalid"
1214
]
1315

1416
@impl TestRunner
@@ -18,6 +20,74 @@ defmodule SyncTestRunner do
1820

1921
@impl TestRunner
2022
def run_test_case(%SpecTestCase{} = testcase) do
23+
original_engine_api_config =
24+
Application.fetch_env!(:lambda_ethereum_consensus, EngineApi)
25+
26+
Application.put_env(
27+
:lambda_ethereum_consensus,
28+
EngineApi,
29+
Keyword.put(original_engine_api_config, :implementation, SyncTestRunner.EngineApiMock)
30+
)
31+
32+
{:ok, _pid} = SyncTestRunner.EngineApiMock.start_link([])
33+
2134
ForkChoiceTestRunner.run_test_case(testcase)
35+
36+
Application.put_env(
37+
:lambda_ethereum_consensus,
38+
EngineApi,
39+
original_engine_api_config
40+
)
41+
end
42+
end
43+
44+
defmodule SyncTestRunner.EngineApiMock do
45+
@moduledoc """
46+
Mocked EngineApi for SyncTestRunner.
47+
"""
48+
use Agent
49+
50+
def start_link(_opts) do
51+
Agent.start_link(fn -> %{new_payload: %{}, forkchoice_updated: %{}} end, name: __MODULE__)
52+
end
53+
54+
def add_new_payload_response(block_hash, payload_status) do
55+
Agent.update(__MODULE__, fn state ->
56+
Map.update!(state, :new_payload, fn new_payload ->
57+
Map.put(new_payload, block_hash, payload_status)
58+
end)
59+
end)
60+
end
61+
62+
def add_forkchoice_updated_response(block_hash, payload_status) do
63+
Agent.update(__MODULE__, fn state ->
64+
Map.update!(state, :forkchoice_updated, fn forkchoice_updated ->
65+
Map.put(forkchoice_updated, block_hash, payload_status)
66+
end)
67+
end)
68+
end
69+
70+
def new_payload(payload) do
71+
Agent.get(__MODULE__, fn state ->
72+
payload_status = Map.get(state.new_payload, payload.block_hash)
73+
74+
if payload_status do
75+
{:ok, payload_status}
76+
else
77+
{:error, "Unknown block hash when calling new_payload"}
78+
end
79+
end)
80+
end
81+
82+
def forkchoice_updated(forkchoice_state, _payload_attributes) do
83+
Agent.get(__MODULE__, fn state ->
84+
payload_status = Map.get(state.forkchoice_updated, forkchoice_state.head_block_hash)
85+
86+
if payload_status do
87+
{:ok, %{"payload_id" => nil, "payload_status" => payload_status}}
88+
else
89+
{:error, "Unknown block hash when calling forkchoice_updated"}
90+
end
91+
end)
2292
end
2393
end

0 commit comments

Comments
 (0)