diff --git a/app/app.go b/app/app.go index b4f5126174..e9246c62d8 100644 --- a/app/app.go +++ b/app/app.go @@ -435,6 +435,10 @@ func NewOKExChainApp( return app } +func (app *OKExChainApp) LoadStartVersion(height int64) error { + return app.LoadVersion(height, app.keys[bam.MainStoreKey]) +} + // Name returns the name of the App func (app *OKExChainApp) Name() string { return app.BaseApp.Name() } diff --git a/cmd/exchaind/main.go b/cmd/exchaind/main.go index d86183d039..fc3e4a0cd0 100644 --- a/cmd/exchaind/main.go +++ b/cmd/exchaind/main.go @@ -79,6 +79,7 @@ func main() { genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics), client.TestnetCmd(ctx, cdc, app.ModuleBasics, auth.GenesisAccountIterator{}), replayCmd(ctx), + repairDataCmd(ctx), // AddGenesisAccountCmd allows users to add accounts to the genesis file AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome), flags.NewCompletionCmd(rootCmd, true), diff --git a/cmd/exchaind/repair_data.go b/cmd/exchaind/repair_data.go new file mode 100644 index 0000000000..316ac74d4b --- /dev/null +++ b/cmd/exchaind/repair_data.go @@ -0,0 +1,131 @@ +package main + +import ( + "fmt" + "github.com/cosmos/cosmos-sdk/server" + "github.com/okex/exchain/app" + "github.com/spf13/cobra" + "github.com/tendermint/iavl" + tmlog "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/mock" + "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/proxy" + sm "github.com/tendermint/tendermint/state" + "github.com/tendermint/tendermint/store" + "github.com/tendermint/tendermint/types" + dbm "github.com/tendermint/tm-db" + "io" + "log" + "path/filepath" +) + +func repairDataCmd(ctx *server.Context) *cobra.Command { + cmd := &cobra.Command{ + Use: "repair-data", + Short: "Repair the SMB(state machine broken) data of node", + Run: func(cmd *cobra.Command, args []string) { + log.Println("--------- repair data start ---------") + + repairData(ctx) + log.Println("--------- repair data success ---------") + }, + } + return cmd +} + +func repairData(ctx *server.Context) { + // set ignore smb check + sm.SetIgnoreSmbCheck(true) + iavl.SetIgnoreVersionCheck(true) + + // load latest block height + rootDir := ctx.Config.RootDir + dataDir := filepath.Join(rootDir, "data") + latestBlockHeight := latestBlockHeight(dataDir) + startBlockHeight := types.GetStartBlockHeight() + if latestBlockHeight <= startBlockHeight+2 { + panic(fmt.Sprintf("There is no need to repair data. The latest block height is %d, start block height is %d", latestBlockHeight, startBlockHeight)) + } + + // create proxy app + proxyApp, repairApp, err := createRepairApp(ctx) + panicError(err) + // load start version + err = repairApp.LoadStartVersion(latestBlockHeight - 2) + panicError(err) + + // load state + stateStoreDB, err := openDB(stateDB, dataDir) + panicError(err) + genesisDocProvider := node.DefaultGenesisDocProviderFunc(ctx.Config) + state, _, err := node.LoadStateFromDBOrGenesisDocProvider(stateStoreDB, genesisDocProvider) + panicError(err) + + // repair data by apply the latest two blocks + doRepair(ctx, state, stateStoreDB, proxyApp, latestBlockHeight, dataDir) +} + +func createRepairApp(ctx *server.Context) (proxy.AppConns, *app.OKExChainApp, error) { + rootDir := ctx.Config.RootDir + dataDir := filepath.Join(rootDir, "data") + db, err := openDB(applicationDB, dataDir) + panicError(err) + repairApp := newRepairApp(ctx.Logger, db, nil) + + clientCreator := proxy.NewLocalClientCreator(repairApp) + // Create the proxyApp and establish connections to the ABCI app (consensus, mempool, query). + proxyApp, err := createAndStartProxyAppConns(clientCreator) + return proxyApp, repairApp, err +} + +func newRepairApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer) *app.OKExChainApp { + return app.NewOKExChainApp( + logger, + db, + traceStore, + false, + map[int64]bool{}, + 0, + ) +} + +func doRepair(ctx *server.Context, state sm.State, stateStoreDB dbm.DB, + proxyApp proxy.AppConns, latestHeight int64, dataDir string) { + var err error + // replay the latest two blocks + height := latestHeight - 1 + for i := 0; i < 2; i++ { + repairBlock, repairBlockMeta := loadBlock(height, dataDir) + blockExec := sm.NewBlockExecutor(stateStoreDB, ctx.Logger, proxyApp.Consensus(), mock.Mempool{}, sm.MockEvidencePool{}) + state, _, err = blockExec.ApplyBlock(state, repairBlockMeta.BlockID, repairBlock) + panicError(err) + res, err := proxyApp.Query().InfoSync(proxy.RequestInfo) + panicError(err) + repairedBlockHeight := res.LastBlockHeight + repairedAppHash := res.LastBlockAppHash + log.Println("Repaired block height", repairedBlockHeight) + log.Println("Repaired app hash", fmt.Sprintf("%X", repairedAppHash)) + height++ + } + +} + +func loadBlock(height int64, dataDir string) (*types.Block, *types.BlockMeta) { + //rootDir := ctx.Config.RootDir + //dataDir := filepath.Join(rootDir, "data") + storeDB, err := openDB(blockStoreDB, dataDir) + defer storeDB.Close() + blockStore := store.NewBlockStore(storeDB) + panicError(err) + block := blockStore.LoadBlock(height) + meta := blockStore.LoadBlockMeta(height) + return block, meta +} + +func latestBlockHeight(dataDir string) int64 { + storeDB, err := openDB(blockStoreDB, dataDir) + panicError(err) + defer storeDB.Close() + blockStore := store.NewBlockStore(storeDB) + return blockStore.Height() +} diff --git a/go.mod b/go.mod index 58cc9c6269..f0c1dcefdc 100644 --- a/go.mod +++ b/go.mod @@ -44,6 +44,7 @@ require ( github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca github.com/tendermint/go-amino v0.15.1 + github.com/tendermint/iavl v0.14.1 github.com/tendermint/tendermint v0.33.9 github.com/tendermint/tm-db v0.5.2 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef @@ -57,8 +58,8 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.39.3-0.20210906101954-ea9c2e5521c8 - github.com/tendermint/iavl => github.com/okex/iavl v0.14.3-exchain - github.com/tendermint/tendermint => github.com/okex/tendermint v0.33.9-okexchain6.0.20210906101911-c04d43a1f4ba + github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.39.2-exchain16 + github.com/tendermint/iavl => github.com/okex/iavl v0.14.3-exchain1 + github.com/tendermint/tendermint => github.com/okex/tendermint v0.33.9-exchain11 github.com/tendermint/tm-db => github.com/okex/tm-db v0.5.2-exchain1 ) diff --git a/go.sum b/go.sum index 859c01768b..cff1d11c18 100644 --- a/go.sum +++ b/go.sum @@ -501,12 +501,12 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/okex/cosmos-sdk v0.39.3-0.20210906101954-ea9c2e5521c8 h1:YZY8B5VDRhDmF3+fiRziVUASPsVFqt6PAq5TcWOaIgk= -github.com/okex/cosmos-sdk v0.39.3-0.20210906101954-ea9c2e5521c8/go.mod h1:IvlniaZoJAtzILHgcmnfaJ5S125TYJWfJvGqY9zSXb4= -github.com/okex/iavl v0.14.3-exchain h1:kwRIwpFD6B8mDDqoaxeUN3Pg2GW0Vr+sA+b86renWcA= -github.com/okex/iavl v0.14.3-exchain/go.mod h1:vHLYxU/zuxBmxxr1v+5Vnd/JzcIsyK17n9P9RDubPVU= -github.com/okex/tendermint v0.33.9-okexchain6.0.20210906101911-c04d43a1f4ba h1:mFF3Nuh+PrqN/fxBCDVa9BCawMYOu6LyfhPXxAPsfsA= -github.com/okex/tendermint v0.33.9-okexchain6.0.20210906101911-c04d43a1f4ba/go.mod h1:EoGTbJUufUueNIigY3zyO6f7GOj29OdpFhuR8sxWdSU= +github.com/okex/cosmos-sdk v0.39.2-exchain16 h1:pwgJFimAo660q8wmopHNNZparWN9fS+QeLGvCVnLMOM= +github.com/okex/cosmos-sdk v0.39.2-exchain16/go.mod h1:IvlniaZoJAtzILHgcmnfaJ5S125TYJWfJvGqY9zSXb4= +github.com/okex/iavl v0.14.3-exchain1 h1:DVzcZq362OkRkFR3JEeTsxSzuydAItzjMXafeJ/LQwk= +github.com/okex/iavl v0.14.3-exchain1/go.mod h1:vHLYxU/zuxBmxxr1v+5Vnd/JzcIsyK17n9P9RDubPVU= +github.com/okex/tendermint v0.33.9-exchain11 h1:v0CjS6/lX/ypPea50WFxDCDNY4OLibT1QxkKqjkDExA= +github.com/okex/tendermint v0.33.9-exchain11/go.mod h1:EoGTbJUufUueNIigY3zyO6f7GOj29OdpFhuR8sxWdSU= github.com/okex/tm-db v0.5.2-exchain1 h1:c8aX7HoNW58GXHEO6e7BR81SwyBfjWJkqGwNUhF3tlc= github.com/okex/tm-db v0.5.2-exchain1/go.mod h1:VrPTx04QJhQ9d8TFUTc2GpPBvBf/U9vIdBIzkjBk7Lk= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=