Skip to content

Commit 8b47bde

Browse files
committed
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_consensus into refactor-pending-blocks
2 parents 6c80456 + 1aa9340 commit 8b47bde

File tree

22 files changed

+498
-283
lines changed

22 files changed

+498
-283
lines changed

.github/dependabot.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "mix"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
- package-ecosystem: "cargo"
8+
directory: "/native/bls_nif"
9+
schedule:
10+
interval: "weekly"
11+
- package-ecosystem: "gomod"
12+
directory: "/native/libp2p_port"
13+
schedule:
14+
interval: "weekly"
15+
- package-ecosystem: "github-actions"
16+
directory: "/" # Expands to `.github/workflows`
17+
schedule:
18+
interval: "weekly"

.github/workflows/ci.yml

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
native/libp2p_port/go.sum
3838
- name: Cache output artifacts
3939
id: output-cache
40-
uses: actions/cache@v3
40+
uses: actions/cache@v4
4141
with:
4242
path: priv/native/*
4343
key: ${{ runner.os }}-native-${{ hashFiles('native/**') }}
@@ -58,7 +58,7 @@ jobs:
5858
- uses: actions/checkout@v4
5959
- name: Cache Beacon Node OAPI
6060
id: output-cache
61-
uses: actions/cache@v3
61+
uses: actions/cache@v4
6262
with:
6363
path: ./beacon-node-oapi.json
6464
key: ${{ runner.os }}-beacon-node-oapi-${{ hashFiles('.oapi_version') }}
@@ -80,19 +80,19 @@ jobs:
8080
version-file: .tool-versions
8181
- name: Fetch native libraries
8282
id: output-cache
83-
uses: actions/cache/restore@v3
83+
uses: actions/cache/restore@v4
8484
with:
8585
path: priv/native/*
8686
key: ${{ runner.os }}-native-${{ hashFiles('native/**') }}
8787
fail-on-cache-miss: true
8888
- name: Restore dependencies cache
89-
uses: actions/cache@v3
89+
uses: actions/cache@v4
9090
with:
9191
path: deps
9292
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
9393
restore-keys: ${{ runner.os }}-mix-
9494
- name: Fetch beacon node oapi file
95-
uses: actions/cache/restore@v3
95+
uses: actions/cache/restore@v4
9696
with:
9797
path: ./beacon-node-oapi.json
9898
key: ${{ runner.os }}-beacon-node-oapi-${{ hashFiles('.oapi_version') }}
@@ -111,7 +111,7 @@ jobs:
111111
- name: Compile Elixir (Warnings as errors)
112112
run: mix compile --warnings-as-errors
113113
- name: Retrieve PLT Cache
114-
uses: actions/cache@v3
114+
uses: actions/cache@v4
115115
id: plt-cache
116116
with:
117117
path: priv/plts
@@ -137,19 +137,19 @@ jobs:
137137
version-file: .tool-versions
138138
- name: Fetch native libraries
139139
id: output-cache
140-
uses: actions/cache/restore@v3
140+
uses: actions/cache/restore@v4
141141
with:
142142
path: priv/native/*
143143
key: ${{ runner.os }}-native-${{ hashFiles('native/**') }}
144144
fail-on-cache-miss: true
145145
- name: Restore dependencies cache
146-
uses: actions/cache@v3
146+
uses: actions/cache@v4
147147
with:
148148
path: deps
149149
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
150150
restore-keys: ${{ runner.os }}-mix-
151151
- name: Fetch beacon node oapi file
152-
uses: actions/cache/restore@v3
152+
uses: actions/cache/restore@v4
153153
with:
154154
path: ./beacon-node-oapi.json
155155
key: ${{ runner.os }}-beacon-node-oapi-${{ hashFiles('.oapi_version') }}
@@ -184,19 +184,19 @@ jobs:
184184
version-file: .tool-versions
185185
- name: Fetch native libraries
186186
id: output-cache
187-
uses: actions/cache/restore@v3
187+
uses: actions/cache/restore@v4
188188
with:
189189
path: priv/native/*
190190
key: ${{ runner.os }}-native-${{ hashFiles('native/**') }}
191191
fail-on-cache-miss: true
192192
- name: Restore dependencies cache
193-
uses: actions/cache@v3
193+
uses: actions/cache@v4
194194
with:
195195
path: deps
196196
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
197197
restore-keys: ${{ runner.os }}-mix-
198198
- name: Fetch beacon node oapi file
199-
uses: actions/cache/restore@v3
199+
uses: actions/cache/restore@v4
200200
with:
201201
path: ./beacon-node-oapi.json
202202
key: ${{ runner.os }}-beacon-node-oapi-${{ hashFiles('.oapi_version') }}
@@ -225,7 +225,7 @@ jobs:
225225
version-type: strict
226226
version-file: .tool-versions
227227
- name: Restore dependencies cache
228-
uses: actions/cache@v3
228+
uses: actions/cache@v4
229229
with:
230230
path: deps
231231
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
@@ -246,7 +246,7 @@ jobs:
246246
- uses: actions/checkout@v4
247247
- name: Cache compressed spectests
248248
id: output-cache
249-
uses: actions/cache@v3
249+
uses: actions/cache@v4
250250
with:
251251
path: ./*.tar.gz
252252
key: ${{ runner.os }}-spectest-${{ hashFiles('.spectest_version') }}
@@ -270,25 +270,25 @@ jobs:
270270
version-type: strict
271271
version-file: .tool-versions
272272
- name: Fetch native libraries
273-
uses: actions/cache/restore@v3
273+
uses: actions/cache/restore@v4
274274
with:
275275
path: priv/native/*
276276
key: ${{ runner.os }}-native-${{ hashFiles('native/**') }}
277277
fail-on-cache-miss: true
278278
- name: Fetch spectest vectors
279-
uses: actions/cache/restore@v3
279+
uses: actions/cache/restore@v4
280280
with:
281281
path: ./*.tar.gz
282282
key: ${{ runner.os }}-spectest-${{ hashFiles('.spectest_version') }}
283283
fail-on-cache-miss: true
284284
- name: Restore dependencies cache
285-
uses: actions/cache@v3
285+
uses: actions/cache@v4
286286
with:
287287
path: deps
288288
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
289289
restore-keys: ${{ runner.os }}-mix-
290290
- name: Fetch beacon node oapi file
291-
uses: actions/cache/restore@v3
291+
uses: actions/cache/restore@v4
292292
with:
293293
path: ./beacon-node-oapi.json
294294
key: ${{ runner.os }}-beacon-node-oapi-${{ hashFiles('.oapi_version') }}

docs/concurrency_design.md

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The following is a sequence diagram on the lifecycle of a block, from the moment
77
```mermaid
88
sequenceDiagram
99
10-
participant port as LibP2P Port <br> (Genserver)
10+
participant port as LibP2P Port <br> (GenServer)
1111
participant sub as Subscriber <br> (GenStage)
1212
participant consumer as GossipConsumer <br> (broadway)
1313
participant pending as Pending Blocks <br> (GenServer)
@@ -66,7 +66,7 @@ Improvements:
6666
### Other issues
6767

6868
- States aren't ever stored in the DB. This is not a concurrency issue, but we should fix it.
69-
- Low priority, but we should evaluate dropping the Subscriber genserver and broadway, and have one task per message under a supervisor.
69+
- Low priority, but we should evaluate dropping the Subscriber GenServer and Broadway, and have one task per message under a supervisor.
7070

7171
## State Diagram
7272

@@ -99,11 +99,11 @@ stateDiagram-v2
9999

100100
```mermaid
101101
sequenceDiagram
102-
participant port as LibP2P Port <br> (Genserver)
102+
participant port as LibP2P Port <br> (GenServer)
103103
participant decoder as Decoder <br> (Supervised task)
104104
participant tracker as Block Tracker <br> (GenServer)
105105
participant down as Downloader <br> (Supervised task)
106-
participant store as Fork Choice Store <br> (Genserver)
106+
participant store as Fork Choice Store <br> (GenServer)
107107
participant state_t as State Transition Task <br> (Supervised task)
108108
participant DB as KV Store
109109
@@ -148,7 +148,7 @@ With this strategy in mind, the block won’t need to be passed around during it
148148

149149
There are some tasks that, of course, will require interaction with the outside world:
150150

151-
- When a parent is missing, we need to download it. The block processor may pause until it receives a notification that the parent was downloaded and transitioned. After that, it may continue with its own state transition.
151+
- When a parent is missing, we need to download it. The block processor may exit and be re-spawned after the parent is downloaded and transitioned. After that, it may continue with its own state transition.
152152
- When validating it will need to interact with the global fork choice store. This just requires validating a few parameters like the epoch/slot, which is a fast process, so it’s a relatively simple call without passing the full block and without changing the store state.
153153
- The final step is updating the store/beacon chain state, which still doesn’t need to pass around big state and is fast. If additional validations are performed or repeated, it doesn’t represent a big performance hit.
154154

@@ -157,9 +157,9 @@ There are some tasks that, of course, will require interaction with the outside
157157
```mermaid
158158
sequenceDiagram
159159
160-
participant port as LibP2P Port <br> (Genserver)
161-
participant bp as Block Processor (Genserver)
162-
participant store as Fork Choice <br> (Genserver)
160+
participant port as LibP2P Port <br> (GenServer)
161+
participant bp as Block Processor (GenServer)
162+
participant store as Fork Choice <br> (GenServer)
163163
participant db as Persistent Store <br> (DB/Cache)
164164
165165
port ->> bp: gossip(block)
@@ -187,33 +187,32 @@ We can see here that:
187187
```mermaid
188188
sequenceDiagram
189189
190-
participant bp as Block Processor (Genserver)
190+
participant bp as Block Processor (GenServer)
191191
participant db as Persistent Store <br> (DB/Cache)
192-
participant dt as Download Task
193-
participant bpp as Parent Block Processor (Genserver)
192+
participant bpp as Parent Block Processor (GenServer)
194193
195194
bp ->>+ db: parent_present?(block_root)
196195
activate bp
197196
db -->>- bp: false
198-
bp ->>+ dt: spawn(parent_root)
197+
bp ->>+ bpp: spawn(parent_root)
198+
bp ->> bp: exit()
199199
deactivate bp
200-
dt ->> dt: download(parent_root)
201-
dt ->>- bpp: spawn(parent)
202-
activate bpp
200+
bpp ->> bpp: download(parent_root)
201+
bpp ->> bpp: decompress <br> ssz decode
203202
bpp ->> db: store_block_if_not_present(block)
204203
bpp ->> bpp: validation and state transition
205-
bpp ->> db: put_state(new_parent_state)
206-
deactivate bpp
207-
db ->>+ bp: parent_ready()
204+
bpp ->>- db: put_state(new_parent_state)
205+
bpp ->>+ bp: spawn(block_root)
208206
bp ->>- bp: validation and state transition
209207
```
210208

211-
This is a simplified sequence diagram highlighting the differences when the parent block is not present. To summarize:
212209

213-
- The block processor spawns a download task under a download supervisor.
214-
- When the download finishes it will start a block processor for the parent, repeating the whole process for the parent.
210+
This is a simplified sequence diagram highlighting the differences when the parent block is not present, so it omits the interaction with fork choice GenServer. To summarize:
211+
212+
- The block processor spawns another processor for the parent, at a `download stage` and exits.
213+
- When the download finishes, the parent processor will do as a normal one, decoding, deserializing, interacting with the db, etc.
215214
- When the parent finishes the state transition, it will have saved both the block and the state to the persistent store.
216-
- The store will then notify the child block processor that it can now proceed with its own state transition.
215+
- The parent process will then spawn a new block processor for the child, at a `transition stage`.
217216

218217
Note that the persistent store here is a simplified structure. Internally, it will contain the fork tree and the cache. The fork tree will contain the relationship between blocks (the tree structure), which will enable to get a block’s children without iterating through the DB.
219218

lib/beacon_api/utils.ex

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@ defmodule BeaconApi.Utils do
44
"""
55
alias LambdaEthereumConsensus.ForkChoice.Helpers
66

7-
@doc """
8-
Checks if the value is 32 bytes and starting with "0x"
9-
"""
10-
@spec is_bytes32?(binary) :: boolean
11-
def is_bytes32?(value) when is_binary(value) do
12-
String.starts_with?(value, "0x") and byte_size(value) == 66
13-
end
14-
157
@spec parse_id(binary) :: Helpers.block_id()
168
def parse_id("genesis"), do: :genesis
179
def parse_id("justified"), do: :justified

lib/lambda_ethereum_consensus/fork_choice/handlers.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ defmodule LambdaEthereumConsensus.ForkChoice.Handlers do
116116
end
117117

118118
defp check_valid_indexed_attestation(target_state, indexed_attestation) do
119-
if Predicates.is_valid_indexed_attestation(target_state, indexed_attestation),
119+
if Predicates.valid_indexed_attestation?(target_state, indexed_attestation),
120120
do: :ok,
121121
else: {:error, "invalid indexed attestation"}
122122
end
@@ -137,13 +137,13 @@ defmodule LambdaEthereumConsensus.ForkChoice.Handlers do
137137
state = BlockStates.get_state!(store.justified_checkpoint.root)
138138

139139
cond do
140-
not Predicates.is_slashable_attestation_data(attestation_1.data, attestation_2.data) ->
140+
not Predicates.slashable_attestation_data?(attestation_1.data, attestation_2.data) ->
141141
{:error, "attestation is not slashable"}
142142

143-
not Predicates.is_valid_indexed_attestation(state, attestation_1) ->
143+
not Predicates.valid_indexed_attestation?(state, attestation_1) ->
144144
{:error, "attestation 1 is not valid"}
145145

146-
not Predicates.is_valid_indexed_attestation(state, attestation_2) ->
146+
not Predicates.valid_indexed_attestation?(state, attestation_2) ->
147147
{:error, "attestation 2 is not valid"}
148148

149149
true ->

lib/lambda_ethereum_consensus/fork_choice/helpers.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ defmodule LambdaEthereumConsensus.ForkChoice.Helpers do
128128
# If the previous epoch is justified, the block should be pulled-up. In this case, check that unrealized
129129
# justification is higher than the store and that the voting source is not more than two epochs ago
130130
correct_justified =
131-
if not correct_justified and is_previous_epoch_justified(store) do
131+
if not correct_justified and previous_epoch_justified?(store) do
132132
store.unrealized_justifications[block_root].epoch >= store.justified_checkpoint.epoch and
133133
voting_source.epoch + 2 >= current_epoch
134134
else
@@ -171,7 +171,7 @@ defmodule LambdaEthereumConsensus.ForkChoice.Helpers do
171171
end
172172
end
173173

174-
def is_previous_epoch_justified(%Store{} = store) do
174+
def previous_epoch_justified?(%Store{} = store) do
175175
current_slot = Store.get_current_slot(store)
176176
current_epoch = Misc.compute_epoch_at_slot(current_slot)
177177
store.justified_checkpoint.epoch + 1 == current_epoch

0 commit comments

Comments
 (0)