diff --git a/.github/workflows/dependencies-review.yml b/.github/workflows/dependencies-review.yml deleted file mode 100644 index 52b58c3a486f..000000000000 --- a/.github/workflows/dependencies-review.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: "Dependency Review" -on: pull_request - -permissions: - contents: read - -jobs: - dependency-review: - runs-on: ubuntu-latest - steps: - - uses: actions/setup-go@v3 - with: - go-version: "1.19" - check-latest: true - - name: "Checkout Repository" - uses: actions/checkout@v3 - - name: "Dependency Review" - uses: actions/dependency-review-action@v3 - - name: "Dependency audit" - run: ./scripts/dep-assert.sh - - name: "Go vulnerability check" - run: make vulncheck diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 2d9b4acec711..bda6a1d32a4e 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -8,10 +8,11 @@ permissions: jobs: labeler: permissions: - contents: read # for actions/labeler to determine modified files - pull-requests: write # for actions/labeler to add labels to PRs + contents: read # for actions/labeler to determine modified files + pull-requests: write # for actions/labeler to add labels to PRs runs-on: ubuntu-latest steps: - - uses: actions/labeler@main + - uses: actions/labeler@v4 with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" \ No newline at end of file + configuration-path: .github/labeler.yml + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml deleted file mode 100644 index d5b4d46b2158..000000000000 --- a/.github/workflows/lint-pr.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: "Lint PR" - -on: - pull_request_target: - types: - - opened - - edited - - synchronize - -permissions: - contents: read - -jobs: - main: - permissions: - pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs - statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR - runs-on: ubuntu-latest - steps: - - uses: amannn/action-semantic-pull-request@v5.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml deleted file mode 100644 index 5978270a57ae..000000000000 --- a/.github/workflows/project.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Add PR to project - -on: - pull_request: - types: - - opened - - reopened - -jobs: - add-to-project: - name: Add pull request to project - runs-on: ubuntu-latest - steps: - - uses: actions/add-to-project@v0.3.0 - with: - project-url: https://github.com/orgs/cosmos/projects/26 - github-token: ${{ secrets.PERSONAL_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 76fa60202e49..3c3c17cc059e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -180,12 +180,6 @@ jobs: with: name: "${{ github.sha }}-e2e-coverage" continue-on-error: true - - name: sonarcloud - if: env.GIT_DIFF - uses: SonarSource/sonarcloud-github-action@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} liveness-test: runs-on: ubuntu-latest @@ -270,12 +264,4 @@ jobs: if: env.GIT_DIFF run: | cd simapp - go test -mod=readonly -timeout 30m -tags='app_v1 norace ledger test_ledger_mock rocksdb_build' ./... - - name: sonarcloud - if: env.GIT_DIFF - uses: SonarSource/sonarcloud-github-action@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - with: - projectBaseDir: simapp/ + go test -mod=readonly -timeout 30m -tags='app_v1 norace ledger test_ledger_mock rocksdb_build' ./... \ No newline at end of file diff --git a/baseapp/block_gas_test.go b/baseapp/block_gas_test.go index 81b39a0c2a81..d14f9077e801 100644 --- a/baseapp/block_gas_test.go +++ b/baseapp/block_gas_test.go @@ -167,7 +167,7 @@ func TestBaseApp_BlockGas(t *testing.T) { require.Equal(t, []byte("ok"), okValue) } // check block gas is always consumed - baseGas := uint64(51682) // baseGas is the gas consumed before tx msg + baseGas := uint64(47842) // baseGas is the gas consumed before tx msg expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas) if expGasConsumed > uint64(simtestutil.DefaultConsensusParams.Block.MaxGas) { // capped by gasLimit diff --git a/baseapp/options.go b/baseapp/options.go index e669495f647d..fab11203e237 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -96,6 +96,11 @@ func SetChainID(chainID string) func(*BaseApp) { return func(app *BaseApp) { app.chainID = chainID } } +// SetStoreLoader allows us to customize the rootMultiStore initialization. +func SetStoreLoader(loader StoreLoader) func(*BaseApp) { + return func(app *BaseApp) { app.SetStoreLoader(loader) } +} + func (app *BaseApp) SetName(name string) { if app.sealed { panic("SetName() on sealed BaseApp") diff --git a/server/start.go b/server/start.go index 374dc5e98572..50c011b534e5 100644 --- a/server/start.go +++ b/server/start.go @@ -3,8 +3,11 @@ package server // DONTCOVER import ( + "bufio" + "encoding/hex" "errors" "fmt" + "io" "net" "net/http" "os" @@ -13,21 +16,23 @@ import ( "strings" "time" + "cosmossdk.io/tools/rosetta" + crgserver "cosmossdk.io/tools/rosetta/lib/server" + db "github.com/cometbft/cometbft-db" "github.com/cometbft/cometbft/abci/server" tcmd "github.com/cometbft/cometbft/cmd/cometbft/commands" + cmtjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/node" "github.com/cometbft/cometbft/p2p" pvm "github.com/cometbft/cometbft/privval" + cmtstate "github.com/cometbft/cometbft/proto/tendermint/state" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cometbft/cometbft/proxy" "github.com/cometbft/cometbft/rpc/client/local" - "github.com/spf13/cobra" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" + sm "github.com/cometbft/cometbft/state" + "github.com/cometbft/cometbft/store" + cmttypes "github.com/cometbft/cometbft/types" - "encoding/hex" - - "cosmossdk.io/tools/rosetta" - crgserver "cosmossdk.io/tools/rosetta/lib/server" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" @@ -40,6 +45,10 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/mempool" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/spf13/cobra" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) const ( @@ -89,6 +98,14 @@ const ( // mempool flags FlagMempoolMaxTxs = "mempool.max-txs" + + // testnet keys + KeyIsTestnet = "is-testnet" + KeyNewChainID = "new-chain-ID" + KeyNewOpAddr = "new-operator-addr" + KeyNewValAddr = "new-validator-addr" + KeyUserPubKey = "user-pub-key" + KeyTriggerTestnetUpgrade = "trigger-testnet-upgrade" ) // StartCmd runs the service passed in, either stand-alone or in-process with @@ -165,49 +182,7 @@ is performed. Note, when enabled, gRPC will also be automatically enabled. }, } - cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") - cmd.Flags().Bool(flagWithTendermint, true, "Run abci app embedded in-process with tendermint") - cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address") - cmd.Flags().String(flagTransport, "socket", "Transport protocol: socket, grpc") - cmd.Flags().String(flagTraceStore, "", "Enable KVStore tracing to an output file") - cmd.Flags().String(FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") - cmd.Flags().IntSlice(FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary") - cmd.Flags().Uint64(FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node") - cmd.Flags().Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node") - cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching") - cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file") - cmd.Flags().Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log") - cmd.Flags().String(FlagPruning, pruningtypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") - cmd.Flags().Uint64(FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')") - cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") - cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") - cmd.Flags().Uint64(FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks") - - cmd.Flags().Bool(FlagAPIEnable, false, "Define if the API server should be enabled") - cmd.Flags().Bool(FlagAPISwagger, false, "Define if swagger documentation should automatically be registered (Note: the API must also be enabled)") - cmd.Flags().String(FlagAPIAddress, serverconfig.DefaultAPIAddress, "the API server address to listen on") - cmd.Flags().Uint(FlagAPIMaxOpenConnections, 1000, "Define the number of maximum open connections") - cmd.Flags().Uint(FlagRPCReadTimeout, 10, "Define the Tendermint RPC read timeout (in seconds)") - cmd.Flags().Uint(FlagRPCWriteTimeout, 0, "Define the Tendermint RPC write timeout (in seconds)") - cmd.Flags().Uint(FlagRPCMaxBodyBytes, 1000000, "Define the Tendermint maximum request body (in bytes)") - cmd.Flags().Bool(FlagAPIEnableUnsafeCORS, false, "Define if CORS should be enabled (unsafe - use it at your own risk)") - - cmd.Flags().Bool(flagGRPCOnly, false, "Start the node in gRPC query only mode (no Tendermint process is started)") - cmd.Flags().Bool(flagGRPCEnable, true, "Define if the gRPC server should be enabled") - cmd.Flags().String(flagGRPCAddress, serverconfig.DefaultGRPCAddress, "the gRPC server address to listen on") - - cmd.Flags().Bool(flagGRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled)") - cmd.Flags().String(flagGRPCWebAddress, serverconfig.DefaultGRPCWebAddress, "The gRPC-Web server address to listen on") - - cmd.Flags().Uint64(FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") - cmd.Flags().Uint32(FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") - - cmd.Flags().Bool(FlagDisableIAVLFastNode, false, "Disable fast node for IAVL tree") - - cmd.Flags().Int(FlagMempoolMaxTxs, mempool.DefaultMaxTx, "Sets MaxTx value for the app-side mempool") - - // add support for all Tendermint-specific command line options - tcmd.AddNodeFlags(cmd) + addStartNodeFlags(cmd, defaultNodeHome) return cmd } @@ -303,7 +278,16 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App return err } - app := appCreator(ctx.Logger, db, traceWriter, ctx.Viper) + var app types.Application + + if isTestnet, ok := ctx.Viper.Get(KeyIsTestnet).(bool); ok && isTestnet { + app, err = testnetify(ctx, home, appCreator, db, traceWriter) + if err != nil { + return err + } + } else { + app = appCreator(ctx.Logger, db, traceWriter, ctx.Viper) + } nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile()) if err != nil { @@ -622,3 +606,305 @@ func returnCommitInfo(ctx *Context, app types.Application, version int64) error ctx.Logger.Error("your node has app hashed. Compare each module's hashes with a node that did not app hash to determine the problematic module", "commitInfo", commitInfoForHeight.String()) return nil } + +// InPlaceTestnetCreator utilizes the provided chainID and operatorAddress as well as the local private validator key to +// control the network represented in the data folder. This is useful to create testnets nearly identical to your +// mainnet environment. +func InPlaceTestnetCreator(testnetAppCreator types.AppCreator, defaultNodeHome string) *cobra.Command { + cmd := &cobra.Command{ + Use: "in-place-testnet [newChainID] [newOperatorAddress]", + Short: "Create and start a testnet from current local state", + Long: `Create and start a testnet from current local state. +After utilizing this command the network will start. If the network is stopped, +the normal "start" command should be used. Re-using this command on state that +has already been modified by this command could result in unexpected behavior. + +Additionally, the first block may take up to one minute to be committed, depending +on how old the block is. For instance, if a snapshot was taken weeks ago and we want +to turn this into a testnet, it is possible lots of pending state needs to be committed +(expiring locks, etc.). It is recommended that you should wait for this block to be committed +before stopping the daemon. + +If the --trigger-testnet-upgrade flag is set, the upgrade handler specified by the flag will be run +on the first block of the testnet. + +Regardless of whether the flag is set or not, if any new stores are introduced in the daemon being run, +those stores will be registered in order to prevent panics. Therefore, you only need to set the flag if +you want to test the upgrade handler itself. +`, + Example: "in-place-testnet localosmosis osmo12smx2wdlyttvyzvzg54y2vnqwq2qjateuf7thj", + Args: cobra.ExactArgs(2), + PreRunE: func(cmd *cobra.Command, _ []string) error { + serverCtx := GetServerContextFromCmd(cmd) + + if err := serverCtx.Viper.BindPFlags(cmd.Flags()); err != nil { + return err + } + + _, err := GetPruningOptionsFromFlags(serverCtx.Viper) + return err + }, + RunE: func(cmd *cobra.Command, args []string) error { + serverCtx := GetServerContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + newChainID := args[0] + newOperatorAddress := args[1] + + skipConfirmation, _ := cmd.Flags().GetBool("skip-confirmation") + + if !skipConfirmation { + // Confirmation prompt to prevent accidental modification of state. + reader := bufio.NewReader(os.Stdin) + fmt.Println("This operation will modify state in your data folder and cannot be undone. Do you want to continue? (y/n)") + text, _ := reader.ReadString('\n') + response := strings.TrimSpace(strings.ToLower(text)) + if response != "y" && response != "yes" { + fmt.Println("Operation canceled.") + return nil + } + } + + serverCtx.Viper.Set(KeyIsTestnet, true) + serverCtx.Viper.Set(KeyNewChainID, newChainID) + serverCtx.Viper.Set(KeyNewOpAddr, newOperatorAddress) + + return startInProcess(serverCtx, clientCtx, testnetAppCreator) + }, + } + + addStartNodeFlags(cmd, defaultNodeHome) + cmd.Flags().String(KeyTriggerTestnetUpgrade, "", "If set (example: \"v21\"), triggers the v21 upgrade handler to run on the first block of the testnet") + cmd.Flags().Bool("skip-confirmation", false, "Skip the confirmation prompt") + return cmd +} + +// testnetify modifies both state and blockStore, allowing the provided operator address and local validator key to control the network +// that the state in the data folder represents. The chainID of the local genesis file is modified to match the provided chainID. +func testnetify(ctx *Context, home string, testnetAppCreator types.AppCreator, db db.DB, traceWriter io.WriteCloser) (types.Application, error) { + config := ctx.Config + + newChainID, ok := ctx.Viper.Get(KeyNewChainID).(string) + if !ok { + return nil, fmt.Errorf("expected string for key %s", KeyNewChainID) + } + + genDocProvider := node.DefaultGenesisDocProviderFunc(config) + + // Initialize blockStore and stateDB. + blockStoreDB, err := node.DefaultDBProvider(&node.DBContext{ID: "blockstore", Config: config}) + if err != nil { + return nil, err + } + blockStore := store.NewBlockStore(blockStoreDB) + + stateDB, err := node.DefaultDBProvider(&node.DBContext{ID: "state", Config: config}) + if err != nil { + return nil, err + } + + defer blockStore.Close() + defer stateDB.Close() + + privValidator := pvm.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()) + userPubKey, err := privValidator.GetPubKey() + if err != nil { + return nil, err + } + validatorAddress := userPubKey.Address() + if err != nil { + return nil, err + } + + stateStore := sm.NewStore(stateDB, sm.StoreOptions{ + DiscardABCIResponses: config.Storage.DiscardABCIResponses, + }) + + state, genDoc, err := node.LoadStateFromDBOrGenesisDocProvider(stateDB, genDocProvider) + if err != nil { + return nil, err + } + + genDoc.ChainID = newChainID + genFilePath := config.GenesisFile() + if err = genutil.ExportGenesisFile(genDoc, genFilePath); err != nil { + return nil, err + } + + // There are times when a user stops their node between commits, resulting in a mismatch between the + // blockStore and state. For convenience, we just discard the uncommitted blockStore block and operate on + // the lastBlockHeight in state. + if blockStore.Height() != state.LastBlockHeight { + err = blockStore.DeleteLatestBlock() + if err != nil { + return nil, err + } + } + + block := blockStore.LoadBlock(blockStore.Height()) + + block.ChainID = newChainID + state.ChainID = newChainID + + block.LastBlockID = state.LastBlockID + block.LastCommit.BlockID = state.LastBlockID + + // Create a vote from our validator + vote := cmttypes.Vote{ + Type: cmtproto.PrecommitType, + Height: state.LastBlockHeight, + Round: 0, + BlockID: state.LastBlockID, + Timestamp: time.Now(), + ValidatorAddress: validatorAddress, + ValidatorIndex: 0, + Signature: []byte{}, + } + + // Sign the vote, and copy the proto changes from the act of signing to the vote itself + voteProto := vote.ToProto() + err = privValidator.SignVote(newChainID, voteProto) + if err != nil { + return nil, err + } + vote.Signature = voteProto.Signature + vote.Timestamp = voteProto.Timestamp + + // Modify the block's lastCommit to be signed only by our validator + block.LastCommit.Signatures[0].ValidatorAddress = validatorAddress + block.LastCommit.Signatures[0].Signature = vote.Signature + block.LastCommit.Signatures = []cmttypes.CommitSig{block.LastCommit.Signatures[0]} + + // Load the seenCommit of the lastBlockHeight and modify it to be signed from our validator + seenCommit := blockStore.LoadSeenCommit(state.LastBlockHeight) + seenCommit.BlockID = state.LastBlockID + seenCommit.Round = vote.Round + seenCommit.Signatures[0].Signature = vote.Signature + seenCommit.Signatures[0].ValidatorAddress = validatorAddress + seenCommit.Signatures[0].Timestamp = vote.Timestamp + seenCommit.Signatures = []cmttypes.CommitSig{seenCommit.Signatures[0]} + err = blockStore.SaveSeenCommit(state.LastBlockHeight, seenCommit) + if err != nil { + return nil, err + } + + // Create ValidatorSet struct containing just our valdiator. + newVal := &cmttypes.Validator{ + Address: validatorAddress, + PubKey: userPubKey, + VotingPower: 900000000000000, + } + newValSet := &cmttypes.ValidatorSet{ + Validators: []*cmttypes.Validator{newVal}, + Proposer: newVal, + } + + // Replace all valSets in state to be the valSet with just our validator. + state.Validators = newValSet + state.LastValidators = newValSet + state.NextValidators = newValSet + state.LastHeightValidatorsChanged = blockStore.Height() + + err = stateStore.Save(state) + if err != nil { + return nil, err + } + + // Create a ValidatorsInfo struct to store in stateDB. + valSet, err := state.Validators.ToProto() + if err != nil { + return nil, err + } + valInfo := &cmtstate.ValidatorsInfo{ + ValidatorSet: valSet, + LastHeightChanged: state.LastBlockHeight, + } + buf, err := valInfo.Marshal() + if err != nil { + return nil, err + } + + // Modfiy Validators stateDB entry. + err = stateDB.Set([]byte(fmt.Sprintf("validatorsKey:%v", blockStore.Height())), buf) + if err != nil { + return nil, err + } + + // Modify LastValidators stateDB entry. + err = stateDB.Set([]byte(fmt.Sprintf("validatorsKey:%v", blockStore.Height()-1)), buf) + if err != nil { + return nil, err + } + + // Modify NextValidators stateDB entry. + err = stateDB.Set([]byte(fmt.Sprintf("validatorsKey:%v", blockStore.Height()+1)), buf) + if err != nil { + return nil, err + } + + b, err := cmtjson.Marshal(genDoc) + if err != nil { + return nil, err + } + if err := stateDB.SetSync([]byte("genesisDoc"), b); err != nil { + return nil, err + } + + // testnetAppCreator makes any application side changes that must be made due to the above modifications. + // Also, it makes any optional application side changes to make running the testnet easier (voting times, fund accounts, etc). + ctx.Viper.Set(KeyNewValAddr, validatorAddress) + ctx.Viper.Set(KeyUserPubKey, userPubKey) + testnetApp := testnetAppCreator(ctx.Logger, db, traceWriter, ctx.Viper) + + return testnetApp, err +} + +// addStartNodeFlags should be added to any CLI commands that start the network. +func addStartNodeFlags(cmd *cobra.Command, defaultNodeHome string) { + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") + cmd.Flags().Bool(flagWithTendermint, true, "Run abci app embedded in-process with tendermint") + cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address") + cmd.Flags().String(flagTransport, "socket", "Transport protocol: socket, grpc") + cmd.Flags().String(flagTraceStore, "", "Enable KVStore tracing to an output file") + cmd.Flags().String(FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") + cmd.Flags().IntSlice(FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary") + cmd.Flags().Uint64(FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node") + cmd.Flags().Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node") + cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching") + cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file") + cmd.Flags().Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log") + cmd.Flags().String(FlagPruning, pruningtypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") + cmd.Flags().Uint64(FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')") + cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") + cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") + cmd.Flags().Uint64(FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks") + + cmd.Flags().Bool(FlagAPIEnable, false, "Define if the API server should be enabled") + cmd.Flags().Bool(FlagAPISwagger, false, "Define if swagger documentation should automatically be registered (Note: the API must also be enabled)") + cmd.Flags().String(FlagAPIAddress, serverconfig.DefaultAPIAddress, "the API server address to listen on") + cmd.Flags().Uint(FlagAPIMaxOpenConnections, 1000, "Define the number of maximum open connections") + cmd.Flags().Uint(FlagRPCReadTimeout, 10, "Define the Tendermint RPC read timeout (in seconds)") + cmd.Flags().Uint(FlagRPCWriteTimeout, 0, "Define the Tendermint RPC write timeout (in seconds)") + cmd.Flags().Uint(FlagRPCMaxBodyBytes, 1000000, "Define the Tendermint maximum request body (in bytes)") + cmd.Flags().Bool(FlagAPIEnableUnsafeCORS, false, "Define if CORS should be enabled (unsafe - use it at your own risk)") + + cmd.Flags().Bool(flagGRPCOnly, false, "Start the node in gRPC query only mode (no Tendermint process is started)") + cmd.Flags().Bool(flagGRPCEnable, true, "Define if the gRPC server should be enabled") + cmd.Flags().String(flagGRPCAddress, serverconfig.DefaultGRPCAddress, "the gRPC server address to listen on") + + cmd.Flags().Bool(flagGRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled)") + cmd.Flags().String(flagGRPCWebAddress, serverconfig.DefaultGRPCWebAddress, "The gRPC-Web server address to listen on") + + cmd.Flags().Uint64(FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") + cmd.Flags().Uint32(FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") + + cmd.Flags().Bool(FlagDisableIAVLFastNode, false, "Disable fast node for IAVL tree") + + cmd.Flags().Int(FlagMempoolMaxTxs, mempool.DefaultMaxTx, "Sets MaxTx value for the app-side mempool") + + // add support for all Tendermint-specific command line options + tcmd.AddNodeFlags(cmd) +} diff --git a/server/util.go b/server/util.go index 9a6ae40f786e..8b41d194aa42 100644 --- a/server/util.go +++ b/server/util.go @@ -324,6 +324,13 @@ func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator type ) } +// AddTestnetCreatorCommand allows chains to create a testnet from the state existing in their node's data directory. +func AddTestnetCreatorCommand(rootCmd *cobra.Command, defaultNodeHome string, appCreator types.AppCreator, addStartFlags types.ModuleInitFlags) { + testnetCreateCmd := InPlaceTestnetCreator(appCreator, defaultNodeHome) + addStartFlags(testnetCreateCmd) + rootCmd.AddCommand(testnetCreateCmd) +} + // https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go // TODO there must be a better way to get external IP func ExternalIP() (string, error) { diff --git a/simapp/go.mod b/simapp/go.mod index 03ca91587aaf..b1bfdda35057 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -175,6 +175,7 @@ require ( replace ( // use cosmos fork of keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 + github.com/cometbft/cometbft => github.com/osmosis-labs/cometbft v0.0.0-20240103055822-28da358e3146 // Simapp always use the latest version of the cosmos-sdk github.com/cosmos/cosmos-sdk => ../. // Fix upstream GHSA-h395-qcrw-5vmq and GHSA-3vp4-m3rf-835h vulnerabilities. diff --git a/simapp/go.sum b/simapp/go.sum index 1c7da6fee9c6..73a2a12992a9 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -311,8 +311,6 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.37.2 h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc= -github.com/cometbft/cometbft v0.37.2/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -799,6 +797,8 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/osmosis-labs/cometbft v0.0.0-20240103055822-28da358e3146 h1:Qkshh58fZCRoHSzbyW8NJf1wBhf9bg1MPFZEuyuI9lE= +github.com/osmosis-labs/cometbft v0.0.0-20240103055822-28da358e3146/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= diff --git a/store/cachekv/search_benchmark_test.go b/store/cachekv/search_benchmark_test.go index 4007c7cda202..ddf4bdf02c15 100644 --- a/store/cachekv/search_benchmark_test.go +++ b/store/cachekv/search_benchmark_test.go @@ -3,8 +3,6 @@ package cachekv import ( "strconv" "testing" - - "github.com/cosmos/cosmos-sdk/store/cachekv/internal" ) func BenchmarkLargeUnsortedMisses(b *testing.B) { @@ -36,9 +34,10 @@ func generateStore() *Store { cache[key] = &cValue{} } - return &Store{ + store := &Store{ cache: cache, unsortedCache: unsorted, - sortedCache: internal.NewBTree(), } + store.resetSortedCache() + return store } diff --git a/store/cachekv/store.go b/store/cachekv/store.go index a8f468979cd9..2cb5a63fa6a4 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -28,7 +28,7 @@ type Store struct { mtx sync.Mutex cache map[string]*cValue unsortedCache map[string]struct{} - sortedCache internal.BTree // always ascending sorted + sortedCache *internal.BTree // always ascending sorted parent types.KVStore } @@ -39,7 +39,7 @@ func NewStore(parent types.KVStore) *Store { return &Store{ cache: make(map[string]*cValue), unsortedCache: make(map[string]struct{}), - sortedCache: internal.NewBTree(), + sortedCache: nil, parent: parent, } } @@ -93,13 +93,18 @@ func (store *Store) Delete(key []byte) { store.setCacheValue(key, nil, true) } +func (store *Store) resetSortedCache() { + newTree := internal.NewBTree() + store.sortedCache = &newTree +} + // Implements Cachetypes.KVStore. func (store *Store) Write() { store.mtx.Lock() defer store.mtx.Unlock() if len(store.cache) == 0 && len(store.unsortedCache) == 0 { - store.sortedCache = internal.NewBTree() + store.sortedCache = nil return } @@ -140,7 +145,7 @@ func (store *Store) Write() { for key := range store.unsortedCache { delete(store.unsortedCache, key) } - store.sortedCache = internal.NewBTree() + store.sortedCache = nil } // CacheWrap implements CacheWrapper. @@ -169,6 +174,9 @@ func (store *Store) ReverseIterator(start, end []byte) types.Iterator { func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator { store.mtx.Lock() defer store.mtx.Unlock() + if store.sortedCache == nil { + store.resetSortedCache() + } store.dirtyItems(start, end) isoSortedCache := store.sortedCache.Copy() diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index 86927466a905..a162910fe5a5 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -73,7 +73,7 @@ func NewStore( } func newCacheMultiStoreFromCMS(cms Store) Store { - stores := make(map[types.StoreKey]types.CacheWrapper) + stores := make(map[types.StoreKey]types.CacheWrapper, len(cms.stores)) for k, v := range cms.stores { stores[k] = v } diff --git a/tests/e2e/auth/vesting/suite.go b/tests/e2e/auth/vesting/suite.go index b9d91fa626c8..e291f0905841 100644 --- a/tests/e2e/auth/vesting/suite.go +++ b/tests/e2e/auth/vesting/suite.go @@ -2,6 +2,8 @@ package testutil import ( "fmt" + "log" + "os" "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/suite" @@ -221,6 +223,10 @@ func (s *E2ETestSuite) TestNewMsgCreatePermanentLockedAccountCmd() { } func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { + pwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } val := s.network.Validators[0] for _, tc := range []struct { name string @@ -234,8 +240,8 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { args: []string{ sdk.AccAddress("addr10______________").String(), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), - fmt.Sprintf("--%s=%s", cli.FlagLockup, "testdata/periods1.json"), - fmt.Sprintf("--%s=%s", cli.FlagVesting, "testdata/periods1.json"), + fmt.Sprintf("--%s=%s", cli.FlagLockup, fmt.Sprintf(pwd+"/testdata/periods1.json")), + fmt.Sprintf("--%s=%s", cli.FlagVesting, fmt.Sprintf(pwd+"/testdata/periods1.json")), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), @@ -249,7 +255,7 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { args: []string{ sdk.AccAddress("addr11______________").String(), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), - fmt.Sprintf("--%s=%s", cli.FlagVesting, "testdata/periods1.json"), + fmt.Sprintf("--%s=%s", cli.FlagVesting, fmt.Sprintf(pwd+"/testdata/periods1.json")), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), @@ -263,7 +269,7 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { args: []string{ sdk.AccAddress("addr12______________").String(), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), - fmt.Sprintf("--%s=%s", cli.FlagLockup, "testdata/periods1.json"), + fmt.Sprintf("--%s=%s", cli.FlagLockup, fmt.Sprintf(pwd+"/testdata/periods1.json")), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), @@ -277,8 +283,8 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { args: []string{ sdk.AccAddress("addr10______________").String(), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), - fmt.Sprintf("--%s=%s", cli.FlagLockup, "testdata/periods1.json"), - fmt.Sprintf("--%s=%s", cli.FlagVesting, "testdata/periods1.json"), + fmt.Sprintf("--%s=%s", cli.FlagLockup, fmt.Sprintf(pwd+"/testdata/periods1.json")), + fmt.Sprintf("--%s=%s", cli.FlagVesting, fmt.Sprintf(pwd+"/testdata/periods1.json")), fmt.Sprintf("--%s=%s", cli.FlagMerge, "true"), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), @@ -306,7 +312,7 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { name: "bad lockup filename", args: []string{ sdk.AccAddress("addr13______________").String(), - fmt.Sprintf("--%s=%s", cli.FlagLockup, "testdata/noexist"), + fmt.Sprintf("--%s=%s", cli.FlagLockup, fmt.Sprintf(pwd+"testdata/noexist")), }, expectErr: true, }, @@ -314,7 +320,7 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { name: "bad lockup json", args: []string{ sdk.AccAddress("addr13______________").String(), - fmt.Sprintf("--%s=%s", cli.FlagLockup, "testdata/badjson"), + fmt.Sprintf("--%s=%s", cli.FlagLockup, fmt.Sprintf(pwd+"testdata/badjson")), }, expectErr: true, }, @@ -322,7 +328,7 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { name: "bad lockup periods", args: []string{ sdk.AccAddress("addr13______________").String(), - fmt.Sprintf("--%s=%s", cli.FlagLockup, "testdata/badperiod.json"), + fmt.Sprintf("--%s=%s", cli.FlagLockup, fmt.Sprintf(pwd+"testdata/badperiod.json")), }, expectErr: true, }, @@ -330,7 +336,7 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { name: "bad vesting filename", args: []string{ sdk.AccAddress("addr13______________").String(), - fmt.Sprintf("--%s=%s", cli.FlagVesting, "testdata/noexist"), + fmt.Sprintf("--%s=%s", cli.FlagVesting, fmt.Sprintf(pwd+"testdata/noexist")), }, expectErr: true, }, @@ -338,7 +344,7 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { name: "bad vesting json", args: []string{ sdk.AccAddress("addr13______________").String(), - fmt.Sprintf("--%s=%s", cli.FlagVesting, "testdata/badjson"), + fmt.Sprintf("--%s=%s", cli.FlagVesting, fmt.Sprintf(pwd+"testdata/badjson")), }, expectErr: true, }, @@ -346,11 +352,17 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { name: "bad vesting periods", args: []string{ sdk.AccAddress("addr13______________").String(), - fmt.Sprintf("--%s=%s", cli.FlagVesting, "testdata/badperiod.json"), + fmt.Sprintf("--%s=%s", cli.FlagVesting, fmt.Sprintf(pwd+"testdata/badperiod.json")), }, expectErr: true, }, } { + // Synchronize height between test runs, to ensure sequence numbers are + // properly updated. + height, err := s.network.LatestHeight() + s.Require().NoError(err, "Getting initial latest height") + s.T().Logf("Initial latest height: %d", height) + s.Run(tc.name, func() { clientCtx := val.ClientCtx @@ -365,24 +377,43 @@ func (s *E2ETestSuite) TestNewMsgCreateClawbackVestingAccountCmd() { s.Require().Equal(tc.expectedCode, txResp.Code) } }) + next, err := s.network.WaitForHeight(height + 1) + s.Require().NoError(err, "Waiting for height...") + height = next + s.T().Logf("Height now: %d", height) } } func (s *E2ETestSuite) TestNewMsgClawbackCmd() { + pwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + val := s.network.Validators[0] addr := sdk.AccAddress("addr30______________") - _, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.NewMsgCreateClawbackVestingAccountCmd(), []string{ + _, err = clitestutil.ExecTestCLICmd(val.ClientCtx, cli.NewMsgCreateClawbackVestingAccountCmd(), []string{ addr.String(), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), - fmt.Sprintf("--%s=%s", cli.FlagLockup, "testdata/periods1.json"), - fmt.Sprintf("--%s=%s", cli.FlagVesting, "testdata/periods1.json"), + fmt.Sprintf("--%s=%s", cli.FlagLockup, fmt.Sprintf(pwd+"/testdata/periods1.json")), + fmt.Sprintf("--%s=%s", cli.FlagVesting, fmt.Sprintf(pwd+"/testdata/periods1.json")), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }) s.Require().NoError(err) + // Synchronize height between test runs, to ensure sequence numbers are + // properly updated. + height, err := s.network.LatestHeight() + s.Require().NoError(err, "Getting initial latest height") + s.T().Logf("Initial latest height: %d", height) + next, err := s.network.WaitForHeight(height + 1) + s.Require().NoError(err, "Waiting for height...") + height = next + s.T().Logf("Height now: %d", height) + for _, tc := range []struct { name string args []string @@ -433,6 +464,12 @@ func (s *E2ETestSuite) TestNewMsgClawbackCmd() { respType: &sdk.TxResponse{}, }, } { + // Synchronize height between test runs, to ensure sequence numbers are + // properly updated. + height, err := s.network.LatestHeight() + s.Require().NoError(err, "Getting initial latest height") + s.T().Logf("Initial latest height: %d", height) + s.Run(tc.name, func() { clientCtx := val.ClientCtx @@ -447,5 +484,9 @@ func (s *E2ETestSuite) TestNewMsgClawbackCmd() { s.Require().Equal(tc.expectedCode, txResp.Code) } }) + next, err := s.network.WaitForHeight(height + 1) + s.Require().NoError(err, "Waiting for height...") + height = next + s.T().Logf("Height now: %d", height) } } diff --git a/x/auth/vesting/client/testutil/testdata/badjson b/tests/e2e/auth/vesting/testdata/badjson similarity index 100% rename from x/auth/vesting/client/testutil/testdata/badjson rename to tests/e2e/auth/vesting/testdata/badjson diff --git a/x/auth/vesting/client/testutil/testdata/badperiod.json b/tests/e2e/auth/vesting/testdata/badperiod.json similarity index 98% rename from x/auth/vesting/client/testutil/testdata/badperiod.json rename to tests/e2e/auth/vesting/testdata/badperiod.json index e580e831438b..ae2735ab690d 100644 --- a/x/auth/vesting/client/testutil/testdata/badperiod.json +++ b/tests/e2e/auth/vesting/testdata/badperiod.json @@ -6,4 +6,4 @@ "length_seconds": -500 } ] -} +} \ No newline at end of file diff --git a/x/auth/vesting/client/testutil/testdata/periods1.json b/tests/e2e/auth/vesting/testdata/periods1.json similarity index 68% rename from x/auth/vesting/client/testutil/testdata/periods1.json rename to tests/e2e/auth/vesting/testdata/periods1.json index 82255f074c99..9c2c0a0d89c4 100644 --- a/x/auth/vesting/client/testutil/testdata/periods1.json +++ b/tests/e2e/auth/vesting/testdata/periods1.json @@ -3,11 +3,11 @@ "periods": [ { "coins": "10stake", - "length": 2592000 + "length_seconds": 2592000 }, { "coins": "10stake", - "length":2592000 + "length_seconds":2592000 } ] } diff --git a/tests/e2e/gov/query.go b/tests/e2e/gov/query.go index b143f910566d..8b8b1a8db518 100644 --- a/tests/e2e/gov/query.go +++ b/tests/e2e/gov/query.go @@ -23,7 +23,7 @@ func (s *E2ETestSuite) TestCmdParams() { { "json output", []string{fmt.Sprintf("--%s=json", flags.FlagOutput)}, - `{"voting_params":{"voting_period":"172800s"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s","voting_period":"172800s","quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000","min_initial_deposit_ratio":"0.000000000000000000","proposal_cancel_ratio":"0.500000000000000000","proposal_cancel_dest":"","expedited_voting_period":"86400s","expedited_threshold":"0.667000000000000000","expedited_min_deposit":[{"denom":"stake","amount":"50000000"}]}}`, + `{"voting_params":{"voting_period":"172800s"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s","voting_period":"172800s","quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000","min_initial_deposit_ratio":"0.000000000000000000","expedited_voting_period":"86400s","expedited_threshold":"0.667000000000000000","expedited_min_deposit":[{"denom":"stake","amount":"50000000"}],"burn_vote_quorum":false,"burn_proposal_deposit_prevote":false,"burn_vote_veto":true}}`, }, { "text output", @@ -35,6 +35,9 @@ deposit_params: - amount: "10000000" denom: stake params: + burn_proposal_deposit_prevote: false + burn_vote_quorum: false + burn_vote_veto: true expedited_min_deposit: - amount: "50000000" denom: stake diff --git a/tests/go.mod b/tests/go.mod index 8f18aa90c67e..afd6507b0cad 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -178,6 +178,7 @@ replace ( // We always want to test against the latest version of the simapp. cosmossdk.io/simapp => ../simapp github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 + github.com/cometbft/cometbft => github.com/osmosis-labs/cometbft v0.0.0-20240103055822-28da358e3146 // We always want to test against the latest version of the SDK. github.com/cosmos/cosmos-sdk => ../. // Fix upstream GHSA-h395-qcrw-5vmq and GHSA-3vp4-m3rf-835h vulnerabilities. diff --git a/tests/go.sum b/tests/go.sum index 7c189c147ae2..e1a7ff74eaf8 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -311,8 +311,6 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.37.2 h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc= -github.com/cometbft/cometbft v0.37.2/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -807,6 +805,8 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/osmosis-labs/cometbft v0.0.0-20240103055822-28da358e3146 h1:Qkshh58fZCRoHSzbyW8NJf1wBhf9bg1MPFZEuyuI9lE= +github.com/osmosis-labs/cometbft v0.0.0-20240103055822-28da358e3146/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= diff --git a/tests/integration/bank/keeper/deterministic_test.go b/tests/integration/bank/keeper/deterministic_test.go index a07e0d48f9da..112d11489260 100644 --- a/tests/integration/bank/keeper/deterministic_test.go +++ b/tests/integration/bank/keeper/deterministic_test.go @@ -218,7 +218,7 @@ func (suite *DeterministicTestSuite) TestGRPCQueryTotalSupply() { suite.Require().NoError(suite.bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, coins)) req := &banktypes.QueryTotalSupplyRequest{} - testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.TotalSupply, 243, false) + testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.TotalSupply, 3285, false) } func (suite *DeterministicTestSuite) TestGRPCQueryTotalSupplyOf() { @@ -238,7 +238,7 @@ func (suite *DeterministicTestSuite) TestGRPCQueryTotalSupplyOf() { suite.Require().NoError(suite.bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} - testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SupplyOf, 1021, false) + testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SupplyOf, 2033, false) } func (suite *DeterministicTestSuite) TestGRPCQueryParams() { @@ -403,50 +403,51 @@ func (suite *DeterministicTestSuite) TestGRPCSendEnabled() { testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SendEnabled, 4063, false) } -func (suite *DeterministicTestSuite) TestGRPCDenomOwners() { - rapid.Check(suite.T(), func(t *rapid.T) { - denom := rapid.StringMatching(denomRegex).Draw(t, "denom") - numAddr := rapid.IntRange(1, 10).Draw(t, "number-address") - for i := 0; i < numAddr; i++ { - addr := testdata.AddressGenerator(t).Draw(t, "address") - - coin := sdk.NewCoin( - denom, - sdk.NewInt(rapid.Int64Min(1).Draw(t, "amount")), - ) - - err := banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, sdk.NewCoins(coin)) - suite.Require().NoError(err) - } - - req := &banktypes.QueryDenomOwnersRequest{ - Denom: denom, - Pagination: testdata.PaginationGenerator(t, uint64(numAddr)).Draw(t, "pagination"), - } - testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomOwners, 0, true) - }) - - denomOwners := []*banktypes.DenomOwner{ - { - Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299", - Balance: coin1, - }, - { - Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut", - Balance: coin1, - }, - } - - for i := 0; i < len(denomOwners); i++ { - addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address) - suite.Require().NoError(err) - - err = banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, sdk.NewCoins(coin1)) - suite.Require().NoError(err) - } - - req := &banktypes.QueryDenomOwnersRequest{ - Denom: coin1.GetDenom(), - } - testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomOwners, 2525, false) -} +// Not implemented in Osmosis +// func (suite *DeterministicTestSuite) TestGRPCDenomOwners() { +// rapid.Check(suite.T(), func(t *rapid.T) { +// denom := rapid.StringMatching(denomRegex).Draw(t, "denom") +// numAddr := rapid.IntRange(1, 10).Draw(t, "number-address") +// for i := 0; i < numAddr; i++ { +// addr := testdata.AddressGenerator(t).Draw(t, "address") + +// coin := sdk.NewCoin( +// denom, +// sdk.NewInt(rapid.Int64Min(1).Draw(t, "amount")), +// ) + +// err := banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, sdk.NewCoins(coin)) +// suite.Require().NoError(err) +// } + +// req := &banktypes.QueryDenomOwnersRequest{ +// Denom: denom, +// Pagination: testdata.PaginationGenerator(t, uint64(numAddr)).Draw(t, "pagination"), +// } +// testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomOwners, 0, true) +// }) + +// denomOwners := []*banktypes.DenomOwner{ +// { +// Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299", +// Balance: coin1, +// }, +// { +// Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut", +// Balance: coin1, +// }, +// } + +// for i := 0; i < len(denomOwners); i++ { +// addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address) +// suite.Require().NoError(err) + +// err = banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, sdk.NewCoins(coin1)) +// suite.Require().NoError(err) +// } + +// req := &banktypes.QueryDenomOwnersRequest{ +// Denom: coin1.GetDenom(), +// } +// testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomOwners, 2525, false) +// } diff --git a/types/result.go b/types/result.go index 7f4910ac45ec..21daec7f1b47 100644 --- a/types/result.go +++ b/types/result.go @@ -14,8 +14,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" ) -var cdc = codec.NewLegacyAmino() - func (gi GasInfo) String() string { bz, _ := codec.MarshalYAML(codec.NewProtoCodec(nil), &gi) return string(bz) @@ -49,7 +47,7 @@ func NewABCIMessageLog(i uint32, log string, events Events) ABCIMessageLog { // String implements the fmt.Stringer interface for the ABCIMessageLogs type. func (logs ABCIMessageLogs) String() (str string) { if logs != nil { - raw, err := cdc.MarshalJSON(logs) + raw, err := json.Marshal(logs) if err == nil { str = string(raw) } diff --git a/types/result_test.go b/types/result_test.go index fe79c8c13f84..d68b05a6608c 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -2,6 +2,7 @@ package types_test import ( "encoding/hex" + "encoding/json" "fmt" "strings" "testing" @@ -13,7 +14,6 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -41,14 +41,13 @@ func (s *resultTestSuite) TestParseABCILog() { } func (s *resultTestSuite) TestABCIMessageLog() { - cdc := codec.NewLegacyAmino() events := sdk.Events{ sdk.NewEvent("transfer", sdk.NewAttribute("sender", "foo")), sdk.NewEvent("transfer", sdk.NewAttribute("sender", "bar")), } msgLog := sdk.NewABCIMessageLog(0, "", events) msgLogs := sdk.ABCIMessageLogs{msgLog} - bz, err := cdc.MarshalJSON(msgLogs) + bz, err := json.Marshal(msgLogs) s.Require().NoError(err) s.Require().Equal(string(bz), msgLogs.String()) diff --git a/x/auth/vesting/client/cli/tx.go b/x/auth/vesting/client/cli/tx.go index 5c2770840417..63a8d90b8251 100644 --- a/x/auth/vesting/client/cli/tx.go +++ b/x/auth/vesting/client/cli/tx.go @@ -3,7 +3,6 @@ package cli import ( "encoding/json" "fmt" - "io/ioutil" "os" "strconv" "time" @@ -221,7 +220,7 @@ func NewMsgCreatePeriodicVestingAccountCmd() *cobra.Command { // readScheduleFile reads the file at path and unmarshals it to get the schedule. // Returns start time, periods, and error. func readScheduleFile(path string) (int64, []types.Period, error) { - contents, err := ioutil.ReadFile(path) + contents, err := os.ReadFile(path) if err != nil { return 0, nil, err } diff --git a/x/auth/vesting/types/period.go b/x/auth/vesting/types/period.go index 85193037b6fb..ca24bdb6b6e9 100644 --- a/x/auth/vesting/types/period.go +++ b/x/auth/vesting/types/period.go @@ -176,11 +176,12 @@ func DisjunctPeriods(startP, startQ int64, periodsP, periodsQ []Period) (int64, for iP < lenP && iQ < lenQ { nextP := timeP + periodsP[iP].Length // next p event in absolute time nextQ := timeQ + periodsQ[iQ].Length // next q event in absolute time - if nextP < nextQ { + switch { + case nextP < nextQ: consumeP(nextP) - } else if nextP > nextQ { + case nextP > nextQ: consumeQ(nextQ) - } else { + default: consumeBoth(nextP) } } @@ -254,7 +255,7 @@ func ConjunctPeriods(startP, startQ int64, periodsP, periodsQ []Period) (startTi } // consumeBoth processes simultaneous events in P and Q and emits an - // event if the minumum of P and Q changes + // event if the minimum of P and Q changes consumeBoth := func(nextTime int64) { amountP = amountP.Add(periodsP[iP].Amount...) amountQ = amountQ.Add(periodsQ[iQ].Amount...) @@ -275,11 +276,12 @@ func ConjunctPeriods(startP, startQ int64, periodsP, periodsQ []Period) (startTi for iP < lenP && iQ < lenQ { nextP := timeP + periodsP[iP].Length // next p event in absolute time nextQ := timeQ + periodsQ[iQ].Length // next q event in absolute time - if nextP < nextQ { + switch { + case nextP < nextQ: consumeP(nextP) - } else if nextP > nextQ { + case nextP > nextQ: consumeQ(nextQ) - } else { + default: consumeBoth(nextP) } } @@ -297,7 +299,7 @@ func ConjunctPeriods(startP, startQ int64, periodsP, periodsQ []Period) (startTi } endTime = time - return + return startTime, endTime, merged } // AlignSchedules rewrites the first period length to align the two arguments to the same start time, diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index ac12810155e0..5d6de4de84c7 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -12,7 +12,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" ) @@ -617,8 +616,10 @@ func marshalYaml(i interface{}) (interface{}, error) { // Clawback Vesting Account -var _ vestexported.VestingAccount = (*ClawbackVestingAccount)(nil) -var _ authtypes.GenesisAccount = (*ClawbackVestingAccount)(nil) +var ( + _ vestexported.VestingAccount = (*ClawbackVestingAccount)(nil) + _ authtypes.GenesisAccount = (*ClawbackVestingAccount)(nil) +) // NewClawbackVestingAccount returns a new ClawbackVestingAccount func NewClawbackVestingAccount( @@ -702,7 +703,6 @@ func CoinEq(a, b sdk.Coins) bool { func (va ClawbackVestingAccount) Validate() error { if va.GetStartTime() >= va.GetEndTime() { return errors.New("vesting start-time must be before end-time") - } lockupEnd := va.GetStartTime() @@ -754,7 +754,7 @@ func NewClawbackGrantAction( grantStartTime int64, grantLockupPeriods, grantVestingPeriods []Period, grantCoins sdk.Coins, -) exported.AddGrantAction { +) vestexported.AddGrantAction { return clawbackGrantAction{ funderAddress: funderAddress, grantStartTime: grantStartTime, @@ -764,7 +764,7 @@ func NewClawbackGrantAction( } } -func (cga clawbackGrantAction) AddToAccount(ctx sdk.Context, rawAccount exported.VestingAccount) error { +func (cga clawbackGrantAction) AddToAccount(ctx sdk.Context, rawAccount vestexported.VestingAccount) error { cva, ok := rawAccount.(*ClawbackVestingAccount) if !ok { return fmt.Errorf("expected *ClawbackVestingAccount, got %T", rawAccount) @@ -778,10 +778,9 @@ func (cga clawbackGrantAction) AddToAccount(ctx sdk.Context, rawAccount exported } cva.addGrant(ctx, cga.grantStartTime, cga.grantLockupPeriods, cga.grantVestingPeriods, cga.grantCoins) return nil - } -func (va *ClawbackVestingAccount) AddGrant(ctx sdk.Context, action exported.AddGrantAction) error { +func (va *ClawbackVestingAccount) AddGrant(ctx sdk.Context, action vestexported.AddGrantAction) error { return action.AddToAccount(ctx, va) } @@ -865,7 +864,7 @@ type clawbackAction struct { bk BankKeeper } -func NewClawbackAction(requestor, dest sdk.AccAddress, ak AccountKeeper, bk BankKeeper) exported.ClawbackAction { +func NewClawbackAction(requestor, dest sdk.AccAddress, ak AccountKeeper, bk BankKeeper) vestexported.ClawbackAction { return clawbackAction{ requestor: requestor, dest: dest, @@ -874,7 +873,7 @@ func NewClawbackAction(requestor, dest sdk.AccAddress, ak AccountKeeper, bk Bank } } -func (ca clawbackAction) TakeFromAccount(ctx sdk.Context, rawAccount exported.VestingAccount) error { +func (ca clawbackAction) TakeFromAccount(ctx sdk.Context, rawAccount vestexported.VestingAccount) error { cva, ok := rawAccount.(*ClawbackVestingAccount) if !ok { return fmt.Errorf("clawback expects *ClawbackVestingAccount, got %T", rawAccount) @@ -885,7 +884,7 @@ func (ca clawbackAction) TakeFromAccount(ctx sdk.Context, rawAccount exported.Ve return cva.clawback(ctx, ca.dest, ca.ak, ca.bk) } -func (va *ClawbackVestingAccount) Clawback(ctx sdk.Context, action exported.ClawbackAction) error { +func (va *ClawbackVestingAccount) Clawback(ctx sdk.Context, action vestexported.ClawbackAction) error { return action.TakeFromAccount(ctx, va) } diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 7cfc9beb8eca..93f92fce87c8 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -250,42 +250,7 @@ func (k BaseKeeper) DenomOwners( if req == nil { return nil, status.Errorf(codes.InvalidArgument, "empty request") } - - if err := sdk.ValidateDenom(req.Denom); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - ctx := sdk.UnwrapSDKContext(goCtx) - denomPrefixStore := k.getDenomAddressPrefixStore(ctx, req.Denom) - - var denomOwners []*types.DenomOwner - pageRes, err := query.FilteredPaginate( - denomPrefixStore, - req.Pagination, - func(key []byte, _ []byte, accumulate bool) (bool, error) { - if accumulate { - address, _, err := types.AddressAndDenomFromBalancesStore(key) - if err != nil { - return false, err - } - - denomOwners = append( - denomOwners, - &types.DenomOwner{ - Address: address.String(), - Balance: k.GetBalance(ctx, address, req.Denom), - }, - ) - } - - return true, nil - }, - ) - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } - - return &types.QueryDenomOwnersResponse{DenomOwners: denomOwners, Pagination: pageRes}, nil + return nil, status.Error(codes.Unimplemented, "not implemented on Osmosis. Use an indexer.") } func (k BaseKeeper) SendEnabled(goCtx context.Context, req *types.QuerySendEnabledRequest) (*types.QuerySendEnabledResponse, error) { diff --git a/x/bank/keeper/grpc_query_test.go b/x/bank/keeper/grpc_query_test.go index 610bc356e5be..abd2fcbaaeb0 100644 --- a/x/bank/keeper/grpc_query_test.go +++ b/x/bank/keeper/grpc_query_test.go @@ -495,7 +495,7 @@ func (suite *KeeperTestSuite) TestGRPCDenomOwners() { req: &types.QueryDenomOwnersRequest{ Denom: "foo", }, - expPass: true, + expPass: false, numAddrs: 0, hasNext: false, total: 0, @@ -508,7 +508,7 @@ func (suite *KeeperTestSuite) TestGRPCDenomOwners() { CountTotal: true, }, }, - expPass: true, + expPass: false, numAddrs: 6, hasNext: true, total: 10, @@ -522,7 +522,7 @@ func (suite *KeeperTestSuite) TestGRPCDenomOwners() { CountTotal: true, }, }, - expPass: true, + expPass: false, numAddrs: 4, hasNext: false, total: 10, @@ -532,20 +532,8 @@ func (suite *KeeperTestSuite) TestGRPCDenomOwners() { for name, tc := range testCases { suite.Run(name, func() { resp, err := suite.queryClient.DenomOwners(gocontext.Background(), tc.req) - if tc.expPass { - suite.NoError(err) - suite.NotNil(resp) - suite.Len(resp.DenomOwners, tc.numAddrs) - suite.Equal(tc.total, resp.Pagination.Total) - - if tc.hasNext { - suite.NotNil(resp.Pagination.NextKey) - } else { - suite.Nil(resp.Pagination.NextKey) - } - } else { - suite.Require().Error(err) - } + suite.Require().Error(err) + suite.Require().Nil(resp) }) } diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 1d65538f3824..60b55cf89c74 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -31,8 +31,8 @@ type Keeper interface { HasSupply(ctx sdk.Context, denom string) bool GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) - GetSupplyOffset(ctx sdk.Context, denom string) sdk.Int - AddSupplyOffset(ctx sdk.Context, denom string, offsetAmount sdk.Int) + GetSupplyOffset(ctx sdk.Context, denom string) math.Int + AddSupplyOffset(ctx sdk.Context, denom string, offsetAmount math.Int) GetSupplyWithOffset(ctx sdk.Context, denom string) sdk.Coin GetPaginatedTotalSupplyWithOffsets(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) IterateTotalSupplyWithOffsets(ctx sdk.Context, cb func(sdk.Coin) bool) diff --git a/x/bank/keeper/send.go b/x/bank/keeper/send.go index fce3008aa8eb..c85b3036f7a7 100644 --- a/x/bank/keeper/send.go +++ b/x/bank/keeper/send.go @@ -368,7 +368,6 @@ func (k BaseSendKeeper) addCoinsImproved(ctx sdk.Context, addr sdk.AccAddress, a balance := k.GetBalance(ctx, addr, coin.Denom) newBalance := balance.Add(coin) - // err := k.setBalance(ctx, addr, balance, newBalance) err := k.setBalance(ctx, addr, newBalance) if err != nil { return err @@ -441,49 +440,8 @@ func (k BaseSendKeeper) initBalances(ctx sdk.Context, addr sdk.AccAddress, balan return nil } -// 2 blocks after osmosis first epoch -var osmosisFirstEpochHeight = int64(12834361) - -// Better add coins implementation for code that is not gas metered. Reduces I/O overhead. -// Used in osmosis epoch. -// Also removes event that should not exist. -// SDK should always use this for teh denom reverse map, but we can't edit right now as that would be a state break. -// Furthermore, this reverse map code should just get deleted. -func (k BaseSendKeeper) setBalanceImproved(ctx sdk.Context, addr sdk.AccAddress, oldBalance sdk.Coin, newBalance sdk.Coin) error { - if !newBalance.IsValid() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, oldBalance.String()) - } - - accountStore := k.getAccountStore(ctx, addr) - denomPrefixStore := k.getDenomAddressPrefixStore(ctx, oldBalance.Denom) - // x/bank invariants prohibit persistence of zero balances - if newBalance.IsZero() { - accountStore.Delete([]byte(newBalance.Denom)) - denomPrefixStore.Delete(address.MustLengthPrefix(addr)) - } else { - amount, err := newBalance.Amount.Marshal() - if err != nil { - return err - } - - accountStore.Set([]byte(newBalance.Denom), amount) - - mustSetDenom := oldBalance.IsZero() - if ctx.BlockHeight() <= osmosisFirstEpochHeight || newBalance.Denom != "uosmo" { - mustSetDenom = true - } - if mustSetDenom { - // Store a reverse index from denomination to account address with a - // sentinel value. - denomAddrKey := address.MustLengthPrefix(addr) - if !denomPrefixStore.Has(denomAddrKey) { - denomPrefixStore.Set(denomAddrKey, []byte{0}) - } - } - } - - return nil -} +// // 2 blocks after osmosis first epoch +// var osmosisFirstEpochHeight = int64(12834361) // setBalance sets the coin balance for an account by address. func (k BaseSendKeeper) setBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error { @@ -505,13 +463,7 @@ func (k BaseSendKeeper) setBalance(ctx sdk.Context, addr sdk.AccAddress, balance } accountStore.Set([]byte(balance.Denom), amount) - - // Store a reverse index from denomination to account address with a - // sentinel value. - denomAddrKey := address.MustLengthPrefix(addr) - if !denomPrefixStore.Has(denomAddrKey) { - denomPrefixStore.Set(denomAddrKey, []byte{0}) - } + // We deleted denomPrefixStore setting. } return nil diff --git a/x/bank/keeper/supply_offset.go b/x/bank/keeper/supply_offset.go index 81d3045f27b3..ddc0f389f2d2 100644 --- a/x/bank/keeper/supply_offset.go +++ b/x/bank/keeper/supply_offset.go @@ -3,6 +3,7 @@ package keeper import ( "fmt" + "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" @@ -10,7 +11,7 @@ import ( ) // GetSupplyOffset retrieves the SupplyOffset from store for a specific denom -func (k BaseViewKeeper) GetSupplyOffset(ctx sdk.Context, denom string) sdk.Int { +func (k BaseViewKeeper) GetSupplyOffset(ctx sdk.Context, denom string) math.Int { store := ctx.KVStore(k.storeKey) supplyOffsetStore := prefix.NewStore(store, types.SupplyOffsetKey) @@ -19,7 +20,7 @@ func (k BaseViewKeeper) GetSupplyOffset(ctx sdk.Context, denom string) sdk.Int { return sdk.NewInt(0) } - var amount sdk.Int + var amount math.Int err := amount.Unmarshal(bz) if err != nil { panic(fmt.Errorf("unable to unmarshal supply offset value %v", err)) @@ -29,7 +30,7 @@ func (k BaseViewKeeper) GetSupplyOffset(ctx sdk.Context, denom string) sdk.Int { } // setSupplyOffset sets the supply offset for the given denom -func (k BaseKeeper) setSupplyOffset(ctx sdk.Context, denom string, offsetAmount sdk.Int) { +func (k BaseKeeper) setSupplyOffset(ctx sdk.Context, denom string, offsetAmount math.Int) { intBytes, err := offsetAmount.Marshal() if err != nil { panic(fmt.Errorf("unable to marshal amount value %v", err)) @@ -47,7 +48,7 @@ func (k BaseKeeper) setSupplyOffset(ctx sdk.Context, denom string, offsetAmount } // AddSupplyOffset adjusts the current supply offset of a denom by the inputted offsetAmount -func (k BaseKeeper) AddSupplyOffset(ctx sdk.Context, denom string, offsetAmount sdk.Int) { +func (k BaseKeeper) AddSupplyOffset(ctx sdk.Context, denom string, offsetAmount math.Int) { k.setSupplyOffset(ctx, denom, k.GetSupplyOffset(ctx, denom).Add(offsetAmount)) } @@ -75,7 +76,7 @@ func (k BaseKeeper) GetPaginatedTotalSupplyWithOffsets(ctx sdk.Context, paginati pageRes, err := query.Paginate(supplyStore, pagination, func(key, value []byte) error { denom := string(key) - var amount sdk.Int + var amount math.Int err := amount.Unmarshal(value) if err != nil { return fmt.Errorf("unable to convert amount string to Int %v", err) @@ -87,7 +88,6 @@ func (k BaseKeeper) GetPaginatedTotalSupplyWithOffsets(ctx sdk.Context, paginati supply = supply.Add(sdk.NewCoin(denom, amount)) return nil }) - if err != nil { return nil, nil, err } @@ -106,7 +106,7 @@ func (k BaseViewKeeper) IterateTotalSupplyWithOffsets(ctx sdk.Context, cb func(s defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - var amount sdk.Int + var amount math.Int err := amount.Unmarshal(iterator.Value()) if err != nil { panic(fmt.Errorf("unable to unmarshal supply value %v", err)) diff --git a/x/bank/migrations/v3/store_test.go b/x/bank/migrations/v3/store_test.go index 52e9efdcd324..51ff85067895 100644 --- a/x/bank/migrations/v3/store_test.go +++ b/x/bank/migrations/v3/store_test.go @@ -5,12 +5,9 @@ import ( "github.com/stretchr/testify/require" - "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" v2 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v2" v3 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v3" @@ -40,19 +37,19 @@ func TestMigrateStore(t *testing.T) { require.NoError(t, v3.MigrateStore(ctx, bankKey, encCfg.Codec)) - for _, b := range balances { - addrPrefixStore := prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) - bz := addrPrefixStore.Get([]byte(b.Denom)) - var expected math.Int - require.NoError(t, expected.Unmarshal(bz)) - require.Equal(t, expected, b.Amount) - } - - for _, b := range balances { - denomPrefixStore := prefix.NewStore(store, v3.CreateDenomAddressPrefix(b.Denom)) - bz := denomPrefixStore.Get(address.MustLengthPrefix(addr)) - require.NotNil(t, bz) - } + // for _, b := range balances { + // addrPrefixStore := prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) + // bz := addrPrefixStore.Get([]byte(b.Denom)) + // var expected math.Int + // require.NoError(t, expected.Unmarshal(bz)) + // require.Equal(t, expected, b.Amount) + // } + + // for _, b := range balances { + // denomPrefixStore := prefix.NewStore(store, v3.CreateDenomAddressPrefix(b.Denom)) + // bz := denomPrefixStore.Get(address.MustLengthPrefix(addr)) + // require.NotNil(t, bz) + // } } func TestMigrateDenomMetaData(t *testing.T) { diff --git a/x/feegrant/keeper/keeper.go b/x/feegrant/keeper/keeper.go index bb36f9c7964f..4510218cc6bb 100644 --- a/x/feegrant/keeper/keeper.go +++ b/x/feegrant/keeper/keeper.go @@ -323,17 +323,25 @@ func (k Keeper) addToFeeAllowanceQueue(ctx sdk.Context, grantKey []byte, exp *ti store.Set(feegrant.FeeAllowancePrefixQueue(exp, grantKey), []byte{}) } +// NOTE: backport from v50 // RemoveExpiredAllowances iterates grantsByExpiryQueue and deletes the expired grants. -func (k Keeper) RemoveExpiredAllowances(ctx sdk.Context) { +func (k Keeper) RemoveExpiredAllowances(ctx sdk.Context, limit int) { exp := ctx.BlockTime() store := ctx.KVStore(k.storeKey) iterator := store.Iterator(feegrant.FeeAllowanceQueueKeyPrefix, sdk.InclusiveEndBytes(feegrant.AllowanceByExpTimeKey(&exp))) defer iterator.Close() + count := 0 for ; iterator.Valid(); iterator.Next() { store.Delete(iterator.Key()) granter, grantee := feegrant.ParseAddressesFromFeeAllowanceQueueKey(iterator.Key()) store.Delete(feegrant.FeeAllowanceKey(granter, grantee)) + + // limit the amount of iterations to avoid taking too much time + count++ + if count == limit { + break + } } } diff --git a/x/feegrant/keeper/keeper_test.go b/x/feegrant/keeper/keeper_test.go index 16d10a532cd6..348c6326bdf5 100644 --- a/x/feegrant/keeper/keeper_test.go +++ b/x/feegrant/keeper/keeper_test.go @@ -33,7 +33,7 @@ func TestKeeperTestSuite(t *testing.T) { } func (suite *KeeperTestSuite) SetupTest() { - suite.addrs = simtestutil.CreateIncrementalAccounts(4) + suite.addrs = simtestutil.CreateIncrementalAccounts(20) key := sdk.NewKVStoreKey(feegrant.StoreKey) testCtx := testutil.DefaultContextWithDB(suite.T(), key, sdk.NewTransientStoreKey("transient_test")) encCfg := moduletestutil.MakeTestEncodingConfig(module.AppModuleBasic{}) @@ -41,10 +41,9 @@ func (suite *KeeperTestSuite) SetupTest() { // setup gomock and initialize some globally expected executions ctrl := gomock.NewController(suite.T()) suite.accountKeeper = feegranttestutil.NewMockAccountKeeper(ctrl) - suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), suite.addrs[0]).Return(authtypes.NewBaseAccountWithAddress(suite.addrs[0])).AnyTimes() - suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), suite.addrs[1]).Return(authtypes.NewBaseAccountWithAddress(suite.addrs[1])).AnyTimes() - suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), suite.addrs[2]).Return(authtypes.NewBaseAccountWithAddress(suite.addrs[2])).AnyTimes() - suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), suite.addrs[3]).Return(authtypes.NewBaseAccountWithAddress(suite.addrs[3])).AnyTimes() + for i := 0; i < len(suite.addrs); i++ { + suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), suite.addrs[i]).Return(authtypes.NewBaseAccountWithAddress(suite.addrs[i])).AnyTimes() + } suite.feegrantKeeper = keeper.NewKeeper(encCfg.Codec, key, suite.accountKeeper) suite.ctx = testCtx.Ctx @@ -447,7 +446,7 @@ func (suite *KeeperTestSuite) TestPruneGrants() { } err := suite.feegrantKeeper.GrantAllowance(suite.ctx, tc.granter, tc.grantee, tc.allowance) suite.NoError(err) - suite.feegrantKeeper.RemoveExpiredAllowances(tc.ctx) + suite.feegrantKeeper.RemoveExpiredAllowances(tc.ctx, 5) grant, err := suite.feegrantKeeper.GetAllowance(tc.ctx, tc.granter, tc.grantee) if tc.expErrMsg != "" { suite.Error(err) @@ -461,3 +460,38 @@ func (suite *KeeperTestSuite) TestPruneGrants() { }) } } + +func (suite *KeeperTestSuite) TestPruneGrantsEdgecases() { + eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) + now := suite.ctx.BlockTime() + oneYearExpiry := now.AddDate(1, 0, 0) + + granter := suite.addrs[1] + grantee1 := suite.addrs[2] + err := suite.feegrantKeeper.GrantAllowance(suite.ctx, granter, grantee1, &feegrant.BasicAllowance{ + SpendLimit: eth, + Expiration: &oneYearExpiry, + }) + suite.NoError(err) + + grantee2 := suite.addrs[3] + err = suite.feegrantKeeper.GrantAllowance(suite.ctx, granter, grantee2, &feegrant.BasicAllowance{ + SpendLimit: eth, + Expiration: &now, + }) + suite.NoError(err) + + // expect 2 active grants + grantsBeforePrune, err := suite.feegrantKeeper.AllowancesByGranter(suite.ctx, &feegrant.QueryAllowancesByGranterRequest{Granter: granter.String()}) + suite.NoError(err) + suite.Len(grantsBeforePrune.Allowances, 2) + + // use blocktime that would result in both grants being expired + expireCtx := suite.ctx.WithBlockTime(now.AddDate(1, 0, 1)) + + // expect 1 grant to be removed due to the imposed limit + suite.feegrantKeeper.RemoveExpiredAllowances(expireCtx, 1) + grantsAfterPrune, err := suite.feegrantKeeper.AllowancesByGranter(suite.ctx, &feegrant.QueryAllowancesByGranterRequest{Granter: granter.String()}) + suite.NoError(err) + suite.Len(grantsAfterPrune.Allowances, 1) +} diff --git a/x/feegrant/module/abci.go b/x/feegrant/module/abci.go index 34c19c528d6a..e6577806080e 100644 --- a/x/feegrant/module/abci.go +++ b/x/feegrant/module/abci.go @@ -6,5 +6,5 @@ import ( ) func EndBlocker(ctx sdk.Context, k keeper.Keeper) { - k.RemoveExpiredAllowances(ctx) + k.RemoveExpiredAllowances(ctx, 200) } diff --git a/x/slashing/keeper/params.go b/x/slashing/keeper/params.go index 4c7fc1824694..b21a4f5a84c8 100644 --- a/x/slashing/keeper/params.go +++ b/x/slashing/keeper/params.go @@ -15,7 +15,7 @@ func (k Keeper) SignedBlocksWindow(ctx sdk.Context) (res int64) { // MinSignedPerWindow - minimum blocks signed per window func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 { params := k.GetParams(ctx) - signedBlocksWindow := k.SignedBlocksWindow(ctx) + signedBlocksWindow := params.SignedBlocksWindow // NOTE: RoundInt64 will never panic as minSignedPerWindow is // less than 1. diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 42af9e04f41b..d4e468db9224 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -847,7 +847,6 @@ func (k Keeper) Undelegate( func (k Keeper) InstantUndelegate( ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec, ) (sdk.Coins, error) { - validator, found := k.GetValidator(ctx, valAddr) if !found { return nil, types.ErrNoDelegatorForAddress @@ -872,7 +871,6 @@ func (k Keeper) InstantUndelegate( return nil, err } return res, nil - } // CompleteUnbonding completes the unbonding of all mature entries in the