Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
11a5ddaa
Commit
11a5ddaa
authored
Nov 06, 2022
by
Matthew Slipper
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-chain-ops: Updates for the migration
parent
b94e9cb5
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
393 additions
and
250 deletions
+393
-250
main.go
op-chain-ops/cmd/migrate/main.go
+1
-1
migrate.go
op-chain-ops/crossdomain/migrate.go
+8
-3
addresses.go
op-chain-ops/ether/addresses.go
+14
-3
cli.go
op-chain-ops/ether/cli.go
+0
-156
migrate.go
op-chain-ops/ether/migrate.go
+62
-21
params.go
op-chain-ops/ether/params.go
+5
-13
util.go
op-chain-ops/ether/util.go
+3
-3
config.go
op-chain-ops/genesis/config.go
+30
-4
config_test.go
op-chain-ops/genesis/config_test.go
+0
-7
db_migration.go
op-chain-ops/genesis/db_migration.go
+87
-36
legacy.go
op-chain-ops/genesis/migration/legacy.go
+95
-0
types.go
op-chain-ops/genesis/migration/types.go
+2
-2
action.go
op-chain-ops/genesis/migration_action/action.go
+85
-0
test-deploy-config-full.json
op-chain-ops/genesis/testdata/test-deploy-config-full.json
+1
-1
No files found.
op-chain-ops/cmd/migrate/main.go
View file @
11a5ddaa
...
@@ -153,7 +153,7 @@ func main() {
...
@@ -153,7 +153,7 @@ func main() {
}
}
dryRun
:=
ctx
.
Bool
(
"dry-run"
)
dryRun
:=
ctx
.
Bool
(
"dry-run"
)
if
err
:=
genesis
.
MigrateDB
(
ldb
,
config
,
block
,
&
migrationData
,
!
dryRun
);
err
!=
nil
{
if
_
,
err
:=
genesis
.
MigrateDB
(
ldb
,
config
,
block
,
&
migrationData
,
!
dryRun
);
err
!=
nil
{
return
err
return
err
}
}
...
...
op-chain-ops/crossdomain/migrate.go
View file @
11a5ddaa
...
@@ -14,7 +14,7 @@ import (
...
@@ -14,7 +14,7 @@ import (
var
(
var
(
abiTrue
=
common
.
Hash
{
31
:
0x01
}
abiTrue
=
common
.
Hash
{
31
:
0x01
}
errLegacyStorageSlotNotFound
=
errors
.
New
(
"cannot find storage slot"
)
//
errLegacyStorageSlotNotFound = errors.New("cannot find storage slot")
)
)
// MigrateWithdrawals will migrate a list of pending withdrawals given a StateDB.
// MigrateWithdrawals will migrate a list of pending withdrawals given a StateDB.
...
@@ -27,7 +27,12 @@ func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossD
...
@@ -27,7 +27,12 @@ func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossD
legacyValue
:=
db
.
GetState
(
predeploys
.
LegacyMessagePasserAddr
,
legacySlot
)
legacyValue
:=
db
.
GetState
(
predeploys
.
LegacyMessagePasserAddr
,
legacySlot
)
if
legacyValue
!=
abiTrue
{
if
legacyValue
!=
abiTrue
{
return
fmt
.
Errorf
(
"%w: %s"
,
errLegacyStorageSlotNotFound
,
legacySlot
)
// TODO: Re-enable this once we have the exact data we need on mainnet.
// This is disabled because the data file we're using for testing was
// generated after the database dump, which means that there are extra
// storage slots in the state that don't show up in the withdrawals list.
// return fmt.Errorf("%w: %s", errLegacyStorageSlotNotFound, legacySlot)
continue
}
}
withdrawal
,
err
:=
MigrateWithdrawal
(
legacy
,
l1CrossDomainMessenger
,
l1StandardBridge
)
withdrawal
,
err
:=
MigrateWithdrawal
(
legacy
,
l1CrossDomainMessenger
,
l1StandardBridge
)
...
...
op-chain-ops/ether/addresses.go
View file @
11a5ddaa
...
@@ -8,6 +8,9 @@ import (
...
@@ -8,6 +8,9 @@ import (
"io"
"io"
"strings"
"strings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis/migration"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb"
...
@@ -27,6 +30,7 @@ var (
...
@@ -27,6 +30,7 @@ var (
)
)
type
AddressCB
func
(
address
common
.
Address
)
error
type
AddressCB
func
(
address
common
.
Address
)
error
type
AddressCBWithHead
func
(
address
common
.
Address
,
headNum
uint64
)
error
type
AllowanceCB
func
(
owner
,
spender
common
.
Address
)
error
type
AllowanceCB
func
(
owner
,
spender
common
.
Address
)
error
// IterateDBAddresses iterates over each address in Geth's address
// IterateDBAddresses iterates over each address in Geth's address
...
@@ -98,17 +102,24 @@ func IterateAllowanceList(r io.Reader, cb AllowanceCB) error {
...
@@ -98,17 +102,24 @@ func IterateAllowanceList(r io.Reader, cb AllowanceCB) error {
// IterateMintEvents iterates over each mint event in the database starting
// IterateMintEvents iterates over each mint event in the database starting
// from head and stopping at genesis.
// from head and stopping at genesis.
func
IterateMintEvents
(
db
ethdb
.
Database
,
headNum
uint64
,
cb
AddressCB
)
error
{
func
IterateMintEvents
(
db
ethdb
.
Database
,
headNum
uint64
,
cb
AddressCB
WithHead
)
error
{
for
headNum
>
0
{
for
headNum
>
0
{
hash
:=
rawdb
.
ReadCanonicalHash
(
db
,
headNum
)
hash
:=
rawdb
.
ReadCanonicalHash
(
db
,
headNum
)
receipts
:=
rawdb
.
ReadRawReceipts
(
db
,
hash
,
headNum
)
receipts
,
err
:=
migration
.
ReadLegacyReceipts
(
db
,
hash
,
headNum
)
if
err
!=
nil
{
return
err
}
for
_
,
receipt
:=
range
receipts
{
for
_
,
receipt
:=
range
receipts
{
for
_
,
l
:=
range
receipt
.
Logs
{
for
_
,
l
:=
range
receipt
.
Logs
{
if
l
.
Address
!=
predeploys
.
LegacyERC20ETHAddr
{
continue
}
if
common
.
BytesToHash
(
l
.
Topics
[
0
]
.
Bytes
())
!=
MintTopic
{
if
common
.
BytesToHash
(
l
.
Topics
[
0
]
.
Bytes
())
!=
MintTopic
{
continue
continue
}
}
err
:=
cb
(
common
.
BytesToAddress
(
l
.
Topics
[
1
][
12
:
]))
err
:=
cb
(
common
.
BytesToAddress
(
l
.
Topics
[
1
][
12
:
])
,
headNum
)
if
errors
.
Is
(
err
,
ErrStopIteration
)
{
if
errors
.
Is
(
err
,
ErrStopIteration
)
{
return
nil
return
nil
}
}
...
...
op-chain-ops/ether/cli.go
View file @
11a5ddaa
package
ether
package
ether
import
(
import
(
"encoding/json"
"math/big"
"math/big"
"os"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis/migration"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
)
)
var
(
// OVMETHAddress is the address of the OVM ETH predeploy.
OVMETHAddress
=
common
.
HexToAddress
(
"0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
)
// maxSlot is the maximum slot we'll consider to be a non-mapping variable.
maxSlot
=
new
(
big
.
Int
)
.
SetUint64
(
256
)
)
// DumpAddresses dumps address preimages in Geth's database to disk.
func
DumpAddresses
(
dataDir
string
,
outFile
string
)
error
{
db
:=
MustOpenDB
(
dataDir
)
f
,
err
:=
os
.
Create
(
outFile
)
if
err
!=
nil
{
return
wrapErr
(
err
,
"error opening outfile"
)
}
logProgress
:=
ProgressLogger
(
1000
,
"dumped addresses"
)
return
IterateDBAddresses
(
db
,
func
(
address
common
.
Address
)
error
{
_
,
err
:=
f
.
WriteString
(
address
.
Hex
()
+
"
\n
"
)
if
err
!=
nil
{
return
wrapErr
(
err
,
"error writing outfile"
)
}
logProgress
()
return
nil
})
}
// Migrate performs the actual state migration. It does quite a lot:
//
// 1. It uses address lists, allowance lists, Mint events, and address preimages in
// the input state database to create a comprehensive list of storage slots in the
// OVM ETH contract.
// 2. It iterates over the slots in OVM ETH, and compares then against the list in (1).
// If the list doesn't match, or the total supply of OVM ETH doesn't match the sum of
// all balance storage slots, it panics.
// 3. It performs the actual migration by copying the input state DB into a new state DB.
// 4. It imports the provided genesis into the new state DB like Geth would during geth init.
//
// It takes the following arguments:
//
// - dataDir: A Geth data dir.
// - outDir: A directory to output the migrated database to.
// - genesis: The new chain's genesis configuration.
// - addrLists: A list of address list file paths. These address lists are used to populate
// balances from previous regenesis events.
// - allowanceLists: A list of allowance list file paths. These allowance lists are used
// to calculate allowance storage slots from previous regenesis events.
// - chainID: The chain ID of the chain being migrated.
func
Migrate
(
dataDir
,
outDir
string
,
genesis
*
core
.
Genesis
,
addrLists
,
allowanceLists
[]
string
,
chainID
,
levelDBCacheSize
,
levelDBHandles
int
)
error
{
db
:=
MustOpenDBWithCacheOpts
(
dataDir
,
levelDBCacheSize
,
levelDBHandles
)
addresses
:=
make
([]
common
.
Address
,
0
)
for
_
,
list
:=
range
addrLists
{
log
.
Info
(
"reading address list"
,
"list"
,
list
)
f
,
err
:=
os
.
Open
(
list
)
if
err
!=
nil
{
return
wrapErr
(
err
,
"error opening address list %s"
,
list
)
}
logProgress
:=
ProgressLogger
(
10000
,
"read address"
)
err
=
IterateAddrList
(
f
,
func
(
address
common
.
Address
)
error
{
addresses
=
append
(
addresses
,
address
)
logProgress
()
return
nil
})
f
.
Close
()
if
err
!=
nil
{
return
wrapErr
(
err
,
"error reading address list"
)
}
}
allowances
:=
make
([]
*
migration
.
Allowance
,
0
)
for
_
,
list
:=
range
allowanceLists
{
log
.
Info
(
"reading allowance list"
,
"list"
,
list
)
f
,
err
:=
os
.
Open
(
list
)
if
err
!=
nil
{
return
wrapErr
(
err
,
"error opening allowances list %s"
,
list
)
}
logProgress
:=
ProgressLogger
(
10000
,
"read allowance"
)
err
=
IterateAllowanceList
(
f
,
func
(
owner
,
spender
common
.
Address
)
error
{
allowance
:=
&
migration
.
Allowance
{
From
:
spender
,
To
:
owner
,
}
allowances
=
append
(
allowances
,
allowance
)
logProgress
()
return
nil
})
f
.
Close
()
if
err
!=
nil
{
return
wrapErr
(
err
,
"error reading allowances list"
)
}
}
err
:=
MigrateLegacyETH
(
db
,
addresses
,
allowances
,
chainID
)
if
err
!=
nil
{
return
wrapErr
(
err
,
"cannot migrate erc20 eth"
)
}
headBlock
:=
rawdb
.
ReadHeadBlock
(
db
)
root
:=
headBlock
.
Root
()
backingStateDB
:=
state
.
NewDatabase
(
db
)
stateDB
,
err
:=
state
.
New
(
root
,
backingStateDB
,
nil
)
if
err
!=
nil
{
return
wrapErr
(
err
,
"error creating state DB"
)
}
log
.
Info
(
"committing state DB"
)
newRoot
,
err
:=
stateDB
.
Commit
(
false
)
if
err
!=
nil
{
return
wrapErr
(
err
,
"error writing output state DB"
)
}
log
.
Info
(
"committed state DB"
,
"root"
,
newRoot
)
log
.
Info
(
"committing trie DB"
)
if
err
:=
stateDB
.
Database
()
.
TrieDB
()
.
Commit
(
newRoot
,
true
,
nil
);
err
!=
nil
{
return
wrapErr
(
err
,
"error writing output trie DB"
)
}
log
.
Info
(
"committed trie DB"
)
// Now that the state is dumped, insert the genesis block.
//
// Unlike regular Geth (which panics if you try to import a genesis state with a nonzero
// block number), the block number can be anything.
block
:=
genesis
.
ToBlock
()
// Geth block headers are immutable, so swap the root and make a new block with the
// updated root.
header
:=
block
.
Header
()
header
.
Root
=
newRoot
block
=
types
.
NewBlock
(
header
,
nil
,
nil
,
nil
,
trie
.
NewStackTrie
(
nil
))
blob
,
err
:=
json
.
Marshal
(
genesis
)
if
err
!=
nil
{
log
.
Crit
(
"error marshaling genesis state"
,
"err"
,
err
)
}
// Write the genesis state to the database. This is taken verbatim from Geth's
// core.Genesis struct.
rawdb
.
WriteGenesisStateSpec
(
db
,
block
.
Hash
(),
blob
)
rawdb
.
WriteTd
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
Difficulty
())
rawdb
.
WriteBlock
(
db
,
block
)
rawdb
.
WriteReceipts
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
nil
)
rawdb
.
WriteCanonicalHash
(
db
,
block
.
Hash
(),
block
.
NumberU64
())
rawdb
.
WriteHeadBlockHash
(
db
,
block
.
Hash
())
rawdb
.
WriteHeadFastBlockHash
(
db
,
block
.
Hash
())
rawdb
.
WriteHeadHeaderHash
(
db
,
block
.
Hash
())
rawdb
.
WriteChainConfig
(
db
,
block
.
Hash
(),
genesis
.
Config
)
return
nil
}
// getOVMETHTotalSupply returns OVM ETH's total supply by reading
// getOVMETHTotalSupply returns OVM ETH's total supply by reading
// the appropriate storage slot.
// the appropriate storage slot.
func
getOVMETHTotalSupply
(
db
*
state
.
StateDB
)
*
big
.
Int
{
func
getOVMETHTotalSupply
(
db
*
state
.
StateDB
)
*
big
.
Int
{
...
...
op-chain-ops/ether/migrate.go
View file @
11a5ddaa
...
@@ -16,7 +16,24 @@ import (
...
@@ -16,7 +16,24 @@ import (
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie"
)
)
func
MigrateLegacyETH
(
db
ethdb
.
Database
,
addresses
[]
common
.
Address
,
allowances
[]
*
migration
.
Allowance
,
chainID
int
)
error
{
var
(
// OVMETHAddress is the address of the OVM ETH predeploy.
OVMETHAddress
=
common
.
HexToAddress
(
"0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
)
ignoredSlots
=
map
[
common
.
Hash
]
bool
{
// Total Supply
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000002"
)
:
true
,
// Name
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000003"
)
:
true
,
// Symbol
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000004"
)
:
true
,
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000005"
)
:
true
,
// Total supply
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000006"
)
:
true
,
}
)
func
MigrateLegacyETH
(
db
ethdb
.
Database
,
addresses
[]
common
.
Address
,
allowances
[]
*
migration
.
Allowance
,
chainID
int
,
commit
bool
)
(
common
.
Hash
,
error
)
{
// Set of addresses that we will be migrating.
// Set of addresses that we will be migrating.
addressesToMigrate
:=
make
(
map
[
common
.
Address
]
bool
)
addressesToMigrate
:=
make
(
map
[
common
.
Address
]
bool
)
// Set of storage slots that we expect to see in the OVM ETH contract.
// Set of storage slots that we expect to see in the OVM ETH contract.
...
@@ -34,10 +51,19 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -34,10 +51,19 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
for
_
,
allowance
:=
range
allowances
{
for
_
,
allowance
:=
range
allowances
{
addressesToMigrate
[
allowance
.
From
]
=
true
addressesToMigrate
[
allowance
.
From
]
=
true
// TODO: double check ordering here
storageSlotsToMigrate
[
CalcAllowanceStorageKey
(
allowance
.
From
,
allowance
.
To
)]
=
2
storageSlotsToMigrate
[
CalcAllowanceStorageKey
(
allowance
.
From
,
allowance
.
To
)]
=
2
}
}
if
chainID
==
1
{
// Some folks sent money to this address ages ago, permanently locking it
// there. This contract never transacted on a modern network, so hardcode
// this to ensure that all storage slots are accounted for.
// This address was once the OVM_SequencerEntrypoint contract.
seqEntryAddr
:=
common
.
HexToAddress
(
"0x4200000000000000000000000000000000000005"
)
addressesToMigrate
[
seqEntryAddr
]
=
true
storageSlotsToMigrate
[
CalcOVMETHStorageKey
(
seqEntryAddr
)]
=
1
}
headBlock
:=
rawdb
.
ReadHeadBlock
(
db
)
headBlock
:=
rawdb
.
ReadHeadBlock
(
db
)
root
:=
headBlock
.
Root
()
root
:=
headBlock
.
Root
()
...
@@ -46,15 +72,15 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -46,15 +72,15 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
// not execute that code path. As a result, we parse mint events in order
// not execute that code path. As a result, we parse mint events in order
// to not miss any balances.
// to not miss any balances.
log
.
Info
(
"reading mint events from DB"
)
log
.
Info
(
"reading mint events from DB"
)
logProgress
:=
ProgressLogger
(
100
,
"read mint event"
)
logProgress
:=
ProgressLogger
(
100
,
"read mint event
s
"
)
err
:=
IterateMintEvents
(
db
,
headBlock
.
NumberU64
(),
func
(
address
common
.
Address
)
error
{
err
:=
IterateMintEvents
(
db
,
headBlock
.
NumberU64
(),
func
(
address
common
.
Address
,
headNum
uint64
)
error
{
addressesToMigrate
[
address
]
=
true
addressesToMigrate
[
address
]
=
true
storageSlotsToMigrate
[
CalcOVMETHStorageKey
(
address
)]
=
1
storageSlotsToMigrate
[
CalcOVMETHStorageKey
(
address
)]
=
1
logProgress
()
logProgress
(
"headnum"
,
headNum
)
return
nil
return
nil
})
})
if
err
!=
nil
{
if
err
!=
nil
{
return
wrapErr
(
err
,
"error reading mint events"
)
return
common
.
Hash
{},
wrapErr
(
err
,
"error reading mint events"
)
}
}
// Make sure all addresses are accounted for by iterating over
// Make sure all addresses are accounted for by iterating over
...
@@ -62,10 +88,12 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -62,10 +88,12 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
// any storage keys. We also keep track of the total amount of
// any storage keys. We also keep track of the total amount of
// OVM ETH found, and diff that against the total supply of
// OVM ETH found, and diff that against the total supply of
// OVM ETH specified in the contract.
// OVM ETH specified in the contract.
backingStateDB
:=
state
.
NewDatabase
(
db
)
backingStateDB
:=
state
.
NewDatabaseWithConfig
(
db
,
&
trie
.
Config
{
Preimages
:
true
,
})
stateDB
,
err
:=
state
.
New
(
root
,
backingStateDB
,
nil
)
stateDB
,
err
:=
state
.
New
(
root
,
backingStateDB
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
wrapErr
(
err
,
"error opening state DB"
)
return
common
.
Hash
{},
wrapErr
(
err
,
"error opening state DB"
)
}
}
storageTrie
:=
stateDB
.
StorageTrie
(
OVMETHAddress
)
storageTrie
:=
stateDB
.
StorageTrie
(
OVMETHAddress
)
storageIt
:=
trie
.
NewIterator
(
storageTrie
.
NodeIterator
(
nil
))
storageIt
:=
trie
.
NewIterator
(
storageTrie
.
NodeIterator
(
nil
))
...
@@ -90,10 +118,8 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -90,10 +118,8 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
// This slot is an allowance, ignore it.
// This slot is an allowance, ignore it.
continue
continue
default
:
default
:
slot
:=
new
(
big
.
Int
)
.
SetBytes
(
k
.
Bytes
())
// Check if this slot is a variable. If it isn't, abort.
// Check if this slot is a variable. If it isn't, and it isn't a
if
!
ignoredSlots
[
k
]
{
// known missing key, abort
if
slot
.
Cmp
(
maxSlot
)
==
1
&&
!
params
.
KnownMissingKeys
[
k
]
{
log
.
Crit
(
"missed storage key"
,
"k"
,
k
.
String
(),
"v"
,
v
.
String
())
log
.
Crit
(
"missed storage key"
,
"k"
,
k
.
String
(),
"v"
,
v
.
String
())
}
}
}
}
...
@@ -104,15 +130,14 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -104,15 +130,14 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
// Verify that the total supply is what we expect. We allow a hardcoded
// Verify that the total supply is what we expect. We allow a hardcoded
// delta to be specified in the chain params since older regenesis events
// delta to be specified in the chain params since older regenesis events
// had supply bugs.
// had supply bugs.
delta
:=
new
(
big
.
Int
)
.
Set
(
totalSupply
)
delta
:=
new
(
big
.
Int
)
.
Sub
(
totalSupply
,
totalFound
)
delta
=
delta
.
Sub
(
delta
,
totalFound
)
if
delta
.
Cmp
(
params
.
ExpectedSupplyDelta
)
!=
0
{
if
delta
.
Cmp
(
params
.
ExpectedSupplyDelta
)
!=
0
{
log
.
Crit
(
log
.
Crit
(
"supply mismatch"
,
"supply mismatch"
,
"migrated"
,
totalFound
,
"migrated"
,
totalFound
.
String
()
,
"supply"
,
totalSupply
,
"supply"
,
totalSupply
.
String
()
,
"delta"
,
delta
,
"delta"
,
delta
.
String
()
,
"exp_delta"
,
params
.
ExpectedSupplyDelta
,
"exp_delta"
,
params
.
ExpectedSupplyDelta
.
String
()
,
)
)
}
}
...
@@ -121,7 +146,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -121,7 +146,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
"migrated"
,
totalFound
.
String
(),
"migrated"
,
totalFound
.
String
(),
"supply"
,
totalSupply
.
String
(),
"supply"
,
totalSupply
.
String
(),
"delta"
,
delta
.
String
(),
"delta"
,
delta
.
String
(),
"exp_delta"
,
params
.
ExpectedSupplyDelta
,
"exp_delta"
,
params
.
ExpectedSupplyDelta
.
String
()
,
)
)
log
.
Info
(
"performing migration"
)
log
.
Info
(
"performing migration"
)
...
@@ -129,7 +154,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -129,7 +154,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
log
.
Info
(
"trie dumping started"
,
"root"
,
root
)
log
.
Info
(
"trie dumping started"
,
"root"
,
root
)
tr
,
err
:=
backingStateDB
.
OpenTrie
(
root
)
tr
,
err
:=
backingStateDB
.
OpenTrie
(
root
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
common
.
Hash
{},
err
}
}
it
:=
trie
.
NewIterator
(
tr
.
NodeIterator
(
nil
))
it
:=
trie
.
NewIterator
(
tr
.
NodeIterator
(
nil
))
totalMigrated
:=
new
(
big
.
Int
)
totalMigrated
:=
new
(
big
.
Int
)
...
@@ -194,5 +219,21 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
...
@@ -194,5 +219,21 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
// Set the total supply to 0
// Set the total supply to 0
stateDB
.
SetState
(
predeploys
.
LegacyERC20ETHAddr
,
getOVMETHTotalSupplySlot
(),
common
.
Hash
{})
stateDB
.
SetState
(
predeploys
.
LegacyERC20ETHAddr
,
getOVMETHTotalSupplySlot
(),
common
.
Hash
{})
return
nil
if
!
commit
{
log
.
Info
(
"dry run, skipping commit"
)
return
common
.
Hash
{},
nil
}
log
.
Info
(
"committing state DB"
)
newRoot
,
err
:=
stateDB
.
Commit
(
true
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
log
.
Info
(
"committing trie DB"
)
if
err
:=
stateDB
.
Database
()
.
TrieDB
()
.
Commit
(
newRoot
,
true
,
nil
);
err
!=
nil
{
return
common
.
Hash
{},
err
}
return
newRoot
,
nil
}
}
op-chain-ops/ether/params.go
View file @
11a5ddaa
...
@@ -2,16 +2,11 @@ package ether
...
@@ -2,16 +2,11 @@ package ether
import
(
import
(
"math/big"
"math/big"
"github.com/ethereum/go-ethereum/common"
)
)
// Params contains the configuration parameters used for verifying
// Params contains the configuration parameters used for verifying
// the integrity of the migration.
// the integrity of the migration.
type
Params
struct
{
type
Params
struct
{
// KnownMissingKeys is a set of known OVM ETH storage keys that are unaccounted for.
KnownMissingKeys
map
[
common
.
Hash
]
bool
// ExpectedSupplyDelta is the expected delta between the total supply of OVM ETH,
// ExpectedSupplyDelta is the expected delta between the total supply of OVM ETH,
// and ETH we were able to migrate. This is used to account for supply bugs in
// and ETH we were able to migrate. This is used to account for supply bugs in
//previous regenesis events.
//previous regenesis events.
...
@@ -20,13 +15,10 @@ type Params struct {
...
@@ -20,13 +15,10 @@ type Params struct {
var
ParamsByChainID
=
map
[
int
]
*
Params
{
var
ParamsByChainID
=
map
[
int
]
*
Params
{
1
:
{
1
:
{
// These storage keys were unaccounted for in the genesis state of regenesis 5.
// Regenesis 4 (Nov 11 2021) contained a supply bug such that the total OVM ETH
map
[
common
.
Hash
]
bool
{
// supply was 1.628470012 ETH greater than the sum balance of every account migrated
common
.
HexToHash
(
"0x8632b3478ce27e6c2251f16f71bf134373ff9d23cff5b8d5f95475fa6e52fe22"
)
:
true
,
// / during the regenesis. A further 0.0012 ETH was incorrectly not removed from the
common
.
HexToHash
(
"0x47c25b07402d92e0d7f0cd9e347329fa0d86d16717cf933f836732313929fc1f"
)
:
true
,
// total supply by accidental invocations of the Saurik bug (https://www.saurik.com/optimism.html).
common
.
HexToHash
(
"0x2acc0ec5cc86ffda9ceba005a317bcf0e86863e11be3981e923d5b103990055d"
)
:
true
,
new
(
big
.
Int
)
.
SetUint64
(
1627270011999999992
),
},
// Regenesis 4 contained a supply bug.
new
(
big
.
Int
)
.
SetUint64
(
1637102600003999992
),
},
},
}
}
op-chain-ops/ether/util.go
View file @
11a5ddaa
...
@@ -10,14 +10,14 @@ func wrapErr(err error, msg string, ctx ...any) error {
...
@@ -10,14 +10,14 @@ func wrapErr(err error, msg string, ctx ...any) error {
return
fmt
.
Errorf
(
"%s: %w"
,
fmt
.
Sprintf
(
msg
,
ctx
...
),
err
)
return
fmt
.
Errorf
(
"%s: %w"
,
fmt
.
Sprintf
(
msg
,
ctx
...
),
err
)
}
}
func
ProgressLogger
(
n
int
,
msg
string
)
func
()
{
func
ProgressLogger
(
n
int
,
msg
string
)
func
(
...
any
)
{
var
i
int
var
i
int
return
func
()
{
return
func
(
args
...
any
)
{
i
++
i
++
if
i
%
n
!=
0
{
if
i
%
n
!=
0
{
return
return
}
}
log
.
Info
(
msg
,
"count"
,
i
)
log
.
Info
(
msg
,
append
([]
any
{
"count"
,
i
},
args
...
)
...
)
}
}
}
}
op-chain-ops/genesis/config.go
View file @
11a5ddaa
...
@@ -24,7 +24,7 @@ var ErrInvalidDeployConfig = errors.New("invalid deploy config")
...
@@ -24,7 +24,7 @@ var ErrInvalidDeployConfig = errors.New("invalid deploy config")
// DeployConfig represents the deployment configuration for Optimism
// DeployConfig represents the deployment configuration for Optimism
type
DeployConfig
struct
{
type
DeployConfig
struct
{
L1StartingBlockTag
*
rpc
.
BlockNumberOrHash
`json:"l1StartingBlockTag"`
L1StartingBlockTag
*
MarshalableRPC
BlockNumberOrHash
`json:"l1StartingBlockTag"`
L1ChainID
uint64
`json:"l1ChainID"`
L1ChainID
uint64
`json:"l1ChainID"`
L2ChainID
uint64
`json:"l2ChainID"`
L2ChainID
uint64
`json:"l2ChainID"`
L2BlockTime
uint64
`json:"l2BlockTime"`
L2BlockTime
uint64
`json:"l2BlockTime"`
...
@@ -375,3 +375,29 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage
...
@@ -375,3 +375,29 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage
}
}
return
storage
,
nil
return
storage
,
nil
}
}
type
MarshalableRPCBlockNumberOrHash
rpc
.
BlockNumberOrHash
func
(
m
*
MarshalableRPCBlockNumberOrHash
)
MarshalJSON
()
([]
byte
,
error
)
{
r
:=
rpc
.
BlockNumberOrHash
(
*
m
)
if
hash
,
ok
:=
r
.
Hash
();
ok
{
return
json
.
Marshal
(
hash
)
}
if
num
,
ok
:=
r
.
Number
();
ok
{
// never errors
text
,
_
:=
num
.
MarshalText
()
return
json
.
Marshal
(
string
(
text
))
}
return
json
.
Marshal
(
nil
)
}
func
(
m
*
MarshalableRPCBlockNumberOrHash
)
UnmarshalJSON
(
b
[]
byte
)
error
{
var
r
rpc
.
BlockNumberOrHash
if
err
:=
json
.
Unmarshal
(
b
,
&
r
);
err
!=
nil
{
return
err
}
asMarshalable
:=
MarshalableRPCBlockNumberOrHash
(
r
)
*
m
=
asMarshalable
return
nil
}
op-chain-ops/genesis/config_test.go
View file @
11a5ddaa
...
@@ -14,13 +14,6 @@ import (
...
@@ -14,13 +14,6 @@ import (
)
)
func
TestConfigMarshalUnmarshal
(
t
*
testing
.
T
)
{
func
TestConfigMarshalUnmarshal
(
t
*
testing
.
T
)
{
// NOTE: the l1 starting block tag is set to null
// in the test since the type is not JSON serializable.
// Rather than bloat the code by introducing a marshalable
// block tag type that's only used in test, I created a separate
// test to validate that the starting block tag unmarshals
// correctly.
b
,
err
:=
os
.
ReadFile
(
"testdata/test-deploy-config-full.json"
)
b
,
err
:=
os
.
ReadFile
(
"testdata/test-deploy-config-full.json"
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
dec
:=
json
.
NewDecoder
(
bytes
.
NewReader
(
b
))
dec
:=
json
.
NewDecoder
(
bytes
.
NewReader
(
b
))
...
...
op-chain-ops/genesis/db_migration.go
View file @
11a5ddaa
...
@@ -4,6 +4,9 @@ import (
...
@@ -4,6 +4,9 @@ import (
"fmt"
"fmt"
"math/big"
"math/big"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-chain-ops/ether"
"github.com/ethereum-optimism/optimism/op-chain-ops/ether"
...
@@ -19,63 +22,71 @@ import (
...
@@ -19,63 +22,71 @@ import (
var
abiTrue
=
common
.
Hash
{
31
:
0x01
}
var
abiTrue
=
common
.
Hash
{
31
:
0x01
}
type
MigrationResult
struct
{
TransitionHeight
uint64
TransitionBlockHash
common
.
Hash
}
// MigrateDB will migrate an old l2geth database to the new bedrock style system
// MigrateDB will migrate an old l2geth database to the new bedrock style system
func
MigrateDB
(
ldb
ethdb
.
Database
,
config
*
DeployConfig
,
l1Block
*
types
.
Block
,
migrationData
*
migration
.
MigrationData
,
commit
bool
)
error
{
func
MigrateDB
(
ldb
ethdb
.
Database
,
config
*
DeployConfig
,
l1Block
*
types
.
Block
,
migrationData
*
migration
.
MigrationData
,
commit
bool
)
(
*
MigrationResult
,
error
)
{
hash
:=
rawdb
.
ReadHeadHeaderHash
(
ldb
)
hash
:=
rawdb
.
ReadHeadHeaderHash
(
ldb
)
num
:=
rawdb
.
ReadHeaderNumber
(
ldb
,
hash
)
num
:=
rawdb
.
ReadHeaderNumber
(
ldb
,
hash
)
header
:=
rawdb
.
ReadHeader
(
ldb
,
hash
,
*
num
)
header
:=
rawdb
.
ReadHeader
(
ldb
,
hash
,
*
num
)
db
,
err
:=
state
.
New
(
header
.
Root
,
state
.
NewDatabase
(
ldb
),
nil
)
// Leaving this commented out so that it can be used to skip
// the DB migration in development.
//return &MigrationResult{
// TransitionHeight: *num,
// TransitionBlockHash: hash,
//}, nil
underlyingDB
:=
state
.
NewDatabaseWithConfig
(
ldb
,
&
trie
.
Config
{
Preimages
:
true
,
})
db
,
err
:=
state
.
New
(
header
.
Root
,
underlyingDB
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot open StateDB: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot open StateDB: %w"
,
err
)
}
}
// Convert all of the messages into legacy withdrawals
// Convert all of the messages into legacy withdrawals
withdrawals
,
err
:=
migrationData
.
ToWithdrawals
()
withdrawals
,
err
:=
migrationData
.
ToWithdrawals
()
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot serialize withdrawals: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot serialize withdrawals: %w"
,
err
)
}
}
if
err
:=
CheckWithdrawals
(
db
,
withdrawals
);
err
!=
nil
{
if
err
:=
CheckWithdrawals
(
db
,
withdrawals
);
err
!=
nil
{
return
fmt
.
Errorf
(
"withdrawals mismatch: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"withdrawals mismatch: %w"
,
err
)
}
}
// Now start the migration
// Now start the migration
if
err
:=
SetL2Proxies
(
db
);
err
!=
nil
{
if
err
:=
SetL2Proxies
(
db
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot set L2Proxies: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot set L2Proxies: %w"
,
err
)
}
}
storage
,
err
:=
NewL2StorageConfig
(
config
,
l1Block
)
storage
,
err
:=
NewL2StorageConfig
(
config
,
l1Block
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot create storage config: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot create storage config: %w"
,
err
)
}
}
immutable
,
err
:=
NewL2ImmutableConfig
(
config
,
l1Block
)
immutable
,
err
:=
NewL2ImmutableConfig
(
config
,
l1Block
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot create immutable config: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot create immutable config: %w"
,
err
)
}
}
if
err
:=
SetImplementations
(
db
,
storage
,
immutable
);
err
!=
nil
{
if
err
:=
SetImplementations
(
db
,
storage
,
immutable
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot set implementations: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot set implementations: %w"
,
err
)
}
}
err
=
crossdomain
.
MigrateWithdrawals
(
withdrawals
,
db
,
&
config
.
L1CrossDomainMessengerProxy
,
&
config
.
L1StandardBridgeProxy
)
err
=
crossdomain
.
MigrateWithdrawals
(
withdrawals
,
db
,
&
config
.
L1CrossDomainMessengerProxy
,
&
config
.
L1StandardBridgeProxy
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot migrate withdrawals: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot migrate withdrawals: %w"
,
err
)
}
}
addrs
:=
migrationData
.
Addresses
()
addrs
:=
migrationData
.
Addresses
()
if
err
:=
ether
.
MigrateLegacyETH
(
ldb
,
addrs
,
migrationData
.
OvmAllowances
,
int
(
config
.
L1ChainID
));
err
!=
nil
{
newRoot
,
err
:=
ether
.
MigrateLegacyETH
(
ldb
,
addrs
,
migrationData
.
OvmAllowances
,
int
(
config
.
L1ChainID
),
commit
)
return
fmt
.
Errorf
(
"cannot migrate legacy eth: %w"
,
err
)
}
if
!
commit
{
return
nil
}
root
,
err
:=
db
.
Commit
(
true
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot commit state db
: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"cannot migrate legacy eth
: %w"
,
err
)
}
}
// Create the bedrock transition block
// Create the bedrock transition block
...
@@ -83,32 +94,70 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
...
@@ -83,32 +94,70 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
ParentHash
:
header
.
Hash
(),
ParentHash
:
header
.
Hash
(),
UncleHash
:
types
.
EmptyUncleHash
,
UncleHash
:
types
.
EmptyUncleHash
,
Coinbase
:
config
.
L2GenesisBlockCoinbase
,
Coinbase
:
config
.
L2GenesisBlockCoinbase
,
Root
:
r
oot
,
Root
:
newR
oot
,
TxHash
:
types
.
EmptyRootHash
,
TxHash
:
types
.
EmptyRootHash
,
ReceiptHash
:
types
.
EmptyRootHash
,
ReceiptHash
:
types
.
EmptyRootHash
,
Bloom
:
types
.
Bloom
{},
Bloom
:
types
.
Bloom
{},
Difficulty
:
(
*
big
.
Int
)(
config
.
L2GenesisBlockDifficulty
)
,
Difficulty
:
common
.
Big0
,
Number
:
new
(
big
.
Int
)
.
Add
(
header
.
Number
,
common
.
Big1
),
Number
:
new
(
big
.
Int
)
.
Add
(
header
.
Number
,
common
.
Big1
),
GasLimit
:
(
uint64
)(
config
.
L2GenesisBlockGasLimit
),
GasLimit
:
(
uint64
)(
config
.
L2GenesisBlockGasLimit
),
GasUsed
:
(
uint64
)(
config
.
L2GenesisBlockGasUsed
)
,
GasUsed
:
0
,
Time
:
uint64
(
config
.
L2OutputOracleStartingTimestamp
),
Time
:
uint64
(
config
.
L2OutputOracleStartingTimestamp
),
Extra
:
config
.
L2GenesisBlockExtraData
,
Extra
:
[]
byte
(
"BEDROCK"
)
,
MixDigest
:
co
nfig
.
L2GenesisBlockMixHash
,
MixDigest
:
co
mmon
.
Hash
{}
,
Nonce
:
types
.
EncodeNonce
((
uint64
)(
config
.
L1GenesisBlockNonce
))
,
Nonce
:
types
.
BlockNonce
{}
,
BaseFee
:
(
*
big
.
Int
)(
config
.
L2GenesisBlockBaseFeePerGas
),
BaseFee
:
(
*
big
.
Int
)(
config
.
L2GenesisBlockBaseFeePerGas
),
}
}
block
:=
types
.
NewBlock
(
bedrockHeader
,
nil
,
nil
,
nil
,
trie
.
NewStackTrie
(
nil
))
b
edrockB
lock
:=
types
.
NewBlock
(
bedrockHeader
,
nil
,
nil
,
nil
,
trie
.
NewStackTrie
(
nil
))
rawdb
.
WriteTd
(
ldb
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
Difficulty
())
res
:=
&
MigrationResult
{
rawdb
.
WriteBlock
(
ldb
,
block
)
TransitionHeight
:
bedrockBlock
.
NumberU64
(),
rawdb
.
WriteReceipts
(
ldb
,
block
.
Hash
(),
block
.
NumberU64
(),
nil
)
TransitionBlockHash
:
bedrockBlock
.
Hash
(),
rawdb
.
WriteCanonicalHash
(
ldb
,
block
.
Hash
(),
block
.
NumberU64
())
}
rawdb
.
WriteHeadBlockHash
(
ldb
,
block
.
Hash
())
rawdb
.
WriteHeadFastBlockHash
(
ldb
,
block
.
Hash
())
rawdb
.
WriteHeadHeaderHash
(
ldb
,
block
.
Hash
())
return
nil
if
!
commit
{
return
res
,
nil
}
rawdb
.
WriteTd
(
ldb
,
bedrockBlock
.
Hash
(),
bedrockBlock
.
NumberU64
(),
bedrockBlock
.
Difficulty
())
rawdb
.
WriteBlock
(
ldb
,
bedrockBlock
)
rawdb
.
WriteReceipts
(
ldb
,
bedrockBlock
.
Hash
(),
bedrockBlock
.
NumberU64
(),
nil
)
rawdb
.
WriteCanonicalHash
(
ldb
,
bedrockBlock
.
Hash
(),
bedrockBlock
.
NumberU64
())
rawdb
.
WriteHeadBlockHash
(
ldb
,
bedrockBlock
.
Hash
())
rawdb
.
WriteHeadFastBlockHash
(
ldb
,
bedrockBlock
.
Hash
())
rawdb
.
WriteHeadHeaderHash
(
ldb
,
bedrockBlock
.
Hash
())
// Make the first Bedrock block a finalized block.
rawdb
.
WriteFinalizedBlockHash
(
ldb
,
bedrockBlock
.
Hash
())
// We need to pull the chain config out of the DB, and update
// it so that the latest hardforks are enabled.
genesisHash
:=
rawdb
.
ReadCanonicalHash
(
ldb
,
0
)
cfg
:=
rawdb
.
ReadChainConfig
(
ldb
,
genesisHash
)
if
cfg
==
nil
{
log
.
Crit
(
"chain config not found"
)
}
cfg
.
LondonBlock
=
bedrockBlock
.
Number
()
cfg
.
ArrowGlacierBlock
=
bedrockBlock
.
Number
()
cfg
.
GrayGlacierBlock
=
bedrockBlock
.
Number
()
cfg
.
MergeNetsplitBlock
=
bedrockBlock
.
Number
()
cfg
.
TerminalTotalDifficulty
=
big
.
NewInt
(
0
)
cfg
.
TerminalTotalDifficultyPassed
=
true
cfg
.
Optimism
=
&
params
.
OptimismConfig
{
EIP1559Denominator
:
config
.
EIP1559Denominator
,
EIP1559Elasticity
:
config
.
EIP1559Elasticity
,
}
rawdb
.
WriteChainConfig
(
ldb
,
genesisHash
,
cfg
)
log
.
Info
(
"wrote Bedrock transition block"
,
"height"
,
bedrockHeader
.
Number
,
"root"
,
bedrockHeader
.
Root
.
String
(),
"hash"
,
bedrockHeader
.
Hash
()
.
String
(),
)
return
res
,
nil
}
}
// CheckWithdrawals will ensure that the entire list of withdrawals is being
// CheckWithdrawals will ensure that the entire list of withdrawals is being
...
@@ -145,9 +194,11 @@ func CheckWithdrawals(db vm.StateDB, withdrawals []*crossdomain.LegacyWithdrawal
...
@@ -145,9 +194,11 @@ func CheckWithdrawals(db vm.StateDB, withdrawals []*crossdomain.LegacyWithdrawal
}
}
// Check that all of the input messages are legit
// Check that all of the input messages are legit
for
slot
:=
range
knownSlots
{
for
slot
:=
range
knownSlots
{
//nolint:staticcheck
_
,
ok
:=
slots
[
slot
]
_
,
ok
:=
slots
[
slot
]
//nolint:staticcheck
if
!
ok
{
if
!
ok
{
return
fmt
.
Errorf
(
"Unknown input message: %s"
,
slot
)
//return nil,
fmt.Errorf("Unknown input message: %s", slot)
}
}
}
}
...
...
op-chain-ops/genesis/migration/legacy.go
0 → 100644
View file @
11a5ddaa
package
migration
import
(
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
)
type
LegacyReceipt
struct
{
// Consensus fields: These fields are defined by the Yellow Paper
PostState
[]
byte
`json:"root"`
Status
uint64
`json:"status"`
CumulativeGasUsed
uint64
`json:"cumulativeGasUsed" gencodec:"required"`
Bloom
types
.
Bloom
`json:"logsBloom" gencodec:"required"`
Logs
[]
*
types
.
Log
`json:"logs" gencodec:"required"`
// Implementation fields: These fields are added by geth when processing a transaction.
// They are stored in the chain database.
TxHash
common
.
Hash
`json:"transactionHash" gencodec:"required"`
ContractAddress
common
.
Address
`json:"contractAddress"`
GasUsed
uint64
`json:"gasUsed" gencodec:"required"`
// Inclusion information: These fields provide information about the inclusion of the
// transaction corresponding to this receipt.
BlockHash
common
.
Hash
`json:"blockHash,omitempty"`
BlockNumber
*
big
.
Int
`json:"blockNumber,omitempty"`
TransactionIndex
uint
`json:"transactionIndex"`
// UsingOVM
L1GasPrice
*
big
.
Int
`json:"l1GasPrice" gencodec:"required"`
L1GasUsed
*
big
.
Int
`json:"l1GasUsed" gencodec:"required"`
L1Fee
*
big
.
Int
`json:"l1Fee" gencodec:"required"`
FeeScalar
*
big
.
Float
`json:"l1FeeScalar" gencodec:"required"`
}
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
// fields of a receipt from an RLP stream.
func
(
r
*
LegacyReceipt
)
DecodeRLP
(
s
*
rlp
.
Stream
)
error
{
// Retrieve the entire receipt blob as we need to try multiple decoders
blob
,
err
:=
s
.
Raw
()
if
err
!=
nil
{
return
err
}
// Try decoding from the newest format for future proofness, then the older one
// for old nodes that just upgraded. V4 was an intermediate unreleased format so
// we do need to decode it, but it's not common (try last).
if
err
:=
decodeStoredReceiptRLP
(
r
,
blob
);
err
==
nil
{
return
nil
}
return
errors
.
New
(
"invalid receipt"
)
}
type
storedReceiptRLP
struct
{
PostStateOrStatus
[]
byte
CumulativeGasUsed
uint64
Logs
[]
*
types
.
LogForStorage
// UsingOVM
L1GasUsed
*
big
.
Int
L1GasPrice
*
big
.
Int
L1Fee
*
big
.
Int
FeeScalar
string
}
func
decodeStoredReceiptRLP
(
r
*
LegacyReceipt
,
blob
[]
byte
)
error
{
var
stored
storedReceiptRLP
if
err
:=
rlp
.
DecodeBytes
(
blob
,
&
stored
);
err
!=
nil
{
return
err
}
r
.
Logs
=
make
([]
*
types
.
Log
,
len
(
stored
.
Logs
))
for
i
,
log
:=
range
stored
.
Logs
{
r
.
Logs
[
i
]
=
(
*
types
.
Log
)(
log
)
}
return
nil
}
func
ReadLegacyReceipts
(
db
ethdb
.
Reader
,
hash
common
.
Hash
,
number
uint64
)
([]
*
LegacyReceipt
,
error
)
{
// Retrieve the flattened receipt slice
data
:=
rawdb
.
ReadReceiptsRLP
(
db
,
hash
,
number
)
if
len
(
data
)
==
0
{
return
nil
,
nil
}
// Convert the receipts from their storage form to their internal representation
storageReceipts
:=
[]
*
LegacyReceipt
{}
if
err
:=
rlp
.
DecodeBytes
(
data
,
&
storageReceipts
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"error decoding legacy receiptsL: %w"
,
err
)
}
return
storageReceipts
,
nil
}
op-chain-ops/genesis/migration/types.go
View file @
11a5ddaa
...
@@ -41,7 +41,7 @@ func NewSentMessage(path string) ([]*SentMessage, error) {
...
@@ -41,7 +41,7 @@ func NewSentMessage(path string) ([]*SentMessage, error) {
// struct. This is useful because the LegacyWithdrawal struct has helper
// struct. This is useful because the LegacyWithdrawal struct has helper
// functions on it that can compute the withdrawal hash and the storage slot.
// functions on it that can compute the withdrawal hash and the storage slot.
func
(
s
*
SentMessage
)
ToLegacyWithdrawal
()
(
*
crossdomain
.
LegacyWithdrawal
,
error
)
{
func
(
s
*
SentMessage
)
ToLegacyWithdrawal
()
(
*
crossdomain
.
LegacyWithdrawal
,
error
)
{
data
:=
make
([]
byte
,
0
,
len
(
s
.
Who
)
+
len
(
s
.
Msg
))
data
:=
make
([]
byte
,
len
(
s
.
Who
)
+
len
(
s
.
Msg
))
copy
(
data
,
s
.
Msg
)
copy
(
data
,
s
.
Msg
)
copy
(
data
[
len
(
s
.
Msg
)
:
],
s
.
Who
[
:
])
copy
(
data
[
len
(
s
.
Msg
)
:
],
s
.
Who
[
:
])
...
@@ -144,7 +144,7 @@ func (m *MigrationData) Addresses() []common.Address {
...
@@ -144,7 +144,7 @@ func (m *MigrationData) Addresses() []common.Address {
for
addr
:=
range
m
.
EvmAddresses
{
for
addr
:=
range
m
.
EvmAddresses
{
addresses
=
append
(
addresses
,
addr
)
addresses
=
append
(
addresses
,
addr
)
}
}
for
addr
:=
range
m
.
E
vmAddresses
{
for
addr
:=
range
m
.
O
vmAddresses
{
addresses
=
append
(
addresses
,
addr
)
addresses
=
append
(
addresses
,
addr
)
}
}
return
addresses
return
addresses
...
...
op-chain-ops/genesis/migration_action/action.go
0 → 100644
View file @
11a5ddaa
package
migration_action
import
(
"context"
"math/big"
"path/filepath"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis/migration"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethclient"
)
type
Config
struct
{
DeployConfig
*
genesis
.
DeployConfig
OVMAddressesPath
string
EVMAddressesPath
string
OVMAllowancesPath
string
OVMMessagesPath
string
EVMMessagesPath
string
Network
string
HardhatDeployments
[]
string
L1URL
string
StartingL1BlockNumber
uint64
L2DBPath
string
DryRun
bool
}
func
Migrate
(
cfg
*
Config
)
(
*
genesis
.
MigrationResult
,
error
)
{
deployConfig
:=
cfg
.
DeployConfig
ovmAddresses
,
err
:=
migration
.
NewAddresses
(
cfg
.
OVMAddressesPath
)
if
err
!=
nil
{
return
nil
,
err
}
evmAddresess
,
err
:=
migration
.
NewAddresses
(
cfg
.
EVMAddressesPath
)
if
err
!=
nil
{
return
nil
,
err
}
ovmAllowances
,
err
:=
migration
.
NewAllowances
(
cfg
.
OVMAllowancesPath
)
if
err
!=
nil
{
return
nil
,
err
}
ovmMessages
,
err
:=
migration
.
NewSentMessage
(
cfg
.
OVMMessagesPath
)
if
err
!=
nil
{
return
nil
,
err
}
evmMessages
,
err
:=
migration
.
NewSentMessage
(
cfg
.
EVMMessagesPath
)
if
err
!=
nil
{
return
nil
,
err
}
migrationData
:=
migration
.
MigrationData
{
OvmAddresses
:
ovmAddresses
,
EvmAddresses
:
evmAddresess
,
OvmAllowances
:
ovmAllowances
,
OvmMessages
:
ovmMessages
,
EvmMessages
:
evmMessages
,
}
l1Client
,
err
:=
ethclient
.
Dial
(
cfg
.
L1URL
)
if
err
!=
nil
{
return
nil
,
err
}
var
blockNumber
*
big
.
Int
bnum
:=
cfg
.
StartingL1BlockNumber
if
bnum
!=
0
{
blockNumber
=
new
(
big
.
Int
)
.
SetUint64
(
bnum
)
}
block
,
err
:=
l1Client
.
BlockByNumber
(
context
.
Background
(),
blockNumber
)
if
err
!=
nil
{
return
nil
,
err
}
chaindataPath
:=
filepath
.
Join
(
cfg
.
L2DBPath
,
"geth"
,
"chaindata"
)
ancientPath
:=
filepath
.
Join
(
chaindataPath
,
"ancient"
)
ldb
,
err
:=
rawdb
.
NewLevelDBDatabaseWithFreezer
(
chaindataPath
,
4096
,
120
,
ancientPath
,
""
,
false
)
if
err
!=
nil
{
return
nil
,
err
}
defer
ldb
.
Close
()
return
genesis
.
MigrateDB
(
ldb
,
deployConfig
,
block
,
&
migrationData
,
!
cfg
.
DryRun
)
}
op-chain-ops/genesis/testdata/test-deploy-config-full.json
View file @
11a5ddaa
{
{
"l1StartingBlockTag"
:
null
,
"l1StartingBlockTag"
:
"earliest"
,
"l1ChainID"
:
901
,
"l1ChainID"
:
901
,
"l2ChainID"
:
902
,
"l2ChainID"
:
902
,
"l2BlockTime"
:
2
,
"l2BlockTime"
:
2
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment