mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
feat(cli): add iavlviewer command (#1922)
* port iavlviewer to kava v0.26.x to debug app hash * add hash subcommand to iavlviewer additionally, use better error handling * update changelog * separate iavlviewer command into subcommands --------- Co-authored-by: Nick DeLuca <nickdeluca08@gmail.com>
This commit is contained in:
parent
110adcab2c
commit
2e8c7ce337
@ -38,6 +38,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### Features
|
||||
- (precisebank) [#1906] Add new `x/precisebank` module with bank decimal extension for EVM usage.
|
||||
- (cli) [#1922] Add `iavlviewer` CLI command for low-level iavl db debugging.
|
||||
|
||||
### Improvements
|
||||
- (rocksdb) [#1903] Bump cometbft-db dependency for use with rocksdb v8.10.0
|
||||
@ -336,6 +337,7 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
|
||||
- [#257](https://github.com/Kava-Labs/kava/pulls/257) Include scripts to run
|
||||
large-scale simulations remotely using aws-batch
|
||||
|
||||
[#1922]: https://github.com/Kava-Labs/kava/pull/1922
|
||||
[#1906]: https://github.com/Kava-Labs/kava/pull/1906
|
||||
[#1903]: https://github.com/Kava-Labs/kava/pull/1903
|
||||
[#1846]: https://github.com/Kava-Labs/kava/pull/1846
|
||||
|
53
cmd/kava/cmd/iavlviewer/data.go
Normal file
53
cmd/kava/cmd/iavlviewer/data.go
Normal file
@ -0,0 +1,53 @@
|
||||
package iavlviewer
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/iavl"
|
||||
ethermintserver "github.com/evmos/ethermint/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newDataCmd(opts ethermintserver.StartOptions) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "data <prefix> [version number]",
|
||||
Short: "View all keys, hash, & size of tree.",
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
prefix := args[0]
|
||||
version := 0
|
||||
if len(args) == 2 {
|
||||
var err error
|
||||
version, err = parseVersion(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tree, err := openPrefixTree(opts, cmd, prefix, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printKeys(tree)
|
||||
hash := tree.Hash()
|
||||
fmt.Printf("Hash: %X\n", hash)
|
||||
fmt.Printf("Size: %X\n", tree.Size())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printKeys(tree *iavl.MutableTree) {
|
||||
fmt.Println("Printing all keys with hashed values (to detect diff)")
|
||||
tree.Iterate(func(key []byte, value []byte) bool { //nolint:errcheck
|
||||
printKey := parseWeaveKey(key)
|
||||
digest := sha256.Sum256(value)
|
||||
fmt.Printf(" %s\n %X\n", printKey, digest)
|
||||
return false
|
||||
})
|
||||
}
|
38
cmd/kava/cmd/iavlviewer/hash.go
Normal file
38
cmd/kava/cmd/iavlviewer/hash.go
Normal file
@ -0,0 +1,38 @@
|
||||
package iavlviewer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
ethermintserver "github.com/evmos/ethermint/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newHashCmd(opts ethermintserver.StartOptions) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "hash <prefix> [version number]",
|
||||
Short: "Print the root hash of the iavl tree.",
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
prefix := args[0]
|
||||
version := 0
|
||||
if len(args) == 2 {
|
||||
var err error
|
||||
version, err = parseVersion(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tree, err := openPrefixTree(opts, cmd, prefix, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Hash: %X\n", tree.Hash())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
85
cmd/kava/cmd/iavlviewer/root.go
Normal file
85
cmd/kava/cmd/iavlviewer/root.go
Normal file
@ -0,0 +1,85 @@
|
||||
package iavlviewer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/store/wrapper"
|
||||
ethermintserver "github.com/evmos/ethermint/server"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/iavl"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultCacheSize int = 10000
|
||||
)
|
||||
|
||||
func NewCmd(opts ethermintserver.StartOptions) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "iavlviewer <data|hash|shape|versions> <prefix> [version number]",
|
||||
Short: "Output various data, hashes, and calculations for an iavl tree",
|
||||
}
|
||||
|
||||
cmd.AddCommand(newDataCmd(opts))
|
||||
cmd.AddCommand(newHashCmd(opts))
|
||||
cmd.AddCommand(newShapeCmd(opts))
|
||||
cmd.AddCommand(newVersionsCmd(opts))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseVersion(arg string) (int, error) {
|
||||
version, err := strconv.Atoi(arg)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid version number: '%s'", arg)
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func openPrefixTree(opts ethermintserver.StartOptions, cmd *cobra.Command, prefix string, version int) (*iavl.MutableTree, error) {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd)
|
||||
ctx := server.GetServerContextFromCmd(cmd)
|
||||
ctx.Config.SetRoot(clientCtx.HomeDir)
|
||||
|
||||
db, err := opts.DBOpener(ctx.Viper, clientCtx.HomeDir, server.GetAppDBBackend(ctx.Viper))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open database at %s: %s", clientCtx.HomeDir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := db.Close(); err != nil {
|
||||
ctx.Logger.Error("error closing db", "error", err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
cosmosdb := wrapper.NewCosmosDB(db)
|
||||
|
||||
tree, err := readTree(cosmosdb, version, []byte(prefix))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read tree with prefix %s: %s", prefix, err)
|
||||
}
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
// ReadTree loads an iavl tree from the directory
|
||||
// If version is 0, load latest, otherwise, load named version
|
||||
// The prefix represents which iavl tree you want to read. The iaviwer will always set a prefix.
|
||||
func readTree(db dbm.DB, version int, prefix []byte) (*iavl.MutableTree, error) {
|
||||
if len(prefix) != 0 {
|
||||
db = dbm.NewPrefixDB(db, prefix)
|
||||
}
|
||||
|
||||
tree := iavl.NewMutableTree(db, DefaultCacheSize, false, log.NewLogger(os.Stdout))
|
||||
ver, err := tree.LoadVersion(int64(version))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Printf("Latest version: %d\n", ver)
|
||||
fmt.Printf("Got version: %d\n", version)
|
||||
return tree, err
|
||||
}
|
47
cmd/kava/cmd/iavlviewer/shape.go
Normal file
47
cmd/kava/cmd/iavlviewer/shape.go
Normal file
@ -0,0 +1,47 @@
|
||||
package iavlviewer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/iavl"
|
||||
ethermintserver "github.com/evmos/ethermint/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newShapeCmd(opts ethermintserver.StartOptions) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "shape <prefix> [version number]",
|
||||
Short: "View shape of iavl tree.",
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
prefix := args[0]
|
||||
version := 0
|
||||
if len(args) == 2 {
|
||||
var err error
|
||||
version, err = parseVersion(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tree, err := openPrefixTree(opts, cmd, prefix, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printShape(tree)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printShape(tree *iavl.MutableTree) {
|
||||
// shape := tree.RenderShape(" ", nil)
|
||||
// TODO: handle this error
|
||||
shape, _ := tree.RenderShape(" ", nodeEncoder)
|
||||
fmt.Println(strings.Join(shape, "\n"))
|
||||
}
|
74
cmd/kava/cmd/iavlviewer/versions.go
Normal file
74
cmd/kava/cmd/iavlviewer/versions.go
Normal file
@ -0,0 +1,74 @@
|
||||
package iavlviewer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/iavl"
|
||||
ethermintserver "github.com/evmos/ethermint/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newVersionsCmd(opts ethermintserver.StartOptions) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "versions <prefix>",
|
||||
Short: "Print all versions of iavl tree",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
prefix := args[0]
|
||||
tree, err := openPrefixTree(opts, cmd, prefix, 15)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printVersions(tree)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printVersions(tree *iavl.MutableTree) {
|
||||
versions := tree.AvailableVersions()
|
||||
fmt.Println("Available versions:")
|
||||
for _, v := range versions {
|
||||
fmt.Printf(" %d\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
// parseWeaveKey assumes a separating : where all in front should be ascii,
|
||||
// and all afterwards may be ascii or binary
|
||||
func parseWeaveKey(key []byte) string {
|
||||
cut := bytes.IndexRune(key, ':')
|
||||
if cut == -1 {
|
||||
return encodeID(key)
|
||||
}
|
||||
prefix := key[:cut]
|
||||
id := key[cut+1:]
|
||||
return fmt.Sprintf("%s:%s", encodeID(prefix), encodeID(id))
|
||||
}
|
||||
|
||||
// casts to a string if it is printable ascii, hex-encodes otherwise
|
||||
func encodeID(id []byte) string {
|
||||
for _, b := range id {
|
||||
if b < 0x20 || b >= 0x80 {
|
||||
return strings.ToUpper(hex.EncodeToString(id))
|
||||
}
|
||||
}
|
||||
return string(id)
|
||||
}
|
||||
|
||||
func nodeEncoder(id []byte, depth int, isLeaf bool) string {
|
||||
prefix := fmt.Sprintf("-%d ", depth)
|
||||
if isLeaf {
|
||||
prefix = fmt.Sprintf("*%d ", depth)
|
||||
}
|
||||
if len(id) == 0 {
|
||||
return fmt.Sprintf("%s<nil>", prefix)
|
||||
}
|
||||
return fmt.Sprintf("%s%s", prefix, parseWeaveKey(id))
|
||||
}
|
@ -25,6 +25,7 @@ import (
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/app/params"
|
||||
"github.com/kava-labs/kava/cmd/kava/cmd/iavlviewer"
|
||||
"github.com/kava-labs/kava/cmd/kava/cmd/rocksdb"
|
||||
"github.com/kava-labs/kava/cmd/kava/opendb"
|
||||
)
|
||||
@ -134,5 +135,6 @@ func addSubCmds(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, de
|
||||
keyCommands(app.DefaultNodeHome),
|
||||
rocksdb.RocksDBCmd,
|
||||
newShardCmd(opts),
|
||||
iavlviewer.NewCmd(opts),
|
||||
)
|
||||
}
|
||||
|
6
go.mod
6
go.mod
@ -4,15 +4,18 @@ go 1.21
|
||||
|
||||
require (
|
||||
cosmossdk.io/errors v1.0.1
|
||||
cosmossdk.io/log v1.3.1
|
||||
cosmossdk.io/math v1.3.0
|
||||
cosmossdk.io/simapp v0.0.0-20231127212628-044ff4d8c015
|
||||
github.com/cenkalti/backoff/v4 v4.1.3
|
||||
github.com/cometbft/cometbft v0.37.4
|
||||
github.com/cometbft/cometbft-db v0.9.1
|
||||
github.com/cosmos/cosmos-db v1.0.0
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.4
|
||||
github.com/cosmos/cosmos-sdk v0.47.10
|
||||
github.com/cosmos/go-bip39 v1.0.0
|
||||
github.com/cosmos/gogoproto v1.4.10
|
||||
github.com/cosmos/iavl v1.0.0
|
||||
github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7 v7.1.3
|
||||
github.com/cosmos/ibc-go/v7 v7.4.0
|
||||
github.com/ethereum/go-ethereum v1.10.26
|
||||
@ -47,7 +50,6 @@ require (
|
||||
cosmossdk.io/api v0.3.1 // indirect
|
||||
cosmossdk.io/core v0.6.1 // indirect
|
||||
cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
|
||||
cosmossdk.io/log v1.3.1 // indirect
|
||||
cosmossdk.io/tools/rosetta v0.2.1 // indirect
|
||||
filippo.io/edwards25519 v1.0.0 // indirect
|
||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
|
||||
@ -77,9 +79,7 @@ require (
|
||||
github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect
|
||||
github.com/confio/ics23/go v0.9.0 // indirect
|
||||
github.com/cosmos/btcutil v1.0.5 // indirect
|
||||
github.com/cosmos/cosmos-db v1.0.0 // indirect
|
||||
github.com/cosmos/gogogateway v1.2.0 // indirect
|
||||
github.com/cosmos/iavl v1.0.0 // indirect
|
||||
github.com/cosmos/ics23/go v0.10.0 // indirect
|
||||
github.com/cosmos/ledger-cosmos-go v0.13.1 // indirect
|
||||
github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect
|
||||
|
Loading…
Reference in New Issue
Block a user