diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 30153a3..96e45c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ concurrency: cancel-in-progress: true env: - GO_VERSION: 1.22.3 + GO_VERSION: 1.22.4 jobs: build: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 30349c6..25c136c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -14,7 +14,7 @@ concurrency: cancel-in-progress: true env: - GO_VERSION: 1.22.3 + GO_VERSION: 1.22.4 jobs: analyze: diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c3ffcde..dd3e194 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -16,7 +16,7 @@ permissions: packages: write env: - GO_VERSION: 1.22.3 + GO_VERSION: 1.22.4 TAR_PATH: /tmp/manifest-docker-image.tar IMAGE_NAME: manifest-docker-image diff --git a/.github/workflows/release-bin.yaml b/.github/workflows/release-bin.yaml index d0e1b6e..80ee2e2 100644 --- a/.github/workflows/release-bin.yaml +++ b/.github/workflows/release-bin.yaml @@ -20,7 +20,7 @@ jobs: - uses: actions/setup-go@v2 with: - go-version: '1.22.3' + go-version: '1.22.4' - name: Clean up dist directory run: rm -rf dist diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cfdc56d..5e76c1a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ on: types: [opened, reopened, synchronize] env: - GO_VERSION: 1.22.3 + GO_VERSION: 1.22.4 concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/Dockerfile b/Dockerfile index 79953a9..d7958f3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ RUN LEDGER_ENABLED=false BUILD_TAGS=muslc LINK_STATICALLY=true make $BUILD_CMD \ && (file /code/build/manifestd | grep "statically linked") # -------------------------------------------------------- -FROM alpine:3.16 +FROM alpine:3.20 COPY --from=go-builder /code/build/manifestd /usr/bin/manifestd diff --git a/Makefile b/Makefile index 191755a..237fe2e 100644 --- a/Makefile +++ b/Makefile @@ -134,7 +134,7 @@ local-image: ifeq (,$(shell which heighliner)) echo 'heighliner' binary not found. Consider running `make get-heighliner` else - heighliner build -c manifest --local -f ./chains.yaml + heighliner build -c manifest --local -f ./chains.yaml --alpine-version 3.20 endif .PHONY: get-heighliner local-image diff --git a/app/upgrades.go b/app/upgrades.go index a5bd017..a55db2d 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -10,10 +10,10 @@ import ( ) // Upgrades list of chain upgrades -var Upgrades = []upgrades.Upgrade{} +var Upgrades []upgrades.Upgrade // RegisterUpgradeHandlers registers the chain upgrade handlers -func (app ManifestApp) RegisterUpgradeHandlers() { +func (app *ManifestApp) RegisterUpgradeHandlers() { if len(Upgrades) == 0 { // always have a unique upgrade registered for the current version to test in system tests Upgrades = append(Upgrades, noop.NewUpgrade(app.Version())) diff --git a/go.mod b/go.mod index a0c61fa..684613d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/liftedinit/manifest-ledger -go 1.22.3 +go 1.22.4 replace ( // core v0.12 was tagged wrong (SDK v51) diff --git a/go.work b/go.work index 1ef3033..34e1e7c 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.22.3 +go 1.22.4 use ( . diff --git a/interchaintest/go.mod b/interchaintest/go.mod index fdec445..5a68f28 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -1,6 +1,6 @@ module github.com/liftedinit/manifest-ledger/interchaintest -go 1.22.3 +go 1.22.4 replace ( cosmossdk.io/core => cosmossdk.io/core v0.11.0 // proper SDK v50 version diff --git a/x/manifest/keeper/keeper.go b/x/manifest/keeper/keeper.go index 091a35b..7977363 100644 --- a/x/manifest/keeper/keeper.go +++ b/x/manifest/keeper/keeper.go @@ -67,10 +67,11 @@ func NewKeeper( return k } -func (k Keeper) Logger() log.Logger { +func (k *Keeper) Logger() log.Logger { return k.logger } +// SetAuthority is only used for testing func (k *Keeper) SetAuthority(authority string) { k.authority = authority } @@ -88,7 +89,7 @@ func (k *Keeper) ExportGenesis(ctx context.Context) *types.GenesisState { } // Payout mints and sends coins to stakeholders. -func (k Keeper) Payout(ctx context.Context, payouts []types.PayoutPair) error { +func (k *Keeper) Payout(ctx context.Context, payouts []types.PayoutPair) error { for _, p := range payouts { p := p addr := p.Address @@ -113,7 +114,7 @@ func (k Keeper) Payout(ctx context.Context, payouts []types.PayoutPair) error { return nil } -func (k Keeper) mintCoinsToAccount(ctx context.Context, sdkAddr sdk.AccAddress, coin sdk.Coin) error { +func (k *Keeper) mintCoinsToAccount(ctx context.Context, sdkAddr sdk.AccAddress, coin sdk.Coin) error { coins := sdk.NewCoins(coin) if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { return err diff --git a/x/manifest/keeper/keeper_test.go b/x/manifest/keeper/keeper_test.go index 572a51f..341692b 100644 --- a/x/manifest/keeper/keeper_test.go +++ b/x/manifest/keeper/keeper_test.go @@ -3,15 +3,20 @@ package keeper_test import ( "testing" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/liftedinit/manifest-ledger/app" "github.com/liftedinit/manifest-ledger/app/apptesting" appparams "github.com/liftedinit/manifest-ledger/app/params" + "github.com/liftedinit/manifest-ledger/x/manifest/types" ) // Sets up the keeper test suite. @@ -44,3 +49,86 @@ func initFixture(t *testing.T) *testFixture { return &s } + +func TestPayout(t *testing.T) { + _, _, authority := testdata.KeyTestPubAddr() + _, _, acc := testdata.KeyTestPubAddr() + f := initFixture(t) + + k := f.App.ManifestKeeper + k.SetAuthority(authority.String()) + + type testcase struct { + name string + payouts []types.PayoutPair + errMsg string + } + + cases := []testcase{ + { + name: "fail: invalid destination address", + payouts: []types.PayoutPair{ + types.NewPayoutPair(acc, "umfx", 1), + {Address: "badaddr", Coin: sdk.NewCoin("umfx", sdkmath.NewInt(2))}, + }, + errMsg: "decoding bech32 failed", + }, + { + name: "fail: invalid coin denom", + payouts: []types.PayoutPair{ + types.NewPayoutPair(acc, "umfx", 1), + {Address: acc.String(), Coin: sdk.Coin{Denom: ":::", Amount: sdkmath.NewInt(2)}}, + }, + errMsg: "invalid payout", + }, + { + name: "fail: invalid coin amount", + payouts: []types.PayoutPair{ + types.NewPayoutPair(acc, "umfx", 1), + {Address: acc.String(), Coin: sdk.Coin{Denom: "umfx", Amount: sdkmath.NewInt(-2)}}, + }, + errMsg: "invalid payout", + }, + } + + for _, c := range cases { + c := c + + t.Run(c.name, func(t *testing.T) { + err := k.Payout(f.Ctx, c.payouts) + + if c.errMsg != "" { + require.Error(t, err) + require.ErrorContains(t, err, c.errMsg) + return + } + + require.NoError(t, err) + + for _, p := range c.payouts { + p := p + addr := p.Address + coin := p.Coin + + accAddr, err := sdk.AccAddressFromBech32(addr) + require.NoError(t, err) + + balance := f.App.BankKeeper.GetBalance(f.Ctx, accAddr, coin.Denom) + require.EqualValues(t, coin.Amount, balance.Amount, "expected %s, got %s", coin.Amount, balance.Amount) + } + }) + } +} + +func TestExportGenesis(t *testing.T) { + f := initFixture(t) + + k := f.App.ManifestKeeper + + _, err := k.Params.Get(f.Ctx) + require.NoError(t, err) + + genState := k.ExportGenesis(f.Ctx) + + require.NotNil(t, genState.Params) +} diff --git a/x/manifest/keeper/msg_server_test.go b/x/manifest/keeper/msg_server_test.go index fe4c267..7849a71 100644 --- a/x/manifest/keeper/msg_server_test.go +++ b/x/manifest/keeper/msg_server_test.go @@ -27,10 +27,10 @@ func TestPerformPayout(t *testing.T) { ms := keeper.NewMsgServerImpl(k) type testcase struct { - name string - sender string - payouts []types.PayoutPair - shouldFail bool + name string + sender string + payouts []types.PayoutPair + errMsg string } cases := []testcase{ @@ -49,7 +49,7 @@ func TestPerformPayout(t *testing.T) { payouts: []types.PayoutPair{ types.NewPayoutPair(acc, "umfx", 1), }, - shouldFail: true, + errMsg: "invalid authority", }, { name: "fail; bad bech32 authority", @@ -57,7 +57,7 @@ func TestPerformPayout(t *testing.T) { payouts: []types.PayoutPair{ types.NewPayoutPair(acc, "umfx", 1), }, - shouldFail: true, + errMsg: "invalid authority", }, { name: "fail; duplicate address", @@ -66,7 +66,7 @@ func TestPerformPayout(t *testing.T) { types.NewPayoutPair(acc, "umfx", 1), types.NewPayoutPair(acc, "umfx", 1), }, - shouldFail: true, + errMsg: "duplicate address", }, { name: "fail; payout to bad address", @@ -76,7 +76,7 @@ func TestPerformPayout(t *testing.T) { {Address: "badaddr", Coin: sdk.NewCoin("umfx", sdkmath.NewInt(2))}, types.NewPayoutPair(acc3, "umfx", 3), }, - shouldFail: true, + errMsg: "decoding bech32 failed", }, { name: "fail; payout with a 0 token", @@ -85,7 +85,7 @@ func TestPerformPayout(t *testing.T) { types.NewPayoutPair(acc, "umfx", 1), types.NewPayoutPair(acc2, "umfx", 0), }, - shouldFail: true, + errMsg: "invalid payout", }, } @@ -99,8 +99,9 @@ func TestPerformPayout(t *testing.T) { } _, err := ms.Payout(f.Ctx, payoutMsg) - if c.shouldFail { + if c.errMsg != "" { require.Error(t, err) + require.ErrorContains(t, err, c.errMsg) return } require.NoError(t, err) @@ -137,7 +138,7 @@ func TestBurnCoins(t *testing.T) { burn sdk.Coins expected sdk.Coins address sdk.AccAddress - success bool + errMsg string } stake := sdk.NewCoin("stake", sdkmath.NewInt(100_000_000)) @@ -150,6 +151,7 @@ func TestBurnCoins(t *testing.T) { burn: sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(7))), expected: sdk.NewCoins(), address: authority, + errMsg: "insufficient funds", }, { name: "fail; bad address", @@ -157,6 +159,7 @@ func TestBurnCoins(t *testing.T) { burn: sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(7))), expected: sdk.NewCoins(), address: sdk.AccAddress{0x0}, + errMsg: "invalid authority", }, { name: "success; burn tokens successfully", @@ -164,7 +167,6 @@ func TestBurnCoins(t *testing.T) { burn: sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(7))), expected: sdk.NewCoins(mfx, stake.SubAmount(sdkmath.NewInt(7))), address: authority, - success: true, }, { name: "success; burn many tokens successfully", @@ -172,7 +174,6 @@ func TestBurnCoins(t *testing.T) { burn: sdk.NewCoins(sdk.NewCoin("umfx", sdkmath.NewInt(9)), sdk.NewCoin("stake", sdkmath.NewInt(7))), expected: sdk.NewCoins(mfx.SubAmount(sdkmath.NewInt(9)), stake.SubAmount(sdkmath.NewInt(7))), address: authority, - success: true, }, { name: "fail; invalid authority", @@ -180,6 +181,7 @@ func TestBurnCoins(t *testing.T) { burn: sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(7))), expected: sdk.NewCoins(stake, mfx), address: acc, + errMsg: "invalid authority", }, } @@ -200,17 +202,18 @@ func TestBurnCoins(t *testing.T) { Authority: c.address.String(), BurnCoins: c.burn, }) - if c.success { + if c.errMsg == "" { require.NoError(t, err) } else { require.Error(t, err) + require.ErrorContains(t, err, c.errMsg) } allBalance := f.App.BankKeeper.GetAllBalances(f.Ctx, c.address) require.Equal(t, c.expected, allBalance) // burn the rest of the coins to reset the balance to 0 for the next test if the test was successful - if c.success { + if c.errMsg == "" { _, err = ms.BurnHeldBalance(f.Ctx, &types.MsgBurnHeldBalance{ Authority: c.address.String(), BurnCoins: allBalance, @@ -220,3 +223,50 @@ func TestBurnCoins(t *testing.T) { }) } } + +func TestUpdateParams(t *testing.T) { + _, _, authority := testdata.KeyTestPubAddr() + + f := initFixture(t) + + k := f.App.ManifestKeeper + k.SetAuthority(authority.String()) + ms := keeper.NewMsgServerImpl(k) + + type tc struct { + name string + sender string + param types.Params + errMsg string + } + + cases := []tc{ + { + name: "success; update params", + sender: authority.String(), + param: types.NewParams(), + }, + { + name: "fail; bad authority", + sender: "bad", + param: types.NewParams(), + errMsg: "invalid authority", + }, + } + + for _, c := range cases { + c := c + t.Run(c.name, func(t *testing.T) { + _, err := ms.UpdateParams(f.Ctx, &types.MsgUpdateParams{ + Authority: c.sender, + Params: c.param, + }) + if c.errMsg != "" { + require.Error(t, err) + require.Contains(t, err.Error(), c.errMsg) + return + } + require.NoError(t, err) + }) + } +} diff --git a/x/manifest/module.go b/x/manifest/module.go index ec260b0..d53a0e0 100644 --- a/x/manifest/module.go +++ b/x/manifest/module.go @@ -103,7 +103,7 @@ func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. // //nolint:stylecheck -func (a AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { +func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { return &autocliv1.ModuleOptions{ Query: &autocliv1.ServiceCommandDescriptor{ Service: manifestv1.Query_ServiceDesc.ServiceName, @@ -132,38 +132,38 @@ func (a AppModuleBasic) RegisterInterfaces(r codectypes.InterfaceRegistry) { types.RegisterInterfaces(r) } -func (a AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState marshaler.MustUnmarshalJSON(message, &genesisState) - if err := a.keeper.Params.Set(ctx, genesisState.Params); err != nil { + if err := am.keeper.Params.Set(ctx, genesisState.Params); err != nil { panic(err) } return nil } -func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { - genState := a.keeper.ExportGenesis(ctx) +func (am AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) return marshaler.MustMarshalJSON(genState) } -func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { } -func (a AppModule) QuerierRoute() string { +func (am AppModule) QuerierRoute() string { return types.QuerierRoute } -func (a AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(a.keeper)) - types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(a.keeper)) +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) } // ConsensusVersion is a sequence number for state-breaking change of the // module. It should be incremented on each consensus-breaking change // introduced by the module. To avoid wrong/empty versions, the initial version // should be set to 1. -func (a AppModule) ConsensusVersion() uint64 { +func (am AppModule) ConsensusVersion() uint64 { return ConsensusVersion } diff --git a/x/manifest/types/codec.go b/x/manifest/types/codec.go index 08a3e76..1c5b88e 100644 --- a/x/manifest/types/codec.go +++ b/x/manifest/types/codec.go @@ -3,19 +3,10 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" ) -var amino = codec.NewLegacyAmino() - -func init() { - RegisterLegacyAminoCodec(amino) - cryptocodec.RegisterCrypto(amino) - sdk.RegisterLegacyAminoCodec(amino) -} - // RegisterLegacyAminoCodec registers concrete types on the LegacyAmino codec func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgUpdateParams{}, ModuleName+"/MsgUpdateParams", nil) diff --git a/x/manifest/types/msgs.go b/x/manifest/types/msgs.go index 9d2360e..34936d3 100644 --- a/x/manifest/types/msgs.go +++ b/x/manifest/types/msgs.go @@ -22,15 +22,10 @@ func NewMsgUpdateParams( } // Route returns the name of the module -func (msg MsgUpdateParams) Route() string { return ModuleName } +func (msg *MsgUpdateParams) Route() string { return ModuleName } -// Type returns the the action -func (msg MsgUpdateParams) Type() string { return "update_params" } - -// GetSignBytes implements the LegacyMsg interface. -func (msg MsgUpdateParams) GetSignBytes() []byte { - return sdk.MustSortJSON(amino.MustMarshalJSON(&msg)) -} +// Type returns the action +func (msg *MsgUpdateParams) Type() string { return "update_params" } // GetSigners returns the expected signers for a MsgUpdateParams message. func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { @@ -38,7 +33,7 @@ func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{addr} } -// ValidateBasic does a sanity check on the provided data. +// Validate does a sanity check on the provided data. func (msg *MsgUpdateParams) Validate() error { if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { return errors.Wrap(err, "invalid authority address") @@ -67,15 +62,10 @@ func NewPayoutPair(addr sdk.AccAddress, denom string, amt int64) PayoutPair { } // Route returns the name of the module -func (msg MsgPayout) Route() string { return ModuleName } - -// Type returns the the action -func (msg MsgPayout) Type() string { return "payout" } +func (msg *MsgPayout) Route() string { return ModuleName } -// GetSignBytes implements the LegacyMsg interface. -func (msg MsgPayout) GetSignBytes() []byte { - return sdk.MustSortJSON(amino.MustMarshalJSON(&msg)) -} +// Type returns the action +func (msg *MsgPayout) Type() string { return "payout" } // GetSigners returns the expected signers for the message. func (msg *MsgPayout) GetSigners() []sdk.AccAddress { @@ -83,7 +73,7 @@ func (msg *MsgPayout) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{addr} } -// ValidateBasic does a sanity check on the provided data. +// Validate does a sanity check on the provided data. func (msg *MsgPayout) Validate() error { if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { return errors.Wrap(err, "invalid authority address") @@ -139,15 +129,10 @@ func NewMsgBurnHeldBalance( } // Route returns the name of the module -func (msg MsgBurnHeldBalance) Route() string { return ModuleName } - -// Type returns the the action -func (msg MsgBurnHeldBalance) Type() string { return "burn_coins" } +func (msg *MsgBurnHeldBalance) Route() string { return ModuleName } -// GetSignBytes implements the LegacyMsg interface. -func (msg MsgBurnHeldBalance) GetSignBytes() []byte { - return sdk.MustSortJSON(amino.MustMarshalJSON(&msg)) -} +// Type returns the action +func (msg *MsgBurnHeldBalance) Type() string { return "burn_coins" } // GetSigners returns the expected signers for the message. func (msg *MsgBurnHeldBalance) GetSigners() []sdk.AccAddress { @@ -155,7 +140,7 @@ func (msg *MsgBurnHeldBalance) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{addr} } -// ValidateBasic does a sanity check on the provided data. +// Validate does a sanity check on the provided data. func (msg *MsgBurnHeldBalance) Validate() error { if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { return errors.Wrap(err, "invalid authority address") diff --git a/x/manifest/types/params.go b/x/manifest/types/params.go index d1a9f9c..e8e13eb 100644 --- a/x/manifest/types/params.go +++ b/x/manifest/types/params.go @@ -9,13 +9,13 @@ func DefaultParams() Params { return NewParams() } -// Params defines the parameters for the module. +// NewParams defines the parameters for the module. func NewParams() Params { return Params{} } // Stringer method for Params. -func (p Params) String() string { +func (p *Params) String() string { bz, err := json.Marshal(p) if err != nil { panic(err) @@ -25,6 +25,6 @@ func (p Params) String() string { } // Validate does the sanity check on the params. -func (p Params) Validate() error { +func (p *Params) Validate() error { return nil }