-
Notifications
You must be signed in to change notification settings - Fork 3.9k
state-surgery: Add state surgery #2655
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
Merged
mergify
merged 2 commits into
ethereum-optimism:develop
from
mslipper:feat/state-surgery
Jun 7, 2022
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| surgery |
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,3 @@ | ||
| surgery: | ||
| go build -o ./surgery ./cmd/main.go | ||
| .PHONY: surgery |
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,60 @@ | ||
| # state-surgery | ||
|
|
||
| This package performs state surgery. It takes the following input: | ||
|
|
||
| 1. A v0 database | ||
| 2. A partial `genesis.json` | ||
| 3. A list of addresses that transacted on the network prior to this past regenesis. | ||
| 4. A list of addresses that performed approvals on prior versions of the OVM ETH contract. | ||
|
|
||
| It creates an initialized Bedrock Geth database as output. It does this by performing the following steps: | ||
|
|
||
| 1. Iterates over the old state. | ||
| 2. For each account in the old state, add that account and its storage to the new state after copying its balance from the OVM_ETH contract. | ||
| 3. Iterates over the pre-allocated accounts in the genesis file and adds them to the new state. | ||
| 4. Imports any accounts that have OVM ETH balances but aren't in state. | ||
| 5. Configures a genesis block in the new state using `genesis.json`. | ||
|
|
||
| It performs the following integrity checks: | ||
|
|
||
| 1. OVM ETH storage slots must be completely accounted for. | ||
| 2. The total supply of OVM ETH migrated must match the total supply of the OVM ETH contract. | ||
|
|
||
| This process takes about two hours on mainnet. | ||
|
|
||
| Unlike previous iterations of our state surgery scripts, this one does not write results to a `genesis.json` file. This is for the following reasons: | ||
|
|
||
| 1. **Performance**. It's much faster to write binary to LevelDB than it is to write strings to a JSON file. | ||
| 2. **State Size**. There are nearly 1MM accounts on mainnet, which would create a genesis file several gigabytes in size. This is impossible for Geth to import without a large amount of memory, since the entire JSON gets buffered into memory. Importing the entire state database will be much faster, and can be done with fewer resources. | ||
|
|
||
| ## Data Files | ||
|
|
||
| The following data files are used for mainnet: | ||
|
|
||
| 1. `mainnet-ovm-4-addresses.csv`: Contains all addresses that used OVM ETH during regenesis 4. Calculated by parsing Mint, Burn, and Transfer events from that network's OVM ETH contract. | ||
| 2. `mainnet-ovm-4-allowances.csv`: Contains all addresses that performed an approval on OVM ETH during regenesis 4 and who they approved. Calculated by parsing Approve events on that network's OVM ETH contract. | ||
|
|
||
| These files are used to build the list of OVM ETH storage slots. | ||
|
|
||
| ## Compilation | ||
|
|
||
| Run `make surgery`. | ||
|
|
||
| ## Usage | ||
|
|
||
| ``` | ||
| NAME: | ||
| surgery - migrates data from v0 to Bedrock | ||
|
|
||
| USAGE: | ||
| surgery [global options] command [command options] [arguments...] | ||
|
|
||
| COMMANDS: | ||
| dump-addresses dumps addresses from OVM ETH | ||
| migrate migrates state in OVM ETH | ||
| help, h Shows a list of commands or help for one command | ||
|
|
||
| GLOBAL OPTIONS: | ||
| --data-dir value, -d value data directory to read | ||
| --help, -h show help (default: false) | ||
| ``` |
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,124 @@ | ||
| package state_surgery | ||
|
|
||
| import ( | ||
| "bufio" | ||
| "bytes" | ||
| "errors" | ||
| "fmt" | ||
| "io" | ||
| "strings" | ||
|
|
||
| l2grawdb "github.com/ethereum-optimism/optimism/l2geth/core/rawdb" | ||
| "github.com/ethereum/go-ethereum/common" | ||
| "github.com/ethereum/go-ethereum/ethdb" | ||
| ) | ||
|
|
||
| var ( | ||
| // AddressPreimagePrefix is the byte prefix of address preimages | ||
| // in Geth's database. | ||
| AddressPreimagePrefix = []byte("addr-preimage-") | ||
|
|
||
| // ErrStopIteration will stop iterators early when returned from the | ||
| // iterator's callback. | ||
| ErrStopIteration = errors.New("iteration stopped") | ||
|
|
||
| // MintTopic is the topic for mint events on OVM ETH. | ||
| MintTopic = common.HexToHash("0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885") | ||
| ) | ||
|
|
||
| type AddressCB func(address common.Address) error | ||
| type AllowanceCB func(owner, spender common.Address) error | ||
|
|
||
| // IterateDBAddresses iterates over each address in Geth's address | ||
| // preimage database, calling the callback with the address. | ||
| func IterateDBAddresses(inDB ethdb.Database, cb AddressCB) error { | ||
| iter := inDB.NewIterator(AddressPreimagePrefix, nil) | ||
| for iter.Next() { | ||
| if iter.Error() != nil { | ||
| return iter.Error() | ||
| } | ||
|
|
||
| addr := common.BytesToAddress(bytes.TrimPrefix(iter.Key(), AddressPreimagePrefix)) | ||
| cbErr := cb(addr) | ||
| if cbErr == ErrStopIteration { | ||
| return nil | ||
| } | ||
| if cbErr != nil { | ||
| return cbErr | ||
| } | ||
| } | ||
| return iter.Error() | ||
| } | ||
|
|
||
| // IterateAddrList iterates over each address in an address list, | ||
| // calling the callback with the address. | ||
| func IterateAddrList(r io.Reader, cb AddressCB) error { | ||
| scan := bufio.NewScanner(r) | ||
| for scan.Scan() { | ||
| addrStr := scan.Text() | ||
| if !common.IsHexAddress(addrStr) { | ||
| return fmt.Errorf("invalid address %s", addrStr) | ||
| } | ||
| err := cb(common.HexToAddress(addrStr)) | ||
| if err == ErrStopIteration { | ||
mslipper marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return nil | ||
| } | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // IterateAllowanceList iterates over each address in an allowance list, | ||
| // calling the callback with the owner and the spender. | ||
| func IterateAllowanceList(r io.Reader, cb AllowanceCB) error { | ||
| scan := bufio.NewScanner(r) | ||
| for scan.Scan() { | ||
| line := scan.Text() | ||
| splits := strings.Split(line, ",") | ||
| if len(splits) != 2 { | ||
| return fmt.Errorf("invalid allowance %s", line) | ||
| } | ||
| owner := splits[0] | ||
| spender := splits[1] | ||
| if !common.IsHexAddress(owner) { | ||
| return fmt.Errorf("invalid address %s", owner) | ||
| } | ||
| if !common.IsHexAddress(spender) { | ||
| return fmt.Errorf("invalid address %s", spender) | ||
| } | ||
| err := cb(common.HexToAddress(owner), common.HexToAddress(spender)) | ||
| if err == ErrStopIteration { | ||
| return nil | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // IterateMintEvents iterates over each mint event in the database starting | ||
| // from head and stopping at genesis. | ||
| func IterateMintEvents(inDB ethdb.Database, headNum uint64, cb AddressCB) error { | ||
| for headNum > 0 { | ||
| hash := l2grawdb.ReadCanonicalHash(inDB, headNum) | ||
| receipts := l2grawdb.ReadRawReceipts(inDB, hash, headNum) | ||
| for _, receipt := range receipts { | ||
| for _, l := range receipt.Logs { | ||
| if common.BytesToHash(l.Topics[0].Bytes()) != MintTopic { | ||
| continue | ||
| } | ||
|
|
||
| err := cb(common.BytesToAddress(l.Topics[1][12:])) | ||
| if errors.Is(err, ErrStopIteration) { | ||
| return nil | ||
| } | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
| } | ||
|
|
||
| headNum-- | ||
| } | ||
| return nil | ||
| } | ||
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.