Skip to content

Commit

Permalink
bug fix starting from 1 when initializing tree (#52)
Browse files Browse the repository at this point in the history
* bug fix starting from 1 when initializing tree

* change workingtree start leaf count

* change workingtree start leaf count in force

* print outputroot

* error logs
  • Loading branch information
sh-cha authored Nov 21, 2024
1 parent dcae51a commit 197ca86
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 30 deletions.
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]
finalizedTreeInfo := merkletypes.FinalizedTreeInfo{
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)
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
}

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

0 comments on commit 197ca86

Please sign in to comment.