diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f6f4bac4f..2ac71a408 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,14 +1,6 @@ --- -on: - push: - paths: - - '**.go' - - 'go.sum' - pull_request: - paths: - - '**.go' - - 'go.sum' -name: build +on: [push, pull_request] +name: Build concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -19,22 +11,22 @@ jobs: runs-on: ubuntu-latest name: build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: '1.20' - run: go build ./... tidy: runs-on: ubuntu-latest name: tidy steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: '1.20' - run: | go mod tidy CHANGES_IN_REPO=$(git status --porcelain) @@ -42,4 +34,4 @@ jobs: echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" git status && git --no-pager diff exit 1 - fi \ No newline at end of file + fi diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1a631167a..99f8006b7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/interchaintest.yml b/.github/workflows/interchaintest.yml index 4529d0fed..760beb1d2 100644 --- a/.github/workflows/interchaintest.yml +++ b/.github/workflows/interchaintest.yml @@ -33,15 +33,15 @@ jobs: push: true platforms: linux/amd64 tags: | - ghcr.io/notional-labs/centauri-ictest:latest + ghcr.io/composablefi/centauri-ictest:latest test-start-cosmos-chain: runs-on: ubuntu-latest needs: build-and-push-image steps: - - name: Set up Go 1.19 + - name: Set up Go 1.20 uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - name: checkout code uses: actions/checkout@v3 @@ -54,10 +54,10 @@ jobs: runs-on: ubuntu-latest needs: build-and-push-image steps: - - name: Set up Go 1.19 + - name: Set up Go 1.20 uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - name: checkout code uses: actions/checkout@v3 @@ -70,10 +70,10 @@ jobs: runs-on: ubuntu-latest needs: build-and-push-image steps: - - name: Set up Go 1.19 + - name: Set up Go 1.20 uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - name: checkout code uses: actions/checkout@v3 @@ -86,10 +86,10 @@ jobs: runs-on: ubuntu-latest needs: build-and-push-image steps: - - name: Set up Go 1.19 + - name: Set up Go 1.20 uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - name: checkout code uses: actions/checkout@v3 @@ -102,10 +102,10 @@ jobs: # runs-on: ubuntu-latest # needs: build-and-push-image # steps: - # - name: Set up Go 1.19 + # - name: Set up Go 1.20 # uses: actions/setup-go@v3 # with: - # go-version: 1.19 + # go-version: 1.20 # - name: checkout code # uses: actions/checkout@v3 @@ -118,10 +118,10 @@ jobs: # runs-on: ubuntu-latest # needs: build-and-push-image # steps: - # - name: Set up Go 1.19 + # - name: Set up Go 1.20 # uses: actions/setup-go@v3 # with: - # go-version: 1.19 + # go-version: 1.20 # - name: checkout code # uses: actions/checkout@v3 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3188ae602..4ff29966a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: "1.20" - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b78394d8b..55a2a0b76 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,10 +12,10 @@ jobs: name: test steps: - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: '1.20' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test run: go test ./... \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2c129d821..3e31d2e6b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,13 +7,15 @@ ARG RUNNER_IMAGE="gcr.io/distroless/static-debian11" # Builder # -------------------------------------------------------- -FROM golang:${GO_VERSION}-alpine as builder +FROM golang:${GO_VERSION}-alpine3.18 as builder ARG GIT_VERSION ARG GIT_COMMIT RUN apk add --no-cache \ ca-certificates \ + musl-dev \ + openssl-dev \ build-base \ linux-headers diff --git a/x/stakingmiddleware/keeper/keeper_test.go b/x/stakingmiddleware/keeper/keeper_test.go new file mode 100644 index 000000000..185dd9d9a --- /dev/null +++ b/x/stakingmiddleware/keeper/keeper_test.go @@ -0,0 +1,110 @@ +package keeper_test + +import ( + "testing" + "time" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/notional-labs/composable/v6/app" + "github.com/notional-labs/composable/v6/app/helpers" + stakingmiddlewarekeeper "github.com/notional-labs/composable/v6/x/stakingmiddleware/keeper" + stakingmiddlewaretypes "github.com/notional-labs/composable/v6/x/stakingmiddleware/types" + "github.com/stretchr/testify/suite" +) + +type KeeperTestSuite struct { + suite.Suite + + ctx sdk.Context + // querier sdk.Querier + app *app.ComposableApp + msgServer stakingmiddlewaretypes.MsgServer +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.app = helpers.SetupComposableAppWithValSet(suite.T()) + suite.ctx = suite.app.BaseApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "centauri-1", Time: time.Now().UTC()}) + encCfg := moduletestutil.MakeTestEncodingConfig() + key := suite.app.GetKey(stakingmiddlewaretypes.StoreKey) + keeper := stakingmiddlewarekeeper.NewKeeper( + encCfg.Codec, + key, + suite.app.AccountKeeper, + suite.app.BankKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + keeper.RegisterKeepers(suite.app.StakingKeeper) + suite.msgServer = stakingmiddlewarekeeper.NewMsgServerImpl(keeper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +var ( + newParams = stakingmiddlewaretypes.Params{ + BlocksPerEpoch: 10, + AllowUnbondAfterEpochProgressBlockNumber: 7, + } + failParams = stakingmiddlewaretypes.Params{ + BlocksPerEpoch: 3, + AllowUnbondAfterEpochProgressBlockNumber: 3, + } + failAllowParams = stakingmiddlewaretypes.Params{ + BlocksPerEpoch: 6, + AllowUnbondAfterEpochProgressBlockNumber: 10, + } +) + +func (suite *KeeperTestSuite) TestSetParams() { + for _, tc := range []struct { + desc string + expectedParams stakingmiddlewaretypes.Params + malleate func() error + shouldErr bool + expectedErr string + }{ + { + desc: "Case success", + expectedParams: newParams, + malleate: func() error { + return suite.app.StakingMiddlewareKeeper.SetParams(suite.ctx, newParams) + }, + shouldErr: false, + }, + { + desc: "Case fail: BlocksPerEpoch < 5", + expectedParams: failParams, + malleate: func() error { + return suite.app.StakingMiddlewareKeeper.SetParams(suite.ctx, failParams) + }, + shouldErr: true, + expectedErr: "BlocksPerEpoch must be greater than or equal to 5", + }, + { + desc: "Case fail: BlocksPerEpoch < AllowUnbondAfterEpochProgressBlockNumber", + expectedParams: failAllowParams, + malleate: func() error { + return suite.app.StakingMiddlewareKeeper.SetParams(suite.ctx, failAllowParams) + }, + shouldErr: true, + expectedErr: "AllowUnbondAfterEpochProgressBlockNumber must be less than or equal to BlocksPerEpoch", + }, + } { + tc := tc + suite.Run(tc.desc, func() { + suite.SetupTest() + err := tc.malleate() + if !tc.shouldErr { + res := suite.app.StakingMiddlewareKeeper.GetParams(suite.ctx) + suite.Equal(res, tc.expectedParams) + } else { + suite.Equal(err.Error(), tc.expectedErr) + } + }) + } +} diff --git a/x/stakingmiddleware/keeper/msg_server_test.go b/x/stakingmiddleware/keeper/msg_server_test.go new file mode 100644 index 000000000..525cf40f0 --- /dev/null +++ b/x/stakingmiddleware/keeper/msg_server_test.go @@ -0,0 +1,117 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingmiddlewaretypes "github.com/notional-labs/composable/v6/x/stakingmiddleware/types" +) + +func (s *KeeperTestSuite) TestMsgUpdateEpochParams() { + ctx, msgServer := s.ctx, s.msgServer + require := s.Require() + testCases := []struct { + name string + input *stakingmiddlewaretypes.MsgUpdateEpochParams + expErr bool + expErrMsg string + }{ + { + name: "valid params", + input: &stakingmiddlewaretypes.MsgUpdateEpochParams{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Params: stakingmiddlewaretypes.Params{ + BlocksPerEpoch: 20, + AllowUnbondAfterEpochProgressBlockNumber: 7, + }, + }, + expErr: false, + }, + { + name: "invalid authority", + input: &stakingmiddlewaretypes.MsgUpdateEpochParams{ + Authority: "invalid", + Params: stakingmiddlewaretypes.Params{ + BlocksPerEpoch: 20, + AllowUnbondAfterEpochProgressBlockNumber: 7, + }, + }, + expErr: true, + expErrMsg: "invalid authority", + }, + } + + for _, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + _, err := msgServer.UpdateEpochParams(ctx, tc.input) + if tc.expErr { + require.Error(err) + require.Contains(err.Error(), tc.expErrMsg) + } else { + require.NoError(err) + } + }) + } +} + +func (s *KeeperTestSuite) TestAddRevenueFundsToStaking() { + accAddrs := []sdk.AccAddress{ + sdk.AccAddress([]byte("addr1_______________")), + } + ctx, msgServer := s.ctx, s.msgServer + require := s.Require() + feeCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(150)) + feeAmount := sdk.NewCoins(feeCoin) + s.app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, feeAmount) + s.app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, accAddrs[0], feeAmount) + testCases := []struct { + name string + input *stakingmiddlewaretypes.MsgAddRevenueFundsToStakingParams + expErr bool + expErrMsg string + }{ + { + name: "success", + input: &stakingmiddlewaretypes.MsgAddRevenueFundsToStakingParams{ + FromAddress: accAddrs[0].String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))), + }, + expErr: false, + }, + { + name: "invalid coin", + input: &stakingmiddlewaretypes.MsgAddRevenueFundsToStakingParams{ + FromAddress: accAddrs[0].String(), + Amount: sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(1))), + }, + expErr: true, + expErrMsg: "Invalid coin", + }, + { + name: "invalid coin: two different coin denom", + input: &stakingmiddlewaretypes.MsgAddRevenueFundsToStakingParams{ + FromAddress: accAddrs[0].String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)), sdk.NewCoin("test", sdk.NewInt(1))), + }, + expErr: true, + expErrMsg: "Invalid coin", + }, + } + + for _, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + _, err := msgServer.AddRevenueFundsToStaking(ctx, tc.input) + if tc.expErr { + require.Error(err) + require.Contains(err.Error(), tc.expErrMsg) + } else { + require.NoError(err) + } + }) + } +}