Skip to content

Commit 9c44baa

Browse files
authored
feat: remove states older than the last finalized checkpoint (#1071)
1 parent 4f577df commit 9c44baa

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ defmodule LambdaEthereumConsensus.ForkChoice do
1212
alias LambdaEthereumConsensus.ForkChoice.Head
1313
alias LambdaEthereumConsensus.P2P.Gossip.OperationsCollector
1414
alias LambdaEthereumConsensus.Store.Blocks
15+
alias LambdaEthereumConsensus.Store.StateDb
1516
alias LambdaEthereumConsensus.Store.StoreDb
1617
alias LambdaEthereumConsensus.Validator
1718
alias Types.Attestation
@@ -72,6 +73,8 @@ defmodule LambdaEthereumConsensus.ForkChoice do
7273

7374
Logger.info("[Fork choice] Adding new block", root: block_root, slot: slot)
7475

76+
%Store{finalized_checkpoint: last_finalized_checkpoint} = store
77+
7578
result =
7679
:telemetry.span([:sync, :on_block], %{}, fn ->
7780
{process_block(block_root, signed_block, store), %{}}
@@ -84,6 +87,15 @@ defmodule LambdaEthereumConsensus.ForkChoice do
8487

8588
Task.async(__MODULE__, :recompute_head, [new_store])
8689

90+
%Store{finalized_checkpoint: new_finalized_checkpoint} = new_store
91+
92+
if last_finalized_checkpoint.epoch < new_finalized_checkpoint.epoch do
93+
new_finalized_slot =
94+
new_finalized_checkpoint.epoch * ChainSpec.get("SLOTS_PER_EPOCH")
95+
96+
Task.async(StateDb, :prune_states_older_than, [new_finalized_slot])
97+
end
98+
8799
GenServer.cast(from, {:block_processed, block_root, true})
88100
{:noreply, new_store}
89101

lib/lambda_ethereum_consensus/store/db.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ defmodule LambdaEthereumConsensus.Store.Db do
1818
Exleveldb.put(ref, key, value)
1919
end
2020

21+
@spec delete(binary) :: :ok
22+
def delete(key) do
23+
ref = GenServer.call(@registered_name, :get_ref)
24+
Exleveldb.delete(ref, key)
25+
end
26+
2127
@spec get(binary) :: {:ok, binary} | :not_found
2228
def get(key) do
2329
ref = GenServer.call(@registered_name, :get_ref)

lib/lambda_ethereum_consensus/store/state_db.ex

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,44 @@ defmodule LambdaEthereumConsensus.Store.StateDb do
3030
Db.put(slothash_key_block, block_root)
3131
end
3232

33+
def prune_states_older_than(slot) do
34+
last_finalized_key = slot |> root_by_slot_key()
35+
36+
with {:ok, it} <- Db.iterate(),
37+
{:ok, @stateslot_prefix <> _slot, _value} <-
38+
Exleveldb.iterator_move(it, last_finalized_key),
39+
{:ok, slots_to_remove} <- get_slots_to_remove(it),
40+
:ok <- Exleveldb.iterator_close(it) do
41+
slots_to_remove |> Enum.map(&remove_by_slot/1)
42+
end
43+
end
44+
45+
defp get_slots_to_remove(slots_to_remove \\ [], iterator) do
46+
case Exleveldb.iterator_move(iterator, :prev) do
47+
{:ok, @stateslot_prefix <> slot, _root} ->
48+
[slot | slots_to_remove] |> get_slots_to_remove(iterator)
49+
50+
_ ->
51+
{:ok, slots_to_remove}
52+
end
53+
end
54+
55+
defp remove_by_slot(binary_slot) do
56+
slot = :binary.decode_unsigned(binary_slot)
57+
key_slot = root_by_slot_key(slot)
58+
59+
with {:ok, block_root} <- Db.get(key_slot),
60+
key_block <- state_key(block_root),
61+
{:ok, encoded_state} <- Db.get(key_block) do
62+
key_state =
63+
encoded_state |> Ssz.from_ssz!(BeaconState) |> Ssz.hash_tree_root!() |> block_key()
64+
65+
Db.delete(key_slot)
66+
Db.delete(key_block)
67+
Db.delete(key_state)
68+
end
69+
end
70+
3371
@spec get_state_by_block_root(Types.root()) ::
3472
{:ok, BeaconState.t()} | {:error, String.t()} | :not_found
3573
def get_state_by_block_root(root) do

lib/ssz.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ defmodule Ssz do
2828
|> to_ssz_rs(schema)
2929
end
3030

31+
@spec from_ssz!(binary, module) :: struct
32+
def from_ssz!(bin, schema) do
33+
{:ok, root} = from_ssz(bin, schema)
34+
root
35+
end
36+
3137
@spec from_ssz(binary, module) :: {:ok, struct} | {:error, String.t()}
3238
def from_ssz(bin, schema) do
3339
with {:ok, map} <- from_ssz_rs(bin, schema) do

0 commit comments

Comments
 (0)