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

bug fix starting from 1 when initializing tree #52

Merged
merged 5 commits into from
Nov 21, 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
7 changes: 3 additions & 4 deletions challenger/child/withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,11 @@ func (ch *Child) handleInitiateWithdrawal(l2Sequence uint64, from string, to str
}

func (ch *Child) prepareTree(blockHeight int64) error {
if ch.InitializeTree(blockHeight) {
return nil
}

err := ch.Merkle().LoadWorkingTree(types.MustInt64ToUint64(blockHeight - 1))
if err == dbtypes.ErrNotFound {
if ch.InitializeTree(blockHeight) {
return nil
}
// must not happened
panic(fmt.Errorf("working tree not found at height: %d, current: %d", blockHeight-1, blockHeight))
} else if err != nil {
Expand Down
59 changes: 57 additions & 2 deletions cmd/opinitd/db.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
package main

import (
"context"
"fmt"
"time"

"github.com/initia-labs/opinit-bots/bot"
bottypes "github.com/initia-labs/opinit-bots/bot/types"
"github.com/initia-labs/opinit-bots/db"
"github.com/initia-labs/opinit-bots/executor"
executortypes "github.com/initia-labs/opinit-bots/executor/types"
"github.com/initia-labs/opinit-bots/node/rpcclient"
"github.com/initia-labs/opinit-bots/provider/child"
"github.com/initia-labs/opinit-bots/types"
"github.com/spf13/cobra"
)

// migration015Cmd handles the one-time migration of withdrawal data for v0.1.5
// migrationCmd handles the one-time migration of withdrawal data for v0.1.5, v0.1.9
// TODO: Remove this command in the future
func migration015Cmd(ctx *cmdContext) *cobra.Command {
func migrationCmd(ctx *cmdContext) *cobra.Command {
cmd := &cobra.Command{
Use: "migrate",
Args: cobra.ExactArgs(1),
Short: "Run database migrations",
Long: `Run database migrations
v0.1.5: Store the sequence number so that it can be accessed by address
v0.1.9-1: Delete finalized trees and create new finalized trees from working trees
v0.1.9-2: Fill block hash of finalized tree
`,
RunE: func(cmd *cobra.Command, args []string) error {
version := args[0]
Expand All @@ -30,10 +38,57 @@ v0.1.5: Store the sequence number so that it can be accessed by address
return err
}
return executor.Migration015(db)
case "v0.1.9-1":
// Run migration for v0.1.9-1
db, err := db.NewDB(bot.GetDBPath(ctx.homePath, bottypes.BotTypeExecutor))
if err != nil {
return err
}
return executor.Migration0191(db)
case "v0.1.9-2":
// Run migration for v0.1.9-2
db, err := db.NewDB(bot.GetDBPath(ctx.homePath, bottypes.BotTypeExecutor))
if err != nil {
return err
}
cmdCtx, done := context.WithCancel(cmd.Context())
gracefulShutdown(done)
interval, err := cmd.Flags().GetDuration(flagPollingInterval)
if err != nil {
return err
}
cmdCtx = types.WithPollingInterval(cmdCtx, interval)

configPath, err := getConfigPath(cmd, ctx.homePath, string(bottypes.BotTypeExecutor))
if err != nil {
return err
}

cfg := &executortypes.Config{}
err = bot.LoadJsonConfig(configPath, cfg)
if err != nil {
return err
}

l2Config := cfg.L2NodeConfig(ctx.homePath)
broadcasterConfig := l2Config.BroadcasterConfig
cdc, _, err := child.GetCodec(broadcasterConfig.Bech32Prefix)
if err != nil {
return err
}

rpcClient, err := rpcclient.NewRPCClient(cdc, l2Config.RPC)
if err != nil {
return err
}

return executor.Migration0192(cmdCtx, db, rpcClient)
default:
return fmt.Errorf("unknown migration version: %s", version)
}
},
}
cmd = configFlag(ctx.v, cmd)
cmd.Flags().Duration(flagPollingInterval, 100*time.Millisecond, "Polling interval in milliseconds")
return cmd
}
2 changes: 1 addition & 1 deletion cmd/opinitd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewRootCmd() *cobra.Command {
resetDBCmd(ctx),
resetHeightsCmd(ctx),
resetHeightCmd(ctx),
migration015Cmd(ctx),
migrationCmd(ctx),
txCmd(ctx),
version.NewVersionCommand(),
)
Expand Down
7 changes: 3 additions & 4 deletions executor/child/withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,11 @@ func (ch *Child) handleInitiateWithdrawal(l2Sequence uint64, from string, to str
}

func (ch *Child) prepareTree(blockHeight int64) error {
if ch.InitializeTree(blockHeight) {
return nil
}

err := ch.Merkle().LoadWorkingTree(types.MustInt64ToUint64(blockHeight) - 1)
if err == dbtypes.ErrNotFound {
if ch.InitializeTree(blockHeight) {
return nil
}
// must not happened
panic(fmt.Errorf("working tree not found at height: %d, current: %d", blockHeight-1, blockHeight))
} else if err != nil {
Expand Down
165 changes: 165 additions & 0 deletions executor/db.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package executor

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"math/bits"
"time"

ophosttypes "github.com/initia-labs/OPinit/x/ophost/types"
dbtypes "github.com/initia-labs/opinit-bots/db/types"
executortypes "github.com/initia-labs/opinit-bots/executor/types"
merkletypes "github.com/initia-labs/opinit-bots/merkle/types"
"github.com/initia-labs/opinit-bots/node"
"github.com/initia-labs/opinit-bots/node/rpcclient"
"github.com/initia-labs/opinit-bots/types"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -72,3 +79,161 @@ func Migration015(db types.DB) error {
return false, nil
})
}

func Migration0191(db types.DB) error {
nodeDB := db.WithPrefix([]byte(types.ChildName))
merkleDB := nodeDB.WithPrefix([]byte(types.MerkleName))

err := merkleDB.PrefixedIterate(merkletypes.FinalizedTreeKey, nil, func(key, value []byte) (bool, error) {
var tree merkletypes.FinalizedTreeInfo
err := json.Unmarshal(value, &tree)
if err != nil {
return true, err
}

err = merkleDB.Delete(key)
if err != nil {
return true, err
}
fmt.Printf("delete finalized tree index: %d, start leaf index: %d, leaf count: %d\n", tree.TreeIndex, tree.StartLeafIndex, tree.LeafCount)
return false, nil
})
if err != nil {
return err
}

nextSequence := uint64(1)
changeWorkingTree := false
err = merkleDB.PrefixedIterate(merkletypes.WorkingTreeKey, nil, func(key, value []byte) (bool, error) {
if len(key) != len(merkletypes.WorkingTreeKey)+1+8 {
return true, fmt.Errorf("unexpected working tree key; expected: %d; got: %d", len(merkletypes.WorkingTreeKey)+1+8, len(key))
}

version := dbtypes.ToUint64Key(key[len(key)-8:])

var workingTree merkletypes.TreeInfo
err := json.Unmarshal(value, &workingTree)
if err != nil {
return true, err
}

if nextSequence != workingTree.StartLeafIndex {
changeWorkingTree = true
}

if changeWorkingTree {
workingTree.StartLeafIndex = nextSequence
workingTreeBz, err := json.Marshal(workingTree)
if err != nil {
return true, err
}
err = merkleDB.Set(key, workingTreeBz)
if err != nil {
return true, err
}
}

if workingTree.Done && workingTree.LeafCount != 0 {
data, err := json.Marshal(executortypes.TreeExtraData{
BlockNumber: types.MustUint64ToInt64(version),
})
if err != nil {
return true, err
}

treeHeight := types.MustIntToUint8(bits.Len64(workingTree.LeafCount - 1))
if workingTree.LeafCount <= 1 {
treeHeight = uint8(workingTree.LeafCount) //nolint
}

treeRootHash := workingTree.LastSiblings[treeHeight]
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
finalizedTreeInfo := merkletypes.FinalizedTreeInfo{
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
TreeIndex: workingTree.Index,
TreeHeight: treeHeight,
Root: treeRootHash,
StartLeafIndex: workingTree.StartLeafIndex,
LeafCount: workingTree.LeafCount,
ExtraData: data,
}

finalizedTreeBz, err := json.Marshal(finalizedTreeInfo)
if err != nil {
return true, err
}

err = merkleDB.Set(finalizedTreeInfo.Key(), finalizedTreeBz)
sh-cha marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return true, err
}

fmt.Printf("finalized tree index: %d, start leaf index: %d, leaf count: %d, block height: %d\n", finalizedTreeInfo.TreeIndex, finalizedTreeInfo.StartLeafIndex, finalizedTreeInfo.LeafCount, version)
nextSequence = workingTree.StartLeafIndex + workingTree.LeafCount
}
return false, nil
})
if err != nil {
return err
}
return nil
}

