diff --git a/lib/lambda_ethereum_consensus/beacon/beacon_chain.ex b/lib/lambda_ethereum_consensus/beacon/beacon_chain.ex index 968a5fe9b..c6abbd833 100644 --- a/lib/lambda_ethereum_consensus/beacon/beacon_chain.ex +++ b/lib/lambda_ethereum_consensus/beacon/beacon_chain.ex @@ -84,7 +84,7 @@ defmodule LambdaEthereumConsensus.Beacon.BeaconChain do genesis_validators_root: anchor_state.genesis_validators_root, fork_choice: %{ head_root: <<0::256>>, - head_slot: 0, + head_slot: anchor_state.slot, finalized_root: anchor_state.finalized_checkpoint.root, finalized_epoch: anchor_state.finalized_checkpoint.epoch }, diff --git a/lib/lambda_ethereum_consensus/execution/engine_api.ex b/lib/lambda_ethereum_consensus/execution/engine_api.ex index 7de43c5e8..71602d727 100644 --- a/lib/lambda_ethereum_consensus/execution/engine_api.ex +++ b/lib/lambda_ethereum_consensus/execution/engine_api.ex @@ -10,9 +10,9 @@ defmodule LambdaEthereumConsensus.Execution.EngineApi do @spec exchange_capabilities() :: {:ok, any} | {:error, any} def exchange_capabilities, do: impl().exchange_capabilities() - @spec new_payload_v1(Types.ExecutionPayload.t()) :: + @spec new_payload(Types.ExecutionPayload.t()) :: {:ok, any} | {:error, any} - def new_payload_v1(execution_payload), do: impl().new_payload_v1(execution_payload) + def new_payload(execution_payload), do: impl().new_payload(execution_payload) @spec forkchoice_updated(map, map | any) :: {:ok, any} | {:error, any} def forkchoice_updated(forkchoice_state, payload_attributes), diff --git a/lib/lambda_ethereum_consensus/execution/engine_api/api.ex b/lib/lambda_ethereum_consensus/execution/engine_api/api.ex index 408160510..ed3d9de0d 100644 --- a/lib/lambda_ethereum_consensus/execution/engine_api/api.ex +++ b/lib/lambda_ethereum_consensus/execution/engine_api/api.ex @@ -17,21 +17,18 @@ defmodule LambdaEthereumConsensus.Execution.EngineApi.Api do call("engine_exchangeCapabilities", [@supported_methods]) end - @spec new_payload_v1(Types.ExecutionPayload.t()) :: + @spec new_payload(Types.ExecutionPayload.t()) :: {:ok, any} | {:error, any} - def new_payload_v1(execution_payload) do - call("engine_newPayloadV2", [execution_payload]) + def new_payload(execution_payload) do + call("engine_newPayloadV2", [RPC.normalize(execution_payload)]) end @spec forkchoice_updated(map, map | any) :: {:ok, any} | {:error, any} def forkchoice_updated(forkchoice_state, payload_attributes) do - forkchoice_state = - forkchoice_state - |> Map.update!(:finalizedBlockHash, &RPC.encode_binary/1) - |> Map.update!(:headBlockHash, &RPC.encode_binary/1) - |> Map.update!(:safeBlockHash, &RPC.encode_binary/1) - - call("engine_forkchoiceUpdatedV2", [forkchoice_state, payload_attributes]) + call("engine_forkchoiceUpdatedV2", [ + RPC.normalize(forkchoice_state), + RPC.normalize(payload_attributes) + ]) end defp call(method, params) do diff --git a/lib/lambda_ethereum_consensus/execution/engine_api/mocked.ex b/lib/lambda_ethereum_consensus/execution/engine_api/mocked.ex index fc7d71de0..f298ca794 100644 --- a/lib/lambda_ethereum_consensus/execution/engine_api/mocked.ex +++ b/lib/lambda_ethereum_consensus/execution/engine_api/mocked.ex @@ -12,9 +12,9 @@ defmodule LambdaEthereumConsensus.Execution.EngineApi.Mocked do {:ok, ["engine_newPayloadV2"]} end - @spec new_payload_v1(Types.ExecutionPayload.t()) :: + @spec new_payload(Types.ExecutionPayload.t()) :: {:ok, any} | {:error, any} - def new_payload_v1(_execution_payload) do + def new_payload(_execution_payload) do {:ok, generic_response()} end diff --git a/lib/lambda_ethereum_consensus/execution/execution_client.ex b/lib/lambda_ethereum_consensus/execution/execution_client.ex index d780c4657..447e6a070 100644 --- a/lib/lambda_ethereum_consensus/execution/execution_client.ex +++ b/lib/lambda_ethereum_consensus/execution/execution_client.ex @@ -9,9 +9,10 @@ defmodule LambdaEthereumConsensus.Execution.ExecutionClient do Verifies the validity of the data contained in the new payload and notifies the Execution client of a new payload """ @spec verify_and_notify_new_payload(Types.ExecutionPayload.t()) :: {:ok, any} | {:error, any} - def verify_and_notify_new_payload(_execution_payload) do - # TODO: call engine api - {:ok, true} + def verify_and_notify_new_payload(execution_payload) do + result = EngineApi.new_payload(execution_payload) + IO.inspect(result |> elem(1)) + result end @doc """ diff --git a/lib/lambda_ethereum_consensus/execution/rpc.ex b/lib/lambda_ethereum_consensus/execution/rpc.ex index f4eea6034..a643285c4 100644 --- a/lib/lambda_ethereum_consensus/execution/rpc.ex +++ b/lib/lambda_ethereum_consensus/execution/rpc.ex @@ -34,8 +34,45 @@ defmodule LambdaEthereumConsensus.Execution.RPC do end end + def normalize(nil), do: nil + + def normalize(payload) when is_struct(payload) do + normalize(Map.from_struct(payload)) + end + + def normalize(payload) when is_map(payload) do + Enum.reduce(payload, %{}, fn {k, v}, acc -> + Map.put(acc, to_camel_case(k), normalize(v)) + end) + end + + def normalize(payload) when is_list(payload) do + Enum.map(payload, &normalize/1) + end + + def normalize(payload) when is_binary(payload) do + encode_binary(payload) + end + + def normalize(payload) when is_integer(payload) do + payload |> encode_integer() + end + @spec encode_binary(binary) :: binary def encode_binary(binary) do "0x" <> Base.encode16(binary, case: :lower) end + + def encode_integer(integer) do + "0x" <> Integer.to_string(integer, 16) + end + + defp to_camel_case(key) when is_atom(key) do + Atom.to_string(key) |> to_camel_case() + end + + defp to_camel_case(key) when is_binary(key) do + key + |> Recase.to_camel() + end end diff --git a/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex b/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex index 97dffae12..8c6129eee 100644 --- a/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex +++ b/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex @@ -72,7 +72,7 @@ defmodule LambdaEthereumConsensus.ForkChoice do @spec init({BeaconState.t(), SignedBeaconBlock.t(), Types.uint64()}) :: {:ok, Store.t()} | {:stop, any} def init({anchor_state = %BeaconState{}, signed_anchor_block = %SignedBeaconBlock{}, time}) do - case Helpers.get_forkchoice_store(anchor_state, signed_anchor_block, true) do + case Helpers.get_forkchoice_store(anchor_state, signed_anchor_block, false) do {:ok, %Store{} = store} -> Logger.info("[Fork choice] Initialized store.") @@ -208,15 +208,19 @@ defmodule LambdaEthereumConsensus.ForkChoice do def recompute_head(store) do {:ok, head_root} = Helpers.get_head(store) - head_block = Map.get(store.blocks, head_root) + head_block = Store.get_block!(store, head_root) + head_execution_hash = head_block.body.execution_payload.block_hash + finalized_checkpoint = store.finalized_checkpoint + finalized_block = Store.get_block!(store, store.finalized_checkpoint.root) + finalized_execution_hash = finalized_block.body.execution_payload.block_hash # TODO: do someting with the result from the execution client # TODO: compute safe block hash ExecutionClient.notify_forkchoice_updated( - head_root, - finalized_checkpoint.root, - finalized_checkpoint.root + head_execution_hash, + finalized_execution_hash, + finalized_execution_hash ) BeaconChain.update_fork_choice_cache( diff --git a/lib/lambda_ethereum_consensus/state_transition/operations.ex b/lib/lambda_ethereum_consensus/state_transition/operations.ex index 3cb4263c9..c395a77e1 100644 --- a/lib/lambda_ethereum_consensus/state_transition/operations.ex +++ b/lib/lambda_ethereum_consensus/state_transition/operations.ex @@ -235,7 +235,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Operations do {:error, "Timestamp verification failed"} # Verify the execution payload is valid if not mocked - verify_and_notify_new_payload.(payload) != {:ok, true} -> + not match?({:ok, _}, verify_and_notify_new_payload.(payload)) -> {:error, "Invalid execution payload"} # Cache execution payload header diff --git a/mix.exs b/mix.exs index 65060d9ad..aa006bb2a 100644 --- a/mix.exs +++ b/mix.exs @@ -39,6 +39,7 @@ defmodule LambdaEthereumConsensus.MixProject do {:snappyer, "~> 1.2"}, {:yaml_elixir, "~> 2.8"}, {:timex, "~> 3.7"}, + {:recase, "~> 0.5"}, {:rexbug, "~> 1.0"}, {:eep, git: "https://github.com/virtan/eep", branch: "master"}, {:protobuf, "~> 0.12.0"}, diff --git a/mix.lock b/mix.lock index 8ba40ff29..69c953dbd 100644 --- a/mix.lock +++ b/mix.lock @@ -42,6 +42,7 @@ "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "recase": {:hex, :recase, "0.7.0", "3f2f719f0886c7a3b7fe469058ec539cb7bbe0023604ae3bce920e186305e5ae", [:mix], [], "hexpm", "36f5756a9f552f4a94b54a695870e32f4e72d5fad9c25e61bc4a3151c08a4e0c"}, "redbug": {:hex, :redbug, "1.2.2", "366d8961770ddc7bb5d209fbadddfa7271005487f938c087a0e385a57abfee33", [:rebar3], [], "hexpm", "b5fe7b94e487be559cb0ec1c0e938c9761205d3e91a96bf263bdf1beaebea729"}, "rexbug": {:hex, :rexbug, "1.0.6", "024071c67d970151fbdc06f299faf8db3e1b2ac759a28623a9cc80a517fc74f2", [:mix], [{:mix_test_watch, ">= 0.5.0", [hex: :mix_test_watch, repo: "hexpm", optional: true]}, {:redbug, "~> 1.2", [hex: :redbug, repo: "hexpm", optional: false]}], "hexpm", "148ea724979413e9fd84ca3b4bb5d2d8b840ac481adfd645f5846fda409a642c"}, "rustler": {:hex, :rustler, "0.29.1", "880f20ae3027bd7945def6cea767f5257bc926f33ff50c0d5d5a5315883c084d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "109497d701861bfcd26eb8f5801fe327a8eef304f56a5b63ef61151ff44ac9b6"},