From b469fd8034cd733ea62c2b4da4f03ba7be70b1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Avila=20Gast=C3=B3n?= <72628438+avilagaston9@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:05:12 -0300 Subject: [PATCH] refactor: persist forkchoice state (#1125) --- .../fork_choice/fork_choice.ex | 29 ++- .../store/store_db.ex | 10 +- lib/lambda_ethereum_consensus/telemetry.ex | 16 +- .../grafana/provisioning/dashboards/home.json | 206 +++++++++++++++++- 4 files changed, 247 insertions(+), 14 deletions(-) diff --git a/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex b/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex index e0018a3ac..18588ffbe 100644 --- a/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex +++ b/lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex @@ -66,11 +66,13 @@ defmodule LambdaEthereumConsensus.ForkChoice do :telemetry.execute([:sync, :store], %{slot: Store.get_current_slot(store)}) :telemetry.execute([:sync, :on_block], %{slot: head_slot}) + persist_store(store) {:ok, store} end @impl GenServer - def handle_cast({:on_block, %BlockInfo{} = block_info, from}, store) do + def handle_cast({:on_block, %BlockInfo{} = block_info, from}, _store) do + store = fetch_store!() slot = block_info.signed_block.message.slot block_root = block_info.root @@ -94,6 +96,7 @@ defmodule LambdaEthereumConsensus.ForkChoice do prune_old_states(last_finalized_checkpoint.epoch, new_finalized_checkpoint.epoch) + persist_store(new_store) GenServer.cast(from, {:block_processed, block_root, true}) {:noreply, new_store} @@ -105,7 +108,8 @@ defmodule LambdaEthereumConsensus.ForkChoice do end @impl GenServer - def handle_cast({:on_attestation, %Attestation{} = attestation}, %Store{} = state) do + def handle_cast({:on_attestation, %Attestation{} = attestation}, %Store{} = _state) do + state = fetch_store!() id = attestation.signature |> Base.encode16() |> String.slice(0, 8) Logger.debug("[Fork choice] Adding attestation #{id} to the store") @@ -115,12 +119,14 @@ defmodule LambdaEthereumConsensus.ForkChoice do _ -> state end + persist_store(state) {:noreply, state} end @impl GenServer - def handle_cast({:attester_slashing, attester_slashing}, state) do + def handle_cast({:attester_slashing, attester_slashing}, _state) do Logger.info("[Fork choice] Adding attester slashing to the store") + state = fetch_store!() state = case Handlers.on_attester_slashing(state, attester_slashing) do @@ -132,16 +138,19 @@ defmodule LambdaEthereumConsensus.ForkChoice do state end + persist_store(state) {:noreply, state} end @impl GenServer - def handle_cast({:on_tick, time}, store) do + def handle_cast({:on_tick, time}, _store) do + store = fetch_store!() %Store{finalized_checkpoint: last_finalized_checkpoint} = store new_store = Handlers.on_tick(store, time) %Store{finalized_checkpoint: new_finalized_checkpoint} = new_store prune_old_states(last_finalized_checkpoint.epoch, new_finalized_checkpoint.epoch) + persist_store(new_store) {:noreply, new_store} end @@ -190,7 +199,6 @@ defmodule LambdaEthereumConsensus.ForkChoice do @spec recompute_head(Store.t()) :: :ok def recompute_head(store) do - persist_store(store) {:ok, head_root} = Head.get_head(store) head_block = Blocks.get_block!(head_root) @@ -215,11 +223,12 @@ defmodule LambdaEthereumConsensus.ForkChoice do end defp persist_store(store) do - pruned_store = Map.put(store, :checkpoint_states, %{}) + StoreDb.persist_store(store) + Logger.debug("[Fork choice] Store persisted") + end - Task.async(fn -> - StoreDb.persist_store(pruned_store) - Logger.debug("[Fork choice] Store persisted") - end) + defp fetch_store!() do + {:ok, store} = StoreDb.fetch_store() + store end end diff --git a/lib/lambda_ethereum_consensus/store/store_db.ex b/lib/lambda_ethereum_consensus/store/store_db.ex index ef3134864..6a662a72a 100644 --- a/lib/lambda_ethereum_consensus/store/store_db.ex +++ b/lib/lambda_ethereum_consensus/store/store_db.ex @@ -8,11 +8,17 @@ defmodule LambdaEthereumConsensus.Store.StoreDb do @snapshot_prefix "snapshot" @spec fetch_store() :: {:ok, Types.Store.t()} | :not_found - def fetch_store(), do: get(@store_prefix) + def fetch_store() do + :telemetry.span([:fork_choice, :fetch], %{}, fn -> + {get(@store_prefix), %{}} + end) + end @spec persist_store(Types.Store.t()) :: :ok def persist_store(%Types.Store{} = store) do - put(@store_prefix, store) + :telemetry.span([:fork_choice, :persist], %{}, fn -> + {put(@store_prefix, store), %{}} + end) end @spec fetch_deposits_snapshot() :: {:ok, Types.DepositTreeSnapshot.t()} | :not_found diff --git a/lib/lambda_ethereum_consensus/telemetry.ex b/lib/lambda_ethereum_consensus/telemetry.ex index 226e8442e..55829b61c 100644 --- a/lib/lambda_ethereum_consensus/telemetry.ex +++ b/lib/lambda_ethereum_consensus/telemetry.ex @@ -122,7 +122,21 @@ defmodule LambdaEthereumConsensus.Telemetry do last_value("vm.uptime.total", unit: :millisecond), # Db Metrics - last_value("db.size.total", unit: :byte) + last_value("db.size.total", unit: :byte), + + # ForkChoice Metrics + last_value("fork_choice.persist.stop.duration", + unit: {:native, :millisecond} + ), + last_value("fork_choice.persist.exception.duration", + unit: {:native, :millisecond} + ), + last_value("fork_choice.fetch.stop.duration", + unit: {:native, :millisecond} + ), + last_value("fork_choice.fetch.exception.duration", + unit: {:native, :millisecond} + ) ] end diff --git a/metrics/grafana/provisioning/dashboards/home.json b/metrics/grafana/provisioning/dashboards/home.json index 621dba1f3..102d878e1 100644 --- a/metrics/grafana/provisioning/dashboards/home.json +++ b/metrics/grafana/provisioning/dashboards/home.json @@ -128,6 +128,210 @@ "title": "Database size", "type": "timeseries" }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "targets": [ + { + "refId": "A", + "expr": "fork_choice_persist_stop_duration", + "range": true, + "instant": true, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "builder", + "legendFormat": "__auto", + "useBackend": false, + "disableTextWrap": false, + "fullMetaSearch": false, + "includeNullMetadata": true, + "hide": false + } + ], + "type": "timeseries", + "title": "ForkChoice Persisting Store Duration", + "gridPos": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "options": { + "tooltip": { + "mode": "single", + "sort": "none", + "maxHeight": 600 + }, + "legend": { + "showLegend": false, + "displayMode": "list", + "placement": "bottom", + "calcs": [] + } + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "barAlignment": 0, + "lineWidth": 2, + "fillOpacity": 0, + "gradientMode": "none", + "spanNulls": false, + "insertNulls": false, + "showPoints": "auto", + "pointSize": 1, + "stacking": { + "mode": "none", + "group": "A" + }, + "axisPlacement": "auto", + "axisLabel": "", + "axisColorMode": "text", + "axisBorderShow": false, + "scaleDistribution": { + "type": "linear" + }, + "axisCenteredZero": false, + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "id": 25 + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "targets": [ + { + "refId": "A", + "expr": "fork_choice_fetch_stop_duration", + "range": true, + "instant": true, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "builder", + "legendFormat": "__auto", + "useBackend": false, + "disableTextWrap": false, + "fullMetaSearch": false, + "includeNullMetadata": true, + "hide": false + } + ], + "type": "timeseries", + "title": "ForkChoice Fetching Store Duration", + "gridPos": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "options": { + "tooltip": { + "mode": "single", + "sort": "none", + "maxHeight": 600 + }, + "legend": { + "showLegend": false, + "displayMode": "list", + "placement": "bottom", + "calcs": [] + } + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "barAlignment": 0, + "lineWidth": 2, + "fillOpacity": 0, + "gradientMode": "none", + "spanNulls": false, + "insertNulls": false, + "showPoints": "auto", + "pointSize": 1, + "stacking": { + "mode": "none", + "group": "A" + }, + "axisPlacement": "auto", + "axisLabel": "", + "axisColorMode": "text", + "axisBorderShow": false, + "scaleDistribution": { + "type": "linear" + }, + "axisCenteredZero": false, + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "id": 26 + }, { "datasource": { "type": "prometheus", @@ -2161,4 +2365,4 @@ "uid": "90EXFQnIk", "version": 1, "weekStart": "" -} +} \ No newline at end of file