Skip to content

Commit b469fd8

Browse files
authored
refactor: persist forkchoice state (#1125)
1 parent af21ee4 commit b469fd8

File tree

4 files changed

+247
-14
lines changed

4 files changed

+247
-14
lines changed

lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ defmodule LambdaEthereumConsensus.ForkChoice do
6666
:telemetry.execute([:sync, :store], %{slot: Store.get_current_slot(store)})
6767
:telemetry.execute([:sync, :on_block], %{slot: head_slot})
6868

69+
persist_store(store)
6970
{:ok, store}
7071
end
7172

7273
@impl GenServer
73-
def handle_cast({:on_block, %BlockInfo{} = block_info, from}, store) do
74+
def handle_cast({:on_block, %BlockInfo{} = block_info, from}, _store) do
75+
store = fetch_store!()
7476
slot = block_info.signed_block.message.slot
7577
block_root = block_info.root
7678

@@ -94,6 +96,7 @@ defmodule LambdaEthereumConsensus.ForkChoice do
9496

9597
prune_old_states(last_finalized_checkpoint.epoch, new_finalized_checkpoint.epoch)
9698

99+
persist_store(new_store)
97100
GenServer.cast(from, {:block_processed, block_root, true})
98101
{:noreply, new_store}
99102

@@ -105,7 +108,8 @@ defmodule LambdaEthereumConsensus.ForkChoice do
105108
end
106109

107110
@impl GenServer
108-
def handle_cast({:on_attestation, %Attestation{} = attestation}, %Store{} = state) do
111+
def handle_cast({:on_attestation, %Attestation{} = attestation}, %Store{} = _state) do
112+
state = fetch_store!()
109113
id = attestation.signature |> Base.encode16() |> String.slice(0, 8)
110114
Logger.debug("[Fork choice] Adding attestation #{id} to the store")
111115

@@ -115,12 +119,14 @@ defmodule LambdaEthereumConsensus.ForkChoice do
115119
_ -> state
116120
end
117121

122+
persist_store(state)
118123
{:noreply, state}
119124
end
120125

121126
@impl GenServer
122-
def handle_cast({:attester_slashing, attester_slashing}, state) do
127+
def handle_cast({:attester_slashing, attester_slashing}, _state) do
123128
Logger.info("[Fork choice] Adding attester slashing to the store")
129+
state = fetch_store!()
124130

125131
state =
126132
case Handlers.on_attester_slashing(state, attester_slashing) do
@@ -132,16 +138,19 @@ defmodule LambdaEthereumConsensus.ForkChoice do
132138
state
133139
end
134140

141+
persist_store(state)
135142
{:noreply, state}
136143
end
137144

138145
@impl GenServer
139-
def handle_cast({:on_tick, time}, store) do
146+
def handle_cast({:on_tick, time}, _store) do
147+
store = fetch_store!()
140148
%Store{finalized_checkpoint: last_finalized_checkpoint} = store
141149

142150
new_store = Handlers.on_tick(store, time)
143151
%Store{finalized_checkpoint: new_finalized_checkpoint} = new_store
144152
prune_old_states(last_finalized_checkpoint.epoch, new_finalized_checkpoint.epoch)
153+
persist_store(new_store)
145154
{:noreply, new_store}
146155
end
147156

@@ -190,7 +199,6 @@ defmodule LambdaEthereumConsensus.ForkChoice do
190199

191200
@spec recompute_head(Store.t()) :: :ok
192201
def recompute_head(store) do
193-
persist_store(store)
194202
{:ok, head_root} = Head.get_head(store)
195203
head_block = Blocks.get_block!(head_root)
196204

@@ -215,11 +223,12 @@ defmodule LambdaEthereumConsensus.ForkChoice do
215223
end
216224

217225
defp persist_store(store) do
218-
pruned_store = Map.put(store, :checkpoint_states, %{})
226+
StoreDb.persist_store(store)
227+
Logger.debug("[Fork choice] Store persisted")
228+
end
219229

220-
Task.async(fn ->
221-
StoreDb.persist_store(pruned_store)
222-
Logger.debug("[Fork choice] Store persisted")
223-
end)
230+
defp fetch_store!() do
231+
{:ok, store} = StoreDb.fetch_store()
232+
store
224233
end
225234
end

lib/lambda_ethereum_consensus/store/store_db.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@ defmodule LambdaEthereumConsensus.Store.StoreDb do
88
@snapshot_prefix "snapshot"
99

1010
@spec fetch_store() :: {:ok, Types.Store.t()} | :not_found
11-
def fetch_store(), do: get(@store_prefix)
11+
def fetch_store() do
12+
:telemetry.span([:fork_choice, :fetch], %{}, fn ->
13+
{get(@store_prefix), %{}}
14+
end)
15+
end
1216

1317
@spec persist_store(Types.Store.t()) :: :ok
1418
def persist_store(%Types.Store{} = store) do
15-
put(@store_prefix, store)
19+
:telemetry.span([:fork_choice, :persist], %{}, fn ->
20+
{put(@store_prefix, store), %{}}
21+
end)
1622
end
1723

1824
@spec fetch_deposits_snapshot() :: {:ok, Types.DepositTreeSnapshot.t()} | :not_found

lib/lambda_ethereum_consensus/telemetry.ex

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,21 @@ defmodule LambdaEthereumConsensus.Telemetry do
122122
last_value("vm.uptime.total", unit: :millisecond),
123123

124124
# Db Metrics
125-
last_value("db.size.total", unit: :byte)
125+
last_value("db.size.total", unit: :byte),
126+
127+
# ForkChoice Metrics
128+
last_value("fork_choice.persist.stop.duration",
129+
unit: {:native, :millisecond}
130+
),
131+
last_value("fork_choice.persist.exception.duration",
132+
unit: {:native, :millisecond}
133+
),
134+
last_value("fork_choice.fetch.stop.duration",
135+
unit: {:native, :millisecond}
136+
),
137+
last_value("fork_choice.fetch.exception.duration",
138+
unit: {:native, :millisecond}
139+
)
126140
]
127141
end
128142

