Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(l1): fix snap sync + add healing #1505

Open
wants to merge 397 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
397 commits
Select commit Hold shift + click to select a range
275659a
Fix
fmoletta Nov 6, 2024
6e1b4b7
[DEBUG] Add debug prints
fmoletta Nov 6, 2024
167c591
[DEBUG] Add debug prints
fmoletta Nov 6, 2024
aad0bcf
Fix
fmoletta Nov 6, 2024
71357dd
[DEBUG] Add debug prints
fmoletta Nov 6, 2024
cd847b9
refactor: add next_choice method
fmoletta Nov 6, 2024
37c93d7
Simplify leaf node encoding
fmoletta Nov 7, 2024
92313f0
Simplify encoding of Leaf
fmoletta Nov 7, 2024
3eb5ee9
Simplify encoding of Extension
fmoletta Nov 7, 2024
eb4fd0c
Simplify encoding of Branch
fmoletta Nov 7, 2024
d50e0ff
Remove the NodeEncoder
fmoletta Nov 7, 2024
856224d
Clippy
fmoletta Nov 7, 2024
f713657
Update TrieIterator
fmoletta Nov 7, 2024
30ba82f
Add proptest
fmoletta Nov 7, 2024
21537d4
Remove old nibble representation
fmoletta Nov 7, 2024
28bd344
Rename DumbNibbles -> Nibbles
fmoletta Nov 7, 2024
c56ad04
Update some doc
fmoletta Nov 7, 2024
bebce62
Simplify BranchNode::remove
fmoletta Nov 7, 2024
08c6668
Simplify
fmoletta Nov 7, 2024
e1f032f
Update doc
fmoletta Nov 7, 2024
9dc2752
Fix unit test
fmoletta Nov 7, 2024
bbe367d
Fix test + code
fmoletta Nov 7, 2024
63f1645
Update test values
fmoletta Nov 7, 2024
237f291
Fix potential panick
fmoletta Nov 7, 2024
d5dfa30
Fix
fmoletta Nov 7, 2024
55b0c37
Fix unit tests
fmoletta Nov 7, 2024
01090b4
Remove outdated comment
fmoletta Nov 7, 2024
e1be0c6
[DEBUG] Remove debug prints
fmoletta Nov 7, 2024
bed25f7
Remove funny name test
fmoletta Nov 7, 2024
f2c2eef
doc nibbles module
fmoletta Nov 7, 2024
9050b0c
Remove todo
fmoletta Nov 7, 2024
345ae96
remove debug print
fmoletta Nov 7, 2024
0fa490f
avoid clone
fmoletta Nov 7, 2024
df62fab
Decode leaf & extension nodes
fmoletta Nov 8, 2024
de3695f
Decode branch nodesc
fmoletta Nov 8, 2024
cb92b60
Impl decode_raw for Node directly
fmoletta Nov 8, 2024
87994d3
Update test & remove impls for each node kind
fmoletta Nov 8, 2024
ec31d42
Clippy
fmoletta Nov 8, 2024
439a010
Remove unused fn
fmoletta Nov 8, 2024
69f583c
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 8, 2024
58d7cb0
Add doc comments
fmoletta Nov 8, 2024
797d486
Fix typos
fmoletta Nov 8, 2024
f2ea85f
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 8, 2024
34e2535
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 8, 2024
5b3f4b9
Merge branch 'decode_node' into validate-account-range
fmoletta Nov 11, 2024
b0beea8
Dont write nodes to DB if they are already inlined
fmoletta Nov 11, 2024
52fec40
Merge branch 'dont-store-if-inlined' into validate-account-range
fmoletta Nov 11, 2024
39b9d19
progress
fmoletta Nov 11, 2024
b2375ca
Save current progress
fmoletta Nov 12, 2024
04f94a3
Fix logic
fmoletta Nov 12, 2024
fc3ecc8
Fix logic
fmoletta Nov 12, 2024
774e1d1
Fix logic
fmoletta Nov 12, 2024
827439e
Add extension node logic to remove internal nodes
fmoletta Nov 12, 2024
377b794
Improve test
fmoletta Nov 12, 2024
185b884
Add comment
fmoletta Nov 12, 2024
2c8bb52
Add proptest
fmoletta Nov 12, 2024
76d719a
Add proptest
fmoletta Nov 12, 2024
9254ce8
Add test case
fmoletta Nov 12, 2024
0a27aab
rename func
fmoletta Nov 12, 2024
68661c9
Add doc
fmoletta Nov 12, 2024
fdcbc99
Add doc
fmoletta Nov 13, 2024
6f1e304
Add special case test
fmoletta Nov 13, 2024
925f536
Fix peripherial code
fmoletta Nov 13, 2024
f7f0bdb
Add proptest for special case: no keys
fmoletta Nov 13, 2024
0023b8a
Fix
fmoletta Nov 13, 2024
8e8dba3
Fix logic
fmoletta Nov 13, 2024
1a534cc
Fix logic
fmoletta Nov 13, 2024
6a9db29
Refactor has_right_element
fmoletta Nov 13, 2024
ff88780
Fix logic
fmoletta Nov 13, 2024
7583488
Unify criteria
fmoletta Nov 13, 2024
849a354
Refactor
fmoletta Nov 13, 2024
0908bd5
Clippy
fmoletta Nov 13, 2024
c445edc
Add doc
fmoletta Nov 13, 2024
ec13ce5
Reorder code + add doc
fmoletta Nov 13, 2024
2445f53
Fix logic
fmoletta Nov 13, 2024
16cb1b6
Check result in tests
fmoletta Nov 13, 2024
8151cef
Add tests for unsuccesful cases
fmoletta Nov 13, 2024
a7d5415
Add tests for unsuccesful cases
fmoletta Nov 13, 2024
6c9dd01
Add error handling
fmoletta Nov 13, 2024
87f2445
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 13, 2024
ad0f921
[Postpone] changes not related to the trie
fmoletta Nov 13, 2024
4fc5244
Fix
fmoletta Nov 13, 2024
dab6172
Remove debug code
fmoletta Nov 13, 2024
d02c374
Rename fn and module
fmoletta Nov 13, 2024
07e1f46
clippy
fmoletta Nov 13, 2024
2b36bbb
Update code
fmoletta Nov 13, 2024
2d711b6
Improve interface
fmoletta Nov 13, 2024
56a4ee9
Remove code leftover from debug
fmoletta Nov 13, 2024
c444a01
Consistency
fmoletta Nov 13, 2024
d59b09a
Fix
fmoletta Nov 13, 2024
8dd7c6d
Add test
fmoletta Nov 13, 2024
7e4205c
Remove TODO
fmoletta Nov 13, 2024
c59b8be
Revert "[Postpone] changes not related to the trie"
fmoletta Nov 13, 2024
03b73c8
Fix
fmoletta Nov 13, 2024
e7d3dc4
Add helper methods
fmoletta Nov 13, 2024
5d4ad34
Add syncmode argument
fmoletta Nov 14, 2024
a3820e4
crate
fmoletta Nov 15, 2024
afcdc5a
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 15, 2024
c3d5106
Add SnapSyncManager + send snap replies to them
fmoletta Nov 15, 2024
fa275ec
Add channel between kademlia table and peer connection handler
fmoletta Nov 15, 2024
c88d114
SyncManager first iteration
fmoletta Nov 21, 2024
798fb05
Start syncer in fork_choice handler
fmoletta Nov 21, 2024
a875680
First iteration of state retrieval planning
fmoletta Nov 22, 2024
356eaf0
[REVERT ME] Make V2 endpoints work in order to run hive sync test
fmoletta Nov 22, 2024
a6d64f9
Add parallel state fetching first draft
fmoletta Nov 25, 2024
3f6df84
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 26, 2024
fc9cc3e
Store block bodies and headers
fmoletta Nov 26, 2024
6b33d11
Set latest block
fmoletta Nov 26, 2024
e6c2a08
Start snap fetching
fmoletta Nov 26, 2024
8f7cbfe
chore: p2p msg boilerplate
fkrause98 Nov 26, 2024
da6cff8
Refactor comunication between backend and peer
fmoletta Nov 26, 2024
64835f3
Avoid holding the mutex for the kademlia table when sending requests …
fmoletta Nov 26, 2024
c798c35
Migrate to full sync
fmoletta Nov 27, 2024
62084e8
Error handling
fmoletta Nov 27, 2024
02a89b2
Fixes
fmoletta Nov 27, 2024
a60948d
revert uneeded changes
fmoletta Nov 27, 2024
cc4452e
revert uneeded changes
fmoletta Nov 27, 2024
c86b553
Updates & fixes
fmoletta Nov 27, 2024
05848a2
Add ethereum/sync test suite to hive (1 test)
fmoletta Nov 27, 2024
9d608f9
Default to full-sync
fmoletta Nov 27, 2024
57f1e29
revert uneeded changes
fmoletta Nov 27, 2024
a7350d8
revert uneeded changes
fmoletta Nov 27, 2024
eb3ff59
Fixes
fmoletta Nov 27, 2024
dc6fdf1
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 27, 2024
0a8d4e8
Clippy
fmoletta Nov 27, 2024
cfce53d
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 27, 2024
493fa91
revert hive workflow change
fmoletta Nov 27, 2024
c6d6767
Revert "[REVERT ME] Make V2 endpoints work in order to run hive sync …
fmoletta Nov 27, 2024
95a9af2
revert hive workflow change
fmoletta Nov 27, 2024
fd90f18
reduce tracing output
fmoletta Nov 27, 2024
3191ddd
fmt
fmoletta Nov 27, 2024
576ee33
Fix
fmoletta Nov 27, 2024
a069f80
Revert "Revert "[REVERT ME] Make V2 endpoints work in order to run hi…
fmoletta Nov 27, 2024
2ac1135
feat: update trait with receipts function
fkrause98 Nov 27, 2024
90f9ca5
Snap Sync: Account Range
fmoletta Nov 27, 2024
bfcff0d
feat: implement receipts_for_block for inmem
fkrause98 Nov 27, 2024
e942876
feat: send response msg
fkrause98 Nov 27, 2024
b00ac70
Update tracing + set correct bytes response limit
fmoletta Nov 28, 2024
024efc9
Fix decoding of GetStorageRange
fmoletta Nov 28, 2024
83999e0
Merge branch 'main' into eth-get-receipts-msg
fkrause98 Nov 28, 2024
7821db9
First steps of bytecode fetch queue + improve task spawning and joini…
fmoletta Nov 29, 2024
85ce202
Connect state rebuilding to bytecode fetcher
fmoletta Nov 29, 2024
973f2d9
Fix
fmoletta Nov 29, 2024
cafa197
Impl request storage ranges
fmoletta Nov 29, 2024
cbdeeb6
Storage fetcher skeleton
fmoletta Nov 29, 2024
c76cfeb
Add storage fetcher process
fmoletta Dec 2, 2024
586ec79
Signal end
fmoletta Dec 2, 2024
3f5bb77
Fix
fmoletta Dec 2, 2024
98f3270
Fix
fmoletta Dec 2, 2024
7028663
Fix
fmoletta Dec 2, 2024
711d987
Mute tracing
fmoletta Dec 2, 2024
d5b1ab5
Update
fmoletta Dec 4, 2024
2a59cdc
Update batch size
fmoletta Dec 4, 2024
e21a77a
Add error handling
fmoletta Dec 4, 2024
aec4c48
Add syncmode enum
fmoletta Dec 4, 2024
e1b2c6e
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 4, 2024
317ccb5
Restore store creation
fmoletta Dec 4, 2024
146d767
Uncomment tracing
fmoletta Dec 4, 2024
f53646c
Remove unused fn
fmoletta Dec 4, 2024
ec6a9d4
Fix storage ranges verify logic
fmoletta Dec 4, 2024
1c945f6
Clippy
fmoletta Dec 4, 2024
5b93fbd
Revert "Revert "Revert "[REVERT ME] Make V2 endpoints work in order t…
fmoletta Dec 4, 2024
776ddc8
Clippy
fmoletta Dec 4, 2024
be70833
Fix clippy
fmoletta Dec 4, 2024
f501b02
Revert unstable lib feature
fmoletta Dec 4, 2024
ca622b6
Improve doc
fmoletta Dec 4, 2024
43c9309
Fix diagram linking
fmoletta Dec 4, 2024
ffb9e68
Improve spacing
fmoletta Dec 4, 2024
fa81f67
Improve spacing
fmoletta Dec 4, 2024
b7197a8
Fix typos
fmoletta Dec 4, 2024
eccaf9e
Add doc about bytecode fetcher
fmoletta Dec 4, 2024
559076c
Add doc about storage_fetcher + add improvement idea
fmoletta Dec 4, 2024
a07f35e
revert uneeded change + add doc
fmoletta Dec 4, 2024
81ae7ed
Commit diagram
fmoletta Dec 4, 2024
563d51b
fmt
fmoletta Dec 4, 2024
f10e6fb
Rename doc files
fmoletta Dec 4, 2024
8d70af3
Typo check
fmoletta Dec 4, 2024
af20a75
Revert "Revert "Revert "Revert "[REVERT ME] Make V2 endpoints work in…
fmoletta Dec 5, 2024
2715bf5
Fix `StorageRanges` decoding
fmoletta Dec 5, 2024
951b208
Update encoding
fmoletta Dec 5, 2024
0f55228
feat: fix decoding of receipts
fkrause98 Dec 6, 2024
3e534e4
feat: cleanup libmdbxp impl
fkrause98 Dec 6, 2024
6a09461
feat: cleanup unwraps
fkrause98 Dec 6, 2024
7b544da
tests: add GetBlockReceipts to devp2p in hive
fkrause98 Dec 6, 2024
8b3360f
Merge branch 'main' into eth-get-receipts-msg
fkrause98 Dec 6, 2024
f4f8f97
feat: implemente receipts for redb
fkrause98 Dec 6, 2024
ba609b3
issue: update todo tag with issue number
fkrause98 Dec 6, 2024
9aeaf94
chore: cargo fmt
fkrause98 Dec 6, 2024
7e4fb45
chore: lint
fkrause98 Dec 6, 2024
fb1ae9b
feat: back to old encoding
fkrause98 Dec 6, 2024
1baf3dc
chore: comments
fkrause98 Dec 6, 2024
35a81c5
Add max retries
fmoletta Dec 9, 2024
90d68f2
Add methods to manipulate trie state during snap sync
fmoletta Dec 9, 2024
ae33bbe
feat: fix hive tests
fkrause98 Dec 9, 2024
97ea513
feat: add some error handling
fkrause98 Dec 9, 2024
1c6ace8
chore: clippy
fkrause98 Dec 9, 2024
2f5961f
chore: fmt
fkrause98 Dec 9, 2024
581b325
State Healing first progress
fmoletta Dec 9, 2024
5d4d2ba
Merge branch 'main' into eth-get-receipts-msg
fkrause98 Dec 10, 2024
4ef7f11
Add storage healing
fmoletta Dec 10, 2024
2238897
Intergrate bytecode sender
fmoletta Dec 10, 2024
d00f74a
Merge branch 'main' into eth-get-receipts-msg
fkrause98 Dec 10, 2024
28e6229
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 10, 2024
a878cf1
Fix
fmoletta Dec 10, 2024
5e0c501
feat: use consensus encoding for receipts
fkrause98 Dec 10, 2024
cd755ed
chore: cargo fmt
fkrause98 Dec 10, 2024
161565c
docs: add some comments about receipts
fkrause98 Dec 10, 2024
bc4b9e0
fix: remove unwraps
fkrause98 Dec 10, 2024
8ff54d9
fix: restore priviliged match
fkrause98 Dec 10, 2024
ef2caf2
Fix
fmoletta Dec 10, 2024
f33584f
Fix
fmoletta Dec 10, 2024
385e264
Fix
fmoletta Dec 10, 2024
f002e91
Fix
fmoletta Dec 11, 2024
52831d0
Fix
fmoletta Dec 11, 2024
5d58c9a
Fix
fmoletta Dec 11, 2024
e90bc1d
Remove debug prints
fmoletta Dec 11, 2024
612deb4
Simplify storage healer + fetcher
fmoletta Dec 11, 2024
86203dd
Avoid requesting storage we already have
fmoletta Dec 11, 2024
8642f53
Fix
fmoletta Dec 11, 2024
74e0e5d
Remove error used as signal
fmoletta Dec 11, 2024
6bbbada
Fix
fmoletta Dec 11, 2024
1351a9d
Snap only pivot block, full sync rest
fmoletta Dec 12, 2024
b6b28db
Fix
fmoletta Dec 13, 2024
ba17409
Add MAX_RETRIES Limit to healing
fmoletta Dec 13, 2024
b5383aa
Fix
fmoletta Dec 13, 2024
2054458
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 13, 2024
fd0518e
Doc new methods + add clippy lint
fmoletta Dec 13, 2024
78e5641
Remove unecessary explicit mapping
fmoletta Dec 13, 2024
dda5e72
Add doc
fmoletta Dec 13, 2024
c272e1b
Update doc
fmoletta Dec 17, 2024
af2fb82
Clippy
fmoletta Dec 17, 2024
215ae80
Fix md format
fmoletta Dec 17, 2024
d52f95d
Improve doc
fmoletta Dec 17, 2024
ff1fd94
Add hive workflow
fmoletta Dec 17, 2024
b54e408
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 17, 2024
efc967b
Merge branch 'main' into eth-get-receipts-msg
mpaulucci Dec 17, 2024
1b4edb7
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 17, 2024
9e41b62
Rename inner_encode_receipt -> encode_inner
fmoletta Dec 18, 2024
7c12d7f
Add decode_inner for Receipt + tests
fmoletta Dec 18, 2024
12b2c77
Simplify logic of RLPDecode impl
fmoletta Dec 18, 2024
a6a52c7
Fix typos in diagram
fmoletta Dec 18, 2024
b26e825
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 18, 2024
04ac9ec
Merge branch 'eth-get-receipts-msg' into snap-fix-plus-receipts
fmoletta Dec 18, 2024
d7e9eee
Add receipt fetching to snap-sync
fmoletta Dec 18, 2024
32be829
Clippy
fmoletta Dec 19, 2024
6f8c9e9
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 19, 2024
72b2156
Update comments
fmoletta Dec 19, 2024
b77bdff
Merge branch 'snap-fix-plus-receipts' into snap-fix
fmoletta Dec 19, 2024
f18ca83
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Dec 19, 2024
bb1a7dd
Merge branch 'main' into snap-fix
fmoletta Dec 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci_l1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ jobs:
- name: "Paris Engine tests"
simulation: ethereum/engine
test_pattern: "engine-api/RPC|Re-Org Back to Canonical Chain From Syncing Chain|Re-org to Previously Validated Sidechain Payload|Re-Org Back into Canonical Chain, Depth=5|Safe Re-Org|Transaction Re-Org|Inconsistent|Suggested Fee|PrevRandao|Fork ID|Unknown|Invalid PayloadAttributes|Bad Hash|Unique Payload ID|Re-Execute Payload|In-Order|Multiple New Payloads|Valid NewPayload|NewPayload with|Invalid NewPayload|Payload Build|Invalid NewPayload, Transaction|ParentHash equals|Build Payload|Invalid Missing Ancestor ReOrg"
- name: "Sync"
simulation: ethereum/sync
test_pattern: ""
steps:
- name: Checkout sources
uses: actions/checkout@v4
Expand Down
32 changes: 21 additions & 11 deletions crates/networking/docs/Sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,33 @@

