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
b41133e5
Unverified
Commit
b41133e5
authored
Nov 09, 2022
by
mergify[bot]
Committed by
GitHub
Nov 09, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3898 from ethereum-optimism/11-06-op-chain-ops_Updates_for_the_migration
op-chain-ops: Updates for the migration
parents
6c238212
11a5ddaa
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 @
b41133e5
...
@@ -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 @
b41133e5
...
@@ -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 @
b41133e5
...
@@ -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 @
b41133e5
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 @
b41133e5
...
@@ -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 @
b41133e5
...
@@ -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 @
b41133e5
...
@@ -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 @
b41133e5
...
@@ -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 @
b41133e5
...
@@ -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 @
b41133e5
...
@@ -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 @
b41133e5
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 @
b41133e5
...
@@ -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 @
b41133e5
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 @
b41133e5
{
{
"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