func Migration0192(ctx context.Context, db types.DB, rpcClient *rpcclient.RPCClient) error {
nodeDB := db.WithPrefix([]byte(types.ChildName))
merkleDB := nodeDB.WithPrefix([]byte(types.MerkleName))

timer := time.NewTicker(types.PollingInterval(ctx))
defer timer.Stop()

return merkleDB.PrefixedIterate(merkletypes.FinalizedTreeKey, nil, func(key, value []byte) (bool, error) {
var tree merkletypes.FinalizedTreeInfo
err := json.Unmarshal(value, &tree)
if err != nil {
return true, err
}

var extraData executortypes.TreeExtraData
err = json.Unmarshal(tree.ExtraData, &extraData)
if err != nil {
return true, err
}

if extraData.BlockHash != nil {
return false, nil
}

for {
select {
case <-ctx.Done():
return true, ctx.Err()
case <-timer.C:
}
height := extraData.BlockNumber + 1
header, err := rpcClient.Header(ctx, &height)
if err != nil {
fmt.Printf("failed to get header for block height: %d; %s\n", height, err.Error())
continue
sh-cha marked this conversation as resolved.
Show resolved Hide resolved
}

extraData.BlockHash = header.Header.LastBlockID.Hash
break
}

tree.ExtraData, err = json.Marshal(extraData)
if err != nil {
return true, err
}
treeBz, err := json.Marshal(tree)
if err != nil {
return true, err
}
err = merkleDB.Set(key, treeBz)
if err != nil {
return true, err
}
outputRoot := ophosttypes.GenerateOutputRoot(1, tree.Root, extraData.BlockHash)
outputRootStr := base64.StdEncoding.EncodeToString(outputRoot[:])

fmt.Printf("finalized tree index: %d, start leaf index: %d, leaf count: %d, block height: %d, block hash: %X, outputRoot: %s\n", tree.TreeIndex, tree.StartLeafIndex, tree.LeafCount, extraData.BlockNumber, extraData.BlockHash, outputRootStr)
return false, nil
})
}
40 changes: 21 additions & 19 deletions provider/child/child.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,28 @@ func (b *BaseChild) Initialize(
var l2Sequence uint64
if b.node.HeightInitialized() {
if !disableDeleteFutureWithdrawals {
l2Sequence, err = b.QueryNextL2Sequence(ctx, processedHeight)
if err != nil {
return 0, err
}
l2Sequence = 1
if processedHeight != 0 {
l2Sequence, err = b.QueryNextL2Sequence(ctx, processedHeight)
if err != nil {
return 0, err
}

err = b.mk.DeleteFutureFinalizedTrees(l2Sequence)
if err != nil {
return 0, err
err = b.mk.DeleteFutureFinalizedTrees(l2Sequence)
if err != nil {
return 0, err
}
}
b.initializeTreeFn = func(blockHeight int64) (bool, error) {
if processedHeight+1 == blockHeight {
b.logger.Info("initialize tree", zap.Uint64("index", startOutputIndex))
err := b.mk.InitializeWorkingTree(startOutputIndex, l2Sequence)
if err != nil {
return false, err
}
return true, nil
}
return false, nil
}
}

Expand All @@ -135,18 +149,6 @@ func (b *BaseChild) Initialize(
if err != nil {
return 0, err
}

b.initializeTreeFn = func(blockHeight int64) (bool, error) {
if processedHeight+1 == blockHeight {
b.logger.Info("initialize tree", zap.Uint64("index", startOutputIndex))
err := b.mk.InitializeWorkingTree(startOutputIndex, 1)
if err != nil {
return false, err
}
return true, nil
}
return false, nil
}
}

if b.OracleEnabled() && oracleKeyringConfig != nil {
Expand Down
Loading