## Snap Sync

A snap sync cycle begins by fetching all the block headers (via p2p) between the current head (latest canonical block) and the sync head (block hash sent by a forkChoiceUpdate).
The next two steps are performed in parallel:
On one side, blocks and receipts for all fetched headers are fetched via p2p and stored.
A snap sync cycle begins by fetching all the block headers (via eth p2p) between the current head (latest canonical block) and the sync head (block hash sent by a forkChoiceUpdate).

On the other side, the state is reconstructed via p2p snap requests. Our current implementation of this works as follows:
We will spawn two processes, the `bytecode_fetcher` which will remain active and process bytecode requests in batches by requesting bytecode batches from peers and storing them, and the `fetch_snap_state` process, which will iterate over the fetched headers and rebuild the block's state via `rebuild_state_trie`.
We will then fetch the block bodies from each header and at the same time select a pivot block (sync head - 64) and start rebuilding its state via snap p2p requests, if the pivot were to become stale during this rebuild we will select a newer pivot (sync head) and restart it.
mpaulucci marked this conversation as resolved.
Show resolved Hide resolved

`rebuild_state_trie` will spawn a `storage_fetcher` process (which works similarly to the `bytecode_fetcher` and is kept alive for the duration of the rebuild process), it will open a new state trie and will fetch the block's accounts in batches and for each account it will: send the account's code hash to the `bytecode_fetcher` (if not empty), send the account's address and storage root to the `storage_fetcher` (if not empty), and add the account to the state trie. Once all accounts are processed, the final state root will be checked and committed.
After we fully rebuilt the pivot state and fetched all the block bodies we will fetch and store the receipts for the range between the current head and the pivot (including it), and at the same time store all blocks in the same range and execute all blocks after the pivot (like in full sync).

