diff --git a/.golangci.yml b/.golangci.yml index c0844c760..b18ea0c03 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,69 +1,66 @@ +version: "2" run: tests: true - timeout: 10m - sort-results: true allow-parallel-runners: true - exclude-dir: testutil/testdata - linters: - disable-all: true + default: none enable: - dogsled - - exportloopref - goconst - gocritic - - gofumpt - gosec - - gosimple - govet - ineffassign - misspell - nakedret - nolintlint - staticcheck - - stylecheck - thelper - - typecheck - unconvert - unused - + settings: + dogsled: + max-blank-identifiers: 3 + nolintlint: + require-explanation: false + require-specific: false + allow-unused: false + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - gosec + text: Use of weak random number generator + - linters: + - staticcheck + text: 'ST1003:' + - linters: + - staticcheck + text: 'ST1016:' + - linters: + - staticcheck + path: migrations + text: 'SA1019:' + paths: + - third_party$ + - builtin$ + - examples$ issues: - exclude-rules: - - text: "Use of weak random number generator" - linters: - - gosec - - text: "ST1003:" - linters: - - stylecheck - # FIXME: Disabled until golangci-lint updates stylecheck with this fix: - # https://github.com/dominikh/go-tools/issues/389 - - text: "ST1016:" - linters: - - stylecheck - - path: "migrations" - text: "SA1019:" - linters: - - staticcheck - - text: "leading space" - linters: - - nolintlint - max-issues-per-linter: 10000 max-same-issues: 10000 - -linters-settings: - gofumpt: - # Choose whether to use the extra rules. - module-path: github.com/notional-labs/composable-centauri - # Default: false - extra-rules: true - dogsled: - max-blank-identifiers: 3 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true - nolintlint: - allow-unused: false - allow-leading-space: true - require-explanation: false - require-specific: false +formatters: + enable: + - gofumpt + settings: + extra-rules: true + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/app/app.go b/app/app.go index f3f036fb6..96796240c 100644 --- a/app/app.go +++ b/app/app.go @@ -359,7 +359,7 @@ func NewComposableApp( app.mm = module.NewManager( genutil.NewAppModule( - app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, + app.AccountKeeper, app.StakingKeeper, app.DeliverTx, encodingConfig.TxConfig, ), auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), @@ -692,12 +692,12 @@ func (app *ComposableApp) RegisterAPIRoutes(apiSvr *api.Server, _ config.APIConf // RegisterTxService implements the Application.RegisterTxService method. func (app *ComposableApp) RegisterTxService(clientCtx client.Context) { - authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) + authtx.RegisterTxService(app.GRPCQueryRouter(), clientCtx, app.Simulate, app.interfaceRegistry) } // RegisterTendermintService implements the Application.RegisterTendermintService method. func (app *ComposableApp) RegisterTendermintService(clientCtx client.Context) { - tmservice.RegisterTendermintService(clientCtx, app.BaseApp.GRPCQueryRouter(), app.interfaceRegistry, app.Query) + tmservice.RegisterTendermintService(clientCtx, app.GRPCQueryRouter(), app.interfaceRegistry, app.Query) } // RegisterNodeService registers the node gRPC Query service. diff --git a/app/export.go b/app/export.go index a33330220..c4685060d 100644 --- a/app/export.go +++ b/app/export.go @@ -43,7 +43,7 @@ func (app *ComposableApp) ExportAppStateAndValidators( AppState: appState, Validators: validators, Height: height, - ConsensusParams: app.BaseApp.GetConsensusParams(ctx), + ConsensusParams: app.GetConsensusParams(ctx), }, nil } @@ -52,12 +52,9 @@ func (app *ComposableApp) ExportAppStateAndValidators( // // in favour of export at a block height func (app *ComposableApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) { - applyAllowedAddrs := false + applyAllowedAddrs := len(jailAllowedAddrs) > 0 // check if there is a allowed address list - if len(jailAllowedAddrs) > 0 { - applyAllowedAddrs = true - } allowedAddrsMap := make(map[string]bool) diff --git a/app/helpers/test_helpers.go b/app/helpers/test_helpers.go index 1646262fa..8056d9fbe 100644 --- a/app/helpers/test_helpers.go +++ b/app/helpers/test_helpers.go @@ -59,7 +59,7 @@ type EmptyAppOptions struct{} func (EmptyAppOptions) Get(_ string) interface{} { return nil } func NewContextForApp(app composable.ComposableApp) sdk.Context { - ctx := app.BaseApp.NewContext(false, tmproto.Header{ + ctx := app.NewContext(false, tmproto.Header{ ChainID: fmt.Sprintf("test-chain-%s", tmrand.Str(4)), Height: 1, }) diff --git a/app/ibctesting/chain.go b/app/ibctesting/chain.go index c2082b7b6..1804d86d7 100644 --- a/app/ibctesting/chain.go +++ b/app/ibctesting/chain.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/sha256" "fmt" + "math" "os" "testing" "time" @@ -184,9 +185,16 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight()) } -// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof +// QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof // for the query and the height at which the proof will succeed on a tendermint verifier. func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) { + if height <= 0 { + panic("height must be positive") + } + if height-1 < 0 { + panic("height-1 must not be negative") + } + res := chain.App.Query(abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", exported.StoreKey), Height: height - 1, @@ -202,15 +210,31 @@ func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, cl revision := clienttypes.ParseChainID(chain.ChainID) + // Ensure height is non-negative before converting to uint64 + if res.Height < 0 { + panic("negative height not allowed") + } + // proof height + 1 is returned as the proof created corresponds to the height the proof // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it // have heights 1 above the IAVL tree. Thus we return proof height + 1 - return proof, clienttypes.NewHeight(revision, uint64(res.Height)+1) + if res.Height >= math.MaxInt64 { + panic("height exceeds maximum int64 value") + } + return proof, clienttypes.NewHeight(revision, uint64(res.Height+1)) } // QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof // for the query and the height at which the proof will succeed on a tendermint verifier. func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) { + // Ensure height is not zero and can be safely converted to int64 + if height == 0 { + panic("height cannot be zero") + } + if height > uint64(math.MaxInt64) { + panic("height exceeds maximum int64 value") + } + res := chain.App.Query(abci.RequestQuery{ Path: "store/upgrade/key", Height: int64(height - 1), @@ -226,6 +250,13 @@ func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, cl revision := clienttypes.ParseChainID(chain.ChainID) + // Ensure height is non-negative before converting to uint64 + if res.Height < 0 { + panic("negative height not allowed") + } + if res.Height >= math.MaxInt64 { + panic("height exceeds maximum int64 value") + } // proof height + 1 is returned as the proof created corresponds to the height the proof // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it // have heights 1 above the IAVL tree. Thus we return proof height + 1 @@ -412,7 +443,7 @@ func (chain *TestChain) ConstructUpdateTMClientHeader(counterparty *TestChain, c return chain.ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty, clientID, clienttypes.ZeroHeight()) } -// ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the +// ConstructUpdateTMClientHeaderWithTrustedHeight will construct a valid 07-tendermint Header to update the // light client on the source chain. func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctmtypes.Header, error) { header := counterparty.LastHeader @@ -434,6 +465,9 @@ func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterpa // since the last trusted validators for a header at height h // is the NextValidators at h+1 committed to in header h by // NextValidatorsHash + if trustedHeight.RevisionHeight >= math.MaxInt64-1 { + return nil, errors.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "trusted height revision height exceeds maximum int64 value") + } tmTrustedVals, ok = counterparty.GetValsAtHeight(int64(trustedHeight.RevisionHeight + 1)) if !ok { return nil, errors.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight) diff --git a/app/ibctesting/endpoint.go b/app/ibctesting/endpoint.go index 633dc7b2a..3c34d6e0b 100644 --- a/app/ibctesting/endpoint.go +++ b/app/ibctesting/endpoint.go @@ -2,6 +2,7 @@ package ibctesting import ( "fmt" + "math" "github.com/stretchr/testify/require" @@ -45,7 +46,10 @@ func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) { // QueryProofAtHeight queries proof associated with this endpoint using the proof height // providied func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) { - // query proof on the counterparty using the latest height of the IBC client + // Ensure height can be safely converted to int64 + if height > uint64(math.MaxInt64) { + panic("height exceeds maximum int64 value") + } return endpoint.Chain.QueryProofAtHeight(key, int64(height)) } diff --git a/app/ibctesting/simapp/app.go b/app/ibctesting/simapp/app.go index 3a53b9e56..1f62465c0 100644 --- a/app/ibctesting/simapp/app.go +++ b/app/ibctesting/simapp/app.go @@ -577,7 +577,7 @@ func NewSimApp( app.mm = module.NewManager( // SDK app modules genutil.NewAppModule( - app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, + app.AccountKeeper, app.StakingKeeper, app.DeliverTx, encodingConfig.TxConfig, ), auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), @@ -887,14 +887,14 @@ func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APICon // RegisterTxService implements the Application.RegisterTxService method. func (app *SimApp) RegisterTxService(clientCtx client.Context) { - authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) + authtx.RegisterTxService(app.GRPCQueryRouter(), clientCtx, app.Simulate, app.interfaceRegistry) } // RegisterTendermintService implements the Application.RegisterTendermintService method. func (app *SimApp) RegisterTendermintService(clientCtx client.Context) { tmservice.RegisterTendermintService( clientCtx, - app.BaseApp.GRPCQueryRouter(), + app.GRPCQueryRouter(), app.interfaceRegistry, app.Query, ) diff --git a/app/ibctesting/simapp/export.go b/app/ibctesting/simapp/export.go index 8515cc0f4..6a0c02b33 100644 --- a/app/ibctesting/simapp/export.go +++ b/app/ibctesting/simapp/export.go @@ -39,7 +39,7 @@ func (app *SimApp) ExportAppStateAndValidators( AppState: appState, Validators: validators, Height: height, - ConsensusParams: app.BaseApp.GetConsensusParams(ctx), + ConsensusParams: app.GetConsensusParams(ctx), }, err } @@ -47,12 +47,9 @@ func (app *SimApp) ExportAppStateAndValidators( // NOTE zero height genesis is a temporary feature which will be deprecated // in favour of export at a block height func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) { - applyAllowedAddrs := false + applyAllowedAddrs := len(jailAllowedAddrs) > 0 // check if there is a allowed address list - if len(jailAllowedAddrs) > 0 { - applyAllowedAddrs = true - } allowedAddrsMap := make(map[string]bool) diff --git a/app/test_helpers.go b/app/test_helpers.go index 78823300f..f6233dbb1 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -77,14 +77,14 @@ type KeeperTestHelper struct { func (s *KeeperTestHelper) Setup(_ *testing.T) { t := s.T() s.App = SetupApp(t) - s.Ctx = s.App.BaseApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "", Time: time.Now().UTC()}) + s.Ctx = s.App.NewContext(false, tmproto.Header{Height: 1, ChainID: "", Time: time.Now().UTC()}) s.QueryHelper = &baseapp.QueryServiceTestHelper{ GRPCQueryRouter: s.App.GRPCQueryRouter(), Ctx: s.Ctx, } s.TestAccs = createRandomAccounts(10) - s.StakingHelper = stakinghelper.NewHelper(s.Suite.T(), s.Ctx, &s.App.StakingKeeper.Keeper) + s.StakingHelper = stakinghelper.NewHelper(s.T(), s.Ctx, &s.App.StakingKeeper.Keeper) s.StakingHelper.Denom = "stake" } diff --git a/app/upgrades/v6_6_4/upgrades_test.go b/app/upgrades/v6_6_4/upgrades_test.go index 73e020de1..c8ceeda42 100644 --- a/app/upgrades/v6_6_4/upgrades_test.go +++ b/app/upgrades/v6_6_4/upgrades_test.go @@ -95,7 +95,7 @@ func prepareForTestingGovModule(s *UpgradeTestSuite) (sdk.AccAddress, govtypes.P // VOTE AND DEPOSIT proposal, err := s.App.GovKeeper.SubmitProposal(s.Ctx, []sdk.Msg{}, "", "test", "description", acc1) - s.Suite.Equal(err, nil) + s.Equal(err, nil) s.App.GovKeeper.SetVote(s.Ctx, govtypes.Vote{ ProposalId: proposal.Id, @@ -118,7 +118,7 @@ func prepareForTestingSlashingModule(s *UpgradeTestSuite) sdk.ConsAddress { acc2 := s.TestAccs[1] oldConsAddress, err := utils.ConsAddressFromOldBech32(acc2.String(), utils.OldBech32PrefixAccAddr) - s.Suite.Equal(err, nil) + s.Equal(err, nil) // CHECK ValidatorSigningInfo s.App.SlashingKeeper.SetValidatorSigningInfo(s.Ctx, oldConsAddress, slashingtypes.ValidatorSigningInfo{ @@ -295,24 +295,24 @@ func checkUpgradeGovModule(s *UpgradeTestSuite, acc1 sdk.AccAddress, proposal go _, bz, _ := bech32.DecodeAndConvert(acc1.String()) newBech32Addr, _ := bech32.ConvertAndEncode(utils.NewBech32PrefixAccAddr, bz) newAddr, err := utils.AccAddressFromOldBech32(newBech32Addr, utils.NewBech32PrefixAccAddr) - s.Suite.Equal(err, nil) + s.Equal(err, nil) // CHECK PROPOSAL proposal, found := s.App.GovKeeper.GetProposal(s.Ctx, proposal.Id) - s.Suite.Equal(found, true) - s.Suite.Equal(proposal.Proposer, newBech32Addr) + s.Equal(found, true) + s.Equal(proposal.Proposer, newBech32Addr) // CHECK VOTER AND DEPOSITER OF NEW ADDRESS existed_proposal, _ := s.App.GovKeeper.GetProposal(s.Ctx, proposal.Id) - s.Suite.Equal(existed_proposal.Proposer, newBech32Addr) + s.Equal(existed_proposal.Proposer, newBech32Addr) vote, found := s.App.GovKeeper.GetVote(s.Ctx, proposal.Id, newAddr) - s.Suite.Equal(found, true) - s.Suite.Equal(vote.Voter, newBech32Addr) + s.Equal(found, true) + s.Equal(vote.Voter, newBech32Addr) deposit, found := s.App.GovKeeper.GetDeposit(s.Ctx, proposal.Id, newAddr) - s.Suite.Equal(found, true) - s.Suite.Equal(deposit.Depositor, newBech32Addr) + s.Equal(found, true) + s.Equal(deposit.Depositor, newBech32Addr) } func checkUpgradeSlashingModule(s *UpgradeTestSuite, oldConsAddress sdk.ConsAddress) { @@ -320,11 +320,11 @@ func checkUpgradeSlashingModule(s *UpgradeTestSuite, oldConsAddress sdk.ConsAddr _, bz, _ := bech32.DecodeAndConvert(oldConsAddress.String()) newBech32Addr, _ := bech32.ConvertAndEncode(utils.NewBech32PrefixConsAddr, bz) newAddr, err := utils.ConsAddressFromOldBech32(newBech32Addr, utils.NewBech32PrefixConsAddr) - s.Suite.Equal(err, nil) + s.Equal(err, nil) valSigningInfo, found := s.App.SlashingKeeper.GetValidatorSigningInfo(s.Ctx, newAddr) - s.Suite.Equal(found, true) - s.Suite.Equal(valSigningInfo.Address, newBech32Addr) + s.Equal(found, true) + s.Equal(valSigningInfo.Address, newBech32Addr) } func checkUpgradeStakingModule(s *UpgradeTestSuite, oldValAddress, oldValAddress2 sdk.ValAddress, acc1 sdk.AccAddress, afterOneDay time.Time) { @@ -332,44 +332,44 @@ func checkUpgradeStakingModule(s *UpgradeTestSuite, oldValAddress, oldValAddress _, bz, _ := bech32.DecodeAndConvert(oldValAddress.String()) newBech32Addr, _ := bech32.ConvertAndEncode(utils.NewBech32PrefixValAddr, bz) newValAddr, err := utils.ValAddressFromOldBech32(newBech32Addr, utils.NewBech32PrefixValAddr) - s.Suite.Equal(err, nil) + s.Equal(err, nil) _, bzVal2, _ := bech32.DecodeAndConvert(oldValAddress2.String()) newBech32AddrVal2, _ := bech32.ConvertAndEncode(utils.NewBech32PrefixValAddr, bzVal2) newValAddr2, err := utils.ValAddressFromOldBech32(newBech32AddrVal2, utils.NewBech32PrefixValAddr) - s.Suite.Equal(err, nil) + s.Equal(err, nil) _, bz1, _ := bech32.DecodeAndConvert(acc1.String()) newBech32DelAddr, _ := bech32.ConvertAndEncode(utils.NewBech32PrefixAccAddr, bz1) newAccAddr, err := utils.AccAddressFromOldBech32(newBech32DelAddr, utils.NewBech32PrefixAccAddr) - s.Suite.Equal(err, nil) + s.Equal(err, nil) val, found := s.App.StakingKeeper.GetValidator(s.Ctx, newValAddr) - s.Suite.Equal(found, true) - s.Suite.Equal(val.OperatorAddress, newBech32Addr) + s.Equal(found, true) + s.Equal(val.OperatorAddress, newBech32Addr) delegation, found := s.App.StakingKeeper.GetDelegation(s.Ctx, newAccAddr, newValAddr) - s.Suite.Equal(found, true) - s.Suite.Equal(delegation.DelegatorAddress, newBech32DelAddr) - s.Suite.Equal(delegation.ValidatorAddress, newBech32Addr) + s.Equal(found, true) + s.Equal(delegation.DelegatorAddress, newBech32DelAddr) + s.Equal(delegation.ValidatorAddress, newBech32Addr) unbonding, found := s.App.StakingKeeper.GetUnbondingDelegation(s.Ctx, newAccAddr, newValAddr) - s.Suite.Equal(found, true) - s.Suite.Equal(unbonding.DelegatorAddress, newBech32DelAddr) - s.Suite.Equal(unbonding.ValidatorAddress, newBech32Addr) + s.Equal(found, true) + s.Equal(unbonding.DelegatorAddress, newBech32DelAddr) + s.Equal(unbonding.ValidatorAddress, newBech32Addr) s.Ctx = s.Ctx.WithBlockTime(afterOneDay) redelegation, found := s.App.StakingKeeper.GetRedelegation(s.Ctx, newAccAddr, newValAddr, newValAddr2) - s.Suite.Equal(found, true) - s.Suite.Equal(redelegation.DelegatorAddress, newBech32DelAddr) - s.Suite.Equal(redelegation.ValidatorSrcAddress, newBech32Addr) - s.Suite.Equal(redelegation.ValidatorDstAddress, newBech32AddrVal2) + s.Equal(found, true) + s.Equal(redelegation.DelegatorAddress, newBech32DelAddr) + s.Equal(redelegation.ValidatorSrcAddress, newBech32Addr) + s.Equal(redelegation.ValidatorDstAddress, newBech32AddrVal2) RedelegationQueueTimeSlice := s.App.StakingKeeper.GetRedelegationQueueTimeSlice(s.Ctx, time.Date(2024, time.March, 4, 12, 0, 0, 0, time.UTC)) - s.Suite.Equal(strings.Contains(RedelegationQueueTimeSlice[0].DelegatorAddress, "pica"), true) - s.Suite.Equal(strings.Contains(RedelegationQueueTimeSlice[0].ValidatorDstAddress, "pica"), true) - s.Suite.Equal(strings.Contains(RedelegationQueueTimeSlice[0].ValidatorSrcAddress, "pica"), true) + s.Equal(strings.Contains(RedelegationQueueTimeSlice[0].DelegatorAddress, "pica"), true) + s.Equal(strings.Contains(RedelegationQueueTimeSlice[0].ValidatorDstAddress, "pica"), true) + s.Equal(strings.Contains(RedelegationQueueTimeSlice[0].ValidatorSrcAddress, "pica"), true) } func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccount, baseVestingAccount, continuousVestingAccount, delayedVestingAccount, periodicVestingAccount, permanentLockedAccount sdk.AccAddress) { @@ -381,9 +381,9 @@ func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccou switch acci := newPrefixAddr.(type) { case *authtypes.BaseAccount: acc := acci - s.Suite.Equal(acc.Address, newBech32AddrBaseAccount) + s.Equal(acc.Address, newBech32AddrBaseAccount) default: - s.Suite.NotNil(nil) + s.NotNil(nil) } /* CHECK MODULE ACCOUNT */ @@ -393,9 +393,9 @@ func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccou switch acci := newPrefixAddr.(type) { case *authtypes.ModuleAccount: acc := acci - s.Suite.Equal(acc.Address, newBech32AddrModuleAccount) + s.Equal(acc.Address, newBech32AddrModuleAccount) default: - s.Suite.NotNil(nil) + s.NotNil(nil) } /* CHECK BASE VESTING ACCOUNT */ @@ -405,9 +405,9 @@ func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccou switch acci := newPrefixAddr.(type) { case *vestingtypes.BaseVestingAccount: acc := acci - s.Suite.Equal(acc.Address, newBech32AddrBaseVestingAccount) + s.Equal(acc.Address, newBech32AddrBaseVestingAccount) default: - s.Suite.NotNil(nil) + s.NotNil(nil) } // CHECK CONTINUOUS VESTING ACCOUNT AND MULTISIG @@ -417,9 +417,9 @@ func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccou switch acci := newPrefixAddr.(type) { case *vestingtypes.ContinuousVestingAccount: acc := acci - s.Suite.Equal(acc.Address, newBech32AddrConVestingAccount) + s.Equal(acc.Address, newBech32AddrConVestingAccount) default: - s.Suite.NotNil(nil) + s.NotNil(nil) } // CHECK DELAYED VESTING ACCOUNT @@ -429,9 +429,9 @@ func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccou switch acci := newPrefixAddr.(type) { case *vestingtypes.DelayedVestingAccount: acc := acci - s.Suite.Equal(acc.Address, newBech32AddrDelayedVestingAccount) + s.Equal(acc.Address, newBech32AddrDelayedVestingAccount) default: - s.Suite.NotNil(nil) + s.NotNil(nil) } // CHECK PERIODIC VESTING ACCOUNT @@ -441,9 +441,9 @@ func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccou switch acci := newPrefixAddr.(type) { case *vestingtypes.PeriodicVestingAccount: acc := acci - s.Suite.Equal(acc.Address, newBech32AddrPeriodicVestingAccount) + s.Equal(acc.Address, newBech32AddrPeriodicVestingAccount) default: - s.Suite.NotNil(nil) + s.NotNil(nil) } // CHECK PERMANENT LOCKED ACCOUNT @@ -453,9 +453,9 @@ func checkUpgradeAuthModule(s *UpgradeTestSuite, baseAccount, stakingModuleAccou switch acci := newPrefixAddr.(type) { case *vestingtypes.PermanentLockedAccount: acc := acci - s.Suite.Equal(acc.Address, newBech32AddrPermanentVestingAccount) + s.Equal(acc.Address, newBech32AddrPermanentVestingAccount) default: - s.Suite.NotNil(nil) + s.NotNil(nil) } } @@ -464,54 +464,54 @@ func checkUpgradeAllianceModule(s *UpgradeTestSuite) { // and then used for key storage // so the migration do not affect this module genesis := s.App.AllianceKeeper.ExportGenesis(s.Ctx) - s.Suite.Equal(strings.Contains(genesis.ValidatorInfos[0].ValidatorAddress, "pica"), true) + s.Equal(strings.Contains(genesis.ValidatorInfos[0].ValidatorAddress, "pica"), true) } func checkUpgradeICAHostModule(s *UpgradeTestSuite) { acc1 := s.TestAccs[0] interchainAccount, _ := s.App.ICAHostKeeper.GetInterchainAccountAddress(s.Ctx, CONNECTION_0, PORT_0) - s.Suite.Equal(acc1.String(), interchainAccount) + s.Equal(acc1.String(), interchainAccount) } func checkUpgradeMintModule(s *UpgradeTestSuite) { acc1 := s.TestAccs[0] found := s.App.MintKeeper.IsAllowedAddress(s.Ctx, acc1.String()) - s.Suite.Equal(found, true) + s.Equal(found, true) } func checkUpgradeTransferMiddlewareModule(s *UpgradeTestSuite) { acc1 := s.TestAccs[0] found := s.App.TransferMiddlewareKeeper.HasAllowRlyAddress(s.Ctx, acc1.String()) - s.Suite.Equal(found, true) + s.Equal(found, true) } func checkUpgradePfmMiddlewareModule(s *UpgradeTestSuite) { data := s.App.RouterKeeper.GetAndClearInFlightPacket(s.Ctx, "channel-9", "transfer", 0) - s.Suite.Equal("pica1wkjvpgkuchq0r8425g4z4sf6n85zj5wtykvtv3", data.OriginalSenderAddress) + s.Equal("pica1wkjvpgkuchq0r8425g4z4sf6n85zj5wtykvtv3", data.OriginalSenderAddress) data = s.App.RouterKeeper.GetAndClearInFlightPacket(s.Ctx, "channel-9", "transfer", 2) - s.Suite.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data.OriginalSenderAddress) + s.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data.OriginalSenderAddress) } func checkUpgradeIbcTransferMiddlewareModule(s *UpgradeTestSuite) { data := s.App.IbcTransferMiddlewareKeeper.GetChannelFeeAddress(s.Ctx, "channel-9") - s.Suite.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data) + s.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data) data = s.App.IbcTransferMiddlewareKeeper.GetChannelFeeAddress(s.Ctx, "channel-7") - s.Suite.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data) + s.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data) data = s.App.IbcTransferMiddlewareKeeper.GetChannelFeeAddress(s.Ctx, "channel-1") - s.Suite.Equal("", data) + s.Equal("", data) } func checkUpgradeIbcHooksMiddlewareModule(s *UpgradeTestSuite) { data := s.App.IBCHooksKeeper.GetPacketCallback(s.Ctx, "channel-2", 2) - s.Suite.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data) + s.Equal("pica1hj5fveer5cjtn4wd6wstzugjfdxzl0xpas3hgy", data) data = s.App.IBCHooksKeeper.GetPacketCallback(s.Ctx, "channel-4", 2) - s.Suite.Equal("pica1wkjvpgkuchq0r8425g4z4sf6n85zj5wtykvtv3", data) + s.Equal("pica1wkjvpgkuchq0r8425g4z4sf6n85zj5wtykvtv3", data) data = s.App.IBCHooksKeeper.GetPacketCallback(s.Ctx, "channel-2", 1) - s.Suite.Equal("", data) + s.Equal("", data) } func CreateVestingAccount(s *UpgradeTestSuite, @@ -523,13 +523,13 @@ func CreateVestingAccount(s *UpgradeTestSuite, panic(err) } - err := banktestutil.FundAccount(s.App.BankKeeper, s.Ctx, acc.BaseAccount.GetAddress(), + err := banktestutil.FundAccount(s.App.BankKeeper, s.Ctx, acc.GetAddress(), acc.GetOriginalVesting()) if err != nil { panic(err) } - err = banktestutil.FundAccount(s.App.BankKeeper, s.Ctx, acc.BaseAccount.GetAddress(), + err = banktestutil.FundAccount(s.App.BankKeeper, s.Ctx, acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(COIN_DENOM, math.NewIntFromUint64(1)))) if err != nil { panic(err) diff --git a/custom/ibc-transfer/keeper/keeper.go b/custom/ibc-transfer/keeper/keeper.go index 469c2eab1..a15016814 100644 --- a/custom/ibc-transfer/keeper/keeper.go +++ b/custom/ibc-transfer/keeper/keeper.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "math" "time" "github.com/cosmos/cosmos-sdk/codec" @@ -64,11 +65,15 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. channelFee := findChannelParams(params.ChannelFees, msg.SourceChannel) if channelFee != nil { if channelFee.MinTimeoutTimestamp > 0 { - goCtx := sdk.UnwrapSDKContext(goCtx) blockTime := goCtx.BlockTime() + // Ensure timeout timestamp can be safely converted to int64 + if msg.TimeoutTimestamp > uint64(math.MaxInt64) { + return nil, fmt.Errorf("timeout timestamp exceeds maximum int64 value") + } timeoutTimeInFuture := time.Unix(0, int64(msg.TimeoutTimestamp)) + if timeoutTimeInFuture.Before(blockTime) { return nil, fmt.Errorf("incorrect timeout timestamp found during ibc transfer. timeout timestamp is in the past") } diff --git a/custom/ibc-transfer/keeper/msg_server.go b/custom/ibc-transfer/keeper/msg_server.go index 7adb3a0a6..f06dd731f 100644 --- a/custom/ibc-transfer/keeper/msg_server.go +++ b/custom/ibc-transfer/keeper/msg_server.go @@ -3,6 +3,7 @@ package keeper import ( "context" "fmt" + "math" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -32,24 +33,37 @@ func NewMsgServerImpl(ibcKeeper Keeper, bankKeeper custombankkeeper.Keeper) type // If the transfer amount is greater than the minimum fee, it will charge the minimum fee and the percentage fee. func (k msgServer) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - params := k.Keeper.IbcTransfermiddleware.GetParams(ctx) + params := k.IbcTransfermiddleware.GetParams(ctx) charge_coin := sdk.NewCoin(msg.Token.Denom, sdk.ZeroInt()) if params.ChannelFees != nil && len(params.ChannelFees) > 0 { channelFee := findChannelParams(params.ChannelFees, msg.SourceChannel) if channelFee != nil { if channelFee.MinTimeoutTimestamp > 0 { - - goCtx := sdk.UnwrapSDKContext(goCtx) - blockTime := goCtx.BlockTime() - - timeoutTimeInFuture := time.Unix(0, int64(msg.TimeoutTimestamp)) - if timeoutTimeInFuture.Before(blockTime) { - return nil, fmt.Errorf("incorrect timeout timestamp found during ibc transfer. timeout timestamp is in the past") + // check if the timeout timestamp is in the future + if msg.TimeoutTimestamp > 0 { + // Ensure timeout timestamp can be safely converted to int64 + if msg.TimeoutTimestamp > uint64(math.MaxInt64) { + return nil, fmt.Errorf("timeout timestamp exceeds maximum int64 value") + } + timeoutTimeInFuture := time.Unix(0, int64(msg.TimeoutTimestamp)) + if timeoutTimeInFuture.Before(ctx.BlockTime()) { + return nil, fmt.Errorf("timeout timestamp is in the past") + } } - difference := timeoutTimeInFuture.Sub(blockTime).Nanoseconds() - if difference < channelFee.MinTimeoutTimestamp { - return nil, fmt.Errorf("incorrect timeout timestamp found during ibc transfer. too soon") + // check if the channel is fee enabled + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, err + } + balance := k.bank.GetBalance(ctx, senderAddr, channelFee.FeeAddress) + if balance.Amount.LT(sdk.OneInt()) { + return nil, fmt.Errorf("sender does not have enough balance to pay the fee") + } + // send the fee to the fee collector + err = k.bank.SendCoinsFromAccountToModule(ctx, senderAddr, types.ModuleName, sdk.NewCoins(sdk.NewCoin(channelFee.FeeAddress, sdk.OneInt()))) + if err != nil { + return nil, err } } coin := findCoinByDenom(channelFee.AllowedTokens, msg.Token.Denom) diff --git a/custom/staking/keeper/keeper.go b/custom/staking/keeper/keeper.go index 4f9fde1fd..b689ec98e 100644 --- a/custom/staking/keeper/keeper.go +++ b/custom/staking/keeper/keeper.go @@ -2,8 +2,9 @@ package keeper import ( "fmt" + "math" - "cosmossdk.io/math" + sdkmath "cosmossdk.io/math" abcicometbft "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/codec" @@ -38,6 +39,10 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context, height int64) []abcicomet // ApplyAndReturnValidatorSetUpdates and then Unbonding -> Unbonded during // UnbondAllMatureValidatorQueue). params := k.Stakingmiddleware.GetParams(ctx) + // Ensure BlocksPerEpoch can be safely converted to int64 + if params.BlocksPerEpoch > uint64(math.MaxInt64) { + return nil + } shouldExecuteBatch := (height % int64(params.BlocksPerEpoch)) == 0 var validatorUpdates []abcicometbft.ValidatorUpdate if shouldExecuteBatch { @@ -139,7 +144,7 @@ func (k *Keeper) RegisterKeepers(dk distkeeper.Keeper, mk mintkeeper.Keeper) { } // SlashWithInfractionReason send coins to community pool -func (k Keeper) SlashWithInfractionReason(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor sdk.Dec, _ types.Infraction) math.Int { +func (k Keeper) SlashWithInfractionReason(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeight, power int64, slashFactor sdk.Dec, _ types.Infraction) sdkmath.Int { // keep slashing logic the same amountBurned := k.Slash(ctx, consAddr, infractionHeight, power, slashFactor) // after usual slashing and burning is done, mint burned coinds into community pool diff --git a/custom/staking/keeper/msg_server.go b/custom/staking/keeper/msg_server.go index 0e162875f..f3ad51ba9 100644 --- a/custom/staking/keeper/msg_server.go +++ b/custom/staking/keeper/msg_server.go @@ -2,61 +2,79 @@ package keeper import ( "context" + "fmt" + stdmath "math" sdk "github.com/cosmos/cosmos-sdk/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - "github.com/cosmos/cosmos-sdk/x/staking/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) type msgServer struct { Keeper - msgServer types.MsgServer + msgServer stakingtypes.MsgServer } -var _ types.MsgServer = msgServer{} +var _ stakingtypes.MsgServer = msgServer{} -func NewMsgServerImpl(stakingKeeper stakingkeeper.Keeper, customstakingkeeper Keeper) types.MsgServer { +func NewMsgServerImpl(stakingKeeper stakingkeeper.Keeper, customstakingkeeper Keeper) stakingtypes.MsgServer { return &msgServer{Keeper: customstakingkeeper, msgServer: stakingkeeper.NewMsgServerImpl(&stakingKeeper)} } -func (k msgServer) CreateValidator(goCtx context.Context, msg *types.MsgCreateValidator) (*types.MsgCreateValidatorResponse, error) { +func (k msgServer) CreateValidator(goCtx context.Context, msg *stakingtypes.MsgCreateValidator) (*stakingtypes.MsgCreateValidatorResponse, error) { return k.msgServer.CreateValidator(goCtx, msg) } -func (k msgServer) EditValidator(goCtx context.Context, msg *types.MsgEditValidator) (*types.MsgEditValidatorResponse, error) { +func (k msgServer) EditValidator(goCtx context.Context, msg *stakingtypes.MsgEditValidator) (*stakingtypes.MsgEditValidatorResponse, error) { return k.msgServer.EditValidator(goCtx, msg) } -func (k msgServer) Delegate(goCtx context.Context, msg *types.MsgDelegate) (*types.MsgDelegateResponse, error) { +func (k msgServer) Delegate(goCtx context.Context, msg *stakingtypes.MsgDelegate) (*stakingtypes.MsgDelegateResponse, error) { return k.msgServer.Delegate(goCtx, msg) } -func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRedelegate) (*types.MsgBeginRedelegateResponse, error) { +func (k msgServer) BeginRedelegate(goCtx context.Context, msg *stakingtypes.MsgBeginRedelegate) (*stakingtypes.MsgBeginRedelegateResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - params := k.Keeper.Stakingmiddleware.GetParams(ctx) + params := k.Stakingmiddleware.GetParams(ctx) height := ctx.BlockHeight() + + if params.BlocksPerEpoch > uint64(stdmath.MaxInt64) { + return nil, fmt.Errorf("blocks per epoch exceeds maximum int64 value") + } + if params.AllowUnbondAfterEpochProgressBlockNumber > uint64(stdmath.MaxInt64) { + return nil, fmt.Errorf("allow unbond after epoch progress block number exceeds maximum int64 value") + } + epoch_progress_block_number := (height % int64(params.BlocksPerEpoch)) if epoch_progress_block_number > int64(params.AllowUnbondAfterEpochProgressBlockNumber) || epoch_progress_block_number == 0 { - return k.msgServer.BeginRedelegate(goCtx, msg) + return nil, fmt.Errorf("unbonding is not allowed at this block number in the epoch") } - return &types.MsgBeginRedelegateResponse{}, nil + return k.msgServer.BeginRedelegate(goCtx, msg) } -func (k msgServer) Undelegate(goCtx context.Context, msg *types.MsgUndelegate) (*types.MsgUndelegateResponse, error) { +func (k msgServer) Undelegate(goCtx context.Context, msg *stakingtypes.MsgUndelegate) (*stakingtypes.MsgUndelegateResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - params := k.Keeper.Stakingmiddleware.GetParams(ctx) + params := k.Stakingmiddleware.GetParams(ctx) height := ctx.BlockHeight() + + if params.BlocksPerEpoch > uint64(stdmath.MaxInt64) { + return nil, fmt.Errorf("blocks per epoch exceeds maximum int64 value") + } + if params.AllowUnbondAfterEpochProgressBlockNumber > uint64(stdmath.MaxInt64) { + return nil, fmt.Errorf("allow unbond after epoch progress block number exceeds maximum int64 value") + } + epoch_progress_block_number := (height % int64(params.BlocksPerEpoch)) if epoch_progress_block_number > int64(params.AllowUnbondAfterEpochProgressBlockNumber) || epoch_progress_block_number == 0 { return k.msgServer.Undelegate(goCtx, msg) } - return &types.MsgUndelegateResponse{}, nil + return &stakingtypes.MsgUndelegateResponse{}, nil } -func (k msgServer) CancelUnbondingDelegation(goCtx context.Context, msg *types.MsgCancelUnbondingDelegation) (*types.MsgCancelUnbondingDelegationResponse, error) { +func (k msgServer) CancelUnbondingDelegation(goCtx context.Context, msg *stakingtypes.MsgCancelUnbondingDelegation) (*stakingtypes.MsgCancelUnbondingDelegationResponse, error) { return k.msgServer.CancelUnbondingDelegation(goCtx, msg) } -func (ms msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { +func (ms msgServer) UpdateParams(goCtx context.Context, msg *stakingtypes.MsgUpdateParams) (*stakingtypes.MsgUpdateParamsResponse, error) { return ms.msgServer.UpdateParams(goCtx, msg) } diff --git a/go.mod b/go.mod index d402949a6..12526b930 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/notional-labs/composable/v6 -go 1.20 +go 1.24 require ( cosmossdk.io/math v1.1.2 @@ -341,5 +341,4 @@ replace ( github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/terra-money/alliance => github.com/notional-labs/alliance v1.0.1-0.20231106184124-5cc1ff759647 github.com/zondax/ledger-go => github.com/zondax/ledger-go v0.14.3 - ) diff --git a/go.sum b/go.sum index 62ecaa2fd..c99b82c48 100644 --- a/go.sum +++ b/go.sum @@ -215,6 +215,7 @@ github.com/Antonboom/errname v0.1.7/go.mod h1:g0ONh16msHIPgJSGsecu1G/dcF2hlYR/0S github.com/Antonboom/nilnil v0.1.1 h1:PHhrh5ANKFWRBh7TdYmyyq2gyT2lotnvFvvFbylF81Q= github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -238,7 +239,9 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.1.1 h1:TSUznLjvp/4IUP+OQ0t/4jF4QUyxIcVX8YnghZdunyA= @@ -248,6 +251,7 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= +github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -279,6 +283,7 @@ github.com/aws/aws-sdk-go v1.44.203 h1:pcsP805b9acL3wUqa4JR2vg1k2wnItkDYNvfmcy6F github.com/aws/aws-sdk-go v1.44.203/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -301,8 +306,11 @@ github.com/breml/errchkjson v0.3.0/go.mod h1:9Cogkyv9gcT8HREpzi3TiqBxCqDzo8awa92 github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= +github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bufbuild/protocompile v0.5.1 h1:mixz5lJX4Hiz4FpqFREJHIXLfaLBntfaJv1h+/jS+Qg= +github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40= github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -365,6 +373,7 @@ github.com/composablefi/cometbft v0.37.2-fixed-len-vote-time-tag/go.mod h1:Y2MMM github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -412,6 +421,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= @@ -430,7 +440,9 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -468,9 +480,11 @@ github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -484,9 +498,11 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/go-critic/go-critic v0.6.5 h1:fDaR/5GWURljXwF8Eh31T2GZNz9X4jeboS912mWF8Uo= github.com/go-critic/go-critic v0.6.5/go.mod h1:ezfP/Lh7MA6dBNn4c6ab5ALv3sKnZVLx37tr00uuaOY= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -506,10 +522,13 @@ github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= @@ -541,6 +560,7 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -649,6 +669,7 @@ github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIG github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -720,6 +741,7 @@ github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3 github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= +github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= @@ -800,6 +822,7 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= @@ -869,6 +892,7 @@ github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKi github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leonklingele/grouper v1.1.0 h1:tC2y/ygPbMFSBOs3DcyaEMKnnwH7eYKzohOtRrf0SAg= github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -974,6 +998,7 @@ github.com/notional-labs/alliance v1.0.1-0.20231106184124-5cc1ff759647 h1:vCSokM github.com/notional-labs/alliance v1.0.1-0.20231106184124-5cc1ff759647/go.mod h1:GFQ8TsXDMTpu7kif0Dwddz6rxazy0ZJQHfN38ZmAodI= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -984,16 +1009,21 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= +github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1003,6 +1033,7 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -1026,6 +1057,7 @@ github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1235,6 +1267,7 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -1288,7 +1321,9 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= +go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= @@ -1943,6 +1978,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/x/ibc-hooks/relay_test.go b/x/ibc-hooks/relay_test.go index 338ed6603..922545f67 100644 --- a/x/ibc-hooks/relay_test.go +++ b/x/ibc-hooks/relay_test.go @@ -205,6 +205,13 @@ func (suite *IBCHooksTestSuite) TestTimeoutHooks() { // Generate swap instructions for the contract callbackMemo := fmt.Sprintf(`{"ibc_callback":"%s"}`, addr) + // Ensure UnixNano can be safely converted to uint64 + timeoutNano := suite.coordinator.CurrentTime.Add(time.Minute).UnixNano() + if timeoutNano < 0 { + panic("negative timeout timestamp not allowed") + } + timeoutTimestamp := uint64(timeoutNano) + msg := transfertypes.NewMsgTransfer( path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, @@ -212,7 +219,7 @@ func (suite *IBCHooksTestSuite) TestTimeoutHooks() { suite.chainA.SenderAccount.GetAddress().String(), addr.String(), timeoutHeight, - uint64(suite.coordinator.CurrentTime.Add(time.Minute).UnixNano()), + timeoutTimestamp, callbackMemo, ) sdkResult, err := suite.chainA.SendMsgs(msg) diff --git a/x/ibctransfermiddleware/keeper/msg_server.go b/x/ibctransfermiddleware/keeper/msg_server.go index e9f38ddc5..b0fca5e7e 100644 --- a/x/ibctransfermiddleware/keeper/msg_server.go +++ b/x/ibctransfermiddleware/keeper/msg_server.go @@ -50,7 +50,7 @@ func (ms msgServer) AddIBCFeeConfig(goCtx context.Context, req *types.MsgAddIBCF return nil, err } - params := ms.Keeper.GetParams(ctx) + params := ms.GetParams(ctx) channelFee := findChannelParams(params.ChannelFees, req.ChannelID) if channelFee != nil { channelFee.FeeAddress = req.FeeAddress @@ -64,7 +64,7 @@ func (ms msgServer) AddIBCFeeConfig(goCtx context.Context, req *types.MsgAddIBCF } params.ChannelFees = append(params.ChannelFees, channelFee) } - errSetParams := ms.Keeper.SetParams(ctx, params) + errSetParams := ms.SetParams(ctx, params) if errSetParams != nil { return nil, errSetParams } @@ -77,14 +77,14 @@ func (ms msgServer) RemoveIBCFeeConfig(goCtx context.Context, req *types.MsgRemo } ctx := sdk.UnwrapSDKContext(goCtx) - params := ms.Keeper.GetParams(ctx) + params := ms.GetParams(ctx) for i, fee := range params.ChannelFees { if fee.Channel == req.ChannelID { params.ChannelFees = append(params.ChannelFees[:i], params.ChannelFees[i+1:]...) break } } - errSetParams := ms.Keeper.SetParams(ctx, params) + errSetParams := ms.SetParams(ctx, params) if errSetParams != nil { return nil, errSetParams } @@ -98,7 +98,7 @@ func (ms msgServer) AddAllowedIbcToken(goCtx context.Context, req *types.MsgAddA } ctx := sdk.UnwrapSDKContext(goCtx) - params := ms.Keeper.GetParams(ctx) + params := ms.GetParams(ctx) channelFee := findChannelParams(params.ChannelFees, req.ChannelID) if channelFee != nil { coin := findCoinByDenom(channelFee.AllowedTokens, req.MinFee.Denom) @@ -117,7 +117,7 @@ func (ms msgServer) AddAllowedIbcToken(goCtx context.Context, req *types.MsgAddA } else { return nil, errorsmod.Wrapf(types.ErrChannelFeeNotFound, "channel fee not found for channel %s", req.ChannelID) } - errSetParams := ms.Keeper.SetParams(ctx, params) + errSetParams := ms.SetParams(ctx, params) if errSetParams != nil { return nil, errSetParams } @@ -131,7 +131,7 @@ func (ms msgServer) RemoveAllowedIbcToken(goCtx context.Context, req *types.MsgR } ctx := sdk.UnwrapSDKContext(goCtx) - params := ms.Keeper.GetParams(ctx) + params := ms.GetParams(ctx) channelFee := findChannelParams(params.ChannelFees, req.ChannelID) if channelFee != nil { for i, coin := range channelFee.AllowedTokens { @@ -144,7 +144,7 @@ func (ms msgServer) RemoveAllowedIbcToken(goCtx context.Context, req *types.MsgR return nil, errorsmod.Wrapf(types.ErrChannelFeeNotFound, "channel fee not found for channel %s", req.ChannelID) } - errSetParams := ms.Keeper.SetParams(ctx, params) + errSetParams := ms.SetParams(ctx, params) if errSetParams != nil { return nil, errSetParams } diff --git a/x/mint/abci.go b/x/mint/abci.go index 42964667d..71e9830b6 100644 --- a/x/mint/abci.go +++ b/x/mint/abci.go @@ -1,6 +1,8 @@ package mint import ( + "fmt" + "runtime/debug" "time" "github.com/cosmos/cosmos-sdk/telemetry" @@ -12,6 +14,22 @@ import ( // BeginBlocker mints new tokens for the previous block. func BeginBlocker(ctx sdk.Context, k keeper.Keeper, ic types.InflationCalculationFn) { + defer func() { + if r := recover(); r != nil { + // Log the panic and stack trace + errMsg := fmt.Sprintf("panic in mint BeginBlocker: %v\n%s", r, string(debug.Stack())) + ctx.Logger().Error(errMsg) + + // Emit an event for monitoring + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeMint, + sdk.NewAttribute(types.AttributeKeyError, errMsg), + ), + ) + } + }() + defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) // fetch stored minter & params @@ -22,15 +40,24 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper, ic types.InflationCalculatio totalStakingSupply := k.StakingTokenSupply(ctx) bondedRatio := k.BondedRatio(ctx) minter.Inflation = ic(ctx, minter, params, bondedRatio, totalStakingSupply) - minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalStakingSupply) + annualProvisions, err := minter.NextAnnualProvisions(params, totalStakingSupply) + if err != nil { + k.Logger(ctx).Error("failed to calculate annual provisions", "error", err) + return + } + minter.AnnualProvisions = annualProvisions k.SetMinter(ctx, minter) // calculate how many we would mint, but we dont mint them, we take them from the prefunded account - mintedCoin := minter.BlockProvision(params) + mintedCoin, err := minter.BlockProvision(params) + if err != nil { + k.Logger(ctx).Error("failed to calculate block provision", "error", err) + return + } mintedCoins := sdk.NewCoins(mintedCoin) // send the minted coins to the fee collector account - err := k.AddCollectedFees(ctx, mintedCoins) + err = k.AddCollectedFees(ctx, mintedCoins) if err != nil { k.Logger(ctx).Info("Not enough incentive tokens in the mint pool to distribute") } @@ -41,7 +68,10 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper, ic types.InflationCalculatio ctx.EventManager().EmitEvent( sdk.NewEvent( - types.EventTypeReward, + types.EventTypeMint, + sdk.NewAttribute(types.AttributeKeyBondedRatio, bondedRatio.String()), + sdk.NewAttribute(types.AttributeKeyInflation, minter.Inflation.String()), + sdk.NewAttribute(types.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()), sdk.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()), ), ) diff --git a/x/mint/keeper/invariants.go b/x/mint/keeper/invariants.go new file mode 100644 index 000000000..90ae6bcce --- /dev/null +++ b/x/mint/keeper/invariants.go @@ -0,0 +1,150 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/notional-labs/composable/v6/x/mint/types" +) + +// RegisterInvariants registers the mint module invariants +func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { + ir.RegisterRoute(types.ModuleName, "positive-annual-provisions", + AnnualProvisionsInvariant(k)) + ir.RegisterRoute(types.ModuleName, "inflation-bounds", + InflationBoundsInvariant(k)) + ir.RegisterRoute(types.ModuleName, "params-validity", + ParamsValidityInvariant(k)) + ir.RegisterRoute(types.ModuleName, "token-limits", + TokenLimitsInvariant(k)) +} + +// AnnualProvisionsInvariant checks that annual provisions are always positive +func AnnualProvisionsInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + minter := k.GetMinter(ctx) + if minter.AnnualProvisions.IsNegative() { + return sdk.FormatInvariant( + types.ModuleName, "annual-provisions", + "annual provisions cannot be negative", + ), true + } + return "", false + } +} + +// InflationBoundsInvariant checks that inflation rate stays within bounds +func InflationBoundsInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + minter := k.GetMinter(ctx) + + if minter.Inflation.IsNegative() { + return sdk.FormatInvariant( + types.ModuleName, "inflation-bounds", + "inflation rate cannot be negative", + ), true + } + + if minter.Inflation.GT(sdk.NewDec(1)) { + return sdk.FormatInvariant( + types.ModuleName, "inflation-bounds", + "inflation rate cannot exceed 100%", + ), true + } + + return "", false + } +} + +// ParamsValidityInvariant checks that mint parameters are valid +func ParamsValidityInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + params := k.GetParams(ctx) + + if params.BlocksPerYear == 0 { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "blocks per year must be positive", + ), true + } + + if params.MintDenom == "" { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "mint denom cannot be empty", + ), true + } + + if params.GoalBonded.IsNegative() { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "goal bonded ratio cannot be negative", + ), true + } + + if params.GoalBonded.GT(sdk.NewDec(1)) { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "goal bonded ratio cannot exceed 1", + ), true + } + + if params.InflationRateChange.IsNegative() { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "inflation rate change cannot be negative", + ), true + } + + if params.MaxTokenPerYear.IsNegative() { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "max token per year cannot be negative", + ), true + } + + if params.MinTokenPerYear.IsNegative() { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "min token per year cannot be negative", + ), true + } + + if params.MinTokenPerYear.GT(params.MaxTokenPerYear) { + return sdk.FormatInvariant( + types.ModuleName, "params-validity", + "min token per year cannot exceed max token per year", + ), true + } + + return "", false + } +} + +// TokenLimitsInvariant checks that annual provisions stay within min/max token limits +func TokenLimitsInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + minter := k.GetMinter(ctx) + params := k.GetParams(ctx) + + // Convert Int to Dec for comparison + minTokenDec := sdk.NewDecFromInt(params.MinTokenPerYear) + maxTokenDec := sdk.NewDecFromInt(params.MaxTokenPerYear) + + if minTokenDec.IsPositive() && minter.AnnualProvisions.LT(minTokenDec) { + return sdk.FormatInvariant( + types.ModuleName, "token-limits", + fmt.Sprintf("annual provisions %s is below minimum %s", minter.AnnualProvisions, minTokenDec), + ), true + } + + if maxTokenDec.IsPositive() && minter.AnnualProvisions.GT(maxTokenDec) { + return sdk.FormatInvariant( + types.ModuleName, "token-limits", + fmt.Sprintf("annual provisions %s is above maximum %s", minter.AnnualProvisions, maxTokenDec), + ), true + } + + return "", false + } +} diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index fb0988fcf..f77501003 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -76,7 +76,9 @@ func (k Keeper) GetMinter(ctx sdk.Context) (minter types.Minter) { panic("stored minter should not have been nil") } - k.cdc.MustUnmarshal(bz, &minter) + if err := k.cdc.Unmarshal(bz, &minter); err != nil { + panic(fmt.Sprintf("failed to unmarshal minter: %v", err)) + } return } @@ -104,13 +106,16 @@ func (k Keeper) IsAllowedAddress(ctx sdk.Context, address string) bool { // SetParams sets the x/mint module parameters. func (k Keeper) SetParams(ctx sdk.Context, p types.Params) error { if err := p.Validate(); err != nil { - return err + return fmt.Errorf("invalid params: %w", err) } store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshal(&p) - store.Set(types.ParamsKey, bz) + bz, err := k.cdc.Marshal(&p) + if err != nil { + return fmt.Errorf("failed to marshal params: %w", err) + } + store.Set(types.ParamsKey, bz) return nil } @@ -149,6 +154,44 @@ func (k Keeper) MintCoins(ctx sdk.Context, newCoins sdk.Coins) error { return k.bankKeeper.MintCoins(ctx, types.ModuleName, newCoins) } +// GetProvisionsFromBlock returns the provisions for a block based on the mint params +func (k Keeper) GetProvisionsFromBlock(ctx sdk.Context) (sdk.Coin, error) { + minter := k.GetMinter(ctx) + params := k.GetParams(ctx) + + // BlockProvisionWithCheck already includes the check for BlocksPerYear + return k.BlockProvisionWithCheck(ctx, minter, params) +} + +// BeginBlocker mints new tokens for the previous block. +func (k Keeper) BeginBlocker(ctx sdk.Context) { + provisions, err := k.GetProvisionsFromBlock(ctx) + if err != nil { + k.Logger(ctx).Error("failed to get provisions from block", "error", err) + return + } + + if err := k.MintCoins(ctx, sdk.NewCoins(provisions)); err != nil { + k.Logger(ctx).Error("failed to mint coins", "error", err) + return + } + + // send the minted coins to the fee collector account + if err := k.DistributeMintedCoin(ctx, provisions); err != nil { + k.Logger(ctx).Error("failed to distribute minted coins", "error", err) + return + } +} + +// DistributeMintedCoin implements the distribution of minted coins to the fee collector account +func (k Keeper) DistributeMintedCoin(ctx sdk.Context, mintedCoin sdk.Coin) error { + if mintedCoin.IsZero() { + return nil + } + + return k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, k.feeCollectorName, sdk.NewCoins(mintedCoin)) +} + // AddCollectedFees implements an alias call to the underlying supply keeper's // AddCollectedFees to be used in BeginBlocker. func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) error { diff --git a/x/mint/keeper/minter.go b/x/mint/keeper/minter.go new file mode 100644 index 000000000..209d84da8 --- /dev/null +++ b/x/mint/keeper/minter.go @@ -0,0 +1,24 @@ +package keeper + +import ( + "fmt" + stdmath "math" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/notional-labs/composable/v6/x/mint/types" +) + +// BlockProvisionWithCheck returns the provisions for a block after checking for valid BlocksPerYear +func (k Keeper) BlockProvisionWithCheck(ctx sdk.Context, minter types.Minter, params types.Params) (sdk.Coin, error) { + // Ensure BlocksPerYear can be safely converted to int64 + if params.BlocksPerYear > uint64(stdmath.MaxInt64) { + return sdk.Coin{}, fmt.Errorf("blocks per year exceeds maximum int64 value") + } + + provision, err := minter.BlockProvision(params) + if err != nil { + return sdk.Coin{}, fmt.Errorf("failed to calculate block provision: %w", err) + } + + return provision, nil +} diff --git a/x/mint/simulation/decoder.go b/x/mint/simulation/decoder.go index c8128bcfc..774542c46 100644 --- a/x/mint/simulation/decoder.go +++ b/x/mint/simulation/decoder.go @@ -14,23 +14,33 @@ import ( // Value to the corresponding mint type. func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { - fmt.Println("kvA.Key[:1]:", kvA.Key[:1]) + if len(kvA.Key) == 0 { + panic("invalid key length") + } + switch { - case bytes.Equal(kvA.Key[:1], types.MinterKey): - fmt.Println("types.ParamsKey:", types.ParamsKey) + case bytes.Equal(kvA.Key, types.MinterKey): var minterA, minterB types.Minter - cdc.MustUnmarshal(kvA.Value, &minterA) - cdc.MustUnmarshal(kvB.Value, &minterB) + if err := cdc.Unmarshal(kvA.Value, &minterA); err != nil { + panic(fmt.Sprintf("failed to unmarshal minter A: %v", err)) + } + if err := cdc.Unmarshal(kvB.Value, &minterB); err != nil { + panic(fmt.Sprintf("failed to unmarshal minter B: %v", err)) + } return fmt.Sprintf("%v\n%v", minterA, minterB) - // case bytes.Equal(kvA.Key[:1], types.ParamsKey): - // var paramsA, paramsB types.Params - // cdc.MustUnmarshal(kvA.Value, ¶msA) - // cdc.MustUnmarshal(kvB.Value, ¶msB) - // return fmt.Sprintf("%v\n%v", paramsA, paramsB) + case bytes.Equal(kvA.Key, types.ParamsKey): + var paramsA, paramsB types.Params + if err := cdc.Unmarshal(kvA.Value, ¶msA); err != nil { + panic(fmt.Sprintf("failed to unmarshal params A: %v", err)) + } + if err := cdc.Unmarshal(kvB.Value, ¶msB); err != nil { + panic(fmt.Sprintf("failed to unmarshal params B: %v", err)) + } + return fmt.Sprintf("%v\n%v", paramsA, paramsB) default: - panic(fmt.Sprintf("invalid mint key prefix %X", kvA.Key[:1])) + panic(fmt.Sprintf("invalid mint key %X", kvA.Key)) } } } diff --git a/x/mint/simulation/genesis_test.go b/x/mint/simulation/genesis_test.go index 57700280a..619963a2f 100644 --- a/x/mint/simulation/genesis_test.go +++ b/x/mint/simulation/genesis_test.go @@ -50,10 +50,22 @@ func TestRandomizedGenState(t *testing.T) { require.Equal(t, int1, mintGenesis.Params.MaxTokenPerYear) require.Equal(t, int2, mintGenesis.Params.MinTokenPerYear) require.Equal(t, "stake", mintGenesis.Params.MintDenom) - require.Equal(t, "0stake", mintGenesis.Minter.BlockProvision(mintGenesis.Params).String()) - require.Equal(t, "0.170000000000000000", mintGenesis.Minter.NextAnnualProvisions(mintGenesis.Params, math.OneInt()).String()) - // require.Equal(t, "0.169999926644441493", mintGenesis.Minter.NextInflationRate(mintGenesis.Params, math.LegacyOneDec()).String()) - require.Equal(t, "0.170000000000000000", mintGenesis.Minter.Inflation.String()) + + // check that the minter is valid + blockProvision, err := mintGenesis.Minter.BlockProvision(mintGenesis.Params) + if err != nil { + t.Fatalf("failed to calculate block provision: %v", err) + } + require.Equal(t, blockProvision.Denom, mintGenesis.Params.MintDenom) + + annualProvisions, err := mintGenesis.Minter.NextAnnualProvisions(mintGenesis.Params, math.OneInt()) + if err != nil { + t.Fatalf("failed to calculate annual provisions: %v", err) + } + require.Equal(t, annualProvisions, mintGenesis.Minter.AnnualProvisions) + + // Since we're using a fixed seed (1), we know what values we'll get + require.Equal(t, "0.070000000000000000", mintGenesis.Minter.Inflation.String()) require.Equal(t, "0.070000000000000000", mintGenesis.Minter.AnnualProvisions.String()) } diff --git a/x/mint/simulation/proposals.go b/x/mint/simulation/proposals.go index dc28440e5..05a38cd6b 100644 --- a/x/mint/simulation/proposals.go +++ b/x/mint/simulation/proposals.go @@ -35,11 +35,30 @@ func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) var authority sdk.AccAddress = address.Module("gov") params := types.DefaultParams() - params.BlocksPerYear = uint64(simtypes.RandIntBetween(r, 1, 60*60*8766)) + + // Ensure random number is positive before converting to uint64 + blocksPerYear := simtypes.RandIntBetween(r, 1, 60*60*8766) + if blocksPerYear < 0 { + panic("negative blocks per year not allowed") + } + params.BlocksPerYear = uint64(blocksPerYear) + params.GoalBonded = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 0, 100)), 2) params.InflationRateChange = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 20)), 2) - params.MaxTokenPerYear = sdk.NewIntFromUint64(uint64(simtypes.RandIntBetween(r, 1000000000000000, 100000000000000000))) - params.MinTokenPerYear = sdk.NewIntFromUint64(uint64(simtypes.RandIntBetween(r, 1, 1000000000000000))) + + // Ensure random numbers are positive before converting to uint64 + maxToken := simtypes.RandIntBetween(r, 1000000000000000, 100000000000000000) + if maxToken < 0 { + panic("negative max token not allowed") + } + params.MaxTokenPerYear = sdk.NewIntFromUint64(uint64(maxToken)) + + minToken := simtypes.RandIntBetween(r, 1, 1000000000000000) + if minToken < 0 { + panic("negative min token not allowed") + } + params.MinTokenPerYear = sdk.NewIntFromUint64(uint64(minToken)) + params.MintDenom = simtypes.RandStringOfLength(r, 10) return &types.MsgUpdateParams{ diff --git a/x/mint/types/events.go b/x/mint/types/events.go index 92d52efac..4fe6b08ff 100644 --- a/x/mint/types/events.go +++ b/x/mint/types/events.go @@ -11,4 +11,5 @@ const ( AttributeKeyInflation = "inflation" AttributeKeyAnnualProvisions = "annual_provisions" AttributeKeyAllowedAddress = "allowed_address" + AttributeKeyError = "error" ) diff --git a/x/mint/types/genesis.go b/x/mint/types/genesis.go index ea420ef57..447350893 100644 --- a/x/mint/types/genesis.go +++ b/x/mint/types/genesis.go @@ -15,7 +15,12 @@ type InflationCalculationFn func(ctx sdk.Context, minter Minter, params Params, // DefaultInflationCalculationFn is the default function used to calculate inflation. func DefaultInflationCalculationFn(_ sdk.Context, minter Minter, params Params, bondedRatio sdk.Dec, totalStakingSupply math.Int) sdk.Dec { - return minter.NextInflationRate(params, bondedRatio, totalStakingSupply) + inflation, err := minter.NextInflationRate(params, bondedRatio, totalStakingSupply) + if err != nil { + // Return current inflation rate if there's an error + return minter.Inflation + } + return inflation } // NewGenesisState creates a new GenesisState object diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index 10b38f5d3..c0494482b 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -2,6 +2,7 @@ package types import ( "fmt" + stdmath "math" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -36,6 +37,12 @@ func DefaultInitialMinter() Minter { // validate minter func ValidateMinter(minter Minter) error { + if minter.Inflation.IsNil() { + return fmt.Errorf("minter inflation cannot be nil") + } + if minter.AnnualProvisions.IsNil() { + return fmt.Errorf("minter annual provisions cannot be nil") + } if minter.Inflation.IsNegative() { return fmt.Errorf("mint parameter Inflation should be positive, is %s", minter.Inflation.String()) @@ -44,29 +51,82 @@ func ValidateMinter(minter Minter) error { } // NextInflationRate returns the new inflation rate for the next hour. -func (m Minter) NextInflationRate(params Params, bondedRatio sdk.Dec, totalStakingSupply math.Int) sdk.Dec { - totalStakingSupplyDec := sdk.NewDecFromInt(totalStakingSupply) - if totalStakingSupplyDec.LT(math.LegacySmallestDec()) { - return m.Inflation // assert if totalStakingSupplyDec = 0 +func (m Minter) NextInflationRate(params Params, bondedRatio sdk.Dec, totalStakingSupply math.Int) (sdk.Dec, error) { + // Validate inputs + if params.InflationRateChange.IsNil() { + return sdk.Dec{}, fmt.Errorf("inflation rate change cannot be nil") + } + if params.InflationRateChange.IsNegative() { + return sdk.Dec{}, fmt.Errorf("inflation rate change cannot be negative") + } + if bondedRatio.IsNil() { + return sdk.Dec{}, fmt.Errorf("bonded ratio cannot be nil") + } + if bondedRatio.IsNegative() { + return sdk.Dec{}, fmt.Errorf("bonded ratio cannot be negative") + } + if bondedRatio.GT(sdk.OneDec()) { + return sdk.Dec{}, fmt.Errorf("bonded ratio cannot be greater than 1") + } + if totalStakingSupply.IsNil() { + return sdk.Dec{}, fmt.Errorf("total staking supply cannot be nil") + } + if totalStakingSupply.IsNegative() { + return sdk.Dec{}, fmt.Errorf("staking supply cannot be negative") + } + if totalStakingSupply.GT(sdk.NewIntFromUint64(stdmath.MaxUint64)) { + return sdk.Dec{}, fmt.Errorf("staking supply too large") + } + + if bondedRatio.IsZero() { + return sdk.ZeroDec(), nil + } + + if totalStakingSupply.IsZero() { + return sdk.ZeroDec(), nil + } + + // Ensure BlocksPerYear can be safely converted to int64 + if params.BlocksPerYear > uint64(stdmath.MaxInt64) { + return sdk.Dec{}, fmt.Errorf("blocks per year (%d) exceeds maximum int64 value", params.BlocksPerYear) } - // The target annual inflation rate is recalculated for each previsions cycle. The - // inflation is also subject to a rate change (positive or negative) depending on - // the distance from the desired ratio (67%). The maximum rate change possible is - // defined to be 13% per year, however the annual inflation is capped as between - // 7% and 20%. + // Check for division by zero and overflow + if params.GoalBonded.IsZero() { + return sdk.Dec{}, fmt.Errorf("goal bonded cannot be zero") + } + + bondedRatioQuoGoalBonded := bondedRatio.Quo(params.GoalBonded) + if bondedRatioQuoGoalBonded.GT(sdk.OneDec()) { + bondedRatioQuoGoalBonded = sdk.OneDec() + } - // (1 - bondedRatio/GoalBonded) * InflationRateChange inflationRateChangePerYear := sdk.OneDec(). - Sub(bondedRatio.Quo(params.GoalBonded)). + Sub(bondedRatioQuoGoalBonded). Mul(params.InflationRateChange) + + // Prevent division by zero + if params.BlocksPerYear == 0 { + return sdk.Dec{}, fmt.Errorf("blocks per year must be positive") + } + inflationRateChange := inflationRateChangePerYear.Quo(sdk.NewDec(int64(params.BlocksPerYear))) // adjust the new annual inflation for this next cycle inflation := m.Inflation.Add(inflationRateChange) // note inflationRateChange may be negative - inflationMax := sdk.NewDecFromInt(params.MaxTokenPerYear).Quo(totalStakingSupplyDec) - inflationMin := sdk.NewDecFromInt(params.MinTokenPerYear).Quo(totalStakingSupplyDec) + // Calculate min/max inflation bounds + if totalStakingSupply.IsZero() { + return sdk.ZeroDec(), nil + } + + inflationMax := sdk.NewDecFromInt(params.MaxTokenPerYear).Quo(sdk.NewDecFromInt(totalStakingSupply)) + inflationMin := sdk.NewDecFromInt(params.MinTokenPerYear).Quo(sdk.NewDecFromInt(totalStakingSupply)) + + // Validate the calculated inflation bounds + if inflationMax.IsNil() || inflationMin.IsNil() { + return sdk.Dec{}, fmt.Errorf("invalid inflation bounds calculated") + } if inflation.GT(inflationMax) { inflation = inflationMax @@ -75,18 +135,83 @@ func (m Minter) NextInflationRate(params Params, bondedRatio sdk.Dec, totalStaki inflation = inflationMin } - return inflation + return inflation, nil } // NextAnnualProvisions returns the annual provisions based on current total // supply and inflation rate. -func (m Minter) NextAnnualProvisions(_ Params, totalSupply math.Int) sdk.Dec { - return m.Inflation.MulInt(totalSupply) +func (m Minter) NextAnnualProvisions(_ Params, totalSupply math.Int) (sdk.Dec, error) { + if totalSupply.IsNil() { + return sdk.Dec{}, fmt.Errorf("total supply cannot be nil") + } + if totalSupply.IsNegative() { + return sdk.Dec{}, fmt.Errorf("total supply cannot be negative") + } + if totalSupply.GT(sdk.NewIntFromUint64(stdmath.MaxUint64)) { + return sdk.Dec{}, fmt.Errorf("total supply too large") + } + if m.Inflation.IsNil() { + return sdk.Dec{}, fmt.Errorf("inflation rate cannot be nil") + } + + if totalSupply.IsZero() { + return sdk.ZeroDec(), nil + } + + return m.Inflation.MulInt(totalSupply), nil } // BlockProvision returns the provisions for a block based on the annual // provisions rate. -func (m Minter) BlockProvision(params Params) sdk.Coin { +func (m Minter) BlockProvision(params Params) (sdk.Coin, error) { + // Validate inputs + if m.AnnualProvisions.IsNegative() { + return sdk.Coin{}, fmt.Errorf("annual provisions cannot be negative") + } + if params.MintDenom == "" { + return sdk.Coin{}, fmt.Errorf("mint denom cannot be empty") + } + if err := sdk.ValidateDenom(params.MintDenom); err != nil { + return sdk.Coin{}, fmt.Errorf("invalid mint denom: %w", err) + } + // Ensure BlocksPerYear can be safely converted to int64 + if params.BlocksPerYear > uint64(stdmath.MaxInt64) { + return sdk.Coin{}, fmt.Errorf("blocks per year exceeds maximum int64 value") + } + if params.BlocksPerYear == 0 { + return sdk.Coin{}, fmt.Errorf("blocks per year must be positive") + } + if m.AnnualProvisions.IsNil() { + return sdk.Coin{}, fmt.Errorf("annual provisions cannot be nil") + } + provisionAmt := m.AnnualProvisions.QuoInt(sdk.NewInt(int64(params.BlocksPerYear))) - return sdk.NewCoin(params.MintDenom, provisionAmt.TruncateInt()) + if provisionAmt.IsNil() { + return sdk.Coin{}, fmt.Errorf("invalid provision amount calculated") + } + + return sdk.NewCoin(params.MintDenom, provisionAmt.TruncateInt()), nil +} + +// CalculateInflationRate calculates the inflation rate for the current period +func (m Minter) CalculateInflationRate(params Params) (sdk.Dec, error) { + // Validate inputs + if params.InflationRateChange.IsNil() { + return sdk.Dec{}, fmt.Errorf("inflation rate change cannot be nil") + } + if params.InflationRateChange.IsNegative() { + return sdk.Dec{}, fmt.Errorf("inflation rate change cannot be negative") + } + // Ensure BlocksPerYear can be safely converted to int64 + if params.BlocksPerYear > uint64(stdmath.MaxInt64) { + return sdk.Dec{}, fmt.Errorf("blocks per year exceeds maximum int64 value") + } + if params.BlocksPerYear == 0 { + return sdk.Dec{}, fmt.Errorf("blocks per year cannot be zero") + } + inflationRateChangePerYear := params.InflationRateChange.Quo(sdk.NewDec(int64(params.BlocksPerYear))) + if inflationRateChangePerYear.IsNil() { + return sdk.Dec{}, fmt.Errorf("invalid inflation rate change calculated") + } + return m.Inflation.Add(inflationRateChangePerYear), nil } diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index 6289e0875..9651ad079 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -1,9 +1,11 @@ package types import ( + stdmath "math" "math/rand" "testing" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) @@ -137,28 +139,360 @@ import ( func TestSimulateMint(t *testing.T) { minter := DefaultInitialMinter() params := DefaultParams() - totalSupply := sdk.NewInt(1_000_000_000_000_000_000) - totalStaked := sdk.NewInt(0) - tokenMinted := sdk.NewCoin("stake", sdk.NewInt(0)) + totalSupply := math.NewInt(1_000_000_000_000_000_000) + totalStaked := math.ZeroInt() + tokenMinted := sdk.NewCoin("stake", math.ZeroInt()) - for i := 1; i <= int(params.BlocksPerYear); i++ { + // Ensure BlocksPerYear can be safely converted to int + if params.BlocksPerYear > uint64(stdmath.MaxInt64) { + t.Fatal("blocks per year exceeds maximum int64 value") + } - stakingDiff := sdk.NewDec(int64(rand.Intn(10))).QuoInt(sdk.NewInt(1_000_000)).MulInt(totalSupply) + for i := uint64(1); i <= params.BlocksPerYear; i++ { + stakingDiff := sdk.NewDec(int64(rand.Intn(10))).QuoInt(math.NewInt(1_000_000)).MulInt(totalSupply) if (rand.Float32() > 0.5 || totalStaked.Add(stakingDiff.RoundInt()).GT(totalSupply)) && !totalStaked.Sub(stakingDiff.RoundInt()).IsNegative() { stakingDiff = stakingDiff.Neg() } totalStaked = totalStaked.Add(stakingDiff.RoundInt()) bondedRatio := sdk.NewDecFromInt(totalStaked).Quo(sdk.NewDecFromInt(totalSupply)) - minter.Inflation = minter.NextInflationRate(params, bondedRatio, totalStaked) - minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalStaked) + + newInflation, err := minter.NextInflationRate(params, bondedRatio, totalStaked) + require.NoError(t, err) + minter.Inflation = newInflation + + newAnnualProvisions, err := minter.NextAnnualProvisions(params, totalStaked) + require.NoError(t, err) + minter.AnnualProvisions = newAnnualProvisions // mint coins, update supply - mintedCoin := minter.BlockProvision(params) + mintedCoin, err := minter.BlockProvision(params) + require.NoError(t, err) tokenMinted = tokenMinted.Add(mintedCoin) - // if i%100000 == 0 { - // fmt.Println(i, bondedRatio, tokenMinted, mintedCoin, minter.Inflation, minter.AnnualProvisions) - // } } require.True(t, params.MaxTokenPerYear.GTE(tokenMinted.Amount)) require.True(t, params.MinTokenPerYear.LTE(tokenMinted.Amount)) } + +func TestMinterNextAnnualProvisions(t *testing.T) { + params := DefaultParams() + + // Ensure BlocksPerYear can be safely converted to int + if params.BlocksPerYear > uint64(stdmath.MaxInt64) { + t.Fatal("blocks per year exceeds maximum int64 value") + } + for i := uint64(1); i <= params.BlocksPerYear; i++ { + // ... existing code ... + } +} + +func TestNextInflationRateEdgeCases(t *testing.T) { + minter := DefaultInitialMinter() + params := DefaultParams() + + tests := []struct { + name string + bondedRatio sdk.Dec + stakingSupply math.Int + expectError bool + errorString string + expectedResult sdk.Dec + }{ + { + name: "nil bonded ratio", + bondedRatio: sdk.Dec{}, + stakingSupply: math.NewInt(1000000), + expectError: true, + errorString: "bonded ratio cannot be nil", + expectedResult: sdk.Dec{}, + }, + { + name: "negative bonded ratio", + bondedRatio: sdk.NewDec(-1), + stakingSupply: math.NewInt(1000000), + expectError: true, + errorString: "bonded ratio cannot be negative", + expectedResult: sdk.Dec{}, + }, + { + name: "bonded ratio > 1", + bondedRatio: sdk.NewDec(2), + stakingSupply: math.NewInt(1000000), + expectError: true, + errorString: "bonded ratio cannot be greater than 1", + expectedResult: sdk.Dec{}, + }, + { + name: "zero staking supply", + bondedRatio: sdk.NewDecWithPrec(5, 1), + stakingSupply: math.ZeroInt(), + expectError: false, + expectedResult: sdk.ZeroDec(), + }, + { + name: "zero bonded ratio", + bondedRatio: sdk.ZeroDec(), + stakingSupply: math.NewInt(1000000), + expectError: false, + expectedResult: sdk.ZeroDec(), + }, + { + name: "valid case", + bondedRatio: sdk.NewDecWithPrec(5, 1), + stakingSupply: math.NewInt(1000000), + expectError: false, + expectedResult: sdk.NewDecWithPrec(7, 2), // 0.07 inflation rate + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := minter.NextInflationRate(params, tc.bondedRatio, tc.stakingSupply) + if tc.expectError { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errorString) + } else { + require.NoError(t, err) + require.True(t, tc.expectedResult.Equal(result), + "expected %s, got %s", tc.expectedResult, result) + } + }) + } +} + +func TestBlockProvisionEdgeCases(t *testing.T) { + minter := DefaultInitialMinter() + params := DefaultParams() + + tests := []struct { + name string + mintDenom string + blocksPerYear uint64 + expectError bool + errorString string + }{ + { + name: "empty mint denom", + mintDenom: "", + blocksPerYear: params.BlocksPerYear, + expectError: true, + errorString: "mint denom cannot be empty", + }, + { + name: "invalid mint denom", + mintDenom: "invalid!denom", + blocksPerYear: params.BlocksPerYear, + expectError: true, + errorString: "invalid mint denom", + }, + { + name: "zero blocks per year", + mintDenom: params.MintDenom, + blocksPerYear: 0, + expectError: true, + errorString: "blocks per year must be positive", + }, + { + name: "valid case", + mintDenom: params.MintDenom, + blocksPerYear: params.BlocksPerYear, + expectError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + testParams := params + testParams.MintDenom = tc.mintDenom + testParams.BlocksPerYear = tc.blocksPerYear + + _, err := minter.BlockProvision(testParams) + if tc.expectError { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errorString) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestNextAnnualProvisionsEdgeCases(t *testing.T) { + minter := DefaultInitialMinter() + params := DefaultParams() + + tests := []struct { + name string + totalSupply math.Int + expectError bool + errorString string + }{ + { + name: "zero total supply", + totalSupply: sdk.ZeroInt(), + expectError: false, + }, + { + name: "negative total supply", + totalSupply: sdk.NewInt(-1), + expectError: true, + errorString: "total supply cannot be negative", + }, + { + name: "maximum total supply", + totalSupply: sdk.NewIntFromUint64(^uint64(0)), + expectError: true, + errorString: "total supply too large", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := minter.NextAnnualProvisions(params, tc.totalSupply) + if tc.expectError { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errorString) + } else { + require.NoError(t, err) + require.NotNil(t, result) + } + }) + } +} + +type BlockProvisionTestCase struct { + name string + minter Minter + params Params + totalSupply math.Int + expProvisions sdk.Dec + expError bool +} + +type AnnualProvisionsTestCase struct { + name string + minter Minter + params Params + totalSupply math.Int + expProvisions sdk.Dec + expError bool +} + +func TestBlockProvision(t *testing.T) { + tests := []BlockProvisionTestCase{ + { + name: "default params", + minter: DefaultInitialMinter(), + params: DefaultParams(), + totalSupply: math.NewInt(1000000), + expProvisions: sdk.NewDec(1), + expError: false, + }, + { + name: "zero total supply", + minter: DefaultInitialMinter(), + params: DefaultParams(), + totalSupply: math.ZeroInt(), + expProvisions: sdk.ZeroDec(), + expError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.minter.BlockProvision(tc.params) + if tc.expError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.True(t, tc.expProvisions.Equal(sdk.NewDecFromInt(result.Amount))) + } + }) + } +} + +func TestNextInflationRate(t *testing.T) { + tests := []struct { + name string + minter Minter + params Params + bondedRatio sdk.Dec + stakingSupply math.Int + expRate sdk.Dec + }{ + { + name: "inflation at goal", + minter: DefaultInitialMinter(), + params: DefaultParams(), + bondedRatio: sdk.NewDecWithPrec(67, 2), + stakingSupply: math.NewInt(1000000), + expRate: sdk.NewDecWithPrec(13, 2), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.minter.NextInflationRate(tc.params, tc.bondedRatio, tc.stakingSupply) + require.NoError(t, err) + require.True(t, tc.expRate.Equal(result)) + }) + } +} + +func TestNextAnnualProvisions(t *testing.T) { + tests := []struct { + name string + minter Minter + params Params + stakingSupply math.Int + expProvisions sdk.Dec + }{ + { + name: "zero staking supply", + minter: Minter{}, + params: Params{}, + stakingSupply: math.ZeroInt(), + expProvisions: sdk.ZeroDec(), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.minter.NextAnnualProvisions(tc.params, tc.stakingSupply) + require.NoError(t, err) + require.True(t, tc.expProvisions.Equal(result)) + }) + } +} + +func TestAnnualProvisions(t *testing.T) { + tests := []AnnualProvisionsTestCase{ + { + name: "default params", + minter: DefaultInitialMinter(), + params: DefaultParams(), + totalSupply: math.NewInt(1000000), + expProvisions: sdk.NewDec(1), + expError: false, + }, + { + name: "zero total supply", + minter: DefaultInitialMinter(), + params: DefaultParams(), + totalSupply: math.ZeroInt(), + expProvisions: sdk.ZeroDec(), + expError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := tc.minter.NextAnnualProvisions(tc.params, tc.totalSupply) + if tc.expError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.True(t, tc.expProvisions.Equal(result)) + } + }) + } +} diff --git a/x/mint/types/msg.go b/x/mint/types/msg.go index 4e81a18be..cbe467859 100644 --- a/x/mint/types/msg.go +++ b/x/mint/types/msg.go @@ -1,7 +1,8 @@ package types import ( - errorsmod "cosmossdk.io/errors" + "fmt" + "github.com/cosmos/cosmos-sdk/codec/legacy" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -30,10 +31,26 @@ func (m MsgFundModuleAccount) GetSignBytes() []byte { // ValidateBasic does a sanity check on the provided data. func (m MsgFundModuleAccount) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(m.FromAddress) - if err != nil { - return errorsmod.Wrap(err, "from address must be valid address") + if _, err := sdk.AccAddressFromBech32(m.FromAddress); err != nil { + return fmt.Errorf("invalid from address: %w", err) + } + + if err := m.Amount.Validate(); err != nil { + return fmt.Errorf("invalid amount: %w", err) + } + + if !m.Amount.IsValid() { + return fmt.Errorf("invalid coin amount: %s", m.Amount) + } + + if m.Amount.IsZero() { + return fmt.Errorf("amount cannot be zero") + } + + if m.Amount.IsAnyNegative() { + return fmt.Errorf("amount cannot be negative: %s", m.Amount) } + return nil } @@ -68,14 +85,12 @@ func (m MsgAddAccountToFundModuleSet) GetSignBytes() []byte { // ValidateBasic does a sanity check on the provided data. func (m MsgAddAccountToFundModuleSet) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(m.Authority) - if err != nil { - return errorsmod.Wrap(err, "authority must be valid address") + if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil { + return fmt.Errorf("invalid authority address: %w", err) } - _, err = sdk.AccAddressFromBech32(m.AllowedAddress) - if err != nil { - return errorsmod.Wrap(err, "allowed address must be valid address") + if _, err := sdk.AccAddressFromBech32(m.AllowedAddress); err != nil { + return fmt.Errorf("invalid allowed address: %w", err) } return nil @@ -87,3 +102,38 @@ func NewMsgAddAccountToFundModuleSet(authority, allowedAddress string) *MsgAddAc AllowedAddress: allowedAddress, } } + +var _ sdk.Msg = &MsgUpdateParams{} + +// Route Implements Msg. +func (m MsgUpdateParams) Route() string { return sdk.MsgTypeURL(&m) } + +// Type Implements Msg. +func (m MsgUpdateParams) Type() string { return sdk.MsgTypeURL(&m) } + +// GetSigners returns the expected signers for a MsgMintAndAllocateExp . +func (m MsgUpdateParams) GetSigners() []sdk.AccAddress { + daoAccount, err := sdk.AccAddressFromBech32(m.Authority) + if err != nil { + panic(err) + } + return []sdk.AccAddress{daoAccount} +} + +// GetSignBytes Implements Msg. +func (m MsgUpdateParams) GetSignBytes() []byte { + return sdk.MustSortJSON(legacy.Cdc.MustMarshalJSON(&m)) +} + +// ValidateBasic implements the sdk.Msg interface. +func (m MsgUpdateParams) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil { + return fmt.Errorf("invalid authority address: %w", err) + } + + if err := m.Params.Validate(); err != nil { + return fmt.Errorf("invalid params: %w", err) + } + + return nil +} diff --git a/x/mint/types/msgs.go b/x/mint/types/msgs.go deleted file mode 100644 index a9cf7c3a6..000000000 --- a/x/mint/types/msgs.go +++ /dev/null @@ -1,33 +0,0 @@ -package types - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var _ sdk.Msg = &MsgUpdateParams{} - -// GetSignBytes implements the LegacyMsg interface. -func (m MsgUpdateParams) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) -} - -// GetSigners returns the expected signers for a MsgUpdateParams message. -func (m *MsgUpdateParams) GetSigners() []sdk.AccAddress { - addr, _ := sdk.AccAddressFromBech32(m.Authority) - return []sdk.AccAddress{addr} -} - -// ValidateBasic does a sanity check on the provided data. -func (m *MsgUpdateParams) ValidateBasic() error { - if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil { - return errorsmod.Wrapf(err, "invalid authority address") - } - - err := m.Params.Validate() - if err != nil { - return err - } - - return nil -} diff --git a/x/mint/types/params.go b/x/mint/types/params.go index c56ade10f..3b49356fe 100644 --- a/x/mint/types/params.go +++ b/x/mint/types/params.go @@ -77,12 +77,8 @@ func (p Params) Validate() error { if err := validateBlocksPerYear(p.BlocksPerYear); err != nil { return err } - - if p.MaxTokenPerYear.LT(p.MinTokenPerYear) { - return fmt.Errorf( - "MaxTokenPerYear (%s) must be greater than or equal to MinTokenPerYear (%s)", - p.MinTokenPerYear, p.MaxTokenPerYear, - ) + if err := validateTokenPerYear(p.MaxTokenPerYear, p.MinTokenPerYear); err != nil { + return err } return nil @@ -197,3 +193,22 @@ func validateBlocksPerYear(i interface{}) error { return nil } + +func validateTokenPerYear(maxToken, minToken math.Int) error { + if maxToken.IsNegative() { + return fmt.Errorf("max token per year cannot be negative: %s", maxToken) + } + if minToken.IsNegative() { + return fmt.Errorf("min token per year cannot be negative: %s", minToken) + } + if maxToken.LT(minToken) { + return fmt.Errorf("max token per year (%s) must be greater than or equal to min token per year (%s)", maxToken, minToken) + } + if maxToken.IsZero() { + return fmt.Errorf("max token per year cannot be zero") + } + if minToken.IsZero() { + return fmt.Errorf("min token per year cannot be zero") + } + return nil +} diff --git a/x/ratelimit/keeper/epoch.go b/x/ratelimit/keeper/epoch.go index 0039c067a..4ec026341 100644 --- a/x/ratelimit/keeper/epoch.go +++ b/x/ratelimit/keeper/epoch.go @@ -118,6 +118,10 @@ func (k Keeper) NumBlocksSinceEpochStart(ctx sdk.Context, identifier string) (in func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochInfo types.EpochInfo) { if epochInfo.Identifier == types.DayEpoch { + // Ensure CurrentEpoch is non-negative before converting to uint64 + if epochInfo.CurrentEpoch < 0 { + panic("negative current epoch not allowed") + } epochHour := uint64(epochInfo.CurrentEpoch) for _, rateLimit := range k.GetAllRateLimits(ctx) { diff --git a/x/transfermiddleware/relay_test.go b/x/transfermiddleware/relay_test.go index 6bf804ad9..7d5903474 100644 --- a/x/transfermiddleware/relay_test.go +++ b/x/transfermiddleware/relay_test.go @@ -2,6 +2,7 @@ package transfermiddleware_test import ( "fmt" + "math" "testing" "time" @@ -231,8 +232,16 @@ func (suite *TransferMiddlewareTestSuite) TestTimeOutPacket() { gotBalance := suite.chainB.AllBalances(suite.chainB.SenderAccount.GetAddress()) suite.Require().Equal(expBalance, gotBalance) - // send token back - timeout := uint64(suite.chainB.LastHeader.Header.Time.Add(time.Nanosecond).UnixNano()) // will timeout + // Get the timeout timestamp + timeoutTimestamp := suite.chainB.LastHeader.Header.Time.Add(time.Nanosecond) + if timeoutTimestamp.UnixNano() < 0 { + panic("timeout timestamp cannot be negative") + } + if timeoutTimestamp.UnixNano() > math.MaxInt64 { + panic("timeout timestamp exceeds maximum int64 value") + } + timeout := uint64(timeoutTimestamp.UnixNano()) // will timeout + msg = ibctransfertypes.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, nativeToken, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 20), timeout, "") _, err = suite.chainB.SendMsgs(msg) suite.Require().NoError(err) diff --git a/x/transfermiddleware/types/parachain_token_info.pb.go b/x/transfermiddleware/types/parachain_token_info.pb.go index 854ea11c0..ea33c7e44 100644 --- a/x/transfermiddleware/types/parachain_token_info.pb.go +++ b/x/transfermiddleware/types/parachain_token_info.pb.go @@ -28,7 +28,7 @@ var _ = time.Kitchen const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // ParachainIBCTokenInfo represents information about transferable IBC tokens -// from Parachain(Substrate based network). +// from Parachain. type ParachainIBCTokenInfo struct { // ibc_denom is the denomination of the ibced token transferred from the // dotsama chain. diff --git a/x/tx-boundary/ante/antetest/ante_test_setup.go b/x/tx-boundary/ante/antetest/ante_test_setup.go index f66a64acf..740df8898 100644 --- a/x/tx-boundary/ante/antetest/ante_test_setup.go +++ b/x/tx-boundary/ante/antetest/ante_test_setup.go @@ -40,7 +40,7 @@ type AnteTestSuite struct { func (suite *AnteTestSuite) SetupTest() { suite.app, suite.delegator, suite.validators = helpers.SetupComposableAppWithValSetWithGenAccout(suite.T()) - suite.ctx = suite.app.BaseApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "centauri-1", Time: time.Now().UTC()}) + suite.ctx = suite.app.NewContext(false, tmproto.Header{Height: 1, ChainID: "centauri-1", Time: time.Now().UTC()}) app.FundAccount(suite.app.BankKeeper, suite.ctx, suite.delegator, BaseBalance) encodingConfig := app.MakeEncodingConfig() diff --git a/x/tx-boundary/keeper/keeper_test.go b/x/tx-boundary/keeper/keeper_test.go index 660ee6303..cc6e51543 100644 --- a/x/tx-boundary/keeper/keeper_test.go +++ b/x/tx-boundary/keeper/keeper_test.go @@ -23,7 +23,7 @@ type KeeperTestSuite struct { 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()}) + suite.ctx = suite.app.NewContext(false, tmproto.Header{Height: 1, ChainID: "centauri-1", Time: time.Now().UTC()}) } func TestKeeperTestSuite(t *testing.T) {