Skip to content

Commit e7e44ad

Browse files
authored
State forking design doc (#437)
1 parent 694d5ea commit e7e44ad

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed
38.4 KB
Loading
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## Motivation
2+
3+
Many projects may rely on state which already exists on the chain.
4+
This might be difficult to replicate on a local testing environment
5+
(this might include deploying multiple contracts, performing many transactions etc.).
6+
In order to make this easier, some frameworks from ethereum (like foundry) introduce "state forking" (see [foundry docs](https://book.getfoundry.sh/forge/fork-testing)).
7+
8+
## State forking in foundry
9+
10+
Original implementation allows for 2 ways of forking the state.
11+
12+
Both of the approaches require the user to specify the source (RPC endpoint) and optionally - a block number we want to fork state from.
13+
14+
### 1. Forking the state once for all tests
15+
This is a simpler way of forking, which requires only to pass some arguments to the forge CLI,
16+
and state is forked for the whole suite.
17+
18+
### 2. Switching forks dynamically in tests, using cheatcodes
19+
Effectively, the state in tests will be switched after creating and selecting the fork.
20+
This allows a per-case configuration which is more flexible and allows for writing more specific tests.
21+
This also enables testing more advanced scenarios like testing RPC adapters, cross-chain swaps etc.
22+
23+
## Considered solutions
24+
25+
For the state to be considered as "forked", we have to swap the storage object
26+
to a one which reads/writes on data from the fork. This can be done in two ways:
27+
28+
- Pulling the state from the fork eagerly (use a fork DB dump as storage, clone and use it for reading & writing)
29+
- Pulling the state from the fork lazily (read from fork on read request, cache locally, write state diffs to local cache)
30+
31+
The latter is preferred as the first is too heavy, inconsistent between node implementations, and generally
32+
unfeasible for fast testing.
33+
34+
## Architecture
35+
36+
All things considered it's worth to implement the data fetching mechanism properly from the get-go,
37+
since it's going to be usable in both forking approaches.
38+
39+
### State-forking architecture
40+
41+
![State forking architecture diagram](./state_forking_arch_diag.jpg)
42+
43+
### Reading data from the fork
44+
45+
![Read state flow diagram](./read_state_flow_diag.jpg)
46+
47+
48+
## Next steps
49+
50+
In order to make things simple and easy to review, we should approach implementing this iteratively,
51+
while considering future expansion.
52+
53+
### MVP
54+
1. Implement fetching data (contracts, state, classes) utilizing a single worker utilizing `ForkDatabase` architecture
55+
2. Implement executing transaction on top of the forked state (should be able to modify the local state only)
56+
3. Implement user interface, enabling the forking in the tests
57+
58+
### Further down the line
59+
4. Implement storing worker cache on disk, loading and clearing it
60+
5. Implement multifork, fetching utilizing multiple workers + controlling cheatcodes
43.8 KB
Loading

0 commit comments

Comments
 (0)