diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e6c6f4ee640c..d2a99a8f0523 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,8 +50,8 @@ jobs: ################### - name: Build run: GOARCH=${{ matrix.go-arch }} make build - - name: Build Legacy - run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS=legacy make build + - name: Build v2 + run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS=v2 make build - name: Build with rocksdb backend if: matrix.go-arch == 'amd64' run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS="rocksdb" make build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4990e889c330..19f27d25d952 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -526,11 +526,6 @@ jobs: run: | cd simapp go test -mod=readonly -timeout 30m -tags='norace ledger test_ledger_mock' ./... - - name: tests simapp v1 - if: env.GIT_DIFF - run: | - cd simapp - go test -mod=readonly -timeout 30m -tags='app_v1 norace ledger test_ledger_mock' ./... test-simapp-v2: runs-on: ubuntu-latest diff --git a/math/CHANGELOG.md b/math/CHANGELOG.md index 7ccd0e252390..1e9d08c3ada6 100644 --- a/math/CHANGELOG.md +++ b/math/CHANGELOG.md @@ -36,6 +36,9 @@ Ref: https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.j ## [Unreleased] +* [#11783](https://github.com/cosmos/cosmos-sdk/issues/11783) feat(math): Upstream GDA based decimal type + + ## [math/v1.4.0](https://github.com/cosmos/cosmos-sdk/releases/tag/math/v1.4.0) - 2024-01-20 ### Features diff --git a/math/dec.go b/math/dec.go index 3f96345e249b..4935fb2eb9a3 100644 --- a/math/dec.go +++ b/math/dec.go @@ -4,6 +4,7 @@ import ( "encoding/json" stderrors "errors" "math/big" + "strconv" "github.com/cockroachdb/apd/v3" @@ -299,7 +300,7 @@ func (x Dec) Int64() (int64, error) { // fit precisely into an *big.Int. func (x Dec) BigInt() (*big.Int, error) { y, _ := x.Reduce() - z, ok := new(big.Int).SetString(y.String(), 10) + z, ok := new(big.Int).SetString(y.Text('f'), 10) if !ok { return nil, ErrNonIntegral } @@ -334,7 +335,7 @@ func (x Dec) SdkIntTrim() (Int, error) { // String formatted in decimal notation: '-ddddd.dddd', no exponent func (x Dec) String() string { - return x.dec.Text('f') + return string(fmtE(x.dec, 'E')) } // Text converts the floating-point number x to a string according @@ -407,14 +408,81 @@ func (x Dec) Reduce() (Dec, int) { return y, n } +// Marshal serializes the decimal value into a byte slice in text format. +// This method represents the decimal in a portable and compact hybrid notation. +// Based on the exponent value, the number is formatted into decimal: -ddddd.ddddd, no exponent +// or scientific notation: -d.ddddE±dd +// +// For example, the following transformations are made: +// - 0 -> 0 +// - 123 -> 123 +// - 10000 -> 10000 +// - -0.001 -> -0.001 +// - -0.000000001 -> -1E-9 +// +// Returns: +// - A byte slice of the decimal in text format. +// - An error if the decimal cannot be reduced or marshaled properly. func (x Dec) Marshal() ([]byte, error) { - // implemented in a new PR. See: https://github.com/cosmos/cosmos-sdk/issues/22525 - panic("not implemented") + var d apd.Decimal + if _, _, err := dec128Context.Reduce(&d, &x.dec); err != nil { + return nil, ErrInvalidDec.Wrap(err.Error()) + } + return fmtE(d, 'E'), nil +} + +// fmtE formats a decimal number into a byte slice in scientific notation or fixed-point notation depending on the exponent. +// If the adjusted exponent is between -6 and 6 inclusive, it uses fixed-point notation, otherwise it uses scientific notation. +func fmtE(d apd.Decimal, fmt byte) []byte { + var scratch, dest [16]byte + buf := dest[:0] + digits := d.Coeff.Append(scratch[:0], 10) + totalDigits := int64(len(digits)) + adj := int64(d.Exponent) + totalDigits - 1 + if adj > -6 && adj < 6 { + return []byte(d.Text('f')) + } + switch { + case totalDigits > 5: + beforeComma := digits[0 : totalDigits-6] + adj -= int64(len(beforeComma) - 1) + buf = append(buf, beforeComma...) + buf = append(buf, '.') + buf = append(buf, digits[totalDigits-6:]...) + case totalDigits > 1: + buf = append(buf, digits[0]) + buf = append(buf, '.') + buf = append(buf, digits[1:]...) + default: + buf = append(buf, digits[0:]...) + } + + buf = append(buf, fmt) + var ch byte + if adj < 0 { + ch = '-' + adj = -adj + } else { + ch = '+' + } + buf = append(buf, ch) + return strconv.AppendInt(buf, adj, 10) } +// Unmarshal parses a byte slice containing a text-formatted decimal and stores the result in the receiver. +// It returns an error if the byte slice does not represent a valid decimal. func (x *Dec) Unmarshal(data []byte) error { - // implemented in a new PR. See: https://github.com/cosmos/cosmos-sdk/issues/22525 - panic("not implemented") + result, err := NewDecFromString(string(data)) + if err != nil { + return ErrInvalidDec.Wrap(err.Error()) + } + + if result.dec.Form != apd.Finite { + return ErrInvalidDec.Wrap("unknown decimal form") + } + + x.dec = result.dec + return nil } // MarshalTo encodes the receiver into the provided byte slice and returns the number of bytes written and any error encountered. @@ -435,7 +503,7 @@ func (x Dec) Size() int { // MarshalJSON serializes the Dec struct into a JSON-encoded byte slice using scientific notation. func (x Dec) MarshalJSON() ([]byte, error) { - return json.Marshal(x.dec.Text('E')) + return json.Marshal(fmtE(x.dec, 'E')) } // UnmarshalJSON implements the json.Unmarshaler interface for the Dec type, converting JSON strings to Dec objects. diff --git a/math/dec_examples_test.go b/math/dec_examples_test.go index 5c2dc8a021ed..c2cf3f5a836f 100644 --- a/math/dec_examples_test.go +++ b/math/dec_examples_test.go @@ -308,7 +308,7 @@ func ExampleDec_MulExact() { // 2.50 // exponent out of range: invalid decimal // unexpected rounding - // 0.00000000000000000000000000000000000 + // 0E-35 // 0 } diff --git a/math/dec_test.go b/math/dec_test.go index ef4c9fbd5de3..0b148032eb1f 100644 --- a/math/dec_test.go +++ b/math/dec_test.go @@ -3,7 +3,6 @@ package math import ( "fmt" "math" - "strconv" "strings" "testing" @@ -152,11 +151,11 @@ func TestNewDecFromInt64(t *testing.T) { }, "max value": { src: math.MaxInt64, - exp: strconv.Itoa(math.MaxInt64), + exp: "9223372036854.775807E+6", }, "min value": { src: math.MinInt64, - exp: strconv.Itoa(math.MinInt64), + exp: "9223372036854.775808E+6", }, } for name, spec := range specs { @@ -1247,15 +1246,17 @@ func TestToBigInt(t *testing.T) { {"12345.6", "", ErrNonIntegral}, } for idx, tc := range tcs { - a, err := NewDecFromString(tc.intStr) - require.NoError(t, err) - b, err := a.BigInt() - if tc.isError == nil { - require.NoError(t, err, "test_%d", idx) - require.Equal(t, tc.out, b.String(), "test_%d", idx) - } else { - require.ErrorIs(t, err, tc.isError, "test_%d", idx) - } + t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) { + a, err := NewDecFromString(tc.intStr) + require.NoError(t, err) + b, err := a.BigInt() + if tc.isError == nil { + require.NoError(t, err, "test_%d", idx) + require.Equal(t, tc.out, b.String(), "test_%d", idx) + } else { + require.ErrorIs(t, err, tc.isError, "test_%d", idx) + } + }) } } @@ -1281,7 +1282,7 @@ func TestToSdkInt(t *testing.T) { {src: "1E100000", expErr: true}, } for _, tc := range tcs { - t.Run(fmt.Sprintf(tc.src), func(t *testing.T) { + t.Run(fmt.Sprint(tc.src), func(t *testing.T) { a, err := NewDecFromString(tc.src) require.NoError(t, err) b, gotErr := a.SdkIntTrim() @@ -1309,55 +1310,38 @@ func must[T any](r T, err error) T { } func TestMarshalUnmarshal(t *testing.T) { - t.Skip("not supported, yet") specs := map[string]struct { x Dec exp string expErr error }{ - "No trailing zeros": { - x: NewDecFromInt64(123456), - exp: "1.23456E+5", - }, - "Trailing zeros": { - x: NewDecFromInt64(123456000), - exp: "1.23456E+8", - }, "Zero value": { x: NewDecFromInt64(0), - exp: "0E+0", + exp: "0", }, "-0": { x: NewDecFromInt64(-0), - exp: "0E+0", - }, - "Decimal value": { - x: must(NewDecFromString("1.30000")), - exp: "1.3E+0", - }, - "Positive value": { - x: NewDecFromInt64(10), - exp: "1E+1", + exp: "0", }, - "negative 10": { - x: NewDecFromInt64(-10), - exp: "-1E+1", + "1 decimal place": { + x: must(NewDecFromString("0.1")), + exp: "0.1", }, - "9 with trailing zeros": { - x: must(NewDecFromString("9." + strings.Repeat("0", 34))), - exp: "9E+0", + "2 decimal places": { + x: must(NewDecFromString("0.01")), + exp: "0.01", }, - "negative 1 with negative exponent zeros": { - x: must(NewDecFromString("-1.000001")), - exp: "-1.000001E+0", + "3 decimal places": { + x: must(NewDecFromString("0.001")), + exp: "0.001", }, - "negative 1 with trailing zeros": { - x: must(NewDecFromString("-1." + strings.Repeat("0", 34))), - exp: "-1E+0", + "4 decimal places": { + x: must(NewDecFromString("0.0001")), + exp: "0.0001", }, "5 decimal places": { x: must(NewDecFromString("0.00001")), - exp: "1E-5", + exp: "0.00001", }, "6 decimal places": { x: must(NewDecFromString("0.000001")), @@ -1367,17 +1351,73 @@ func TestMarshalUnmarshal(t *testing.T) { x: must(NewDecFromString("0.0000001")), exp: "1E-7", }, + "1": { + x: must(NewDecFromString("1")), + exp: "1", + }, + "12": { + x: must(NewDecFromString("12")), + exp: "12", + }, + "123": { + x: must(NewDecFromString("123")), + exp: "123", + }, + "1234": { + x: must(NewDecFromString("1234")), + exp: "1234", + }, + "12345": { + x: must(NewDecFromString("12345")), + exp: "12345", + }, + "123456": { + x: must(NewDecFromString("123456")), + exp: "123456", + }, + "1234567": { + x: must(NewDecFromString("1234567")), + exp: "1.234567E+6", + }, + "12345678": { + x: must(NewDecFromString("12345678")), + exp: "12.345678E+6", + }, + "123456789": { + x: must(NewDecFromString("123456789")), + exp: "123.456789E+6", + }, + "1234567890": { + x: must(NewDecFromString("1234567890")), + exp: "123.456789E+7", + }, + "12345678900": { + x: must(NewDecFromString("12345678900")), + exp: "123.456789E+8", + }, + "negative 1 with negative exponent": { + x: must(NewDecFromString("-1.000001")), + exp: "-1.000001", + }, + "-1.0000001 - negative 1 with negative exponent": { + x: must(NewDecFromString("-1.0000001")), + exp: "-1.0000001", + }, + "3 decimal places before the comma": { + x: must(NewDecFromString("100")), + exp: "100", + }, "4 decimal places before the comma": { x: must(NewDecFromString("1000")), - exp: "1E+3", + exp: "1000", }, "5 decimal places before the comma": { x: must(NewDecFromString("10000")), - exp: "1E+4", + exp: "10000", }, "6 decimal places before the comma": { x: must(NewDecFromString("100000")), - exp: "1E+5", + exp: "100000", }, "7 decimal places before the comma": { x: must(NewDecFromString("1000000")), @@ -1388,12 +1428,12 @@ func TestMarshalUnmarshal(t *testing.T) { exp: "1E+100000", }, "1.1e100000": { - x: NewDecWithExp(11, 100_000), - expErr: ErrInvalidDec, + x: must(NewDecFromString("1.1e100000")), + exp: "1.1E+100000", }, - "1.e100000": { - x: NewDecWithExp(1, 100_000), - exp: "1E+100000", + "1e100001": { + x: NewDecWithExp(1, 100_001), + expErr: ErrInvalidDec, }, } for name, spec := range specs { @@ -1404,9 +1444,12 @@ func TestMarshalUnmarshal(t *testing.T) { return } require.NoError(t, gotErr) - unmarshalled := new(Dec) - require.NoError(t, unmarshalled.Unmarshal(marshaled)) - assert.Equal(t, spec.exp, unmarshalled.dec.Text('E')) + assert.Equal(t, spec.exp, string(marshaled)) + // and backwards + unmarshalledDec := new(Dec) + require.NoError(t, unmarshalledDec.Unmarshal(marshaled)) + assert.Equal(t, spec.exp, unmarshalledDec.String()) + assert.True(t, spec.x.Equal(*unmarshalledDec)) }) } } diff --git a/schema/indexer/start.go b/schema/indexer/start.go index f675c2916026..66fbdb52a6d3 100644 --- a/schema/indexer/start.go +++ b/schema/indexer/start.go @@ -120,7 +120,7 @@ func StartIndexing(opts IndexingOptions) (IndexingTarget, error) { targetCfg.Config, err = unmarshalIndexerCustomConfig(targetCfg.Config, init.ConfigType) if err != nil { - return IndexingTarget{}, fmt.Errorf("failed to unmarshal indexer config for target %q: %v", targetName, err) + return IndexingTarget{}, fmt.Errorf("failed to unmarshal indexer config for target %q: %v", targetName, err) //nolint:errorlint // we support go 1.12, so no error wrapping } initRes, err := init.InitFunc(InitParams{ diff --git a/scripts/build/build.mk b/scripts/build/build.mk index 4727b05e98a3..581ee1dbe06d 100644 --- a/scripts/build/build.mk +++ b/scripts/build/build.mk @@ -48,10 +48,6 @@ ifeq (secp,$(findstring secp,$(COSMOS_BUILD_OPTIONS))) build_tags += libsecp256k1_sdk endif -ifeq (legacy,$(findstring legacy,$(COSMOS_BUILD_OPTIONS))) - build_tags += app_v1 -endif - ifeq (v2,$(findstring v2,$(COSMOS_BUILD_OPTIONS))) SIMAPP = simapp/v2 APPNAME = simdv2 diff --git a/scripts/go-lint-all.bash b/scripts/go-lint-all.bash index 565aa6a41649..f643cc56aa46 100755 --- a/scripts/go-lint-all.bash +++ b/scripts/go-lint-all.bash @@ -21,11 +21,6 @@ lint_module() { fi echo "linting $(grep "^module" go.mod) [$(date -Iseconds -u)]" golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --build-tags=${LINT_TAGS} - - # always lint simapp with app_v1 build tag, otherwise it never gets linted - if [[ "$(grep "^module" go.mod)" == "module cosmossdk.io/simapp" ]]; then - golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --build-tags=app_v1 - fi } export -f lint_module diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index b31bd33db977..19f7eaae545c 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -230,7 +230,7 @@ func (a appManager[T]) Query(ctx context.Context, version uint64, request transa _, queryState, err = a.db.StateLatest() } if err != nil { - return nil, err + return nil, fmt.Errorf("invalid height: %w", err) } return a.stf.Query(ctx, queryState, a.config.QueryGasLimit, request) } diff --git a/server/v2/cometbft/abci_test.go b/server/v2/cometbft/abci_test.go index cfc649884660..17ff917c6511 100644 --- a/server/v2/cometbft/abci_test.go +++ b/server/v2/cometbft/abci_test.go @@ -15,7 +15,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" abciproto "github.com/cometbft/cometbft/api/cometbft/abci/v1" v1 "github.com/cometbft/cometbft/api/cometbft/types/v1" - "github.com/cosmos/gogoproto/proto" gogoproto "github.com/cosmos/gogoproto/proto" gogotypes "github.com/cosmos/gogoproto/types" "github.com/stretchr/testify/require" @@ -65,11 +64,11 @@ var ( func getQueryRouterBuilder[T any, PT interface { *T - proto.Message + gogoproto.Message }, U any, UT interface { *U - proto.Message + gogoproto.Message }]( t *testing.T, handler func(ctx context.Context, msg PT) (UT, error), @@ -77,7 +76,7 @@ func getQueryRouterBuilder[T any, PT interface { t.Helper() queryRouterBuilder := stf.NewMsgRouterBuilder() err := queryRouterBuilder.RegisterHandler( - proto.MessageName(PT(new(T))), + gogoproto.MessageName(PT(new(T))), func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) { typedReq := msg.(PT) typedResp, err := handler(ctx, typedReq) @@ -107,7 +106,7 @@ func getMsgRouterBuilder[T any, PT interface { t.Helper() msgRouterBuilder := stf.NewMsgRouterBuilder() err := msgRouterBuilder.RegisterHandler( - proto.MessageName(PT(new(T))), + gogoproto.MessageName(PT(new(T))), func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) { typedReq := msg.(PT) typedResp, err := handler(ctx, typedReq) @@ -821,18 +820,18 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock. return typedResp, nil } - queryRouterBuilder.RegisterHandler( - proto.MessageName(&testdata.SayHelloRequest{}), + _ = queryRouterBuilder.RegisterHandler( + gogoproto.MessageName(&testdata.SayHelloRequest{}), helloFooHandler, ) - queryHandler[proto.MessageName(&testdata.SayHelloRequest{})] = appmodulev2.Handler{ + queryHandler[gogoproto.MessageName(&testdata.SayHelloRequest{})] = appmodulev2.Handler{ Func: helloFooHandler, MakeMsg: func() transaction.Msg { - return reflect.New(gogoproto.MessageType(proto.MessageName(&testdata.SayHelloRequest{})).Elem()).Interface().(transaction.Msg) + return reflect.New(gogoproto.MessageType(gogoproto.MessageName(&testdata.SayHelloRequest{})).Elem()).Interface().(transaction.Msg) }, MakeMsgResp: func() transaction.Msg { - return reflect.New(gogoproto.MessageType(proto.MessageName(&testdata.SayHelloResponse{})).Elem()).Interface().(transaction.Msg) + return reflect.New(gogoproto.MessageType(gogoproto.MessageName(&testdata.SayHelloResponse{})).Elem()).Interface().(transaction.Msg) }, } @@ -895,7 +894,7 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock. cfg: Config{AppTomlConfig: DefaultAppTomlConfig()}, txCodec: mock.TxCodec{}, chainID: "test", - getProtoRegistry: sync.OnceValues(proto.MergedRegistry), + getProtoRegistry: sync.OnceValues(gogoproto.MergedRegistry), queryHandlersMap: queryHandler, addrPeerFilter: addrPeerFilter, idPeerFilter: idPeerFilter, diff --git a/server/v2/testdata/app.toml b/server/v2/testdata/app.toml index 3f0e640a8c3e..be2f82566692 100644 --- a/server/v2/testdata/app.toml +++ b/server/v2/testdata/app.toml @@ -30,13 +30,6 @@ ss-type = 'pebble' # State commitment database type. Currently we support: "iavl" and "iavl-v2" sc-type = 'iavl' -# Pruning options for state storage -[store.options.ss-pruning-option] -# Number of recent heights to keep on disk. -keep-recent = 2 -# Height interval at which pruned heights are removed from disk. -interval = 100 - # Pruning options for state commitment [store.options.sc-pruning-option] # Number of recent heights to keep on disk. diff --git a/simapp/CHANGELOG.md b/simapp/CHANGELOG.md index edc90c22cf89..55861fab0d3d 100644 --- a/simapp/CHANGELOG.md +++ b/simapp/CHANGELOG.md @@ -47,7 +47,7 @@ Always refer to the [UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/mai * [#19726](https://github.com/cosmos/cosmos-sdk/pull/19726) Update APIs to match CometBFT v1. * [#21466](https://github.com/cosmos/cosmos-sdk/pull/21466) Allow chains to plug in their own public key types in `base.Account` * [#21508](https://github.com/cosmos/cosmos-sdk/pull/21508) Abstract the way we update the version of the app state in `app.go` using the interface `VersionModifier`. - + ## v0.47 to v0.50 diff --git a/simapp/app.go b/simapp/app.go deleted file mode 100644 index 7417205250c0..000000000000 --- a/simapp/app.go +++ /dev/null @@ -1,890 +0,0 @@ -//go:build app_v1 - -package simapp - -import ( - "encoding/json" - "fmt" - "io" - "maps" - "os" - "path/filepath" - - abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" - cmtcrypto "github.com/cometbft/cometbft/crypto" - cmted25519 "github.com/cometbft/cometbft/crypto/ed25519" - "github.com/cosmos/gogoproto/proto" - "github.com/spf13/cast" - - autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" - reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - "cosmossdk.io/client/v2/autocli" - clienthelpers "cosmossdk.io/client/v2/helpers" - coreaddress "cosmossdk.io/core/address" - corestore "cosmossdk.io/core/store" - "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/accounts" - "cosmossdk.io/x/accounts/accountstd" - baseaccount "cosmossdk.io/x/accounts/defaults/base" - lockup "cosmossdk.io/x/accounts/defaults/lockup" - "cosmossdk.io/x/accounts/defaults/multisig" - "cosmossdk.io/x/accounts/testing/account_abstraction" - "cosmossdk.io/x/accounts/testing/counter" - "cosmossdk.io/x/authz" - authzkeeper "cosmossdk.io/x/authz/keeper" - authzmodule "cosmossdk.io/x/authz/module" - "cosmossdk.io/x/bank" - bankkeeper "cosmossdk.io/x/bank/keeper" - banktypes "cosmossdk.io/x/bank/types" - "cosmossdk.io/x/circuit" - circuitkeeper "cosmossdk.io/x/circuit/keeper" - circuittypes "cosmossdk.io/x/circuit/types" - "cosmossdk.io/x/consensus" - consensusparamkeeper "cosmossdk.io/x/consensus/keeper" - consensustypes "cosmossdk.io/x/consensus/types" - distr "cosmossdk.io/x/distribution" - distrkeeper "cosmossdk.io/x/distribution/keeper" - distrtypes "cosmossdk.io/x/distribution/types" - "cosmossdk.io/x/epochs" - epochskeeper "cosmossdk.io/x/epochs/keeper" - epochstypes "cosmossdk.io/x/epochs/types" - "cosmossdk.io/x/evidence" - evidencekeeper "cosmossdk.io/x/evidence/keeper" - evidencetypes "cosmossdk.io/x/evidence/types" - "cosmossdk.io/x/feegrant" - feegrantkeeper "cosmossdk.io/x/feegrant/keeper" - feegrantmodule "cosmossdk.io/x/feegrant/module" - "cosmossdk.io/x/gov" - govkeeper "cosmossdk.io/x/gov/keeper" - govtypes "cosmossdk.io/x/gov/types" - govv1 "cosmossdk.io/x/gov/types/v1" - govv1beta1 "cosmossdk.io/x/gov/types/v1beta1" - "cosmossdk.io/x/group" - groupkeeper "cosmossdk.io/x/group/keeper" - groupmodule "cosmossdk.io/x/group/module" - "cosmossdk.io/x/mint" - mintkeeper "cosmossdk.io/x/mint/keeper" - minttypes "cosmossdk.io/x/mint/types" - "cosmossdk.io/x/nft" - nftkeeper "cosmossdk.io/x/nft/keeper" - nftmodule "cosmossdk.io/x/nft/module" - "cosmossdk.io/x/protocolpool" - poolkeeper "cosmossdk.io/x/protocolpool/keeper" - pooltypes "cosmossdk.io/x/protocolpool/types" - "cosmossdk.io/x/slashing" - slashingkeeper "cosmossdk.io/x/slashing/keeper" - slashingtypes "cosmossdk.io/x/slashing/types" - "cosmossdk.io/x/staking" - stakingkeeper "cosmossdk.io/x/staking/keeper" - stakingtypes "cosmossdk.io/x/staking/types" - txdecode "cosmossdk.io/x/tx/decode" - "cosmossdk.io/x/tx/signing" - "cosmossdk.io/x/upgrade" - upgradekeeper "cosmossdk.io/x/upgrade/keeper" - upgradetypes "cosmossdk.io/x/upgrade/types" - - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" - nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/runtime" - runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" - "github.com/cosmos/cosmos-sdk/server" - "github.com/cosmos/cosmos-sdk/server/api" - "github.com/cosmos/cosmos-sdk/server/config" - servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/std" - testdata_pulsar "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/types/msgservice" - sigtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" - "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx" - authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/cosmos/cosmos-sdk/x/auth/posthandler" - authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" - authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" - vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" -) - -const appName = "SimApp" - -var ( - // DefaultNodeHome default home directories for the application daemon - DefaultNodeHome string - - // module account permissions - maccPerms = map[string][]string{ - authtypes.FeeCollectorName: nil, - distrtypes.ModuleName: nil, - pooltypes.ModuleName: nil, - pooltypes.StreamAccount: nil, - pooltypes.ProtocolPoolDistrAccount: nil, - minttypes.ModuleName: {authtypes.Minter}, - stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, - stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, - govtypes.ModuleName: {authtypes.Burner}, - nft.ModuleName: nil, - } -) - -var ( - _ runtime.AppI = (*SimApp)(nil) - _ servertypes.Application = (*SimApp)(nil) -) - -// SimApp extends an ABCI application, but with most of its parameters exported. -// They are exported for convenience in creating helper functions, as object -// capabilities aren't needed for testing. -type SimApp struct { - *baseapp.BaseApp - logger log.Logger - legacyAmino *codec.LegacyAmino - appCodec codec.Codec - txConfig client.TxConfig - interfaceRegistry types.InterfaceRegistry - - // keys to access the substores - keys map[string]*storetypes.KVStoreKey - - // keepers - AccountsKeeper accounts.Keeper - AuthKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.BaseKeeper - StakingKeeper *stakingkeeper.Keeper - SlashingKeeper slashingkeeper.Keeper - MintKeeper *mintkeeper.Keeper - DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - UpgradeKeeper *upgradekeeper.Keeper - AuthzKeeper authzkeeper.Keeper - EvidenceKeeper evidencekeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - GroupKeeper groupkeeper.Keeper - NFTKeeper nftkeeper.Keeper - ConsensusParamsKeeper consensusparamkeeper.Keeper - CircuitKeeper circuitkeeper.Keeper - PoolKeeper poolkeeper.Keeper - EpochsKeeper *epochskeeper.Keeper - - // managers - ModuleManager *module.Manager - UnorderedTxManager *unorderedtx.Manager - sm *module.SimulationManager - - // module configurator - configurator module.Configurator //nolint:staticcheck // SA1019: Configurator is deprecated but still used in runtime v1. -} - -func init() { - var err error - DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".simapp") - if err != nil { - panic(err) - } -} - -// NewSimApp returns a reference to an initialized SimApp. -func NewSimApp( - logger log.Logger, - db corestore.KVStoreWithBatch, - traceStore io.Writer, - loadLatest bool, - appOpts servertypes.AppOptions, - baseAppOptions ...func(*baseapp.BaseApp), -) *SimApp { - interfaceRegistry, _ := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{ - ProtoFiles: proto.HybridResolver, - SigningOptions: signing.Options{ - AddressCodec: address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), - ValidatorAddressCodec: address.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), - }, - }) - appCodec := codec.NewProtoCodec(interfaceRegistry) - legacyAmino := codec.NewLegacyAmino() - signingCtx := interfaceRegistry.SigningContext() - txDecoder, err := txdecode.NewDecoder(txdecode.Options{ - SigningContext: signingCtx, - ProtoCodec: appCodec, - }) - if err != nil { - panic(err) - } - txConfig := authtx.NewTxConfig(appCodec, signingCtx.AddressCodec(), signingCtx.ValidatorAddressCodec(), authtx.DefaultSignModes) - - govModuleAddr, err := signingCtx.AddressCodec().BytesToString(authtypes.NewModuleAddress(govtypes.ModuleName)) - if err != nil { - panic(err) - } - - if err := signingCtx.Validate(); err != nil { - panic(err) - } - - std.RegisterLegacyAminoCodec(legacyAmino) - std.RegisterInterfaces(interfaceRegistry) - - // Below we could construct and set an application specific mempool and - // ABCI 1.0 PrepareProposal and ProcessProposal handlers. These defaults are - // already set in the SDK's BaseApp, this shows an example of how to override - // them. - // - // Example: - // - // bApp := baseapp.NewBaseApp(...) - // nonceMempool := mempool.NewSenderNonceMempool() - // abciPropHandler := NewDefaultProposalHandler(nonceMempool, bApp) - // - // bApp.SetMempool(nonceMempool) - // bApp.SetPrepareProposal(abciPropHandler.PrepareProposalHandler()) - // bApp.SetProcessProposal(abciPropHandler.ProcessProposalHandler()) - // - // Alternatively, you can construct BaseApp options, append those to - // baseAppOptions and pass them to NewBaseApp. - // - // Example: - // - // prepareOpt = func(app *baseapp.BaseApp) { - // abciPropHandler := baseapp.NewDefaultProposalHandler(nonceMempool, app) - // app.SetPrepareProposal(abciPropHandler.PrepareProposalHandler()) - // } - // baseAppOptions = append(baseAppOptions, prepareOpt) - - // create and set dummy vote extension handler - voteExtOp := func(bApp *baseapp.BaseApp) { - voteExtHandler := NewVoteExtensionHandler() - voteExtHandler.SetHandlers(bApp) - } - baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution(), - baseapp.SetIncludeNestedMsgsGas([]sdk.Msg{&govv1.MsgSubmitProposal{}})) - - bApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), baseAppOptions...) - bApp.SetCommitMultiStoreTracer(traceStore) - bApp.SetVersion(version.Version) - bApp.SetInterfaceRegistry(interfaceRegistry) - bApp.SetTxEncoder(txConfig.TxEncoder()) - - keys := storetypes.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, - minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, consensustypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, - evidencetypes.StoreKey, circuittypes.StoreKey, - authzkeeper.StoreKey, nftkeeper.StoreKey, group.StoreKey, pooltypes.StoreKey, - accounts.StoreKey, epochstypes.StoreKey, - ) - - // register streaming services - if err := bApp.RegisterStreamingServices(appOpts, keys); err != nil { - panic(err) - } - - app := &SimApp{ - BaseApp: bApp, - logger: logger, - legacyAmino: legacyAmino, - appCodec: appCodec, - txConfig: txConfig, - interfaceRegistry: interfaceRegistry, - keys: keys, - } - cometService := runtime.NewContextAwareCometInfoService() - - // set the BaseApp's parameter store - app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[consensustypes.StoreKey]), logger.With(log.ModuleKey, "x/consensus")), govModuleAddr) - bApp.SetParamStore(app.ConsensusParamsKeeper.ParamsStore) - - // set the version modifier - bApp.SetVersionModifier(consensus.ProvideAppVersionModifier(app.ConsensusParamsKeeper)) - - // add keepers - accountsKeeper, err := accounts.NewKeeper( - appCodec, - runtime.NewEnvironment(runtime.NewKVStoreService(keys[accounts.StoreKey]), logger.With(log.ModuleKey, "x/accounts"), runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), - signingCtx.AddressCodec(), - appCodec.InterfaceRegistry(), - txDecoder, - // TESTING: do not add - accountstd.AddAccount("counter", counter.NewAccount), - accountstd.AddAccount("aa_minimal", account_abstraction.NewMinimalAbstractedAccount), - // Lockup account - accountstd.AddAccount(lockup.CONTINUOUS_LOCKING_ACCOUNT, lockup.NewContinuousLockingAccount), - accountstd.AddAccount(lockup.PERIODIC_LOCKING_ACCOUNT, lockup.NewPeriodicLockingAccount), - accountstd.AddAccount(lockup.DELAYED_LOCKING_ACCOUNT, lockup.NewDelayedLockingAccount), - accountstd.AddAccount(lockup.PERMANENT_LOCKING_ACCOUNT, lockup.NewPermanentLockingAccount), - accountstd.AddAccount("multisig", multisig.NewAccount), - // PRODUCTION: add - baseaccount.NewAccount("base", txConfig.SignModeHandler(), baseaccount.WithSecp256K1PubKey()), - ) - if err != nil { - panic(err) - } - app.AccountsKeeper = accountsKeeper - - app.AuthKeeper = authkeeper.NewAccountKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), logger.With(log.ModuleKey, "x/auth")), appCodec, authtypes.ProtoBaseAccount, accountsKeeper, maccPerms, signingCtx.AddressCodec(), sdk.Bech32MainPrefix, govModuleAddr) - - blockedAddrs, err := BlockedAddresses(signingCtx.AddressCodec()) - if err != nil { - panic(err) - } - app.BankKeeper = bankkeeper.NewBaseKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), logger.With(log.ModuleKey, "x/bank")), - appCodec, - app.AuthKeeper, - blockedAddrs, - govModuleAddr, - ) - - // optional: enable sign mode textual by overwriting the default tx config (after setting the bank keeper) - enabledSignModes := append(authtx.DefaultSignModes, sigtypes.SignMode_SIGN_MODE_TEXTUAL) - txConfigOpts := authtx.ConfigOptions{ - EnabledSignModes: enabledSignModes, - TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(app.BankKeeper), - SigningOptions: &signing.Options{ - AddressCodec: signingCtx.AddressCodec(), - ValidatorAddressCodec: signingCtx.ValidatorAddressCodec(), - }, - } - txConfig, err = authtx.NewTxConfigWithOptions( - appCodec, - txConfigOpts, - ) - if err != nil { - panic(err) - } - app.txConfig = txConfig - - app.StakingKeeper = stakingkeeper.NewKeeper( - appCodec, - runtime.NewEnvironment( - runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), - logger.With(log.ModuleKey, "x/staking"), - runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), - runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), - app.AuthKeeper, - app.BankKeeper, - app.ConsensusParamsKeeper, - govModuleAddr, - signingCtx.ValidatorAddressCodec(), - authcodec.NewBech32Codec(sdk.Bech32PrefixConsAddr), - cometService, - ) - - app.MintKeeper = mintkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[minttypes.StoreKey]), logger.With(log.ModuleKey, "x/mint")), app.AuthKeeper, app.BankKeeper, authtypes.FeeCollectorName, govModuleAddr) - if err := app.MintKeeper.SetMintFn(mintkeeper.DefaultMintFn(minttypes.DefaultInflationCalculationFn, app.StakingKeeper, app.MintKeeper)); err != nil { - panic(err) - } - - app.PoolKeeper = poolkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[pooltypes.StoreKey]), logger.With(log.ModuleKey, "x/protocolpool")), app.AuthKeeper, app.BankKeeper, govModuleAddr) - - app.DistrKeeper = distrkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[distrtypes.StoreKey]), logger.With(log.ModuleKey, "x/distribution")), app.AuthKeeper, app.BankKeeper, app.StakingKeeper, cometService, authtypes.FeeCollectorName, govModuleAddr) - - app.SlashingKeeper = slashingkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), logger.With(log.ModuleKey, "x/slashing")), - appCodec, legacyAmino, app.StakingKeeper, govModuleAddr, - ) - - app.FeeGrantKeeper = feegrantkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[feegrant.StoreKey]), logger.With(log.ModuleKey, "x/feegrant")), appCodec, app.AuthKeeper.AddressCodec()) - - // register the staking hooks - // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks - app.StakingKeeper.SetHooks( - stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()), - ) - - app.CircuitKeeper = circuitkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[circuittypes.StoreKey]), logger.With(log.ModuleKey, "x/circuit")), appCodec, govModuleAddr, app.AuthKeeper.AddressCodec()) - app.BaseApp.SetCircuitBreaker(&app.CircuitKeeper) - - app.AuthzKeeper = authzkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[authzkeeper.StoreKey]), logger.With(log.ModuleKey, "x/authz"), runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), appCodec, signingCtx.AddressCodec()) - - groupConfig := group.DefaultConfig() - /* - Example of group params: - config.MaxExecutionPeriod = "1209600s" // example execution period in seconds - config.MaxMetadataLen = 1000 // example metadata length in bytes - config.MaxProposalTitleLen = 255 // example max title length in characters - config.MaxProposalSummaryLen = 10200 // example max summary length in characters - */ - app.GroupKeeper = groupkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[group.StoreKey]), logger.With(log.ModuleKey, "x/group"), runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), appCodec, app.AuthKeeper, groupConfig) - - // get skipUpgradeHeights from the app options - skipUpgradeHeights := map[int64]bool{} - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - homePath := cast.ToString(appOpts.Get(flags.FlagHome)) - // set the governance module account as the authority for conducting upgrades - app.UpgradeKeeper = upgradekeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[upgradetypes.StoreKey]), logger.With(log.ModuleKey, "x/upgrade"), runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), skipUpgradeHeights, appCodec, homePath, app.BaseApp, govModuleAddr, app.ConsensusParamsKeeper) - - // Register the proposal types - // Deprecated: Avoid adding new handlers, instead use the new proposal flow - // by granting the governance module the right to execute the message. - // See: https://docs.cosmos.network/main/modules/gov#proposal-messages - govRouter := govv1beta1.NewRouter() - govConfig := govkeeper.DefaultConfig() - /* - Example of setting gov params: - govConfig.MaxMetadataLen = 10000 - */ - govKeeper := govkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[govtypes.StoreKey]), logger.With(log.ModuleKey, "x/gov"), runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), app.AuthKeeper, app.BankKeeper, app.StakingKeeper, app.PoolKeeper, govConfig, govModuleAddr) - - // Set legacy router for backwards compatibility with gov v1beta1 - govKeeper.SetLegacyRouter(govRouter) - - app.GovKeeper = *govKeeper.SetHooks( - govtypes.NewMultiGovHooks( - // register the governance hooks - ), - ) - - app.NFTKeeper = nftkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[nftkeeper.StoreKey]), logger.With(log.ModuleKey, "x/nft")), appCodec, app.AuthKeeper, app.BankKeeper) - - // create evidence keeper with router - evidenceKeeper := evidencekeeper.NewKeeper( - appCodec, - runtime.NewEnvironment(runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), logger.With(log.ModuleKey, "x/evidence"), runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), - app.StakingKeeper, - app.SlashingKeeper, - app.ConsensusParamsKeeper, - app.AuthKeeper.AddressCodec(), - app.StakingKeeper.ConsensusAddressCodec(), - ) - // If evidence needs to be handled for the app, set routes in router here and seal - app.EvidenceKeeper = *evidenceKeeper - - app.EpochsKeeper = epochskeeper.NewKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[epochstypes.StoreKey]), logger.With(log.ModuleKey, "x/epochs")), - appCodec, - ) - - app.EpochsKeeper.SetHooks( - epochstypes.NewMultiEpochHooks( - // insert epoch hooks receivers here - ), - ) - - /**** Module Options ****/ - - // NOTE: Any module instantiated in the module manager that is later modified - // must be passed by reference here. - app.ModuleManager = module.NewManager( - genutil.NewAppModule(appCodec, app.AuthKeeper, app.StakingKeeper, app, txConfig, genutiltypes.DefaultMessageValidator), - accounts.NewAppModule(appCodec, app.AccountsKeeper), - auth.NewAppModule(appCodec, app.AuthKeeper, app.AccountsKeeper, authsims.RandomGenesisAccounts, nil), - vesting.NewAppModule(app.AuthKeeper, app.BankKeeper), - bank.NewAppModule(appCodec, app.BankKeeper, app.AuthKeeper), - feegrantmodule.NewAppModule(appCodec, app.FeeGrantKeeper, app.interfaceRegistry), - gov.NewAppModule(appCodec, &app.GovKeeper, app.AuthKeeper, app.BankKeeper, app.PoolKeeper), - mint.NewAppModule(appCodec, app.MintKeeper, app.AuthKeeper), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AuthKeeper, app.BankKeeper, app.StakingKeeper, app.interfaceRegistry, cometService), - distr.NewAppModule(appCodec, app.DistrKeeper, app.StakingKeeper), - staking.NewAppModule(appCodec, app.StakingKeeper), - upgrade.NewAppModule(app.UpgradeKeeper), - evidence.NewAppModule(appCodec, app.EvidenceKeeper, cometService), - authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.interfaceRegistry), - groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AuthKeeper, app.BankKeeper, app.interfaceRegistry), - nftmodule.NewAppModule(appCodec, app.NFTKeeper, app.AuthKeeper, app.BankKeeper, app.interfaceRegistry), - consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), - circuit.NewAppModule(appCodec, app.CircuitKeeper), - protocolpool.NewAppModule(appCodec, app.PoolKeeper, app.AuthKeeper, app.BankKeeper), - epochs.NewAppModule(appCodec, app.EpochsKeeper), - ) - - app.ModuleManager.RegisterLegacyAminoCodec(legacyAmino) - app.ModuleManager.RegisterInterfaces(interfaceRegistry) - - // NOTE: upgrade module is required to be prioritized - app.ModuleManager.SetOrderPreBlockers( - upgradetypes.ModuleName, - ) - // During begin block slashing happens after distr.BeginBlocker so that - // there is nothing left over in the validator fee pool, so as to keep the - // CanWithdrawInvariant invariant. - // NOTE: staking module is required if HistoricalEntries param > 0 - app.ModuleManager.SetOrderBeginBlockers( - minttypes.ModuleName, - distrtypes.ModuleName, - pooltypes.ModuleName, - slashingtypes.ModuleName, - evidencetypes.ModuleName, - stakingtypes.ModuleName, - genutiltypes.ModuleName, - authz.ModuleName, - epochstypes.ModuleName, - ) - app.ModuleManager.SetOrderEndBlockers( - govtypes.ModuleName, - stakingtypes.ModuleName, - genutiltypes.ModuleName, - feegrant.ModuleName, - group.ModuleName, - pooltypes.ModuleName, - ) - - // NOTE: The genutils module must occur after staking so that pools are - // properly initialized with tokens from genesis accounts. - // NOTE: The genutils module must also occur after auth so that it can access the params from auth. - genesisModuleOrder := []string{ - consensustypes.ModuleName, - accounts.ModuleName, - authtypes.ModuleName, - banktypes.ModuleName, - distrtypes.ModuleName, - stakingtypes.ModuleName, - slashingtypes.ModuleName, - govtypes.ModuleName, - minttypes.ModuleName, - genutiltypes.ModuleName, - evidencetypes.ModuleName, - authz.ModuleName, - feegrant.ModuleName, - nft.ModuleName, - group.ModuleName, - upgradetypes.ModuleName, - vestingtypes.ModuleName, - circuittypes.ModuleName, - pooltypes.ModuleName, - epochstypes.ModuleName, - } - app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) - app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...) - - // Uncomment if you want to set a custom migration order here. - // app.ModuleManager.SetOrderMigrations(custom order) - - app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) - err = app.ModuleManager.RegisterServices(app.configurator) - if err != nil { - panic(err) - } - - // RegisterUpgradeHandlers is used for registering any on-chain upgrades. - // Make sure it's called after `app.ModuleManager` and `app.configurator` are set. - app.RegisterUpgradeHandlers() - - autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.ModuleManager.Modules)) - - reflectionSvc, err := runtimeservices.NewReflectionService() - if err != nil { - panic(err) - } - reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc) - - // add test gRPC service for testing gRPC queries in isolation - testdata_pulsar.RegisterQueryServer(app.GRPCQueryRouter(), testdata_pulsar.QueryImpl{}) - - // create the simulation manager and define the order of the modules for deterministic simulations - // - // NOTE: this is not required apps that don't use the simulator for fuzz testing - // transactions - overrideModules := map[string]module.AppModuleSimulation{ - authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AuthKeeper, app.AccountsKeeper, authsims.RandomGenesisAccounts, nil), - } - app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules) - - // create, start, and load the unordered tx manager - utxDataDir := filepath.Join(homePath, "data") - app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir) - app.UnorderedTxManager.Start() - - if err := app.UnorderedTxManager.OnInit(); err != nil { - panic(fmt.Errorf("failed to initialize unordered tx manager: %w", err)) - } - - // register custom snapshot extensions (if any) - if manager := app.SnapshotManager(); manager != nil { - err := manager.RegisterExtensions( - unorderedtx.NewSnapshotter(app.UnorderedTxManager), - ) - if err != nil { - panic(fmt.Errorf("failed to register snapshot extension: %w", err)) - } - } - - app.sm.RegisterStoreDecoders() - - // initialize stores - app.MountKVStores(keys) - - // initialize BaseApp - app.SetInitChainer(app.InitChainer) - app.SetPreBlocker(app.PreBlocker) - app.SetBeginBlocker(app.BeginBlocker) - app.SetEndBlocker(app.EndBlocker) - app.setAnteHandler(txConfig) - - // In v0.46, the SDK introduces _postHandlers_. PostHandlers are like - // antehandlers, but are run _after_ the `runMsgs` execution. They are also - // defined as a chain, and have the same signature as antehandlers. - // - // In baseapp, postHandlers are run in the same store branch as `runMsgs`, - // meaning that both `runMsgs` and `postHandler` state will be committed if - // both are successful, and both will be reverted if any of the two fails. - // - // The SDK exposes a default postHandlers chain - // - // Please note that changing any of the anteHandler or postHandler chain is - // likely to be a state-machine breaking change, which needs a coordinated - // upgrade. - app.setPostHandler() - - // At startup, after all modules have been registered, check that all prot - // annotations are correct. - protoFiles, err := proto.MergedRegistry() - if err != nil { - panic(err) - } - err = msgservice.ValidateProtoAnnotations(protoFiles) - if err != nil { - // Once we switch to using protoreflect-based antehandlers, we might - // want to panic here instead of logging a warning. - fmt.Fprintln(os.Stderr, err.Error()) - } - - if loadLatest { - if err := app.LoadLatestVersion(); err != nil { - panic(fmt.Errorf("error loading last version: %w", err)) - } - } - - return app -} - -func (app *SimApp) setAnteHandler(txConfig client.TxConfig) { - anteHandler, err := NewAnteHandler( - HandlerOptions{ - ante.HandlerOptions{ - Environment: runtime.NewEnvironment(nil, app.logger, runtime.EnvWithMsgRouterService(app.MsgServiceRouter()), runtime.EnvWithQueryRouterService(app.GRPCQueryRouter())), // nil is set as the kvstoreservice to avoid module access - AccountAbstractionKeeper: app.AccountsKeeper, - AccountKeeper: app.AuthKeeper, - BankKeeper: app.BankKeeper, - ConsensusKeeper: app.ConsensusParamsKeeper, - SignModeHandler: txConfig.SignModeHandler(), - FeegrantKeeper: app.FeeGrantKeeper, - SigGasConsumer: ante.DefaultSigVerificationGasConsumer, - UnorderedTxManager: app.UnorderedTxManager, - }, - &app.CircuitKeeper, - }, - ) - if err != nil { - panic(err) - } - - // Set the AnteHandler for the app - app.SetAnteHandler(anteHandler) -} - -func (app *SimApp) setPostHandler() { - postHandler, err := posthandler.NewPostHandler( - posthandler.HandlerOptions{}, - ) - if err != nil { - panic(err) - } - - app.SetPostHandler(postHandler) -} - -// Close closes all necessary application resources. -// It implements servertypes.Application. -func (app *SimApp) Close() error { - if err := app.BaseApp.Close(); err != nil { - return err - } - - return app.UnorderedTxManager.Close() -} - -// Name returns the name of the App -func (app *SimApp) Name() string { return app.BaseApp.Name() } - -// PreBlocker application updates every pre block -func (app *SimApp) PreBlocker(ctx sdk.Context, _ *abci.FinalizeBlockRequest) error { - app.UnorderedTxManager.OnNewBlock(ctx.BlockTime()) - return app.ModuleManager.PreBlock(ctx) -} - -// BeginBlocker application updates every begin block -func (app *SimApp) BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) { - return app.ModuleManager.BeginBlock(ctx) -} - -// EndBlocker application updates every end block -func (app *SimApp) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) { - return app.ModuleManager.EndBlock(ctx) -} - -func (a *SimApp) Configurator() module.Configurator { //nolint:staticcheck // SA1019: Configurator is deprecated but still used in runtime v1. - return a.configurator -} - -// InitChainer application update at chain initialization -func (app *SimApp) InitChainer(ctx sdk.Context, req *abci.InitChainRequest) (*abci.InitChainResponse, error) { - var genesisState GenesisState - err := json.Unmarshal(req.AppStateBytes, &genesisState) - if err != nil { - return nil, err - } - err = app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap()) - if err != nil { - return nil, err - } - return app.ModuleManager.InitGenesis(ctx, genesisState) -} - -// LoadHeight loads a particular height -func (app *SimApp) LoadHeight(height int64) error { - return app.LoadVersion(height) -} - -// LegacyAmino returns SimApp's amino codec. -// -// NOTE: This is solely to be used for testing purposes as it may be desirable -// for modules to register their own custom testing types. -func (app *SimApp) LegacyAmino() *codec.LegacyAmino { - return app.legacyAmino -} - -// AppCodec returns SimApp's app codec. -// -// NOTE: This is solely to be used for testing purposes as it may be desirable -// for modules to register their own custom testing types. -func (app *SimApp) AppCodec() codec.Codec { - return app.appCodec -} - -// InterfaceRegistry returns SimApp's InterfaceRegistry -func (app *SimApp) InterfaceRegistry() types.InterfaceRegistry { - return app.interfaceRegistry -} - -// TxConfig returns SimApp's TxConfig -func (app *SimApp) TxConfig() client.TxConfig { - return app.txConfig -} - -// AutoCliOpts returns the autocli options for the app. -func (app *SimApp) AutoCliOpts() autocli.AppOptions { - return autocli.AppOptions{ - Modules: app.ModuleManager.Modules, - ModuleOptions: runtimeservices.ExtractAutoCLIOptions(app.ModuleManager.Modules), - } -} - -// DefaultGenesis returns a default genesis from the registered AppModule's. -func (a *SimApp) DefaultGenesis() map[string]json.RawMessage { - return a.ModuleManager.DefaultGenesis() -} - -// GetKey returns the KVStoreKey for the provided store key. -// -// NOTE: This is solely to be used for testing purposes. -func (app *SimApp) GetKey(storeKey string) *storetypes.KVStoreKey { - return app.keys[storeKey] -} - -// GetStoreKeys returns all the stored store keys. -func (app *SimApp) GetStoreKeys() []storetypes.StoreKey { - keys := make([]storetypes.StoreKey, 0, len(app.keys)) - for _, key := range app.keys { - keys = append(keys, key) - } - - return keys -} - -// SimulationManager implements the SimulationApp interface -func (app *SimApp) SimulationManager() *module.SimulationManager { - return app.sm -} - -// RegisterAPIRoutes registers all application module routes with the provided -// API server. -func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { - clientCtx := apiSvr.ClientCtx - // Register new tx routes from grpc-gateway. - authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - - // Register new CometBFT queries routes from grpc-gateway. - cmtservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - - // Register node gRPC service for grpc-gateway. - nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - - // Register grpc-gateway routes for all modules. - app.ModuleManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - - // register swagger API from root so that other applications can override easily - if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { - panic(err) - } -} - -// RegisterTxService implements the Application.RegisterTxService method. -func (app *SimApp) RegisterTxService(clientCtx client.Context) { - authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) -} - -// RegisterTendermintService implements the Application.RegisterTendermintService method. -func (app *SimApp) RegisterTendermintService(clientCtx client.Context) { - cmtApp := server.NewCometABCIWrapper(app) - cmtservice.RegisterTendermintService( - clientCtx, - app.BaseApp.GRPCQueryRouter(), - app.interfaceRegistry, - cmtApp.Query, - ) -} - -func (app *SimApp) RegisterNodeService(clientCtx client.Context, cfg config.Config) { - nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter(), cfg) -} - -// ValidatorKeyProvider returns a function that generates a validator key -// Supported key types are those supported by Comet: ed25519, secp256k1, bls12-381 -func (app *SimApp) ValidatorKeyProvider() runtime.KeyGenF { - return func() (cmtcrypto.PrivKey, error) { - return cmted25519.GenPrivKey(), nil - } -} - -// GetMaccPerms returns a copy of the module account permissions -// -// NOTE: This is solely to be used for testing purposes. -func GetMaccPerms() map[string][]string { - return maps.Clone(maccPerms) -} - -// BlockedAddresses returns all the app's blocked account addresses. -func BlockedAddresses(ac coreaddress.Codec) (map[string]bool, error) { - modAccAddrs := make(map[string]bool) - for acc := range GetMaccPerms() { - addr, err := ac.BytesToString(authtypes.NewModuleAddress(acc)) - if err != nil { - return nil, err - } - modAccAddrs[addr] = true - } - - // allow the following addresses to receive funds - addr, err := ac.BytesToString(authtypes.NewModuleAddress(govtypes.ModuleName)) - if err != nil { - return nil, err - } - delete(modAccAddrs, addr) - - return modAccAddrs, nil -} diff --git a/simapp/app_di.go b/simapp/app_di.go index 6e8f8d4f63ee..90de295e8b7d 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -1,5 +1,3 @@ -//go:build !app_v1 - package simapp import ( diff --git a/simapp/go.mod b/simapp/go.mod index 71e1c2d67cca..973d5e993666 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -32,14 +32,14 @@ require ( cosmossdk.io/x/protocolpool v0.0.0-20230925135524-a1bc045b3190 cosmossdk.io/x/slashing v0.0.0-00010101000000-000000000000 cosmossdk.io/x/staking v0.0.0-20240226161501-23359a0b6d91 - cosmossdk.io/x/tx v1.0.0-alpha.1 + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect cosmossdk.io/x/upgrade v0.0.0-20230613133644-0a778132a60f github.com/cometbft/cometbft v1.0.0-rc2.0.20241127125717-4ce33b646ac9 github.com/cometbft/cometbft/api v1.0.0-rc2 // this version is not used as it is always replaced by the latest Cosmos SDK version github.com/cosmos/cosmos-sdk v0.53.0 github.com/cosmos/gogoproto v1.7.0 - github.com/spf13/cast v1.7.0 + github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go deleted file mode 100644 index 7851629e7716..000000000000 --- a/simapp/simd/cmd/root.go +++ /dev/null @@ -1,137 +0,0 @@ -//go:build app_v1 - -package cmd - -import ( - "os" - - "github.com/spf13/cobra" - - coretesting "cosmossdk.io/core/testing" - "cosmossdk.io/log" - "cosmossdk.io/simapp" - "cosmossdk.io/simapp/params" - txsigning "cosmossdk.io/x/tx/signing" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/config" - nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/server" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - "github.com/cosmos/cosmos-sdk/x/auth/tx" - authtxconfig "github.com/cosmos/cosmos-sdk/x/auth/tx/config" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -// NewRootCmd creates a new root command for simd. It is called once in the -// main function. -func NewRootCmd() *cobra.Command { - // we "pre"-instantiate the application for getting the injected/configured encoding configuration - // note, this is not necessary when using app wiring, as depinject can be directly used (see root_v2.go) - tempApp := simapp.NewSimApp(log.NewNopLogger(), coretesting.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(simapp.DefaultNodeHome)) - encodingConfig := params.EncodingConfig{ - InterfaceRegistry: tempApp.InterfaceRegistry(), - Codec: tempApp.AppCodec(), - TxConfig: tempApp.TxConfig(), - Amino: tempApp.LegacyAmino(), - } - - initClientCtx := client.Context{}. - WithCodec(encodingConfig.Codec). - WithInterfaceRegistry(encodingConfig.InterfaceRegistry). - WithTxConfig(encodingConfig.TxConfig). - WithLegacyAmino(encodingConfig.Amino). - WithInput(os.Stdin). - WithAccountRetriever(types.AccountRetriever{}). - WithAddressCodec(addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix())). - WithValidatorAddressCodec(addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix())). - WithConsensusAddressCodec(addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix())). - WithHomeDir(simapp.DefaultNodeHome). - WithViper(""). // uses by default the binary name as prefix - WithAddressPrefix(sdk.GetConfig().GetBech32AccountAddrPrefix()). - WithValidatorPrefix(sdk.GetConfig().GetBech32ValidatorAddrPrefix()) - - rootCmd := &cobra.Command{ - Use: "simd", - Short: "simulation app", - SilenceErrors: true, - PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { - // set the default command outputs - cmd.SetOut(cmd.OutOrStdout()) - cmd.SetErr(cmd.ErrOrStderr()) - - initClientCtx = initClientCtx.WithCmdContext(cmd.Context()) - initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) - if err != nil { - return err - } - - customClientTemplate, customClientConfig := initClientConfig() - initClientCtx, err = config.CreateClientConfig(initClientCtx, customClientTemplate, customClientConfig) - if err != nil { - return err - } - - // This needs to go after CreateClientConfig, as that function - // sets the RPC client needed for SIGN_MODE_TEXTUAL. This sign mode - // is only available if the client is online. - if !initClientCtx.Offline { - enabledSignModes := append(tx.DefaultSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) - txConfigOpts := tx.ConfigOptions{ - EnabledSignModes: enabledSignModes, - TextualCoinMetadataQueryFn: authtxconfig.NewGRPCCoinMetadataQueryFn(initClientCtx), - SigningOptions: &txsigning.Options{ - AddressCodec: initClientCtx.InterfaceRegistry.SigningContext().AddressCodec(), - ValidatorAddressCodec: initClientCtx.InterfaceRegistry.SigningContext().ValidatorAddressCodec(), - }, - } - txConfig, err := tx.NewTxConfigWithOptions( - initClientCtx.Codec, - txConfigOpts, - ) - if err != nil { - return err - } - - initClientCtx = initClientCtx.WithTxConfig(txConfig) - } - - if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { - return err - } - - customAppTemplate, customAppConfig := initAppConfig() - customCMTConfig := initCometBFTConfig() - - return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customCMTConfig) - }, - } - - initRootCmd(rootCmd, tempApp.ModuleManager) - - // autocli opts - customClientTemplate, customClientConfig := initClientConfig() - var err error - initClientCtx, err = config.CreateClientConfig(initClientCtx, customClientTemplate, customClientConfig) - if err != nil { - panic(err) - } - - autoCliOpts := tempApp.AutoCliOpts() - autoCliOpts.AddressCodec = initClientCtx.AddressCodec - autoCliOpts.ValidatorAddressCodec = initClientCtx.ValidatorAddressCodec - autoCliOpts.ConsensusAddressCodec = initClientCtx.ConsensusAddressCodec - autoCliOpts.Cdc = initClientCtx.Codec - - nodeCmds := nodeservice.NewNodeCommands() - autoCliOpts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions() - - if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { - panic(err) - } - - return rootCmd -} diff --git a/simapp/simd/cmd/root_di.go b/simapp/simd/cmd/root_di.go index ea6e70f37a99..4d3b2d5774ac 100644 --- a/simapp/simd/cmd/root_di.go +++ b/simapp/simd/cmd/root_di.go @@ -1,5 +1,3 @@ -//go:build !app_v1 - package cmd import ( diff --git a/systemtests/CHANGELOG.md b/systemtests/CHANGELOG.md index 77787b91d7a8..2a27c4162cf2 100644 --- a/systemtests/CHANGELOG.md +++ b/systemtests/CHANGELOG.md @@ -36,6 +36,10 @@ Ref: https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.j ## [Unreleased] +## [v1.0.0-rc.3] - 2024-12-05 + +* [#22774](https://github.com/cosmos/cosmos-sdk/pull/22774) Add greater than or equal support in Rest test suite + ## [v1.0.0-rc.2] - 2024-11-26 * [#22577](https://github.com/cosmos/cosmos-sdk/pull/22577) Support invalid RPC response for CometBFT v1 diff --git a/systemtests/rest_support.go b/systemtests/rest_support.go index aa7efd807cc4..b2615fc2aed6 100644 --- a/systemtests/rest_support.go +++ b/systemtests/rest_support.go @@ -7,15 +7,14 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/testutil" ) type RestTestCase struct { - Name string - Url string - ExpCode int - ExpOut string + Name string + Url string + ExpCode int + ExpCodeGTE int + ExpOut string } // RunRestQueries runs given Rest testcases by making requests and @@ -25,33 +24,71 @@ func RunRestQueries(t *testing.T, testCases ...RestTestCase) { for _, tc := range testCases { t.Run(tc.Name, func(t *testing.T) { - resp := GetRequestWithHeaders(t, tc.Url, nil, tc.ExpCode) + if tc.ExpCodeGTE > 0 && tc.ExpCode > 0 { + require.Fail(t, "only one of ExpCode or ExpCodeGTE should be set") + } + + var resp []byte + if tc.ExpCodeGTE > 0 { + resp = GetRequestWithHeadersGreaterThanOrEqual(t, tc.Url, nil, tc.ExpCodeGTE) + } else { + resp = GetRequestWithHeaders(t, tc.Url, nil, tc.ExpCode) + } require.JSONEq(t, tc.ExpOut, string(resp)) }) } } -// TestRestQueryIgnoreNumbers runs given rest testcases by making requests and +// RunRestQueriesIgnoreNumbers runs given rest testcases by making requests and // checking response with expected output ignoring number values // This method is used when number values in response are non-deterministic -func TestRestQueryIgnoreNumbers(t *testing.T, testCases ...RestTestCase) { +func RunRestQueriesIgnoreNumbers(t *testing.T, testCases ...RestTestCase) { t.Helper() + // regex for standalone quoted numbers (e.g., "-3" or "0.02") + standaloneQuotedNumberRegex := regexp.MustCompile(`"(-?\d+(\.\d+)?)"`) + // regex for numbers in escaped strings (e.g., \"-3\") + escapedNumberRegex := regexp.MustCompile(`\\\"(-?\d+(\.\d+)?)\\\"`) + // regex for unquoted numbers (e.g., 2, -1, 0.02,) + unquotedNumberRegex := regexp.MustCompile(`\b-?\d+(\.\d+)?\b,`) + + replaceNumber := func(input string) string { + // handle numbers in escaped strings + result := escapedNumberRegex.ReplaceAllStringFunc(input, func(match string) string { + // replace with escaped "NUMBER" + return `\"NUMBER\"` + }) + + // handle standalone quoted numbers + result = standaloneQuotedNumberRegex.ReplaceAllStringFunc(result, func(match string) string { + // replace with "NUMBER" (quotes preserved) + return `"NUMBER"` + }) + + // handle unquoted numbers + result = unquotedNumberRegex.ReplaceAllStringFunc(result, func(match string) string { + // replace with "NUMBER" (add quotes to ensure json validity) + return `"NUMBER",` + }) + + return result + } + for _, tc := range testCases { t.Run(tc.Name, func(t *testing.T) { - resp, err := testutil.GetRequest(tc.Url) - require.NoError(t, err) - - // regular expression pattern to match any numeric value in the JSON - numberRegexPattern := `"\d+(\.\d+)?"` + if tc.ExpCodeGTE > 0 && tc.ExpCode > 0 { + require.Fail(t, "only one of ExpCode or ExpCodeGTE should be set") + } - // compile the regex - r, err := regexp.Compile(numberRegexPattern) - require.NoError(t, err) + var resp []byte + if tc.ExpCodeGTE > 0 { + resp = GetRequestWithHeadersGreaterThanOrEqual(t, tc.Url, nil, tc.ExpCodeGTE) + } else { + resp = GetRequestWithHeaders(t, tc.Url, nil, tc.ExpCode) + } - // replace all numeric values in the above JSONs with `NUMBER` text - expectedJSON := r.ReplaceAllString(tc.ExpOut, `"NUMBER"`) - actualJSON := r.ReplaceAllString(string(resp), `"NUMBER"`) + expectedJSON := replaceNumber(tc.ExpOut) + actualJSON := replaceNumber(string(resp)) // compare two jsons require.JSONEq(t, expectedJSON, actualJSON) @@ -85,3 +122,25 @@ func GetRequestWithHeaders(t *testing.T, url string, headers map[string]string, return body } + +func GetRequestWithHeadersGreaterThanOrEqual(t *testing.T, url string, headers map[string]string, expCode int) []byte { + t.Helper() + req, err := http.NewRequest("GET", url, nil) + require.NoError(t, err) + + for key, value := range headers { + req.Header.Set(key, value) + } + + httpClient := &http.Client{} + res, err := httpClient.Do(req) + require.NoError(t, err) + defer func() { + _ = res.Body.Close() + }() + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + require.GreaterOrEqual(t, res.StatusCode, expCode, "status code should be greater or equal to %d, got: %d, %s", expCode, res.StatusCode, body) + + return body +} diff --git a/tests/integration/slashing/app_config.go b/tests/integration/slashing/app_config.go deleted file mode 100644 index 415bea47145d..000000000000 --- a/tests/integration/slashing/app_config.go +++ /dev/null @@ -1,32 +0,0 @@ -package slashing - -import ( - _ "cosmossdk.io/x/accounts" // import as blank for app wiring - _ "cosmossdk.io/x/bank" // import as blank for app wiring - _ "cosmossdk.io/x/consensus" // import as blank for app wiring - _ "cosmossdk.io/x/distribution" // import as blank for app wiring - _ "cosmossdk.io/x/mint" // import as blank for app wiring - _ "cosmossdk.io/x/protocolpool" // import as blank for app wiring - _ "cosmossdk.io/x/slashing" // import as blank for app wiring - _ "cosmossdk.io/x/staking" // import as blank for app wiring - - "github.com/cosmos/cosmos-sdk/testutil/configurator" - _ "github.com/cosmos/cosmos-sdk/x/auth" // import as blank for app wiring - _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import as blank for app wiring - _ "github.com/cosmos/cosmos-sdk/x/genutil" // import as blank for app wiring -) - -var AppConfig = configurator.NewAppConfig( - configurator.AccountsModule(), - configurator.AuthModule(), - configurator.BankModule(), - configurator.StakingModule(), - configurator.SlashingModule(), - configurator.TxModule(), - configurator.ValidateModule(), - configurator.ConsensusModule(), - configurator.GenutilModule(), - configurator.MintModule(), - configurator.DistributionModule(), - configurator.ProtocolPoolModule(), -) diff --git a/tests/integration/slashing/slashing_test.go b/tests/integration/slashing/slashing_test.go deleted file mode 100644 index be116892c240..000000000000 --- a/tests/integration/slashing/slashing_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package slashing_test - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/core/header" - "cosmossdk.io/depinject" - "cosmossdk.io/log" - "cosmossdk.io/math" - bankkeeper "cosmossdk.io/x/bank/keeper" - "cosmossdk.io/x/slashing/keeper" - "cosmossdk.io/x/slashing/types" - stakingkeeper "cosmossdk.io/x/staking/keeper" - stakingtypes "cosmossdk.io/x/staking/types" - - "github.com/cosmos/cosmos-sdk/client" - codecaddress "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/testutil/configurator" - "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -var ( - priv1 = secp256k1.GenPrivKey() - addr1 = sdk.AccAddress(priv1.PubKey().Address()) - addrCodec = codecaddress.NewBech32Codec("cosmos") - valaddrCodec = codecaddress.NewBech32Codec("cosmosvaloper") - - valKey = ed25519.GenPrivKey() - valAddr = sdk.AccAddress(valKey.PubKey().Address()) -) - -func TestSlashingMsgs(t *testing.T) { - genTokens := sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction) - bondTokens := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) - genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) - bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens) - - addrStr, err := addrCodec.BytesToString(addr1) - require.NoError(t, err) - acc1 := &authtypes.BaseAccount{ - Address: addrStr, - } - accs := []sims.GenesisAccount{{GenesisAccount: acc1, Coins: sdk.Coins{genCoin}}} - - startupCfg := sims.DefaultStartUpConfig() - startupCfg.GenesisAccounts = accs - - var ( - stakingKeeper *stakingkeeper.Keeper - bankKeeper bankkeeper.Keeper - slashingKeeper keeper.Keeper - txConfig client.TxConfig - ) - - app, err := sims.SetupWithConfiguration( - depinject.Configs( - configurator.NewAppConfig( - configurator.AccountsModule(), - configurator.AuthModule(), - configurator.StakingModule(), - configurator.SlashingModule(), - configurator.TxModule(), - configurator.ValidateModule(), - configurator.ConsensusModule(), - configurator.BankModule(), - ), - depinject.Supply(log.NewNopLogger()), - ), - startupCfg, &stakingKeeper, &bankKeeper, &slashingKeeper, &txConfig) - require.NoError(t, err) - - baseApp := app.BaseApp - - ctxCheck := baseApp.NewContext(true) - require.True(t, sdk.Coins{genCoin}.Equal(bankKeeper.GetAllBalances(ctxCheck, addr1))) - - require.NoError(t, err) - - description := stakingtypes.NewDescription("foo_moniker", "", "", "", "", &stakingtypes.Metadata{}) - commission := stakingtypes.NewCommissionRates(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec()) - - addrStrVal, err := valaddrCodec.BytesToString(addr1) - require.NoError(t, err) - createValidatorMsg, err := stakingtypes.NewMsgCreateValidator( - addrStrVal, valKey.PubKey(), bondCoin, description, commission, math.OneInt(), - ) - require.NoError(t, err) - - headerInfo := header.Info{Height: app.LastBlockHeight() + 1} - _, _, err = sims.SignCheckDeliver(t, txConfig, app.BaseApp, headerInfo, []sdk.Msg{createValidatorMsg}, "", []uint64{0}, []uint64{0}, true, true, priv1) - require.NoError(t, err) - require.True(t, sdk.Coins{genCoin.Sub(bondCoin)}.Equal(bankKeeper.GetAllBalances(ctxCheck, addr1))) - - ctxCheck = baseApp.NewContext(true) - validator, err := stakingKeeper.GetValidator(ctxCheck, sdk.ValAddress(addr1)) - require.NoError(t, err) - - require.Equal(t, addrStrVal, validator.OperatorAddress) - require.Equal(t, stakingtypes.Bonded, validator.Status) - require.True(math.IntEq(t, bondTokens, validator.BondedTokens())) - unjailMsg := &types.MsgUnjail{ValidatorAddr: addrStrVal} - - ctxCheck = app.BaseApp.NewContext(true) - _, err = slashingKeeper.ValidatorSigningInfo.Get(ctxCheck, sdk.ConsAddress(valAddr)) - require.NoError(t, err) - - // unjail should fail with unknown validator - headerInfo = header.Info{Height: app.LastBlockHeight() + 1} - _, _, err = sims.SignCheckDeliver(t, txConfig, app.BaseApp, headerInfo, []sdk.Msg{unjailMsg}, "", []uint64{0}, []uint64{1}, false, false, priv1) - require.Error(t, err) - require.True(t, errors.Is(err, types.ErrValidatorNotJailed)) -} diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go index 8eba29665cf3..72a4873cba6b 100644 --- a/tests/integration/v2/app.go +++ b/tests/integration/v2/app.go @@ -445,6 +445,8 @@ func (a *App) SignCheckDeliver( // It required the context to have the integration context. // a new state is committed if the option WithAutomaticCommit is set in options. func (app *App) RunMsg(t *testing.T, ctx context.Context, handler handler, option ...Option) (resp transaction.Msg, err error) { + t.Helper() + // set options cfg := &RunMsgConfig{} for _, opt := range option { diff --git a/tests/integration/v2/evidence/infraction_test.go b/tests/integration/v2/evidence/infraction_test.go index 16cd31f4e83d..351b2f3ea9be 100644 --- a/tests/integration/v2/evidence/infraction_test.go +++ b/tests/integration/v2/evidence/infraction_test.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/hex" - "fmt" "testing" "time" @@ -25,7 +24,6 @@ import ( _ "cosmossdk.io/x/evidence" // import as blank for app wiring "cosmossdk.io/x/evidence/exported" "cosmossdk.io/x/evidence/keeper" - evidencetypes "cosmossdk.io/x/evidence/types" minttypes "cosmossdk.io/x/mint/types" _ "cosmossdk.io/x/slashing" // import as blank for app wiring slashingkeeper "cosmossdk.io/x/slashing/keeper" @@ -251,6 +249,7 @@ func TestHandleDoubleSign_TooOld(t *testing.T) { require.NotNil(t, f.consensusKeeper.ParamsStore) require.NoError(t, f.consensusKeeper.ParamsStore.Set(ctx, *simtestutil.DefaultConsensusParams)) cp, err := f.consensusKeeper.ParamsStore.Get(ctx) + require.NoError(t, err) ctx = integration.SetCometInfo(ctx, nci) ctx = integration.SetHeaderInfo(ctx, header.Info{ @@ -412,21 +411,3 @@ func newPubKey(pk string) (res cryptotypes.PubKey) { return pubkey } - -func testEquivocationHandler(_ interface{}) evidencetypes.Handler { - return func(ctx context.Context, e exported.Evidence) error { - if err := e.ValidateBasic(); err != nil { - return err - } - - ee, ok := e.(*evidencetypes.Equivocation) - if !ok { - return fmt.Errorf("unexpected evidence type: %T", e) - } - if ee.Height%2 == 0 { - return fmt.Errorf("unexpected even evidence height: %d", ee.Height) - } - - return nil - } -} diff --git a/tests/integration/slashing/abci_test.go b/tests/integration/v2/slashing/abci_test.go similarity index 50% rename from tests/integration/slashing/abci_test.go rename to tests/integration/v2/slashing/abci_test.go index 96e869743e5d..f771941cf096 100644 --- a/tests/integration/slashing/abci_test.go +++ b/tests/integration/v2/slashing/abci_test.go @@ -8,68 +8,43 @@ import ( "cosmossdk.io/core/comet" coreheader "cosmossdk.io/core/header" - "cosmossdk.io/depinject" - "cosmossdk.io/log" - bankkeeper "cosmossdk.io/x/bank/keeper" + "cosmossdk.io/runtime/v2/services" "cosmossdk.io/x/slashing" - slashingkeeper "cosmossdk.io/x/slashing/keeper" "cosmossdk.io/x/slashing/testutil" - stakingkeeper "cosmossdk.io/x/staking/keeper" stakingtestutil "cosmossdk.io/x/staking/testutil" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" ) // TestBeginBlocker is a unit test function that tests the behavior of the BeginBlocker function. // It sets up the necessary dependencies and context, creates a validator, and performs various operations // to test the slashing logic. It checks if the validator is correctly jailed after a certain number of blocks. func TestBeginBlocker(t *testing.T) { - var ( - interfaceRegistry codectypes.InterfaceRegistry - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - stakingKeeper *stakingkeeper.Keeper - slashingKeeper slashingkeeper.Keeper - ) - - app, err := simtestutil.Setup( - depinject.Configs( - AppConfig, - depinject.Supply(log.NewNopLogger()), - ), - &interfaceRegistry, - &accountKeeper, - &bankKeeper, - &stakingKeeper, - &slashingKeeper, - ) - require.NoError(t, err) + f := initFixture(t) - ctx := app.BaseApp.NewContext(false) + ctx := f.ctx pks := simtestutil.CreateTestPubKeys(1) - simtestutil.AddTestAddrsFromPubKeys(bankKeeper, stakingKeeper, ctx, pks, stakingKeeper.TokensFromConsensusPower(ctx, 200)) + simtestutil.AddTestAddrsFromPubKeys(f.bankKeeper, f.stakingKeeper, ctx, pks, f.stakingKeeper.TokensFromConsensusPower(ctx, 200)) addr, pk := sdk.ValAddress(pks[0].Address()), pks[0] - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) + tstaking := stakingtestutil.NewHelper(t, ctx, f.stakingKeeper) // bond the validator power := int64(100) - acc := accountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(addr)) - accountKeeper.SetAccount(ctx, acc) + acc := f.accountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(addr)) + f.accountKeeper.SetAccount(ctx, acc) amt := tstaking.CreateValidatorWithValPower(addr, pk, power, true) - _, err = stakingKeeper.EndBlocker(ctx) + _, err := f.stakingKeeper.EndBlocker(ctx) require.NoError(t, err) - bondDenom, err := stakingKeeper.BondDenom(ctx) + bondDenom, err := f.stakingKeeper.BondDenom(ctx) require.NoError(t, err) require.Equal( - t, bankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), + t, f.bankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(bondDenom, testutil.InitTokens.Sub(amt))), ) - val, err := stakingKeeper.Validator(ctx, addr) + val, err := f.stakingKeeper.Validator(ctx, addr) require.NoError(t, err) require.Equal(t, amt, val.GetBondedTokens()) @@ -78,57 +53,58 @@ func TestBeginBlocker(t *testing.T) { Power: power, } - ctx = ctx.WithCometInfo(comet.Info{ + ctx = integration.SetCometInfo(ctx, comet.Info{ LastCommit: comet.CommitInfo{Votes: []comet.VoteInfo{{ Validator: abciVal, BlockIDFlag: comet.BlockIDFlagCommit, }}}, }) - cometInfoService := runtime.NewContextAwareCometInfoService() + cometInfoService := &services.ContextAwareCometInfoService{} - err = slashing.BeginBlocker(ctx, slashingKeeper, cometInfoService) + err = slashing.BeginBlocker(ctx, f.slashingKeeper, cometInfoService) require.NoError(t, err) - info, err := slashingKeeper.ValidatorSigningInfo.Get(ctx, sdk.ConsAddress(pk.Address())) + info, err := f.slashingKeeper.ValidatorSigningInfo.Get(ctx, sdk.ConsAddress(pk.Address())) require.NoError(t, err) - require.Equal(t, ctx.HeaderInfo().Height, info.StartHeight) + require.Equal(t, integration.HeaderInfoFromContext(ctx).Height, info.StartHeight) require.Equal(t, int64(0), info.IndexOffset) require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) require.Equal(t, int64(0), info.MissedBlocksCounter) height := int64(0) - signedBlocksWindow, err := slashingKeeper.SignedBlocksWindow(ctx) + signedBlocksWindow, err := f.slashingKeeper.SignedBlocksWindow(ctx) require.NoError(t, err) // for 100 blocks, mark the validator as having signed for ; height < signedBlocksWindow; height++ { - ctx = ctx.WithHeaderInfo(coreheader.Info{Height: height}) + ctx = integration.SetHeaderInfo(ctx, coreheader.Info{Height: height}) - err = slashing.BeginBlocker(ctx, slashingKeeper, cometInfoService) + err = slashing.BeginBlocker(ctx, f.slashingKeeper, cometInfoService) require.NoError(t, err) } - minSignedPerWindow, err := slashingKeeper.MinSignedPerWindow(ctx) + minSignedPerWindow, err := f.slashingKeeper.MinSignedPerWindow(ctx) require.NoError(t, err) // for 50 blocks, mark the validator as having not signed for ; height < ((signedBlocksWindow * 2) - minSignedPerWindow + 1); height++ { - ctx = ctx.WithHeaderInfo(coreheader.Info{Height: height}).WithCometInfo(comet.Info{ + ctx = integration.SetHeaderInfo(ctx, coreheader.Info{Height: height}) + ctx = integration.SetCometInfo(ctx, comet.Info{ LastCommit: comet.CommitInfo{Votes: []comet.VoteInfo{{ Validator: abciVal, BlockIDFlag: comet.BlockIDFlagAbsent, }}}, }) - err = slashing.BeginBlocker(ctx, slashingKeeper, cometInfoService) + err = slashing.BeginBlocker(ctx, f.slashingKeeper, cometInfoService) require.NoError(t, err) } // end block - _, err = stakingKeeper.EndBlocker(ctx) + _, err = f.stakingKeeper.EndBlocker(ctx) require.NoError(t, err) // validator should be jailed - validator, err := stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk)) + validator, err := f.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk)) require.NoError(t, err) require.Equal(t, sdk.Unbonding, validator.GetStatus()) } diff --git a/tests/integration/slashing/keeper/keeper_test.go b/tests/integration/v2/slashing/keeper_test.go similarity index 59% rename from tests/integration/slashing/keeper/keeper_test.go rename to tests/integration/v2/slashing/keeper_test.go index 74ccf5da61f8..94a84de3cf12 100644 --- a/tests/integration/slashing/keeper/keeper_test.go +++ b/tests/integration/v2/slashing/keeper_test.go @@ -1,4 +1,4 @@ -package keeper_test +package slashing import ( "context" @@ -6,173 +6,21 @@ import ( "time" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" "gotest.tools/v3/assert" - "cosmossdk.io/core/appmodule" "cosmossdk.io/core/comet" coreheader "cosmossdk.io/core/header" - "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/bank" - bankkeeper "cosmossdk.io/x/bank/keeper" - banktypes "cosmossdk.io/x/bank/types" - "cosmossdk.io/x/consensus" - consensusparamkeeper "cosmossdk.io/x/consensus/keeper" - consensustypes "cosmossdk.io/x/consensus/types" - minttypes "cosmossdk.io/x/mint/types" - "cosmossdk.io/x/slashing" - slashingkeeper "cosmossdk.io/x/slashing/keeper" + "cosmossdk.io/core/transaction" "cosmossdk.io/x/slashing/testutil" slashingtypes "cosmossdk.io/x/slashing/types" - "cosmossdk.io/x/staking" - stakingkeeper "cosmossdk.io/x/staking/keeper" stakingtestutil "cosmossdk.io/x/staking/testutil" stakingtypes "cosmossdk.io/x/staking/types" - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/testutil/integration" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" - moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" - "github.com/cosmos/cosmos-sdk/x/auth" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) -type fixture struct { - app *integration.App - - ctx sdk.Context - - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - slashingKeeper slashingkeeper.Keeper - stakingKeeper *stakingkeeper.Keeper - - addrDels []sdk.AccAddress - valAddrs []sdk.ValAddress -} - -func initFixture(tb testing.TB) *fixture { - tb.Helper() - keys := storetypes.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, slashingtypes.StoreKey, stakingtypes.StoreKey, consensustypes.StoreKey, - ) - encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}) - cdc := encodingCfg.Codec - - authority := authtypes.NewModuleAddress("gov") - - maccPerms := map[string][]string{ - minttypes.ModuleName: {authtypes.Minter}, - stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, - stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, - } - - msgRouter := baseapp.NewMsgServiceRouter() - queryRouter := baseapp.NewGRPCQueryRouter() - - // gomock initializations - ctrl := gomock.NewController(tb) - acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl) - accNum := uint64(0) - acctsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) (uint64, error) { - currentNum := accNum - accNum++ - return currentNum, nil - }) - - accountKeeper := authkeeper.NewAccountKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), - cdc, - authtypes.ProtoBaseAccount, - acctsModKeeper, - maccPerms, - addresscodec.NewBech32Codec(sdk.Bech32MainPrefix), - sdk.Bech32MainPrefix, - authority.String(), - ) - - blockedAddresses := map[string]bool{ - accountKeeper.GetAuthority(): false, - } - bankKeeper := bankkeeper.NewBaseKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), - cdc, - accountKeeper, - blockedAddresses, - authority.String(), - ) - - cometInfoService := runtime.NewContextAwareCometInfoService() - - consensusParamsKeeper := consensusparamkeeper.NewKeeper(cdc, runtime.NewEnvironment(runtime.NewKVStoreService(keys[consensustypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), authtypes.NewModuleAddress("gov").String()) - - stakingKeeper := stakingkeeper.NewKeeper(cdc, runtime.NewEnvironment(runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), accountKeeper, bankKeeper, consensusParamsKeeper, authority.String(), addresscodec.NewBech32Codec(sdk.Bech32PrefixValAddr), addresscodec.NewBech32Codec(sdk.Bech32PrefixConsAddr), cometInfoService) - - slashingKeeper := slashingkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), cdc, &codec.LegacyAmino{}, stakingKeeper, authority.String()) - - bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper) - stakingModule := staking.NewAppModule(cdc, stakingKeeper) - slashingModule := slashing.NewAppModule(cdc, slashingKeeper, accountKeeper, bankKeeper, stakingKeeper, cdc.InterfaceRegistry(), cometInfoService) - consensusModule := consensus.NewAppModule(cdc, consensusParamsKeeper) - - integrationApp := integration.NewIntegrationApp(log.NewNopLogger(), keys, cdc, - encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(), - encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(), - map[string]appmodule.AppModule{ - banktypes.ModuleName: bankModule, - stakingtypes.ModuleName: stakingModule, - slashingtypes.ModuleName: slashingModule, - consensustypes.ModuleName: consensusModule, - }, - msgRouter, - queryRouter, - ) - - sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) - - // Register MsgServer and QueryServer - slashingtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), slashingkeeper.NewMsgServerImpl(slashingKeeper)) - slashingtypes.RegisterQueryServer(integrationApp.QueryHelper(), slashingkeeper.NewQuerier(slashingKeeper)) - - // set default staking params - // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 - err := slashingKeeper.Params.Set(sdkCtx, testutil.TestParams()) - assert.NilError(tb, err) - addrDels := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, sdkCtx, 6, stakingKeeper.TokensFromConsensusPower(sdkCtx, 200)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) - - consaddr0, err := stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[0]) - assert.NilError(tb, err) - consaddr1, err := stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[1]) - assert.NilError(tb, err) - - info1 := slashingtypes.NewValidatorSigningInfo(consaddr0, int64(4), time.Unix(2, 0), false, int64(10)) - info2 := slashingtypes.NewValidatorSigningInfo(consaddr1, int64(5), time.Unix(2, 0), false, int64(10)) - - err = slashingKeeper.ValidatorSigningInfo.Set(sdkCtx, sdk.ConsAddress(addrDels[0]), info1) - assert.NilError(tb, err) - err = slashingKeeper.ValidatorSigningInfo.Set(sdkCtx, sdk.ConsAddress(addrDels[1]), info2) - assert.NilError(tb, err) - return &fixture{ - app: integrationApp, - ctx: sdkCtx, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, - slashingKeeper: slashingKeeper, - stakingKeeper: stakingKeeper, - addrDels: addrDels, - valAddrs: valAddrs, - } -} - func TestUnJailNotBonded(t *testing.T) { t.Parallel() f := initFixture(t) @@ -194,8 +42,8 @@ func TestUnJailNotBonded(t *testing.T) { _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) - newHeight := f.ctx.BlockHeight() + 1 - f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight}) + newHeight := int64(f.app.LastBlockHeight()) + 1 + 1 + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight}) // create a 6th validator with less power than the cliff validator (won't be bonded) addr, val := f.valAddrs[5], pks[5] @@ -211,8 +59,8 @@ func TestUnJailNotBonded(t *testing.T) { _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) - newHeight = f.ctx.BlockHeight() + 1 - f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight}) + newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1 + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight}) tstaking.CheckValidator(addr, stakingtypes.Unbonded, false) @@ -226,8 +74,8 @@ func TestUnJailNotBonded(t *testing.T) { _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) - newHeight = f.ctx.BlockHeight() + 1 - f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight}) + newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1 + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight}) // verify that validator is jailed tstaking.CheckValidator(addr, -1, true) @@ -237,16 +85,20 @@ func TestUnJailNotBonded(t *testing.T) { ValidatorAddr: addr.String(), } _, err = f.app.RunMsg( - &msgUnjail, - integration.WithAutomaticFinalizeBlock(), + t, + f.ctx, + func(ctx context.Context) (transaction.Msg, error) { + res, err := f.slashingMsgServer.Unjail(ctx, &msgUnjail) + return res, err + }, integration.WithAutomaticCommit(), ) assert.ErrorContains(t, err, "cannot be unjailed") _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) - newHeight = f.ctx.BlockHeight() + 1 - f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight}) + newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1 + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight}) // bond to meet minimum self-delegationa accAddr, err = f.accountKeeper.AddressCodec().BytesToString(addr) assert.NilError(t, err) @@ -256,13 +108,17 @@ func TestUnJailNotBonded(t *testing.T) { _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) - newHeight = f.ctx.BlockHeight() + 1 - f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight}) + newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1 + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight}) // verify we can immediately unjail _, err = f.app.RunMsg( - &msgUnjail, - integration.WithAutomaticFinalizeBlock(), + t, + f.ctx, + func(ctx context.Context) (transaction.Msg, error) { + res, err := f.slashingMsgServer.Unjail(ctx, &msgUnjail) + return res, err + }, integration.WithAutomaticCommit(), ) assert.NilError(t, err) @@ -277,18 +133,25 @@ func TestHandleNewValidator(t *testing.T) { t.Parallel() f := initFixture(t) + bondDenom, err := f.stakingKeeper.BondDenom(f.ctx) + require.NoError(t, err) + + bondPool := f.stakingKeeper.GetBondedPool(f.ctx) + + initialBondPoolBal := f.bankKeeper.GetBalance(f.ctx, bondPool.GetAddress(), bondDenom).Amount + pks := simtestutil.CreateTestPubKeys(1) addr, valpubkey := f.valAddrs[0], pks[0] tstaking := stakingtestutil.NewHelper(t, f.ctx, f.stakingKeeper) signedBlocksWindow, err := f.slashingKeeper.SignedBlocksWindow(f.ctx) assert.NilError(t, err) - f.ctx = f.ctx.WithBlockHeight(signedBlocksWindow + 1).WithHeaderInfo(coreheader.Info{Height: signedBlocksWindow + 1}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: signedBlocksWindow + 1}) assert.NilError(t, f.slashingKeeper.AddrPubkeyRelation.Set(f.ctx, pks[0].Address(), pks[0])) consaddr, err := f.stakingKeeper.ConsensusAddressCodec().BytesToString(valpubkey.Address()) assert.NilError(t, err) - info := slashingtypes.NewValidatorSigningInfo(consaddr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0)) + info := slashingtypes.NewValidatorSigningInfo(consaddr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0)) assert.NilError(t, f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, sdk.ConsAddress(valpubkey.Address()), info)) assert.Equal(t, signedBlocksWindow+1, info.StartHeight) @@ -300,9 +163,6 @@ func TestHandleNewValidator(t *testing.T) { _, err = f.stakingKeeper.EndBlocker(f.ctx) require.NoError(t, err) - bondDenom, err := f.stakingKeeper.BondDenom(f.ctx) - require.NoError(t, err) - assert.DeepEqual( t, f.bankKeeper.GetAllBalances(f.ctx, sdk.AccAddress(addr)), sdk.NewCoins(sdk.NewCoin(bondDenom, testutil.InitTokens.Sub(amt))), @@ -314,7 +174,7 @@ func TestHandleNewValidator(t *testing.T) { // Now a validator, for two blocks assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, valpubkey.Address(), 100, comet.BlockIDFlagCommit)) - f.ctx = f.ctx.WithBlockHeight(signedBlocksWindow + 2).WithHeaderInfo(coreheader.Info{Height: signedBlocksWindow + 2}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: signedBlocksWindow + 2}) assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, valpubkey.Address(), 100, comet.BlockIDFlagAbsent)) info, found := f.slashingKeeper.ValidatorSigningInfo.Get(f.ctx, sdk.ConsAddress(valpubkey.Address())) @@ -326,8 +186,7 @@ func TestHandleNewValidator(t *testing.T) { // validator should be bonded still, should not have been jailed or slashed validator, _ := f.stakingKeeper.GetValidatorByConsAddr(f.ctx, sdk.GetConsAddress(valpubkey)) assert.Equal(t, sdk.Bonded, validator.GetStatus()) - bondPool := f.stakingKeeper.GetBondedPool(f.ctx) - expTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 100) + expTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 100).Add(initialBondPoolBal) assert.Assert(t, expTokens.Equal(f.bankKeeper.GetBalance(f.ctx, bondPool.GetAddress(), bondDenom).Amount)) } @@ -348,7 +207,7 @@ func TestHandleAlreadyJailed(t *testing.T) { consaddr, err := f.stakingKeeper.ConsensusAddressCodec().BytesToString(val.Address()) assert.NilError(t, err) - info := slashingtypes.NewValidatorSigningInfo(consaddr, f.ctx.HeaderInfo().Height, time.Unix(0, 0), false, int64(0)) + info := slashingtypes.NewValidatorSigningInfo(consaddr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0)) assert.NilError(t, f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, sdk.ConsAddress(val.Address()), info)) acc := f.accountKeeper.NewAccountWithAddress(f.ctx, sdk.AccAddress(addr)) @@ -365,7 +224,7 @@ func TestHandleAlreadyJailed(t *testing.T) { // 1000 first blocks OK height := int64(0) for ; height < signedBlocksWindow; height++ { - f.ctx = f.ctx.WithHeaderInfo(coreheader.Info{Height: height}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}) err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit) assert.NilError(t, err) } @@ -375,7 +234,7 @@ func TestHandleAlreadyJailed(t *testing.T) { // 501 blocks missed for ; height < signedBlocksWindow+(signedBlocksWindow-minSignedPerWindow)+1; height++ { - f.ctx = f.ctx.WithHeaderInfo(coreheader.Info{Height: height}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}) err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent) assert.NilError(t, err) } @@ -393,7 +252,7 @@ func TestHandleAlreadyJailed(t *testing.T) { assert.DeepEqual(t, resultingTokens, validator.GetTokens()) // another block missed - f.ctx = f.ctx.WithHeaderInfo(coreheader.Info{Height: height}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}) assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent)) // validator should not have been slashed twice @@ -432,19 +291,20 @@ func TestValidatorDippingInAndOut(t *testing.T) { consaddrStr, err := f.stakingKeeper.ConsensusAddressCodec().BytesToString(addr) assert.NilError(t, err) - info := slashingtypes.NewValidatorSigningInfo(consaddrStr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0)) + info := slashingtypes.NewValidatorSigningInfo(consaddrStr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0)) assert.NilError(t, f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, consAddr, info)) tstaking.CreateValidatorWithValPower(valAddr, val, power, true) validatorUpdates, err := f.stakingKeeper.EndBlocker(f.ctx) require.NoError(t, err) - assert.Equal(t, 1, len(validatorUpdates)) + // validator updates length should be equal to 2 as we already have one default validator + assert.Equal(t, 2, len(validatorUpdates)) tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) // 100 first blocks OK height := int64(0) for ; height < int64(100); height++ { - f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}) assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit)) } @@ -458,8 +318,10 @@ func TestValidatorDippingInAndOut(t *testing.T) { // 600 more blocks happened height += 600 - f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}) + // store this height as we don't have block height value in context + startHeight := height // validator added back in accAddr, err := f.accountKeeper.AddressCodec().BytesToString(sdk.AccAddress(pks[2].Address())) assert.NilError(t, err) @@ -488,7 +350,7 @@ func TestValidatorDippingInAndOut(t *testing.T) { // misses 500 blocks + within the signing windows i.e. 700-1700 // validators misses all 1000 blocks of a SignedBlockWindows for ; height < latest+1; height++ { - err = f.slashingKeeper.HandleValidatorSignature(f.ctx.WithHeaderInfo(coreheader.Info{Height: height}), val.Address(), newPower, comet.BlockIDFlagAbsent) + err = f.slashingKeeper.HandleValidatorSignature(integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}), val.Address(), newPower, comet.BlockIDFlagAbsent) assert.NilError(t, err) } @@ -497,7 +359,7 @@ func TestValidatorDippingInAndOut(t *testing.T) { assert.NilError(t, err) tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true) - info = slashingtypes.NewValidatorSigningInfo(consaddrStr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0)) + info = slashingtypes.NewValidatorSigningInfo(consaddrStr, startHeight, time.Unix(0, 0), false, int64(0)) err = f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, consAddr, info) assert.NilError(t, err) @@ -510,9 +372,9 @@ func TestValidatorDippingInAndOut(t *testing.T) { // some blocks pass height = int64(5000) - f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}) - info = slashingtypes.NewValidatorSigningInfo(consaddrStr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0)) + info = slashingtypes.NewValidatorSigningInfo(consaddrStr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0)) err = f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, consAddr, info) assert.NilError(t, err) @@ -538,7 +400,7 @@ func TestValidatorDippingInAndOut(t *testing.T) { // validator misses 501 blocks after SignedBlockWindow period (1000 blocks) latest = signedBlocksWindow + height for ; height < latest+minSignedPerWindow; height++ { - f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height}) + f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}) err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagAbsent) assert.NilError(t, err) } diff --git a/tests/integration/slashing/keeper/slash_redelegation_test.go b/tests/integration/v2/slashing/slash_redelegation_test.go similarity index 61% rename from tests/integration/slashing/keeper/slash_redelegation_test.go rename to tests/integration/v2/slashing/slash_redelegation_test.go index b1a8ce858925..4d4b56ff2d33 100644 --- a/tests/integration/slashing/keeper/slash_redelegation_test.go +++ b/tests/integration/v2/slashing/slash_redelegation_test.go @@ -1,4 +1,4 @@ -package keeper_test +package slashing import ( "context" @@ -8,50 +8,24 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/core/header" - "cosmossdk.io/depinject" - "cosmossdk.io/log" "cosmossdk.io/math" bankkeeper "cosmossdk.io/x/bank/keeper" banktestutil "cosmossdk.io/x/bank/testutil" - distributionkeeper "cosmossdk.io/x/distribution/keeper" - slashingkeeper "cosmossdk.io/x/slashing/keeper" stakingkeeper "cosmossdk.io/x/staking/keeper" stakingtypes "cosmossdk.io/x/staking/types" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/tests/integration/slashing" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" sdk "github.com/cosmos/cosmos-sdk/types" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" ) func TestSlashRedelegation(t *testing.T) { - // setting up - var ( - authKeeper authkeeper.AccountKeeper - stakingKeeper *stakingkeeper.Keeper - bankKeeper bankkeeper.Keeper - slashKeeper slashingkeeper.Keeper - distrKeeper distributionkeeper.Keeper - ) - - app, err := simtestutil.Setup( - depinject.Configs( - depinject.Supply(log.NewNopLogger()), - slashing.AppConfig, - ), - &stakingKeeper, - &bankKeeper, - &slashKeeper, - &distrKeeper, - &authKeeper, - ) - require.NoError(t, err) - - // get sdk context, staking msg server and bond denom - ctx := app.BaseApp.NewContext(false) - stakingMsgServer := stakingkeeper.NewMsgServerImpl(stakingKeeper) - bondDenom, err := stakingKeeper.BondDenom(ctx) + f := initFixture(t) + ctx := f.ctx + + stakingMsgServer := stakingkeeper.NewMsgServerImpl(f.stakingKeeper) + bondDenom, err := f.stakingKeeper.BondDenom(ctx) require.NoError(t, err) // evilVal will be slashed, goodVal won't be slashed @@ -65,12 +39,12 @@ func TestSlashRedelegation(t *testing.T) { testAcc2 := sdk.AccAddress([]byte("addr2_______________")) // fund acc 1 and acc 2 - testCoin := sdk.NewCoin(bondDenom, stakingKeeper.TokensFromConsensusPower(ctx, 10)) - fundAccount(t, ctx, bankKeeper, authKeeper, testAcc1, testCoin) - fundAccount(t, ctx, bankKeeper, authKeeper, testAcc2, testCoin) + testCoin := sdk.NewCoin(bondDenom, f.stakingKeeper.TokensFromConsensusPower(ctx, 10)) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc1, testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc2, testCoin) - balance1Before := bankKeeper.GetBalance(ctx, testAcc1, bondDenom) - balance2Before := bankKeeper.GetBalance(ctx, testAcc2, bondDenom) + balance1Before := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom) + balance2Before := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom) // assert acc 1 and acc 2 balance require.Equal(t, balance1Before.Amount.String(), testCoin.Amount.String()) @@ -78,7 +52,7 @@ func TestSlashRedelegation(t *testing.T) { // creating evil val evilValAddr := sdk.ValAddress(evilValPubKey.Address()) - fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(evilValAddr), testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(evilValAddr), testCoin) createValMsg1, _ := stakingtypes.NewMsgCreateValidator( evilValAddr.String(), evilValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt()) _, err = stakingMsgServer.CreateValidator(ctx, createValMsg1) @@ -86,16 +60,17 @@ func TestSlashRedelegation(t *testing.T) { // creating good val goodValAddr := sdk.ValAddress(goodValPubKey.Address()) - fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(goodValAddr), testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(goodValAddr), testCoin) createValMsg2, _ := stakingtypes.NewMsgCreateValidator( goodValAddr.String(), goodValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt()) _, err = stakingMsgServer.CreateValidator(ctx, createValMsg2) require.NoError(t, err) - ctx = ctx.WithBlockHeight(1).WithHeaderInfo(header.Info{Height: 1}) + ctx = integration.SetHeaderInfo(ctx, header.Info{Height: 1}) // next block, commit height 1, move to height 2 // acc 1 and acc 2 delegate to evil val - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state := f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // Acc 2 delegate @@ -111,13 +86,14 @@ func TestSlashRedelegation(t *testing.T) { // next block, commit height 2, move to height 3 // with the new delegations, evil val increases in voting power and commit byzantine behavior at height 3 consensus // at the same time, acc 1 and acc 2 withdraw delegation from evil val - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) - evilVal, err := stakingKeeper.GetValidator(ctx, evilValAddr) + evilVal, err := f.stakingKeeper.GetValidator(ctx, evilValAddr) require.NoError(t, err) - evilPower := stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens) + evilPower := f.stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens) // Acc 1 redelegate from evil val to good val redelMsg := stakingtypes.NewMsgBeginRedelegate(testAcc1.String(), evilValAddr.String(), goodValAddr.String(), testCoin) @@ -135,81 +111,60 @@ func TestSlashRedelegation(t *testing.T) { require.NoError(t, err) // next block, commit height 3, move to height 4 - // Slash evil val for byzantine behavior at height 3 consensus, + // Slash evil val for byzantine behavior at height 2 consensus, // at which acc 1 and acc 2 still contributed to evil val voting power // even tho they undelegate at block 3, the valset update is applied after committed block 3 when height 3 consensus already passes - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // slash evil val with slash factor = 0.9, leaving only 10% of stake after slashing - evilVal, _ = stakingKeeper.GetValidator(ctx, evilValAddr) + evilVal, _ = f.stakingKeeper.GetValidator(ctx, evilValAddr) evilValConsAddr, err := evilVal.GetConsAddr() require.NoError(t, err) - err = slashKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr("0.9"), evilPower, 3) + err = f.slashingKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr("0.9"), evilPower, 2) require.NoError(t, err) - // assert invariant to make sure we conduct slashing correctly - _, stop := stakingkeeper.AllInvariants(stakingKeeper)(ctx) - require.False(t, stop) - - _, stop = bankkeeper.AllInvariants(bankKeeper)(ctx) - require.False(t, stop) - - _, stop = distributionkeeper.AllInvariants(distrKeeper)(ctx) - require.False(t, stop) - // one eternity later - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1000000000000000000)) - require.NoError(t, err) - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + ctxHeader := integration.HeaderInfoFromContext(ctx) + ctxHeader.Time = ctxHeader.Time.Add(time.Duration(1000000000000000000)) + ctx = integration.SetHeaderInfo(ctx, ctxHeader) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // confirm that account 1 and account 2 has been slashed, and the slash amount is correct - balance1AfterSlashing := bankKeeper.GetBalance(ctx, testAcc1, bondDenom) - balance2AfterSlashing := bankKeeper.GetBalance(ctx, testAcc2, bondDenom) + balance1AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom) + balance2AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom) require.Equal(t, balance1AfterSlashing.Amount.Mul(math.NewIntFromUint64(10)).String(), balance1Before.Amount.String()) require.Equal(t, balance2AfterSlashing.Amount.Mul(math.NewIntFromUint64(10)).String(), balance2Before.Amount.String()) } -func fundAccount(t *testing.T, ctx context.Context, bankKeeper bankkeeper.Keeper, authKeeper authkeeper.AccountKeeper, addr sdk.AccAddress, amount ...sdk.Coin) { +func fundAccount(t *testing.T, ctx context.Context, bankKeeper bankkeeper.Keeper, accountKeeper authkeeper.AccountKeeper, addr sdk.AccAddress, amount ...sdk.Coin) { t.Helper() - if authKeeper.GetAccount(ctx, addr) == nil { - addrAcc := authKeeper.NewAccountWithAddress(ctx, addr) - authKeeper.SetAccount(ctx, addrAcc) + if accountKeeper.GetAccount(ctx, addr) == nil { + addrAcc := accountKeeper.NewAccountWithAddress(ctx, addr) + accountKeeper.SetAccount(ctx, addrAcc) } require.NoError(t, banktestutil.FundAccount(ctx, bankKeeper, addr, amount)) } func TestOverSlashing(t *testing.T) { + f := initFixture(t) + ctx := f.ctx + // slash penalty percentage slashFraction := "0.45" // percentage of (undelegation/(undelegation + redelegation)) undelegationPercentageStr := "0.30" - // setting up - var ( - stakingKeeper *stakingkeeper.Keeper - bankKeeper bankkeeper.Keeper - slashKeeper slashingkeeper.Keeper - distrKeeper distributionkeeper.Keeper - authKeeper authkeeper.AccountKeeper - ) - - app, err := simtestutil.Setup(depinject.Configs( - depinject.Supply(log.NewNopLogger()), - slashing.AppConfig, - ), &stakingKeeper, &bankKeeper, &slashKeeper, &distrKeeper, &authKeeper) - require.NoError(t, err) - - // get sdk context, staking msg server and bond denom - ctx := app.BaseApp.NewContext(false) - stakingMsgServer := stakingkeeper.NewMsgServerImpl(stakingKeeper) - bondDenom, err := stakingKeeper.BondDenom(ctx) + stakingMsgServer := stakingkeeper.NewMsgServerImpl(f.stakingKeeper) + bondDenom, err := f.stakingKeeper.BondDenom(ctx) require.NoError(t, err) // evilVal will be slashed, goodVal won't be slashed @@ -231,13 +186,13 @@ func TestOverSlashing(t *testing.T) { // fund all accounts testCoin := sdk.NewCoin(bondDenom, math.NewInt(1_000_000)) - fundAccount(t, ctx, bankKeeper, authKeeper, testAcc1, testCoin) - fundAccount(t, ctx, bankKeeper, authKeeper, testAcc2, testCoin) - fundAccount(t, ctx, bankKeeper, authKeeper, testAcc3, testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc1, testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc2, testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc3, testCoin) - balance1Before := bankKeeper.GetBalance(ctx, testAcc1, bondDenom) - balance2Before := bankKeeper.GetBalance(ctx, testAcc2, bondDenom) - balance3Before := bankKeeper.GetBalance(ctx, testAcc3, bondDenom) + balance1Before := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom) + balance2Before := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom) + balance3Before := f.bankKeeper.GetBalance(ctx, testAcc3, bondDenom) // assert acc 1, 2 and 3 balance require.Equal(t, testCoin.Amount.String(), balance1Before.Amount.String()) @@ -246,7 +201,7 @@ func TestOverSlashing(t *testing.T) { // create evil val evilValAddr := sdk.ValAddress(evilValPubKey.Address()) - fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(evilValAddr), testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(evilValAddr), testCoin) createValMsg1, _ := stakingtypes.NewMsgCreateValidator( evilValAddr.String(), evilValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt()) _, err = stakingMsgServer.CreateValidator(ctx, createValMsg1) @@ -254,15 +209,16 @@ func TestOverSlashing(t *testing.T) { // create good val 1 goodValAddr := sdk.ValAddress(goodValPubKey.Address()) - fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(goodValAddr), testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(goodValAddr), testCoin) createValMsg2, _ := stakingtypes.NewMsgCreateValidator( goodValAddr.String(), goodValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt()) _, err = stakingMsgServer.CreateValidator(ctx, createValMsg2) require.NoError(t, err) // next block - ctx = ctx.WithBlockHeight(app.LastBlockHeight() + 1).WithHeaderInfo(header.Info{Height: app.LastBlockHeight() + 1}) - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + ctx = integration.SetHeaderInfo(ctx, header.Info{Height: int64(f.app.LastBlockHeight()) + 1}) + _, state := f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // delegate all accs to evil val @@ -279,21 +235,23 @@ func TestOverSlashing(t *testing.T) { require.NoError(t, err) // next block - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // evilValAddr done something bad - misbehaveHeight := ctx.BlockHeader().Height - evilVal, err := stakingKeeper.GetValidator(ctx, evilValAddr) + misbehaveHeight := integration.HeaderInfoFromContext(ctx).Height + evilVal, err := f.stakingKeeper.GetValidator(ctx, evilValAddr) require.NoError(t, err) evilValConsAddr, err := evilVal.GetConsAddr() require.NoError(t, err) - evilPower := stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens) + evilPower := f.stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens) // next block - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // acc 1: redelegate to goodval1 and undelegate FULL amount @@ -319,7 +277,8 @@ func TestOverSlashing(t *testing.T) { amountToUndelegate := undelegationAmountDec.TruncateInt() // next block - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) portionofTestCoins := sdk.NewCoin(bondDenom, amountToUndelegate) @@ -328,38 +287,35 @@ func TestOverSlashing(t *testing.T) { require.NoError(t, err) // next block - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // slash the evil val - err = slashKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr(slashFraction), evilPower, misbehaveHeight) + err = f.slashingKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr(slashFraction), evilPower, misbehaveHeight) require.NoError(t, err) - // assert invariants - _, stop := stakingkeeper.AllInvariants(stakingKeeper)(ctx) - require.False(t, stop) - _, stop = bankkeeper.AllInvariants(bankKeeper)(ctx) - require.False(t, stop) - _, stop = distributionkeeper.AllInvariants(distrKeeper)(ctx) - require.False(t, stop) - // fastforward 2 blocks to complete redelegations and unbondings for i := 0; i < 2; i++ { - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1000000000000000000)) + ctxHeader := integration.HeaderInfoFromContext(ctx) + ctxHeader.Time = ctxHeader.Time.Add(time.Duration(1000000000000000000)) + ctx = integration.SetHeaderInfo(ctx, ctxHeader) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) } // we check all accounts should be slashed with the equal amount, and they should end up with same balance including staked amount - stakedAcc1, err := stakingKeeper.GetDelegatorBonded(ctx, testAcc1) + stakedAcc1, err := f.stakingKeeper.GetDelegatorBonded(ctx, testAcc1) require.NoError(t, err) - stakedAcc2, err := stakingKeeper.GetDelegatorBonded(ctx, testAcc2) + stakedAcc2, err := f.stakingKeeper.GetDelegatorBonded(ctx, testAcc2) require.NoError(t, err) - stakedAcc3, err := stakingKeeper.GetDelegatorBonded(ctx, testAcc3) + stakedAcc3, err := f.stakingKeeper.GetDelegatorBonded(ctx, testAcc3) require.NoError(t, err) - balance1AfterSlashing := bankKeeper.GetBalance(ctx, testAcc1, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc1)) - balance2AfterSlashing := bankKeeper.GetBalance(ctx, testAcc2, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc2)) - balance3AfterSlashing := bankKeeper.GetBalance(ctx, testAcc3, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc3)) + balance1AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc1)) + balance2AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc2)) + balance3AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc3, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc3)) require.Equal(t, "550000stake", balance1AfterSlashing.String()) require.Equal(t, "550000stake", balance2AfterSlashing.String()) @@ -367,32 +323,11 @@ func TestOverSlashing(t *testing.T) { } func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) { - // setting up - var ( - authKeeper authkeeper.AccountKeeper - stakingKeeper *stakingkeeper.Keeper - bankKeeper bankkeeper.Keeper - slashKeeper slashingkeeper.Keeper - distrKeeper distributionkeeper.Keeper - ) - - app, err := simtestutil.Setup( - depinject.Configs( - depinject.Supply(log.NewNopLogger()), - slashing.AppConfig, - ), - &stakingKeeper, - &bankKeeper, - &slashKeeper, - &distrKeeper, - &authKeeper, - ) - require.NoError(t, err) - - // get sdk context, staking msg server and bond denom - ctx := app.BaseApp.NewContext(false).WithBlockHeight(1).WithHeaderInfo(header.Info{Height: 1}) - stakingMsgServer := stakingkeeper.NewMsgServerImpl(stakingKeeper) - bondDenom, err := stakingKeeper.BondDenom(ctx) + f := initFixture(t) + ctx := f.ctx + + stakingMsgServer := stakingkeeper.NewMsgServerImpl(f.stakingKeeper) + bondDenom, err := f.stakingKeeper.BondDenom(ctx) require.NoError(t, err) // create validators DST and SRC @@ -402,9 +337,9 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) { dstAddr := sdk.ValAddress(dstPubKey.Address()) srcAddr := sdk.ValAddress(srcPubKey.Address()) - testCoin := sdk.NewCoin(bondDenom, stakingKeeper.TokensFromConsensusPower(ctx, 1000)) - fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(dstAddr), testCoin) - fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(srcAddr), testCoin) + testCoin := sdk.NewCoin(bondDenom, f.stakingKeeper.TokensFromConsensusPower(ctx, 1000)) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(dstAddr), testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(srcAddr), testCoin) createValMsgDST, _ := stakingtypes.NewMsgCreateValidator( dstAddr.String(), dstPubKey, testCoin, stakingtypes.Description{Details: "Validator DST"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt()) @@ -418,10 +353,10 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) { // create a user accounts and delegate to SRC and DST userAcc := sdk.AccAddress([]byte("user1_______________")) - fundAccount(t, ctx, bankKeeper, authKeeper, userAcc, testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, userAcc, testCoin) userAcc2 := sdk.AccAddress([]byte("user2_______________")) - fundAccount(t, ctx, bankKeeper, authKeeper, userAcc2, testCoin) + fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, userAcc2, testCoin) delMsg := stakingtypes.NewMsgDelegate(userAcc.String(), srcAddr.String(), testCoin) _, err = stakingMsgServer.Delegate(ctx, delMsg) @@ -431,18 +366,20 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) { _, err = stakingMsgServer.Delegate(ctx, delMsg) require.NoError(t, err) - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state := f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // commit an infraction with DST and store the power at this height - dstVal, err := stakingKeeper.GetValidator(ctx, dstAddr) + dstVal, err := f.stakingKeeper.GetValidator(ctx, dstAddr) require.NoError(t, err) - dstPower := stakingKeeper.TokensToConsensusPower(ctx, dstVal.Tokens) + dstPower := f.stakingKeeper.TokensToConsensusPower(ctx, dstVal.Tokens) dstConsAddr, err := dstVal.GetConsAddr() require.NoError(t, err) - dstInfractionHeight := ctx.BlockHeight() + dstInfractionHeight := f.app.LastBlockHeight() + 1 - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // undelegate all the user tokens from DST @@ -451,14 +388,15 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) { require.NoError(t, err) // commit an infraction with SRC and store the power at this height - srcVal, err := stakingKeeper.GetValidator(ctx, srcAddr) + srcVal, err := f.stakingKeeper.GetValidator(ctx, srcAddr) require.NoError(t, err) - srcPower := stakingKeeper.TokensToConsensusPower(ctx, srcVal.Tokens) + srcPower := f.stakingKeeper.TokensToConsensusPower(ctx, srcVal.Tokens) srcConsAddr, err := srcVal.GetConsAddr() require.NoError(t, err) - srcInfractionHeight := ctx.BlockHeight() + srcInfractionHeight := f.app.LastBlockHeight() + 1 - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) // redelegate all the user tokens from SRC to DST @@ -471,7 +409,8 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) { _, err = stakingMsgServer.Undelegate(ctx, undelMsg) require.NoError(t, err) - ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1)) + _, state = f.app.Deliver(t, ctx, nil) + _, err = f.app.Commit(state) require.NoError(t, err) undelMsg = stakingtypes.NewMsgUndelegate(userAcc.String(), dstAddr.String(), testCoin) @@ -479,24 +418,14 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) { require.NoError(t, err) // check that dst now has zero tokens - valDst, err := stakingKeeper.GetValidator(ctx, dstAddr) + valDst, err := f.stakingKeeper.GetValidator(ctx, dstAddr) require.NoError(t, err) require.Equal(t, math.ZeroInt().String(), valDst.Tokens.String()) // slash the infractions - err = slashKeeper.Slash(ctx, dstConsAddr, math.LegacyMustNewDecFromStr("0.8"), dstPower, dstInfractionHeight) + err = f.slashingKeeper.Slash(ctx, dstConsAddr, math.LegacyMustNewDecFromStr("0.8"), dstPower, int64(dstInfractionHeight)) require.NoError(t, err) - err = slashKeeper.Slash(ctx, srcConsAddr, math.LegacyMustNewDecFromStr("0.5"), srcPower, srcInfractionHeight) + err = f.slashingKeeper.Slash(ctx, srcConsAddr, math.LegacyMustNewDecFromStr("0.5"), srcPower, int64(srcInfractionHeight)) require.NoError(t, err) - - // assert invariants to ensure correctness - _, stop := stakingkeeper.AllInvariants(stakingKeeper)(ctx) - require.False(t, stop) - - _, stop = bankkeeper.AllInvariants(bankKeeper)(ctx) - require.False(t, stop) - - _, stop = distributionkeeper.AllInvariants(distrKeeper)(ctx) - require.False(t, stop) } diff --git a/tests/integration/v2/slashing/slashing_test.go b/tests/integration/v2/slashing/slashing_test.go new file mode 100644 index 000000000000..bc835e84a39a --- /dev/null +++ b/tests/integration/v2/slashing/slashing_test.go @@ -0,0 +1,175 @@ +package slashing + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + "gotest.tools/v3/assert" + + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/math" + _ "cosmossdk.io/x/accounts" // import as blank for app wiring + _ "cosmossdk.io/x/bank" // import as blank for app wiring + bankkeeper "cosmossdk.io/x/bank/keeper" + banktestutil "cosmossdk.io/x/bank/testutil" + _ "cosmossdk.io/x/consensus" // import as blank for app wiring + _ "cosmossdk.io/x/distribution" // import as blank for app wiring + distrkeeper "cosmossdk.io/x/distribution/keeper" + _ "cosmossdk.io/x/mint" // import as blank for app wiring + _ "cosmossdk.io/x/protocolpool" // import as blank for app wiring + _ "cosmossdk.io/x/slashing" // import as blank for app wiring + slashingkeeper "cosmossdk.io/x/slashing/keeper" + "cosmossdk.io/x/slashing/testutil" + slashingtypes "cosmossdk.io/x/slashing/types" + _ "cosmossdk.io/x/staking" // import as blank for app wiring + stakingkeeper "cosmossdk.io/x/staking/keeper" + stakingtypes "cosmossdk.io/x/staking/types" + + "github.com/cosmos/cosmos-sdk/client" + codecaddress "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/x/auth" // import as blank for app wiring + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import as blank for app wiring + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + _ "github.com/cosmos/cosmos-sdk/x/genutil" // import as blank for app wiring +) + +var ( + priv1 = secp256k1.GenPrivKey() + addr1 = sdk.AccAddress(priv1.PubKey().Address()) + valaddrCodec = codecaddress.NewBech32Codec("cosmosvaloper") + + valKey = ed25519.GenPrivKey() + valAddr = sdk.AccAddress(valKey.PubKey().Address()) +) + +type fixture struct { + app *integration.App + + ctx context.Context + + accountKeeper authkeeper.AccountKeeper + bankKeeper bankkeeper.Keeper + slashingKeeper slashingkeeper.Keeper + stakingKeeper *stakingkeeper.Keeper + distrKeeper distrkeeper.Keeper + + slashingMsgServer slashingtypes.MsgServer + txConfig client.TxConfig + + valAddrs []sdk.ValAddress +} + +func initFixture(t *testing.T) *fixture { + t.Helper() + + res := fixture{} + + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.StakingModule(), + configurator.SlashingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.GenutilModule(), + configurator.MintModule(), + configurator.DistributionModule(), + configurator.ProtocolPoolModule(), + } + + acc := &authtypes.BaseAccount{ + Address: addr1.String(), + } + + var err error + startupCfg := integration.DefaultStartUpConfig(t) + startupCfg.GenesisAccounts = []integration.GenesisAccount{{GenesisAccount: acc}} + + startupCfg.BranchService = &integration.BranchService{} + startupCfg.HeaderService = &integration.HeaderService{} + + res.app, err = integration.NewApp( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), + startupCfg, + &res.bankKeeper, &res.accountKeeper, &res.stakingKeeper, &res.slashingKeeper, &res.distrKeeper, &res.txConfig) + require.NoError(t, err) + + res.ctx = res.app.StateLatestContext(t) + + // set default staking params + // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 + err = res.slashingKeeper.Params.Set(res.ctx, testutil.TestParams()) + assert.NilError(t, err) + + addrDels := simtestutil.AddTestAddrsIncremental(res.bankKeeper, res.stakingKeeper, res.ctx, 6, res.stakingKeeper.TokensFromConsensusPower(res.ctx, 200)) + valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) + + consaddr0, err := res.stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[0]) + require.NoError(t, err) + consaddr1, err := res.stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[1]) + require.NoError(t, err) + + info1 := slashingtypes.NewValidatorSigningInfo(consaddr0, int64(4), time.Unix(2, 0), false, int64(10)) + info2 := slashingtypes.NewValidatorSigningInfo(consaddr1, int64(5), time.Unix(2, 0), false, int64(10)) + + err = res.slashingKeeper.ValidatorSigningInfo.Set(res.ctx, sdk.ConsAddress(addrDels[0]), info1) + require.NoError(t, err) + err = res.slashingKeeper.ValidatorSigningInfo.Set(res.ctx, sdk.ConsAddress(addrDels[1]), info2) + require.NoError(t, err) + + res.valAddrs = valAddrs + res.slashingMsgServer = slashingkeeper.NewMsgServerImpl(res.slashingKeeper) + + return &res +} + +func TestSlashingMsgs(t *testing.T) { + f := initFixture(t) + + genTokens := sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction) + bondTokens := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) + genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) + bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens) + + require.NoError(t, banktestutil.FundAccount(f.ctx, f.bankKeeper, addr1, sdk.NewCoins(genCoin))) + + description := stakingtypes.NewDescription("foo_moniker", "", "", "", "", &stakingtypes.Metadata{}) + commission := stakingtypes.NewCommissionRates(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec()) + + addrStrVal, err := valaddrCodec.BytesToString(addr1) + require.NoError(t, err) + createValidatorMsg, err := stakingtypes.NewMsgCreateValidator( + addrStrVal, valKey.PubKey(), bondCoin, description, commission, math.OneInt(), + ) + require.NoError(t, err) + + _ = f.app.SignCheckDeliver(t, f.ctx, []sdk.Msg{createValidatorMsg}, "", []uint64{0}, []uint64{0}, []cryptotypes.PrivKey{priv1}, "") + require.True(t, sdk.Coins{genCoin.Sub(bondCoin)}.Equal(f.bankKeeper.GetAllBalances(f.ctx, addr1))) + + validator, err := f.stakingKeeper.GetValidator(f.ctx, sdk.ValAddress(addr1)) + require.NoError(t, err) + + require.Equal(t, addrStrVal, validator.OperatorAddress) + require.Equal(t, stakingtypes.Bonded, validator.Status) + require.True(math.IntEq(t, bondTokens, validator.BondedTokens())) + unjailMsg := &slashingtypes.MsgUnjail{ValidatorAddr: addrStrVal} + + _, err = f.slashingKeeper.ValidatorSigningInfo.Get(f.ctx, sdk.ConsAddress(valAddr)) + require.NoError(t, err) + + // unjail should fail with validator not jailed error + _ = f.app.SignCheckDeliver(t, f.ctx, []sdk.Msg{unjailMsg}, "", []uint64{0}, []uint64{1}, []cryptotypes.PrivKey{priv1}, slashingtypes.ErrValidatorNotJailed.Error()) +} diff --git a/tests/systemtests/authz_test.go b/tests/systemtests/authz_test.go index 902b6631e8f8..9e6f117bb905 100644 --- a/tests/systemtests/authz_test.go +++ b/tests/systemtests/authz_test.go @@ -682,78 +682,78 @@ func TestAuthzGRPCQueries(t *testing.T) { grantTestCases := []systest.RestTestCase{ { - "invalid granter address", - fmt.Sprintf(grantURL, "invalid_granter", grantee1Addr, msgSendTypeURL), - http.StatusInternalServerError, - bech32FailOutput, + Name: "invalid granter address", + Url: fmt.Sprintf(grantURL, "invalid_granter", grantee1Addr, msgSendTypeURL), + ExpCodeGTE: http.StatusBadRequest, + ExpOut: bech32FailOutput, }, { - "invalid grantee address", - fmt.Sprintf(grantURL, granterAddr, "invalid_grantee", msgSendTypeURL), - http.StatusInternalServerError, - bech32FailOutput, + Name: "invalid grantee address", + Url: fmt.Sprintf(grantURL, granterAddr, "invalid_grantee", msgSendTypeURL), + ExpCodeGTE: http.StatusBadRequest, + ExpOut: bech32FailOutput, }, { - "with empty granter", - fmt.Sprintf(grantURL, "", grantee1Addr, msgSendTypeURL), - http.StatusInternalServerError, - emptyStrOutput, + Name: "with empty granter", + Url: fmt.Sprintf(grantURL, "", grantee1Addr, msgSendTypeURL), + ExpCodeGTE: http.StatusBadRequest, + ExpOut: emptyStrOutput, }, { - "with empty grantee", - fmt.Sprintf(grantURL, granterAddr, "", msgSendTypeURL), - http.StatusInternalServerError, - emptyStrOutput, + Name: "with empty grantee", + Url: fmt.Sprintf(grantURL, granterAddr, "", msgSendTypeURL), + ExpCodeGTE: http.StatusBadRequest, + ExpOut: emptyStrOutput, }, { - "invalid msg-type", - fmt.Sprintf(grantURL, granterAddr, grantee1Addr, "invalidMsg"), - http.StatusInternalServerError, - invalidMsgTypeOutput, + Name: "invalid msg-type", + Url: fmt.Sprintf(grantURL, granterAddr, grantee1Addr, "invalidMsg"), + ExpCode: http.StatusInternalServerError, + ExpOut: invalidMsgTypeOutput, }, { - "valid grant query", - fmt.Sprintf(grantURL, granterAddr, grantee1Addr, msgSendTypeURL), - http.StatusOK, - expGrantOutput, + Name: "valid grant query", + Url: fmt.Sprintf(grantURL, granterAddr, grantee1Addr, msgSendTypeURL), + ExpCode: http.StatusOK, + ExpOut: expGrantOutput, }, } - systest.RunRestQueries(t, grantTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, grantTestCases...) // test query grants grpc endpoint grantsURL := baseurl + "/cosmos/authz/v1beta1/grants?granter=%s&grantee=%s" grantsTestCases := []systest.RestTestCase{ { - "expect single grant", - fmt.Sprintf(grantsURL, granterAddr, grantee1Addr), - http.StatusOK, - fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"1"}}`, grant1), + Name: "expect single grant", + Url: fmt.Sprintf(grantsURL, granterAddr, grantee1Addr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"1"}}`, grant1), }, { - "expect two grants", - fmt.Sprintf(grantsURL, granterAddr, grantee2Addr), - http.StatusOK, - fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"2"}}`, grant2, grant3), + Name: "expect two grants", + Url: fmt.Sprintf(grantsURL, granterAddr, grantee2Addr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"2"}}`, grant2, grant3), }, { - "expect single grant with pagination", - fmt.Sprintf(grantsURL+"&pagination.limit=1", granterAddr, grantee2Addr), - http.StatusOK, - fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":"L2Nvc21vcy5nb3YudjEuTXNnVm90ZQ==","total":"0"}}`, grant2), + Name: "expect single grant with pagination", + Url: fmt.Sprintf(grantsURL+"&pagination.limit=1", granterAddr, grantee2Addr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":"L2Nvc21vcy5nb3YudjEuTXNnVm90ZQ==","total":"0"}}`, grant2), }, { - "expect single grant with pagination limit and offset", - fmt.Sprintf(grantsURL+"&pagination.limit=1&pagination.offset=1", granterAddr, grantee2Addr), - http.StatusOK, - fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant3), + Name: "expect single grant with pagination limit and offset", + Url: fmt.Sprintf(grantsURL+"&pagination.limit=1&pagination.offset=1", granterAddr, grantee2Addr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant3), }, { - "expect two grants with pagination", - fmt.Sprintf(grantsURL+"&pagination.limit=2", granterAddr, grantee2Addr), - http.StatusOK, - fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant2, grant3), + Name: "expect two grants with pagination", + Url: fmt.Sprintf(grantsURL+"&pagination.limit=2", granterAddr, grantee2Addr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant2, grant3), }, } @@ -768,26 +768,26 @@ func TestAuthzGRPCQueries(t *testing.T) { granterTestCases := []systest.RestTestCase{ { - "invalid granter account address", - fmt.Sprintf(grantsByGranterURL, "invalid address"), - http.StatusInternalServerError, - decodingFailedOutput, + Name: "invalid granter account address", + Url: fmt.Sprintf(grantsByGranterURL, "invalid address"), + ExpCodeGTE: http.StatusBadRequest, + ExpOut: decodingFailedOutput, }, { - "no authorizations found from granter", - fmt.Sprintf(grantsByGranterURL, grantee2Addr), - http.StatusOK, - noAuthorizationsOutput, + Name: "no authorizations found from granter", + Url: fmt.Sprintf(grantsByGranterURL, grantee2Addr), + ExpCode: http.StatusOK, + ExpOut: noAuthorizationsOutput, }, { - "valid granter query", - fmt.Sprintf(grantsByGranterURL, grantee1Addr), - http.StatusOK, - granterQueryOutput, + Name: "valid granter query", + Url: fmt.Sprintf(grantsByGranterURL, grantee1Addr), + ExpCode: http.StatusOK, + ExpOut: granterQueryOutput, }, } - systest.RunRestQueries(t, granterTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, granterTestCases...) // test query grants by grantee grpc endpoint grantsByGranteeURL := baseurl + "/cosmos/authz/v1beta1/grants/grantee/%s" @@ -795,26 +795,26 @@ func TestAuthzGRPCQueries(t *testing.T) { granteeTestCases := []systest.RestTestCase{ { - "invalid grantee account address", - fmt.Sprintf(grantsByGranteeURL, "invalid address"), - http.StatusInternalServerError, - decodingFailedOutput, + Name: "invalid grantee account address", + Url: fmt.Sprintf(grantsByGranteeURL, "invalid address"), + ExpCodeGTE: http.StatusBadRequest, + ExpOut: decodingFailedOutput, }, { - "no authorizations found from grantee", - fmt.Sprintf(grantsByGranteeURL, granterAddr), - http.StatusOK, - noAuthorizationsOutput, + Name: "no authorizations found from grantee", + Url: fmt.Sprintf(grantsByGranteeURL, granterAddr), + ExpCode: http.StatusOK, + ExpOut: noAuthorizationsOutput, }, { - "valid grantee query", - fmt.Sprintf(grantsByGranteeURL, grantee1Addr), - http.StatusOK, - grantee1GrantsOutput, + Name: "valid grantee query", + Url: fmt.Sprintf(grantsByGranteeURL, grantee1Addr), + ExpCode: http.StatusOK, + ExpOut: grantee1GrantsOutput, }, } - systest.RunRestQueries(t, granteeTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, granteeTestCases...) } func setupChain(t *testing.T) (*systest.CLIWrapper, string, string) { diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index 1171e1466ab8..c5c45bca6d63 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -265,7 +265,7 @@ func TestBankGRPCQueries(t *testing.T) { map[string]string{ blockHeightHeader: fmt.Sprintf("%d", blockHeight+5), }, - http.StatusInternalServerError, + http.StatusBadRequest, "invalid height", }, { @@ -280,7 +280,7 @@ func TestBankGRPCQueries(t *testing.T) { for _, tc := range supplyTestCases { t.Run(tc.name, func(t *testing.T) { - resp := systest.GetRequestWithHeaders(t, tc.url, tc.headers, tc.expHttpCode) + resp := systest.GetRequestWithHeadersGreaterThanOrEqual(t, tc.url, tc.headers, tc.expHttpCode) require.Contains(t, string(resp), tc.expOut) }) } @@ -289,22 +289,22 @@ func TestBankGRPCQueries(t *testing.T) { denomMetadataUrl := baseurl + "/cosmos/bank/v1beta1/denoms_metadata" dmTestCases := []systest.RestTestCase{ { - "test GRPC client metadata", - denomMetadataUrl, - http.StatusOK, - fmt.Sprintf(`{"metadatas":%s,"pagination":{"next_key":null,"total":"2"}}`, bankDenomMetadata), + Name: "test GRPC client metadata", + Url: denomMetadataUrl, + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"metadatas":%s,"pagination":{"next_key":null,"total":"2"}}`, bankDenomMetadata), }, { - "test GRPC client metadata of a specific denom", - denomMetadataUrl + "/uatom", - http.StatusOK, - fmt.Sprintf(`{"metadata":%s}`, atomDenomMetadata), + Name: "test GRPC client metadata of a specific denom", + Url: denomMetadataUrl + "/uatom", + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"metadata":%s}`, atomDenomMetadata), }, { - "test GRPC client metadata of a bogus denom", - denomMetadataUrl + "/foobar", - http.StatusNotFound, - `{"code":5, "message":"client metadata for denom foobar", "details":[]}`, + Name: "test GRPC client metadata of a bogus denom", + Url: denomMetadataUrl + "/foobar", + ExpCode: http.StatusNotFound, + ExpOut: `{"code":5, "message":"client metadata for denom foobar", "details":[]}`, }, } @@ -316,22 +316,22 @@ func TestBankGRPCQueries(t *testing.T) { balanceTestCases := []systest.RestTestCase{ { - "test GRPC total account balance", - balanceUrl + account1Addr, - http.StatusOK, - allBalancesOutput, + Name: "test GRPC total account balance", + Url: balanceUrl + account1Addr, + ExpCode: http.StatusOK, + ExpOut: allBalancesOutput, }, { - "test GRPC account balance of a specific denom", - fmt.Sprintf("%s%s/by_denom?denom=%s", balanceUrl, account1Addr, newDenom), - http.StatusOK, - fmt.Sprintf(`{"balance":%s}`, specificDenomOutput), + Name: "test GRPC account balance of a specific denom", + Url: fmt.Sprintf("%s%s/by_denom?denom=%s", balanceUrl, account1Addr, newDenom), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"balance":%s}`, specificDenomOutput), }, { - "test GRPC account balance of a bogus denom", - fmt.Sprintf("%s%s/by_denom?denom=foobar", balanceUrl, account1Addr), - http.StatusOK, - fmt.Sprintf(`{"balance":%s}`, bogusDenomOutput), + Name: "test GRPC account balance of a bogus denom", + Url: fmt.Sprintf("%s%s/by_denom?denom=foobar", balanceUrl, account1Addr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"balance":%s}`, bogusDenomOutput), }, } diff --git a/tests/systemtests/distribution_test.go b/tests/systemtests/distribution_test.go index 7e40589bf5da..495fd5807e81 100644 --- a/tests/systemtests/distribution_test.go +++ b/tests/systemtests/distribution_test.go @@ -129,10 +129,10 @@ func TestDistrValidatorGRPCQueries(t *testing.T) { paramsTestCases := []systest.RestTestCase{ { - "gRPC request params", - paramsURL, - http.StatusOK, - `{"params":{"community_tax":"0.020000000000000000","base_proposer_reward":"0.000000000000000000","bonus_proposer_reward":"0.000000000000000000","withdraw_addr_enabled":true}}`, + Name: "gRPC request params", + Url: paramsURL, + ExpCode: http.StatusOK, + ExpOut: `{"params":{"community_tax":"0.020000000000000000","base_proposer_reward":"0.000000000000000000","bonus_proposer_reward":"0.000000000000000000","withdraw_addr_enabled":true}}`, }, } systest.RunRestQueries(t, paramsTestCases...) @@ -143,39 +143,39 @@ func TestDistrValidatorGRPCQueries(t *testing.T) { validatorsTestCases := []systest.RestTestCase{ { - "gRPC request validator with valid validator address", - fmt.Sprintf(validatorsURL, valOperAddr), - http.StatusOK, - validatorsOutput, + Name: "gRPC request validator with valid validator address", + Url: fmt.Sprintf(validatorsURL, valOperAddr), + ExpCode: http.StatusOK, + ExpOut: validatorsOutput, }, } - systest.TestRestQueryIgnoreNumbers(t, validatorsTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, validatorsTestCases...) // test outstanding rewards grpc endpoint outstandingRewardsURL := baseurl + `/cosmos/distribution/v1beta1/validators/%s/outstanding_rewards` rewardsTestCases := []systest.RestTestCase{ { - "gRPC request outstanding rewards with valid validator address", - fmt.Sprintf(outstandingRewardsURL, valOperAddr), - http.StatusOK, - fmt.Sprintf(`{"rewards":{"rewards":[%s]}}`, expectedAmountOutput), + Name: "gRPC request outstanding rewards with valid validator address", + Url: fmt.Sprintf(outstandingRewardsURL, valOperAddr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"rewards":{"rewards":[%s]}}`, expectedAmountOutput), }, } - systest.TestRestQueryIgnoreNumbers(t, rewardsTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, rewardsTestCases...) // test validator commission grpc endpoint commissionURL := baseurl + `/cosmos/distribution/v1beta1/validators/%s/commission` commissionTestCases := []systest.RestTestCase{ { - "gRPC request commission with valid validator address", - fmt.Sprintf(commissionURL, valOperAddr), - http.StatusOK, - fmt.Sprintf(`{"commission":{"commission":[%s]}}`, expectedAmountOutput), + Name: "gRPC request commission with valid validator address", + Url: fmt.Sprintf(commissionURL, valOperAddr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"commission":{"commission":[%s]}}`, expectedAmountOutput), }, } - systest.TestRestQueryIgnoreNumbers(t, commissionTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, commissionTestCases...) // test validator slashes grpc endpoint slashURL := baseurl + `/cosmos/distribution/v1beta1/validators/%s/slashes` @@ -183,25 +183,25 @@ func TestDistrValidatorGRPCQueries(t *testing.T) { slashTestCases := []systest.RestTestCase{ { - "invalid start height", - fmt.Sprintf(slashURL+`?starting_height=%s&ending_height=%s`, valOperAddr, "-3", "3"), - http.StatusBadRequest, - invalidHeightOutput, + Name: "invalid start height", + Url: fmt.Sprintf(slashURL+`?starting_height=%s&ending_height=%s`, valOperAddr, "-3", "3"), + ExpCode: http.StatusBadRequest, + ExpOut: invalidHeightOutput, }, { - "invalid end height", - fmt.Sprintf(slashURL+`?starting_height=%s&ending_height=%s`, valOperAddr, "1", "-3"), - http.StatusBadRequest, - invalidHeightOutput, + Name: "invalid end height", + Url: fmt.Sprintf(slashURL+`?starting_height=%s&ending_height=%s`, valOperAddr, "1", "-3"), + ExpCode: http.StatusBadRequest, + ExpOut: invalidHeightOutput, }, { - "valid request get slashes", - fmt.Sprintf(slashURL+`?starting_height=%s&ending_height=%s`, valOperAddr, "1", "3"), - http.StatusOK, - `{"slashes":[],"pagination":{"next_key":null,"total":"0"}}`, + Name: "valid request get slashes", + Url: fmt.Sprintf(slashURL+`?starting_height=%s&ending_height=%s`, valOperAddr, "1", "3"), + ExpCode: http.StatusOK, + ExpOut: `{"slashes":[],"pagination":{"next_key":null,"total":"0"}}`, }, } - systest.RunRestQueries(t, slashTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, slashTestCases...) } func TestDistrDelegatorGRPCQueries(t *testing.T) { @@ -257,28 +257,28 @@ func TestDistrDelegatorGRPCQueries(t *testing.T) { delegatorRewardsTestCases := []systest.RestTestCase{ { - "valid rewards request with valid delegator address", - fmt.Sprintf(delegatorRewardsURL, delAddr), - http.StatusOK, - rewardsOutput, + Name: "valid rewards request with valid delegator address", + Url: fmt.Sprintf(delegatorRewardsURL, delAddr), + ExpCode: http.StatusOK, + ExpOut: rewardsOutput, }, { - "valid request(specific validator rewards)", - fmt.Sprintf(delegatorRewardsURL+`/%s`, delAddr, valOperAddr), - http.StatusOK, - fmt.Sprintf(`{"rewards":[%s]}`, expectedAmountOutput), + Name: "valid request(specific validator rewards)", + Url: fmt.Sprintf(delegatorRewardsURL+`/%s`, delAddr, valOperAddr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"rewards":[%s]}`, expectedAmountOutput), }, } - systest.TestRestQueryIgnoreNumbers(t, delegatorRewardsTestCases...) + systest.RunRestQueriesIgnoreNumbers(t, delegatorRewardsTestCases...) // test delegator validators grpc endpoint delegatorValsURL := baseurl + `/cosmos/distribution/v1beta1/delegators/%s/validators` valsTestCases := []systest.RestTestCase{ { - "gRPC request delegator validators with valid delegator address", - fmt.Sprintf(delegatorValsURL, delAddr), - http.StatusOK, - fmt.Sprintf(`{"validators":["%s"]}`, valOperAddr), + Name: "gRPC request delegator validators with valid delegator address", + Url: fmt.Sprintf(delegatorValsURL, delAddr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"validators":["%s"]}`, valOperAddr), }, } systest.RunRestQueries(t, valsTestCases...) @@ -287,10 +287,10 @@ func TestDistrDelegatorGRPCQueries(t *testing.T) { withdrawAddrURL := baseurl + `/cosmos/distribution/v1beta1/delegators/%s/withdraw_address` withdrawAddrTestCases := []systest.RestTestCase{ { - "gRPC request withdraw address with valid delegator address", - fmt.Sprintf(withdrawAddrURL, delAddr), - http.StatusOK, - fmt.Sprintf(`{"withdraw_address":"%s"}`, delAddr), + Name: "gRPC request withdraw address with valid delegator address", + Url: fmt.Sprintf(withdrawAddrURL, delAddr), + ExpCode: http.StatusOK, + ExpOut: fmt.Sprintf(`{"withdraw_address":"%s"}`, delAddr), }, } systest.RunRestQueries(t, withdrawAddrTestCases...) diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index 558c01f2699a..0305bff6e11e 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -4,7 +4,7 @@ go 1.23 require ( cosmossdk.io/math v1.4.0 - cosmossdk.io/systemtests v1.0.0-rc.1.0.20241128092904-215d5c16f64d + cosmossdk.io/systemtests v1.0.0-rc.2.0.20241205143753-9e94ea87f6e4 github.com/cosmos/cosmos-sdk v0.50.6 ) diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index b8ade34dcea5..8c0abace40bd 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -16,8 +16,8 @@ cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ= cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk= cosmossdk.io/store v1.1.0 h1:LnKwgYMc9BInn9PhpTFEQVbL9UK475G2H911CGGnWHk= cosmossdk.io/store v1.1.0/go.mod h1:oZfW/4Fc/zYqu3JmQcQdUJ3fqu5vnYTn3LZFFy8P8ng= -cosmossdk.io/systemtests v1.0.0-rc.1.0.20241128092904-215d5c16f64d h1:zZUt9DD+3qvwnpQHPwYJ5+NEUU4wMFeNpPBegWMfbn8= -cosmossdk.io/systemtests v1.0.0-rc.1.0.20241128092904-215d5c16f64d/go.mod h1:ME2eFY/+2CjaFrPOMW8paPXupMzYaDMTKQ1sRvi71hU= +cosmossdk.io/systemtests v1.0.0-rc.2.0.20241205143753-9e94ea87f6e4 h1:gt0rrxBW4x9KM3+ES8Gy5BZbKIHI3AspYEuvWZO6fgU= +cosmossdk.io/systemtests v1.0.0-rc.2.0.20241205143753-9e94ea87f6e4/go.mod h1:B3RY1tY/iwLjQ9MUTz+GsiXV9gEdS8mfUvSQtWUwaAo= cosmossdk.io/x/tx v0.13.3-0.20240419091757-db5906b1e894 h1:kHEvzVqpNv/9pnaEPBsgE/FMc+cVmWjSsInRufkZkpQ= cosmossdk.io/x/tx v0.13.3-0.20240419091757-db5906b1e894/go.mod h1:Tb6/tpONmtL5qFdOMdv1pdvrtJNxcazZBoz04HB71ss= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= diff --git a/tests/systemtests/mint_test.go b/tests/systemtests/mint_test.go index d1c43bd9d863..e6712c4af327 100644 --- a/tests/systemtests/mint_test.go +++ b/tests/systemtests/mint_test.go @@ -40,13 +40,6 @@ func TestMintQueries(t *testing.T) { baseurl := systest.Sut.APIAddress() blockHeightHeader := "x-cosmos-block-height" queryAtHeight := "1" - - // TODO: check why difference in values when querying with height between v1 and v2 - // ref: https://github.com/cosmos/cosmos-sdk/issues/22302 - if systest.IsV2() { - queryAtHeight = "2" - } - paramsResp := `{"params":{"mint_denom":"stake","inflation_rate_change":"0.130000000000000000","inflation_max":"1.000000000000000000","inflation_min":"0.000000000000000000","goal_bonded":"0.670000000000000000","blocks_per_year":"6311520","max_supply":"0"}}` inflationResp := `{"inflation":"1.000000000000000000"}` annualProvisionsResp := `{"annual_provisions":"2000000000.000000000000000000"}` diff --git a/tests/systemtests/staking_test.go b/tests/systemtests/staking_test.go index ba734d6e8d90..b1b3829a9d1f 100644 --- a/tests/systemtests/staking_test.go +++ b/tests/systemtests/staking_test.go @@ -42,7 +42,11 @@ func TestStakeUnstake(t *testing.T) { assert.Equal(t, int64(8999999), cli.QueryBalance(account1Addr, "stake")) // check validator has been updated - rsp = cli.CustomQuery("q", "block-results", gjson.Get(rsp, "height").String()) + if systest.IsV2() { + rsp = cli.CustomQuery("q", "comet", "block-results", gjson.Get(rsp, "height").String()) + } else { + rsp = cli.CustomQuery("q", "block-results", gjson.Get(rsp, "height").String()) + } validatorUpdates := gjson.Get(rsp, "validator_updates").Array() assert.NotEmpty(t, validatorUpdates) vpk := gjson.Get(validatorUpdates[0].String(), "pub_key_bytes").String() diff --git a/testutil/sims/address_helpers.go b/testutil/sims/address_helpers.go index d0b8bb8ce7fc..f90225502b80 100644 --- a/testutil/sims/address_helpers.go +++ b/testutil/sims/address_helpers.go @@ -2,6 +2,7 @@ package sims import ( "bytes" + "context" "encoding/hex" "errors" "strconv" @@ -20,7 +21,7 @@ const mintModuleName = "mint" type GenerateAccountStrategy func(int) []sdk.AccAddress // AddTestAddrsFromPubKeys adds the addresses into the SimApp providing only the public keys. -func AddTestAddrsFromPubKeys(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt math.Int) { +func AddTestAddrsFromPubKeys(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx context.Context, pubKeys []cryptotypes.PubKey, accAmt math.Int) { bondDenom, err := stakingKeeper.BondDenom(ctx) if err != nil { panic(err) @@ -39,11 +40,11 @@ func AddTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Co } // AddTestAddrsIncremental constructs and returns accNum amount of accounts with an initial balance of accAmt in random order -func AddTestAddrsIncremental(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Context, accNum int, accAmt math.Int) []sdk.AccAddress { +func AddTestAddrsIncremental(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx context.Context, accNum int, accAmt math.Int) []sdk.AccAddress { return addTestAddrs(bankKeeper, stakingKeeper, ctx, accNum, accAmt, CreateIncrementalAccounts) } -func addTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Context, accNum int, accAmt math.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { +func addTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx context.Context, accNum int, accAmt math.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { testAddrs := strategy(accNum) bondDenom, err := stakingKeeper.BondDenom(ctx) if err != nil { @@ -58,7 +59,7 @@ func addTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Co return testAddrs } -func initAccountWithCoins(bankKeeper BankKeeper, ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) { +func initAccountWithCoins(bankKeeper BankKeeper, ctx context.Context, addr sdk.AccAddress, coins sdk.Coins) { if err := bankKeeper.MintCoins(ctx, mintModuleName, coins); err != nil { panic(err) } diff --git a/tools/confix/upgrade.go b/tools/confix/upgrade.go index d212bbfb7927..d0ced95da66f 100644 --- a/tools/confix/upgrade.go +++ b/tools/confix/upgrade.go @@ -44,7 +44,7 @@ func Upgrade(ctx context.Context, plan transform.Plan, doc *tomledit.Document, c } // ignore validation for serverv2 by checking any default field found in doc - isServerV2 := doc.First(strings.Split("store.options.ss-pruning-option", ".")...) != nil + isServerV2 := doc.First(strings.Split("store.options.sc-pruning-option", ".")...) != nil // allow to skip validation if !skipValidate && !isServerV2 { diff --git a/x/accounts/defaults/lockup/README.md b/x/accounts/defaults/lockup/README.md index 8525b18cd5ef..879d4a9a7e1d 100644 --- a/x/accounts/defaults/lockup/README.md +++ b/x/accounts/defaults/lockup/README.md @@ -8,6 +8,7 @@ * [PeriodicLockup](#periodiclockup) * [PermanentLocked](#permanentlocked) * [Genesis Initialization](#genesis-initialization) +* [In An Event Of Slashing](#in-an-event-of-slashing) * [Examples](#examples) * [Simple](#simple) * [Slashing](#slashing) @@ -108,6 +109,29 @@ type PermanentLockingAccount struct { +## In An Event Of Slashing + +As defined, base lockup store `DelegatedLocking` by amount. In an event of a validator that the lockup account delegate to is slash which affect the actual delegation amount, this will leave the `DelegatedLocking` have an excess amount even if user undelegate all of the +account delegated amount. This excess amount would affect the spendable amount, further details are as below: + +The spendable amount is calculated as: +`spendableAmount` = `balance` - `notBondedLockedAmount` +where `notBondedLockedAmount` = `lockedAmount` - `Min(lockedAmount, delegatedLockedAmount)` + +As seen in the formula `notBondedLockedAmout` can only be 0 or a positive value when `DelegatedLockedAmount` < `LockedAmount`. Let call `NewDelegatedLockedAmount` is the `delegatedLockedAmount` when applying N slash + +1. Case 1: Originally `DelegatedLockedAmount` > `lockedAmount` but when applying the slash amount the `NewDelegatedLockedAmount` < `lockedAmount` then + * When not applying slash `notBondedLockedAmout` will be 0 + * When apply slash `notBondedLockedAmout` will be `lockedAmount` - `NewDelegatedLockedAmount` = a positive amount +2. Case 2: where originally `DelegatedLockedAmount` < `lockedAmount` when applying the slash amount the `NewDelegatedLockedAmount` < `lockedAmount` then + * When not applying slash `lockedAmount` - `DelegatedLockedAmount` + * When apply slash `notBondedLockedAmout` will be `lockedAmount` - `NewDelegatedLockedAmount` = `lockedAmount` - `(DelegatedLockedAmount - N)` = `lockedAmount` - `DelegatedLockedAmount` + N +3. Case 3: where originally `DelegatedLockedAmount` > `lockedAmount` when applying the slash amount still the `NewDelegatedLockedAmount` > `lockedAmount` then `notBondedLockedAmout` will be 0 applying slash or not + +In cases 1 and 2, `notBondedLockedAmount` decreases when not applying the slash, resulting in a higher `spendableAmount`. + +Due to the nature of x/accounts, as other modules cannot assume certain account types exist so the handling of slashing event must be done internally within x/accounts's accounts. For lockup accounts, this would make the logic overcomplicated. Since these effects are only an edge case that affect a small number of users, so here we would accept the trade off for a simpler design. This design decision aligns with the legacy vesting account implementation. + ## Examples ### Simple @@ -206,7 +230,7 @@ It can still, however, delegate. BC = 2.5 + 5 = 7.5 ``` - Notice how we have an excess amount of `DV`. + Notice how we have an excess amount of `DV`. This is explained in [In An Event Of Slashing](#in-an-event-of-slashing) ### Periodic Lockup