Skip to content
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

Migration script fixes #179

Merged
merged 3 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 2 additions & 25 deletions op-chain-ops/cmd/celo-migrate/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ import (

// Constants for the database
const (
DBCache = 1024 // size of the cache in MB
DBHandles = 60 // number of handles
LastMigratedNonAncientBlockKey = "celoLastMigratedNonAncientBlock"
DBCache = 1024 // size of the cache in MB
DBHandles = 60 // number of handles
)

var (
Expand All @@ -35,28 +34,6 @@ func headerKey(number uint64, hash common.Hash) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
}

// readLastMigratedNonAncientBlock returns the last migration number. If it doesn't exist, it returns 0.
func readLastMigratedNonAncientBlock(db ethdb.KeyValueReader) uint64 {
data, err := db.Get([]byte(LastMigratedNonAncientBlockKey))
if err != nil {
return 0
}
number := binary.BigEndian.Uint64(data)
return number
}

// writeLastMigratedNonAncientBlock stores the last migration number.
func writeLastMigratedNonAncientBlock(db ethdb.KeyValueWriter, number uint64) error {
enc := make([]byte, 8)
binary.BigEndian.PutUint64(enc, number)
return db.Put([]byte(LastMigratedNonAncientBlockKey), enc)
}

// deleteLastMigratedNonAncientBlock removes the last migration number.
func deleteLastMigratedNonAncientBlock(db ethdb.KeyValueWriter) error {
return db.Delete([]byte(LastMigratedNonAncientBlockKey))
}

// openDB opens the chaindata database at the given path. Note this path is below the datadir
func openDB(chaindataPath string) (ethdb.Database, error) {
if _, err := os.Stat(chaindataPath); errors.Is(err, os.ErrNotExist) {
Expand Down
41 changes: 17 additions & 24 deletions op-chain-ops/cmd/celo-migrate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ var (
Name: "clear-all",
Usage: "Use this to start with a fresh new db, deleting all data including ancients. CAUTION: Re-migrating ancients takes time.",
}
keepNonAncientsFlag = &cli.BoolFlag{
Name: "keep-non-ancients",
Usage: "CAUTION: Not recommended for production. Use to keep all data in the new db as is, including any partially migrated non-ancient blocks and state data. If non-ancient blocks are partially migrated, the script will attempt to resume the migration.",
}
onlyAncientsFlag = &cli.BoolFlag{
Name: "only-ancients",
Usage: "Use to only migrate ancient blocks. Ignored when running full migration",
Expand All @@ -99,7 +95,6 @@ var (
bufferSizeFlag,
memoryLimitFlag,
clearAllFlag,
keepNonAncientsFlag,
}
stateMigrationFlags = []cli.Flag{
newDBPathFlag,
Expand All @@ -115,14 +110,13 @@ var (
)

type blockMigrationOptions struct {
oldDBPath string
newDBPath string
batchSize uint64
bufferSize uint64
memoryLimit int64
clearAll bool
keepNonAncients bool
onlyAncients bool
oldDBPath string
newDBPath string
batchSize uint64
bufferSize uint64
memoryLimit int64
clearAll bool
onlyAncients bool
}

type stateMigrationOptions struct {
Expand All @@ -137,14 +131,13 @@ type stateMigrationOptions struct {

func parseBlockMigrationOptions(ctx *cli.Context) blockMigrationOptions {
return blockMigrationOptions{
oldDBPath: ctx.String(oldDBPathFlag.Name),
newDBPath: ctx.String(newDBPathFlag.Name),
batchSize: ctx.Uint64(batchSizeFlag.Name),
bufferSize: ctx.Uint64(bufferSizeFlag.Name),
memoryLimit: ctx.Int64(memoryLimitFlag.Name),
clearAll: ctx.Bool(clearAllFlag.Name),
keepNonAncients: ctx.Bool(keepNonAncientsFlag.Name),
onlyAncients: ctx.Bool(onlyAncientsFlag.Name),
oldDBPath: ctx.String(oldDBPathFlag.Name),
newDBPath: ctx.String(newDBPathFlag.Name),
batchSize: ctx.Uint64(batchSizeFlag.Name),
bufferSize: ctx.Uint64(bufferSizeFlag.Name),
memoryLimit: ctx.Int64(memoryLimitFlag.Name),
clearAll: ctx.Bool(clearAllFlag.Name),
onlyAncients: ctx.Bool(onlyAncientsFlag.Name),
}
}

Expand Down Expand Up @@ -232,7 +225,7 @@ func runBlockMigration(opts blockMigrationOptions) error {

debug.SetMemoryLimit(opts.memoryLimit * 1 << 20) // Set memory limit, converting from MiB to bytes

log.Info("Block Migration Started", "oldDBPath", opts.oldDBPath, "newDBPath", opts.newDBPath, "batchSize", opts.batchSize, "memoryLimit", opts.memoryLimit, "clearAll", opts.clearAll, "keepNonAncients", opts.keepNonAncients, "onlyAncients", opts.onlyAncients)
log.Info("Block Migration Started", "oldDBPath", opts.oldDBPath, "newDBPath", opts.newDBPath, "batchSize", opts.batchSize, "memoryLimit", opts.memoryLimit, "clearAll", opts.clearAll, "onlyAncients", opts.onlyAncients)

var err error

Expand All @@ -244,7 +237,7 @@ func runBlockMigration(opts blockMigrationOptions) error {
if err = os.RemoveAll(opts.newDBPath); err != nil {
return fmt.Errorf("failed to remove new database: %w", err)
}
} else if !opts.keepNonAncients {
} else {
if err = cleanupNonAncientDb(opts.newDBPath); err != nil {
return fmt.Errorf("failed to reset non-ancient database: %w", err)
}
Expand All @@ -258,7 +251,7 @@ func runBlockMigration(opts blockMigrationOptions) error {

var numNonAncients uint64
if !opts.onlyAncients {
if numNonAncients, err = migrateNonAncientsDb(opts.oldDBPath, opts.newDBPath, numAncientsNewAfter-1, opts.batchSize); err != nil {
if numNonAncients, err = migrateNonAncientsDb(opts.oldDBPath, opts.newDBPath, numAncientsNewAfter, opts.batchSize); err != nil {
return fmt.Errorf("failed to migrate non-ancients database: %w", err)
}
} else {
Expand Down
51 changes: 18 additions & 33 deletions op-chain-ops/cmd/celo-migrate/non-ancients.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/ethereum/go-ethereum/log"
)

func migrateNonAncientsDb(oldDbPath, newDbPath string, lastAncientBlock, batchSize uint64) (uint64, error) {
func migrateNonAncientsDb(oldDbPath, newDbPath string, numAncients, batchSize uint64) (uint64, error) {
// First copy files from old database to new database
log.Info("Copy files from old database (excluding ancients)", "process", "non-ancients")

Expand Down Expand Up @@ -51,22 +51,10 @@ func migrateNonAncientsDb(oldDbPath, newDbPath string, lastAncientBlock, batchSi
// get the last block number
hash := rawdb.ReadHeadHeaderHash(newDB)
lastBlock := *rawdb.ReadHeaderNumber(newDB, hash)
lastMigratedNonAncientBlock := readLastMigratedNonAncientBlock(newDB) // returns 0 if not found

// if migration was interrupted, start from the last migrated block
fromBlock := max(lastAncientBlock, lastMigratedNonAncientBlock) + 1
log.Info("Non-Ancient Block Migration Started", "process", "non-ancients", "startBlock", numAncients, "endBlock", lastBlock, "count", lastBlock-numAncients, "lastAncientBlock", numAncients)

if fromBlock >= lastBlock {
log.Info("Non-Ancient Block Migration Skipped", "process", "non-ancients", "lastAncientBlock", lastAncientBlock, "endBlock", lastBlock, "lastMigratedNonAncientBlock", lastMigratedNonAncientBlock)
if lastMigratedNonAncientBlock != lastBlock {
return 0, fmt.Errorf("migration range empty but last migrated block is not the last block in the database")
}
return 0, nil
}

log.Info("Non-Ancient Block Migration Started", "process", "non-ancients", "startBlock", fromBlock, "endBlock", lastBlock, "count", lastBlock-fromBlock, "lastAncientBlock", lastAncientBlock, "lastMigratedNonAncientBlock", lastMigratedNonAncientBlock)

for i := fromBlock; i <= lastBlock; i += batchSize {
for i := numAncients; i <= lastBlock; i += batchSize {
numbersHash := rawdb.ReadAllHashesInRange(newDB, i, i+batchSize-1)

log.Info("Processing Block Range", "process", "non-ancients", "from", i, "to(inclusve)", i+batchSize-1, "count", len(numbersHash))
Expand Down Expand Up @@ -94,30 +82,27 @@ func migrateNonAncientsDb(oldDbPath, newDbPath string, lastAncientBlock, batchSi
batch := newDB.NewBatch()
rawdb.WriteBodyRLP(batch, numberHash.Hash, numberHash.Number, newBody)
_ = batch.Put(headerKey(numberHash.Number, numberHash.Hash), newHeader)
_ = writeLastMigratedNonAncientBlock(batch, numberHash.Number)
if err := batch.Write(); err != nil {
return 0, fmt.Errorf("failed to write header and body: block %d - %x: %w", numberHash.Number, numberHash.Hash, err)
}
}
}

toBeRemoved := rawdb.ReadAllHashesInRange(newDB, 1, lastAncientBlock)
log.Info("Removing frozen blocks", "process", "non-ancients", "count", len(toBeRemoved))
batch := newDB.NewBatch()
for _, numberHash := range toBeRemoved {
rawdb.DeleteBlockWithoutNumber(batch, numberHash.Hash, numberHash.Number)
rawdb.DeleteCanonicalHash(batch, numberHash.Number)
}
if err := batch.Write(); err != nil {
return 0, fmt.Errorf("failed to delete frozen blocks: %w", err)
}

// if migration finished, remove the last migration number
if err := deleteLastMigratedNonAncientBlock(newDB); err != nil {
return 0, fmt.Errorf("failed to delete last migration number: %w", err)
if numAncients > 0 {
toBeRemoved := rawdb.ReadAllHashesInRange(newDB, 1, numAncients)
log.Info("Removing frozen blocks", "process", "non-ancients", "count", len(toBeRemoved))
batch := newDB.NewBatch()
for _, numberHash := range toBeRemoved {
rawdb.DeleteBlockWithoutNumber(batch, numberHash.Hash, numberHash.Number)
rawdb.DeleteCanonicalHash(batch, numberHash.Number)
}
if err := batch.Write(); err != nil {
return 0, fmt.Errorf("failed to delete frozen blocks: %w", err)
}
log.Info("Removed frozen blocks, still in leveldb", "process", "non-ancients", "removedBlocks", len(toBeRemoved))
}
migratedCount := lastBlock - numAncients + 1
log.Info("Non-Ancient Block Migration Ended", "process", "non-ancients", "migratedBlocks", migratedCount)

log.Info("Non-Ancient Block Migration Ended", "process", "non-ancients", "migratedBlocks", lastBlock-fromBlock+1, "removedBlocks", len(toBeRemoved))

return lastBlock - fromBlock + 1, nil
return migratedCount, nil
}
10 changes: 9 additions & 1 deletion op-chain-ops/cmd/celo-migrate/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ func applyStateMigrationChanges(config *genesis.DeployConfig, genesis *core.Gene
migrationBlockTime = uint64(time.Now().Unix())
}

// If gas limit was zero at the transition point use a default of 30M.
// Note that in op-geth we use gasLimit==0 to indicate a pre-gingerbread
// block and adjust encoding appropriately, so we must make sure that
// gasLimit is non-zero, bacause L2 blocks are all post gingerbread.
gasLimit := header.GasLimit
if gasLimit == 0 {
gasLimit = 30e6
}
// Create the header for the Cel2 transition block.
cel2Header := &types.Header{
ParentHash: header.Hash(),
Expand All @@ -135,7 +143,7 @@ func applyStateMigrationChanges(config *genesis.DeployConfig, genesis *core.Gene
Bloom: types.Bloom{},
Difficulty: new(big.Int).Set(common.Big0),
Number: migrationBlock,
GasLimit: header.GasLimit,
GasLimit: gasLimit,
GasUsed: 0,
Time: migrationBlockTime,
Extra: []byte("CeL2 migration"),
Expand Down
Loading