This repository was archived by the owner on Jul 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
Rename state write -> reversible write #10
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| # Reversible Write Reversion | ||
|
|
||
| Reversible write reversion might be the most tricky part to explain of the EVM circuit. This note aims to illustrate how the current approach works with some diagrams, and collect all the other approaches for comparison. | ||
|
|
||
| ## Revert or not | ||
|
|
||
| With full execution trace of a block, if we iterate over it once, we can know if each call (including create) is successful or not, and then determine which reversible writes are persistent, and which are not. | ||
|
|
||
| So each call could be annotated with 2 tags: | ||
|
|
||
| - `is_success` - If this call ends with `STOP` or `RETURN` | ||
| - `is_persistent` - If this call and all its caller have `is_success == true` | ||
|
|
||
| Only reversible writes inside a call with `is_persistent == true` will be applied to the new state. Reversible writes in a call with `is_persistent == false` will be reverted at the closest call that has `is_success == false`. | ||
|
|
||
| ## Current approach | ||
|
|
||
| Since the only requirement of a read/write access is `rw_counter` uniqueness, we are not restricted to only do read/writes with sequential `rw_counter` in a step, instead we can do read/write with any `rw_counter`, as long as we don't break the `rw_counter` uniqueness requirement. | ||
|
|
||
| We ask the prover to tell us each call's information including: | ||
|
|
||
| - `is_success` - Described above | ||
| - `is_persistent` - Described above | ||
| - `rw_counter_end_of_reversion` - The `rw_counter` at the end of reversion of the call if it has `is_persistent == false` | ||
|
|
||
| In EVM circuit we track the value `reversible_write_counter` to count how many reversible writes have been made so far. This value is initialized at `0` of each call. | ||
|
|
||
| With `is_persistent`, `rw_counter_end_of_reversion` and `reversible_write_counter`, we can do the reversible write with its corresponding reversion at the same step, because we know at which point it should happen. The pseudo code of reversible write looks like: | ||
|
|
||
| ```python | ||
| rw_table.lookup( | ||
| rw_counter=rw_counter, | ||
| reversible_write=reversible_write, # write to new value | ||
| ) | ||
|
|
||
| if not is_persistent: | ||
| rw_table.lookup( | ||
| rw_counter=rw_counter_end_of_reversion - reversible_write_counter, | ||
| reversible_write=reversible_write.reverted(), # write to previous value | ||
| ) | ||
|
|
||
| rw_counter += 1 | ||
| reversible_write_counter += 1 | ||
| ``` | ||
|
|
||
| Note that the we are increasing the `reversible_write_counter`, so the reversions are applied in reverse order in `rw_table`, which is exactly the behavior we want. | ||
|
|
||
| Another important check is to ensure `rw_counter_end_of_reversion` is correct. At the step that does the reversions, we check if there is a gap of `rw_counter` to the next step, where the gap size is exactly the `reversible_write_counter`. And in the end of the gap, the `rw_counter` is exactly `rw_counter_end_of_reversion`. The pseudo code looks like: | ||
|
|
||
| ```python | ||
| if not is_persistent: | ||
| assert rw_counter_end_of_reversion == rw_counter + reversible_write_counter | ||
| rw_counter = call.rw_counter_end_of_reversion + 1 | ||
| ``` | ||
|
|
||
| With illustration: | ||
|
|
||
|  | ||
|
|
||
| The step that does the reversions is also responsible for reversions of its successful callees. Note that each callee's `reversible_write_counter` is initialized at `0`. To make sure they can do the reversion at correct `rw_counter`, we need to propagate the `rw_counter_end_of_reversion` to be itself minus the current accumulated `reversible_write_counter`. The pseudo code looks like: | ||
|
|
||
| ```python | ||
| if not is_persistent and callee_is_success: | ||
| assert callee_rw_counter_end_of_reversion \ | ||
| == rw_counter_end_of_reversion - reversible_write_counter | ||
| ``` | ||
|
|
||
|  | ||
|
|
||
| At the end of successful callee, we accumulate the `reversible_write_counter` to its caller. | ||
|
|
||
| ### Adjustment for `SELFDESTRUCT` | ||
|
|
||
| See [Design Notes, Reversible Write Reversion Note2, SELFDESTRUCT](./reversible-write-reversion2.md#selfdestruct) | ||
|
|
||
| ## Other approaches | ||
|
|
||
| ### With `revision_id` | ||
|
|
||
| TODO |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.