feat!: bootstrap comet cmd for local state sync (#16061)
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: HuangYi <huang@crypto.com>
This commit is contained in:
parent
7e160b0e85
commit
25df90d0fc
@ -108,6 +108,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (x/bank) [#15764](https://github.com/cosmos/cosmos-sdk/pull/15764) Speedup x/bank InitGenesis
|
||||
* (x/auth) [#15867](https://github.com/cosmos/cosmos-sdk/pull/15867) Support better logging for signature verification failure.
|
||||
* (types/query) [#16041](https://github.com/cosmos/cosmos-sdk/pull/16041) change pagination max limit to a variable in order to be modifed by application devs
|
||||
* (server) [#16061](https://github.com/cosmos/cosmos-sdk/pull/16061) add comet bootstrap command
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
|
||||
@ -165,3 +165,15 @@ In config.toml:
|
||||
```toml
|
||||
log_level: "state:info,p2p:info,consensus:info,x/staking:info,x/ibc:info,*error"
|
||||
```
|
||||
|
||||
## State Sync
|
||||
|
||||
State sync is the act in which a node syncs the latest or close to the latest state of a blockchain. This is useful for users who don't want to sync all the blocks in history. You can read more here: https://docs.cometbft.com/v0.37/core/state-sync
|
||||
|
||||
### Local State Sync
|
||||
|
||||
Local state sync work similar to normal state sync except that it works off a local snapshot of state instead of one provided via the p2p network. The steps to start local state sync are similar to normal state sync with a few different designs.
|
||||
|
||||
1. As mentioned in https://docs.cometbft.com/v0.37/core/state-sync, one must set a height and hash in the config.toml along with a few rpc servers (the afromentioned link has instructions on how to do this).
|
||||
2. Bootsrapping Comet state in order to start the node after the snapshot has been ingested. This can be done with the bootstrap command `<app> comet bootstrap-state`
|
||||
<!-- 3. TODO after https://github.com/cosmos/cosmos-sdk/pull/16060 is merged -->
|
||||
|
||||
@ -5,8 +5,15 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"github.com/cometbft/cometbft/light"
|
||||
"github.com/cometbft/cometbft/node"
|
||||
"github.com/cometbft/cometbft/p2p"
|
||||
pvm "github.com/cometbft/cometbft/privval"
|
||||
cmtstore "github.com/cometbft/cometbft/proto/tendermint/store"
|
||||
sm "github.com/cometbft/cometbft/state"
|
||||
"github.com/cometbft/cometbft/statesync"
|
||||
"github.com/cometbft/cometbft/store"
|
||||
cmtversion "github.com/cometbft/cometbft/version"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/yaml"
|
||||
@ -15,6 +22,8 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
servercmtlog "github.com/cosmos/cosmos-sdk/server/log"
|
||||
"github.com/cosmos/cosmos-sdk/server/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/query"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@ -249,3 +258,92 @@ $ %s query block --%s=%s <hash>
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func BootstrapStateCmd(appCreator types.AppCreator) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "bootstrap-state",
|
||||
Short: "Bootstrap CometBFT state at an arbitrary block height using a light client",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
serverCtx := GetServerContextFromCmd(cmd)
|
||||
logger := log.NewLogger(cmd.OutOrStdout())
|
||||
cfg := serverCtx.Config
|
||||
|
||||
height, err := cmd.Flags().GetInt64("height")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if height == 0 {
|
||||
home := serverCtx.Viper.GetString(flags.FlagHome)
|
||||
db, err := openDB(home, GetAppDBBackend(serverCtx.Viper))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app := appCreator(logger, db, nil, serverCtx.Viper)
|
||||
height = app.CommitMultiStore().LastCommitID().Version
|
||||
}
|
||||
|
||||
blockStoreDB, err := node.DefaultDBProvider(&node.DBContext{ID: "blockstore", Config: cfg})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blockStore := store.NewBlockStore(blockStoreDB)
|
||||
|
||||
stateDB, err := node.DefaultDBProvider(&node.DBContext{ID: "state", Config: cfg})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardABCIResponses: cfg.Storage.DiscardABCIResponses,
|
||||
})
|
||||
|
||||
genState, _, err := node.LoadStateFromDBOrGenesisDocProvider(stateDB, node.DefaultGenesisDocProviderFunc(cfg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stateProvider, err := statesync.NewLightClientStateProvider(
|
||||
cmd.Context(),
|
||||
genState.ChainID, genState.Version, genState.InitialHeight,
|
||||
cfg.StateSync.RPCServers, light.TrustOptions{
|
||||
Period: cfg.StateSync.TrustPeriod,
|
||||
Height: cfg.StateSync.TrustHeight,
|
||||
Hash: cfg.StateSync.TrustHashBytes(),
|
||||
}, servercmtlog.CometLoggerWrapper{Logger: logger.With("module", "light")})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set up light client state provider: %w", err)
|
||||
}
|
||||
|
||||
state, err := stateProvider.State(cmd.Context(), uint64(height))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get state: %w", err)
|
||||
}
|
||||
|
||||
commit, err := stateProvider.Commit(cmd.Context(), uint64(height))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get commit: %w", err)
|
||||
}
|
||||
|
||||
if err := stateStore.Bootstrap(state); err != nil {
|
||||
return fmt.Errorf("failed to bootstrap state: %w", err)
|
||||
}
|
||||
|
||||
if err := blockStore.SaveSeenCommit(state.LastBlockHeight, commit); err != nil {
|
||||
return fmt.Errorf("failed to save seen commit: %w", err)
|
||||
}
|
||||
|
||||
store.SaveBlockStoreState(&cmtstore.BlockStoreState{
|
||||
// it breaks the invariant that blocks in range [Base, Height] must exists, but it do works in practice.
|
||||
Base: state.LastBlockHeight,
|
||||
Height: state.LastBlockHeight,
|
||||
}, blockStoreDB)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Int64("height", 0, "Block height to bootstrap state at, if not provided will use the latest block height in app state")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -320,6 +320,7 @@ func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator type
|
||||
VersionCmd(),
|
||||
cmtcmd.ResetAllCmd,
|
||||
cmtcmd.ResetStateCmd,
|
||||
BootstrapStateCmd(appCreator),
|
||||
)
|
||||
|
||||
startCmd := StartCmd(appCreator, defaultNodeHome)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user