metrics/grafana/provisioning/dashboards/home.json

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,210 @@
128128
"title": "Database size",
129129
"type": "timeseries"
130130
},
131+
{
132+
"datasource": {
133+
"type": "prometheus",
134+
"uid": "PBFA97CFB590B2093"
135+
},
136+
"targets": [
137+
{
138+
"refId": "A",
139+
"expr": "fork_choice_persist_stop_duration",
140+
"range": true,
141+
"instant": true,
142+
"datasource": {
143+
"type": "prometheus",
144+
"uid": "PBFA97CFB590B2093"
145+
},
146+
"editorMode": "builder",
147+
"legendFormat": "__auto",
148+
"useBackend": false,
149+
"disableTextWrap": false,
150+
"fullMetaSearch": false,
151+
"includeNullMetadata": true,
152+
"hide": false
153+
}
154+
],
155+
"type": "timeseries",
156+
"title": "ForkChoice Persisting Store Duration",
157+
"gridPos": {
158+
"x": 0,
159+
"y": 0,
160+
"w": 12,
161+
"h": 8
162+
},
163+
"options": {
164+
"tooltip": {
165+
"mode": "single",
166+
"sort": "none",
167+
"maxHeight": 600
168+
},
169+
"legend": {
170+
"showLegend": false,
171+
"displayMode": "list",
172+
"placement": "bottom",
173+
"calcs": []
174+
}
175+
},
176+
"fieldConfig": {
177+
"defaults": {
178+
"custom": {
179+
"drawStyle": "line",
180+
"lineInterpolation": "linear",
181+
"barAlignment": 0,
182+
"lineWidth": 2,
183+
"fillOpacity": 0,
184+
"gradientMode": "none",
185+
"spanNulls": false,
186+
"insertNulls": false,
187+
"showPoints": "auto",
188+
"pointSize": 1,
189+
"stacking": {
190+
"mode": "none",
191+
"group": "A"
192+
},
193+
"axisPlacement": "auto",
194+
"axisLabel": "",
195+
"axisColorMode": "text",
196+
"axisBorderShow": false,
197+
"scaleDistribution": {
198+
"type": "linear"
199+
},
200+
"axisCenteredZero": false,
201+
"hideFrom": {
202+
"tooltip": false,
203+
"viz": false,
204+
"legend": false
205+
},
206+
"thresholdsStyle": {
207+
"mode": "off"
208+
}
209+
},
210+
"color": {
211+
"mode": "palette-classic"
212+
},
213+
"mappings": [],
214+
"thresholds": {
215+
"mode": "absolute",
216+
"steps": [
217+
{
218+
"value": null,
219+
"color": "green"
220+
},
221+
{
222+
"value": 80,
223+
"color": "red"
224+
}
225+
]
226+
},
227+
"unit": "ms"
228+
},
229+
"overrides": []
230+
},
231+
"id": 25
232+
},
233+
{
234+
"datasource": {
235+
"type": "prometheus",
236+
"uid": "PBFA97CFB590B2093"
237+
},
238+
"targets": [
239+
{
240+
"refId": "A",
241+
"expr": "fork_choice_fetch_stop_duration",
242+
"range": true,
243+
"instant": true,
244+
"datasource": {
245+
"type": "prometheus",
246+
"uid": "PBFA97CFB590B2093"
247+
},
248+
"editorMode": "builder",
249+
"legendFormat": "__auto",
250+
"useBackend": false,
251+
"disableTextWrap": false,
252+
"fullMetaSearch": false,
253+
"includeNullMetadata": true,
254+
"hide": false
255+
}
256+
],
257+
"type": "timeseries",
258+
"title": "ForkChoice Fetching Store Duration",
259+
"gridPos": {
260+
"x": 0,
261+
"y": 0,
262+
"w": 12,
263+
"h": 8
264+
},
265+
"options": {
266+
"tooltip": {
267+
"mode": "single",
268+
"sort": "none",
269+
"maxHeight": 600
270+
},
271+
"legend": {
272+
"showLegend": false,
273+
"displayMode": "list",
274+
"placement": "bottom",
275+
"calcs": []
276+
}
277+
},
278+
"fieldConfig": {
279+
"defaults": {
280+
"custom": {
281+
"drawStyle": "line",
282+
"lineInterpolation": "linear",
283+
"barAlignment": 0,
284+
"lineWidth": 2,
285+
"fillOpacity": 0,
286+
"gradientMode": "none",
287+
"spanNulls": false,
288+
"insertNulls": false,
289+
"showPoints": "auto",
290+
"pointSize": 1,
291+
"stacking": {
292+
"mode": "none",
293+
"group": "A"
294+
},
295+
"axisPlacement": "auto",
296+
"axisLabel": "",
297+
"axisColorMode": "text",
298+
"axisBorderShow": false,
299+
"scaleDistribution": {
300+
"type": "linear"
301+
},
302+
"axisCenteredZero": false,
303+
"hideFrom": {
304+
"tooltip": false,
305+
"viz": false,
306+
"legend": false
307+
},
308+
"thresholdsStyle": {
309+
"mode": "off"
310+
}
311+
},
312+
"color": {
313+
"mode": "palette-classic"
314+
},
315+
"mappings": [],
316+
"thresholds": {
317+
"mode": "absolute",
318+
"steps": [
319+
{
320+
"value": null,
321+
"color": "green"
322+
},
323+
{
324+
"value": 80,
325+
"color": "red"
326+
}
327+
]
328+
},
329+
"unit": "ms"
330+
},
331+
"overrides": []
332+
},
333+
"id": 26
334+
},
131335
{
132336
"datasource": {
133337
"type": "prometheus",
@@ -2161,4 +2365,4 @@
21612365
"uid": "90EXFQnIk",
21622366
"version": 1,
21632367
"weekStart": ""
2164-
}
2368+
}

0 commit comments

Comments
 (0)