(Not implemented yet) When `fetch_snap_state` runs out of available state (aka, the state we need to fetch is older than 128 blocks and peers don't provide it), it will begin the `state_healing` process.
This diagram illustrates the process described above:

![snap_sync](/crates/networking/docs/diagrams/snap_sync.jpg)
![snap_sync](/crates/networking/docs/diagrams/snap_sync.jpg).
mpaulucci marked this conversation as resolved.
Show resolved Hide resolved

### Snap State Rebuild

During snap sync we need to fully rebuild the pivot block's state. We can divide this process into the initial sync and the healing phase.
For the first phase we will spawn two processes, the `bytecode_fetcher` and the `storage_fetcher` which will both remain active and listening for requests from the main rebuild process which they will then queue and process in fixed size batches (more on this later). It will then request the full extent of accounts from the pivot block's state trie via p2p snap requests. For each obtained range we will send the account's code hash and storage root to the `bytecode_fetcher` and `storage_fetcher` respectively for fetching. Once we fetch all accounts (or the account state is no longer available), we will signal the `storage_fetcher` to finish all pending requests and move on to the next phase, while keeping the `bytecode_fetcher` active.

In the healing phase we will spawn another queue-like process called `storage_healer`, and we will begin requesting state trie nodes. We will begin by requesting the pivot block's state's root node proceed by requesting the current node's children (if they are not already part of the state) until we have the full trie stored (aka all child nodes are known). For each fetched leaf node we will send its code hash to the `bytecode_fetcher` and account hash to the `storage_healer`.

The `storage_healer` will contain a list of pending account hashes and paths. And will add new entries by either adding the root node of an account's storage trie when receiving an account hash from the main process or by adding the unknown children of nodes returned by peers.

The `bytecode_fetcher` has its own channel where it receives code hashes from active `rebuild_state_trie` processes. Once a code hash is received, it is added to a pending queue. When the queue has enough messages for a full batch it will request a batch of bytecodes via snap p2p and store them. If a bytecode could not be fetched by the request (aka, we reached the response limit) it is added back to the pending queue. After the whole state is synced `fetch_snap_state` will send an empty list to the `bytecode_fetcher` to signal the end of the requests so it can request the last (incomplete) bytecode batch and end gracefully.
This diagram illustrates the process described above:

![snap_sync](/crates/networking/docs/diagrams/bytecode_fetcher.jpg)
![rebuild_state](/crates/networking/docs/diagrams/rebuild_state_trie.jpg).

The `storage_fetcher` works almost alike, but one will be spawned for each `rebuild_state_trie` process as we can't fetch storages from different blocks in the same request.
To exemplify how queue-like processes work we will explain how the `bytecode_fetcher` works:

The `bytecode_fetcher` has its own channel where it receives code hashes from an active `rebuild_state_trie` process. Once a code hash is received, it is added to a pending queue. When the queue has enough messages for a full batch it will request a batch of bytecodes via snap p2p and store them. If a bytecode could not be fetched by the request (aka, we reached the response limit) it is added back to the pending queue. After the whole state is synced `fetch_snap_state` will send an empty list to the `bytecode_fetcher` to signal the end of the requests so it can request the last (incomplete) bytecode batch and end gracefully.

This diagram illustrates the process described above:

![snap_sync](/crates/networking/docs/diagrams/bytecode_fetcher.jpg)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified crates/networking/docs/diagrams/snap_sync.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
157 changes: 151 additions & 6 deletions crates/networking/p2p/peer_channels.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
use std::{sync::Arc, time::Duration};
use std::{collections::BTreeMap, sync::Arc, time::Duration};

use bytes::Bytes;
use ethrex_core::{
types::{AccountState, BlockBody, BlockHeader},
types::{AccountState, BlockBody, BlockHeader, Receipt},
H256, U256,
};
use ethrex_rlp::encode::RLPEncode;
use ethrex_trie::verify_range;
use ethrex_trie::Nibbles;
use ethrex_trie::{verify_range, Node};
use tokio::sync::{mpsc, Mutex};

use crate::{
rlpx::{
eth::blocks::{
BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders, BLOCK_HEADER_LIMIT,
eth::{
blocks::{
BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders, BLOCK_HEADER_LIMIT,
},
receipts::{GetReceipts, Receipts},
},
snap::{
AccountRange, ByteCodes, GetAccountRange, GetByteCodes, GetStorageRanges, StorageRanges,
AccountRange, ByteCodes, GetAccountRange, GetByteCodes, GetStorageRanges, GetTrieNodes,
StorageRanges, TrieNodes,
},
},
snap::encodable_to_proof,
Expand Down Expand Up @@ -121,6 +126,38 @@ impl PeerChannels {
(!block_bodies.is_empty() && block_bodies.len() <= block_hashes_len).then_some(block_bodies)
}

/// Requests all receipts in a set of blocks from the peer given their block hashes
/// Returns the lists of receipts or None if:
/// - There are no available peers (the node just started up or was rejected by all other nodes)
/// - The response timed out
/// - The response was empty or not valid
pub async fn request_receipts(&self, block_hashes: Vec<H256>) -> Option<Vec<Vec<Receipt>>> {
let block_hashes_len = block_hashes.len();
let request_id = rand::random();
let request = RLPxMessage::GetReceipts(GetReceipts {
id: request_id,
block_hashes,
});
self.sender.send(request).await.ok()?;
let mut receiver = self.receiver.lock().await;
let receipts = tokio::time::timeout(PEER_REPLY_TIMOUT, async move {
loop {
match receiver.recv().await {
Some(RLPxMessage::Receipts(Receipts { id, receipts })) if id == request_id => {
return Some(receipts)
}
// Ignore replies that don't match the expected id (such as late responses)
Some(_) => continue,
None => return None,
}
}
})
.await
.ok()??;
// Check that the response is not empty and does not contain more bodies than the ones requested
(!receipts.is_empty() && receipts.len() <= block_hashes_len).then_some(receipts)
}

/// Requests an account range from the peer given the state trie's root and the starting hash (the limit hash will be the maximum value of H256)
/// Will also return a boolean indicating if there is more state to be fetched towards the right of the trie
/// Returns the response message or None if:
Expand Down Expand Up @@ -318,4 +355,112 @@ impl PeerChannels {
}
Some((storage_keys, storage_values, should_continue))
}

/// Requests state trie nodes given the root of the trie where they are contained and their path (be them full or partial)
/// Returns the nodes or None if:
/// - There are no available peers (the node just started up or was rejected by all other nodes)
/// - The response timed out
/// - The response was empty or not valid
pub async fn request_state_trienodes(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't read the implementation for this, but it's not clear what happens if some nodes are found and others have issues (partial success). Does it return None or the nodes that are valid? Seems like the comment should make this clear

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a node is invalid then the whole response would be invalid, there are no partial successes.

&self,
state_root: H256,
paths: Vec<Nibbles>,
) -> Option<Vec<Node>> {
let request_id = rand::random();
let expected_nodes = paths.len();
let request = RLPxMessage::GetTrieNodes(GetTrieNodes {
id: request_id,
root_hash: state_root,
// [acc_path, acc_path,...] -> [[acc_path], [acc_path]]
paths: paths
.into_iter()
.map(|vec| vec![Bytes::from(vec.encode_compact())])
.collect(),
bytes: MAX_RESPONSE_BYTES,
});
self.sender.send(request).await.ok()?;
let mut receiver = self.receiver.lock().await;
let nodes = tokio::time::timeout(PEER_REPLY_TIMOUT, async move {
loop {
match receiver.recv().await {
Some(RLPxMessage::TrieNodes(TrieNodes { id, nodes })) if id == request_id => {
return Some(nodes)
}
// Ignore replies that don't match the expected id (such as late responses)
Some(_) => continue,
None => return None,
}
}
})
.await
.ok()??;
(!nodes.is_empty() && nodes.len() <= expected_nodes)
.then(|| {
nodes
.iter()
.map(|node| Node::decode_raw(node))
.collect::<Result<Vec<_>, _>>()
.ok()
})
.flatten()
}

/// Requests storage trie nodes given the root of the state trie where they are contained and
/// a hashmap mapping the path to the account in the state trie (aka hashed address) to the paths to the nodes in its storage trie (can be full or partial)
/// Returns the nodes or None if:
/// - There are no available peers (the node just started up or was rejected by all other nodes)
/// - The response timed out
/// - The response was empty or not valid
pub async fn request_storage_trienodes(
&self,
state_root: H256,
paths: BTreeMap<H256, Vec<Nibbles>>,
) -> Option<Vec<Node>> {
let request_id = rand::random();
let expected_nodes = paths.iter().fold(0, |acc, item| acc + item.1.len());
let request = RLPxMessage::GetTrieNodes(GetTrieNodes {
id: request_id,
root_hash: state_root,
// {acc_path: [path, path, ...]} -> [[acc_path, path, path, ...]]
paths: paths
.into_iter()
.map(|(acc_path, paths)| {
[
vec![Bytes::from(acc_path.0.to_vec())],
paths
.into_iter()
.map(|path| Bytes::from(path.encode_compact()))
.collect(),
]
.concat()
})
.collect(),
bytes: MAX_RESPONSE_BYTES,
});
self.sender.send(request).await.ok()?;
let mut receiver = self.receiver.lock().await;
let nodes = tokio::time::timeout(PEER_REPLY_TIMOUT, async move {
loop {
match receiver.recv().await {
Some(RLPxMessage::TrieNodes(TrieNodes { id, nodes })) if id == request_id => {
return Some(nodes)
}
// Ignore replies that don't match the expected id (such as late responses)
Some(_) => continue,
None => return None,
}
}
})
.await
.ok()??;
(!nodes.is_empty() && nodes.len() <= expected_nodes)
.then(|| {
nodes
.iter()
.map(|node| Node::decode_raw(node))
.collect::<Result<Vec<_>, _>>()
.ok()
})
.flatten()
}
}
Loading
Loading