From 099f728339411327c8215f52462b74cedea4b14d Mon Sep 17 00:00:00 2001 From: John Letey Date: Tue, 8 Oct 2024 21:08:59 +0200 Subject: [PATCH] refactor: utilize collections for state management (#23) --- genesis.go | 36 ++- go.mod | 4 +- keeper/keeper.go | 40 ++- keeper/keeper_test.go | 71 ++++-- keeper/msg_server.go | 68 +++-- keeper/msg_server_blocklist.go | 20 +- keeper/msg_server_blocklist_test.go | 90 ++++++- keeper/msg_server_test.go | 346 +++++++++++++++++++++++--- keeper/query_server_blocklist_test.go | 10 +- keeper/query_server_test.go | 22 +- keeper/state.go | 175 +++++-------- keeper/state_blocklist.go | 55 ++-- keeper/state_blocklist_test.go | 4 +- types/blocklist/keys.go | 4 - types/keys.go | 16 -- utils/mocks/store.go | 99 ++++++++ utils/store.go | 12 + 17 files changed, 796 insertions(+), 276 deletions(-) create mode 100644 utils/mocks/store.go create mode 100644 utils/store.go diff --git a/genesis.go b/genesis.go index b57d59c..6c51173 100644 --- a/genesis.go +++ b/genesis.go @@ -9,24 +9,42 @@ import ( ) func InitGenesis(ctx sdk.Context, k *keeper.Keeper, addressCodec address.Codec, genesis types.GenesisState) { - k.SetBlocklistOwner(ctx, genesis.BlocklistState.Owner) - k.SetBlocklistPendingOwner(ctx, genesis.BlocklistState.PendingOwner) + if err := k.SetBlocklistOwner(ctx, genesis.BlocklistState.Owner); err != nil { + panic(err) + } + if err := k.SetBlocklistPendingOwner(ctx, genesis.BlocklistState.PendingOwner); err != nil { + panic(err) + } for _, account := range genesis.BlocklistState.BlockedAddresses { address, _ := addressCodec.StringToBytes(account) - k.SetBlockedAddress(ctx, address) + if err := k.SetBlockedAddress(ctx, address); err != nil { + panic(err) + } } - k.SetPaused(ctx, genesis.Paused) - k.SetOwner(ctx, genesis.Owner) - k.SetPendingOwner(ctx, genesis.PendingOwner) + if err := k.SetPaused(ctx, genesis.Paused); err != nil { + panic(err) + } + if err := k.SetOwner(ctx, genesis.Owner); err != nil { + panic(err) + } + if err := k.SetPendingOwner(ctx, genesis.PendingOwner); err != nil { + panic(err) + } for _, burner := range genesis.Burners { - k.SetBurner(ctx, burner.Address, burner.Allowance) + if err := k.SetBurner(ctx, burner.Address, burner.Allowance); err != nil { + panic(err) + } } for _, minter := range genesis.Minters { - k.SetMinter(ctx, minter.Address, minter.Allowance) + if err := k.SetMinter(ctx, minter.Address, minter.Allowance); err != nil { + panic(err) + } } for _, pauser := range genesis.Pausers { - k.SetPauser(ctx, pauser) + if err := k.SetPauser(ctx, pauser); err != nil { + panic(err) + } } } diff --git a/go.mod b/go.mod index 2d02d6d..f161c89 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,14 @@ go 1.22.7 require ( cosmossdk.io/api v0.7.5 + cosmossdk.io/collections v0.4.0 cosmossdk.io/core v0.11.1 cosmossdk.io/depinject v1.0.0 cosmossdk.io/errors v1.0.1 cosmossdk.io/math v1.3.0 cosmossdk.io/store v1.1.1 github.com/cometbft/cometbft v0.38.12 + github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.50.10 github.com/cosmos/gogoproto v1.7.0 @@ -27,7 +29,6 @@ require ( require ( 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 4d63.com/gochecknoglobals v0.2.1 // indirect - cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/log v1.4.1 // indirect cosmossdk.io/x/tx v0.13.5 // indirect cosmossdk.io/x/upgrade v0.1.4 // indirect @@ -79,7 +80,6 @@ require ( github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v0.11.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-db v1.0.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.2.0 // indirect diff --git a/keeper/keeper.go b/keeper/keeper.go index b91c333..a5b561c 100644 --- a/keeper/keeper.go +++ b/keeper/keeper.go @@ -4,20 +4,36 @@ import ( "context" "fmt" + "cosmossdk.io/collections" "cosmossdk.io/core/address" "cosmossdk.io/core/event" "cosmossdk.io/core/store" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" "github.com/ondoprotocol/usdy-noble/v2/types" + "github.com/ondoprotocol/usdy-noble/v2/types/blocklist" ) type Keeper struct { Denom string + schema collections.Schema storeService store.KVStoreService eventService event.Service + Paused collections.Item[bool] + Owner collections.Item[string] + PendingOwner collections.Item[string] + Burners collections.Map[string, math.Int] + Minters collections.Map[string, math.Int] + Pausers collections.Map[string, []byte] + BlockedChannels collections.Map[string, []byte] + + BlocklistOwner collections.Item[string] + BlocklistPendingOwner collections.Item[string] + BlockedAddresses collections.Map[[]byte, []byte] + addressCodec address.Codec bankKeeper types.BankKeeper } @@ -29,15 +45,37 @@ func NewKeeper( addressCodec address.Codec, bankKeeper types.BankKeeper, ) *Keeper { - return &Keeper{ + builder := collections.NewSchemaBuilder(storeService) + + keeper := &Keeper{ Denom: denom, storeService: storeService, eventService: eventService, + Paused: collections.NewItem(builder, types.PausedKey, "paused", collections.BoolValue), + Owner: collections.NewItem(builder, types.OwnerKey, "owner", collections.StringValue), + PendingOwner: collections.NewItem(builder, types.PendingOwnerKey, "pending_owner", collections.StringValue), + Burners: collections.NewMap(builder, types.BurnerPrefix, "burners", collections.StringKey, sdk.IntValue), + Minters: collections.NewMap(builder, types.MinterPrefix, "minters", collections.StringKey, sdk.IntValue), + Pausers: collections.NewMap(builder, types.PauserPrefix, "pausers", collections.StringKey, collections.BytesValue), + BlockedChannels: collections.NewMap(builder, types.BlockedChannelPrefix, "blocked_channels", collections.StringKey, collections.BytesValue), + + BlocklistOwner: collections.NewItem(builder, blocklist.OwnerKey, "blocklist_owner", collections.StringValue), + BlocklistPendingOwner: collections.NewItem(builder, blocklist.PendingOwnerKey, "blocklist_pending_owner", collections.StringValue), + BlockedAddresses: collections.NewMap(builder, blocklist.BlockedAddressPrefix, "blocked_address", collections.BytesKey, collections.BytesValue), + addressCodec: addressCodec, bankKeeper: bankKeeper, } + + schema, err := builder.Build() + if err != nil { + panic(err) + } + + keeper.schema = schema + return keeper } // SetBankKeeper overwrites the bank keeper used in this module. diff --git a/keeper/keeper_test.go b/keeper/keeper_test.go index 81daa7b..801e250 100644 --- a/keeper/keeper_test.go +++ b/keeper/keeper_test.go @@ -5,8 +5,11 @@ import ( "testing" "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + "github.com/ondoprotocol/usdy-noble/v2/keeper" "github.com/ondoprotocol/usdy-noble/v2/types" "github.com/ondoprotocol/usdy-noble/v2/utils" "github.com/ondoprotocol/usdy-noble/v2/utils/mocks" @@ -15,8 +18,8 @@ import ( func TestSendRestrictionBurn(t *testing.T) { user := utils.TestAccount() - keeper, ctx := mocks.AuraKeeper() - coins := sdk.NewCoins(sdk.NewCoin(keeper.Denom, ONE)) + k, ctx := mocks.AuraKeeper() + coins := sdk.NewCoins(sdk.NewCoin(k.Denom, ONE)) testCases := []struct { name string @@ -53,16 +56,16 @@ func TestSendRestrictionBurn(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { // ARRANGE: Set paused state. - keeper.SetPaused(ctx, testCase.paused) + require.NoError(t, k.SetPaused(ctx, testCase.paused)) // ARRANGE: Set blocked state. if testCase.blocked { - keeper.SetBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, user.Bytes)) } else { - keeper.DeleteBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.DeleteBlockedAddress(ctx, user.Bytes)) } // ACT: Attempt to burn. - _, err := keeper.SendRestrictionFn(ctx, user.Bytes, types.ModuleAddress, coins) + _, err := k.SendRestrictionFn(ctx, user.Bytes, types.ModuleAddress, coins) // ASSERT: Send restriction correctly handled test case. if testCase.err != nil { @@ -76,8 +79,8 @@ func TestSendRestrictionBurn(t *testing.T) { func TestSendRestrictionMint(t *testing.T) { user := utils.TestAccount() - keeper, ctx := mocks.AuraKeeper() - coins := sdk.NewCoins(sdk.NewCoin(keeper.Denom, ONE)) + k, ctx := mocks.AuraKeeper() + coins := sdk.NewCoins(sdk.NewCoin(k.Denom, ONE)) testCases := []struct { name string @@ -114,16 +117,16 @@ func TestSendRestrictionMint(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { // ARRANGE: Set paused state. - keeper.SetPaused(ctx, testCase.paused) + require.NoError(t, k.SetPaused(ctx, testCase.paused)) // ARRANGE: Set blocked state. if testCase.blocked { - keeper.SetBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, user.Bytes)) } else { - keeper.DeleteBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.DeleteBlockedAddress(ctx, user.Bytes)) } // ACT: Attempt to mint. - _, err := keeper.SendRestrictionFn(ctx, types.ModuleAddress, user.Bytes, coins) + _, err := k.SendRestrictionFn(ctx, types.ModuleAddress, user.Bytes, coins) // ASSERT: Send restriction correctly handled test case. if testCase.err != nil { @@ -137,8 +140,8 @@ func TestSendRestrictionMint(t *testing.T) { func TestSendRestrictionTransfer(t *testing.T) { alice, bob := utils.TestAccount(), utils.TestAccount() - keeper, ctx := mocks.AuraKeeper() - coins := sdk.NewCoins(sdk.NewCoin(keeper.Denom, ONE)) + k, ctx := mocks.AuraKeeper() + coins := sdk.NewCoins(sdk.NewCoin(k.Denom, ONE)) testCases := []struct { name string @@ -225,22 +228,22 @@ func TestSendRestrictionTransfer(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { // ARRANGE: Set paused state. - keeper.SetPaused(ctx, testCase.paused) + require.NoError(t, k.SetPaused(ctx, testCase.paused)) // ARRANGE: Set sender blocked state. if testCase.senderBlocked { - keeper.SetBlockedAddress(ctx, alice.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, alice.Bytes)) } else { - keeper.DeleteBlockedAddress(ctx, alice.Bytes) + require.NoError(t, k.DeleteBlockedAddress(ctx, alice.Bytes)) } // ARRANGE: Set recipient blocked state. if testCase.recipientBlocked { - keeper.SetBlockedAddress(ctx, bob.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, bob.Bytes)) } else { - keeper.DeleteBlockedAddress(ctx, bob.Bytes) + require.NoError(t, k.DeleteBlockedAddress(ctx, bob.Bytes)) } // ACT: Attempt to transfer. - _, err := keeper.SendRestrictionFn(ctx, alice.Bytes, bob.Bytes, testCase.coins) + _, err := k.SendRestrictionFn(ctx, alice.Bytes, bob.Bytes, testCase.coins) // ASSERT: Send restriction correctly handled test case. if testCase.err != nil { @@ -254,17 +257,37 @@ func TestSendRestrictionTransfer(t *testing.T) { func TestSendRestrictionIBCTransfer(t *testing.T) { user := utils.TestAccount() - keeper, ctx := mocks.AuraKeeper() - coins := sdk.NewCoins(sdk.NewCoin(keeper.Denom, ONE)) + k, ctx := mocks.AuraKeeper() + coins := sdk.NewCoins(sdk.NewCoin(k.Denom, ONE)) // ARRANGE: Set a blocked channel in state. - keeper.SetBlockedChannel(ctx, "channel-0") + require.NoError(t, k.SetBlockedChannel(ctx, "channel-0")) escrow := transfertypes.GetEscrowAddress(transfertypes.PortID, "channel-0") // ACT: Attempt to transfer from user to escrow account. // This is to mimic the underlying transfer that occurs when using IBC. - _, err := keeper.SendRestrictionFn(ctx, user.Bytes, escrow, coins) + _, err := k.SendRestrictionFn(ctx, user.Bytes, escrow, coins) // ASSERT: The action should've failed due to blocked channel. require.ErrorContains(t, err, "transfers are blocked") } + +func TestNewKeeper(t *testing.T) { + // ARRANGE: Set the PausedKey to an already existing key + types.PausedKey = types.OwnerKey + + // ACT: Attempt to create a new Keeper with overlapping prefixes + require.Panics(t, func() { + keeper.NewKeeper( + "ausdy", + mocks.FailingStore(mocks.Set, nil), + runtime.ProvideEventService(), + address.NewBech32Codec("noble"), + mocks.BankKeeper{}, + ) + }) + // ASSERT: The function should've panicked. + + // ARRANGE: Restore the original PausedKey + types.PausedKey = []byte("paused") +} diff --git a/keeper/msg_server.go b/keeper/msg_server.go index 64b3e5a..538f949 100644 --- a/keeper/msg_server.go +++ b/keeper/msg_server.go @@ -48,7 +48,9 @@ func (k msgServer) Burn(ctx context.Context, msg *types.MsgBurn) (*types.MsgBurn return nil, sdkerrors.Wrapf(err, "unable to burn from module") } - k.SetBurner(ctx, msg.Signer, allowance.Sub(msg.Amount)) + if err := k.SetBurner(ctx, msg.Signer, allowance.Sub(msg.Amount)); err != nil { + return nil, err + } // NOTE: The bank module emits an event for us. return &types.MsgBurnResponse{}, nil @@ -82,7 +84,9 @@ func (k msgServer) Mint(ctx context.Context, msg *types.MsgMint) (*types.MsgMint return nil, sdkerrors.Wrapf(err, "unable to transfer from module to user") } - k.SetMinter(ctx, msg.Signer, allowance.Sub(msg.Amount)) + if err := k.SetMinter(ctx, msg.Signer, allowance.Sub(msg.Amount)); err != nil { + return nil, err + } // NOTE: The bank module emits an event for us. return &types.MsgMintResponse{}, nil @@ -96,7 +100,9 @@ func (k msgServer) Pause(ctx context.Context, msg *types.MsgPause) (*types.MsgPa return nil, errors.New("module is already paused") } - k.SetPaused(ctx, true) + if err := k.SetPaused(ctx, true); err != nil { + return nil, err + } return &types.MsgPauseResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.Paused{ Account: msg.Signer, @@ -116,7 +122,9 @@ func (k msgServer) Unpause(ctx context.Context, msg *types.MsgUnpause) (*types.M return nil, errors.New("module is already unpaused") } - k.SetPaused(ctx, false) + if err := k.SetPaused(ctx, false); err != nil { + return nil, err + } return &types.MsgUnpauseResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.Unpaused{ Account: msg.Signer, @@ -136,7 +144,9 @@ func (k msgServer) TransferOwnership(ctx context.Context, msg *types.MsgTransfer return nil, types.ErrSameOwner } - k.SetPendingOwner(ctx, msg.NewOwner) + if err := k.SetPendingOwner(ctx, msg.NewOwner); err != nil { + return nil, err + } return &types.MsgTransferOwnershipResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.OwnershipTransferStarted{ PreviousOwner: owner, @@ -155,8 +165,12 @@ func (k msgServer) AcceptOwnership(ctx context.Context, msg *types.MsgAcceptOwne owner := k.GetOwner(ctx) - k.SetOwner(ctx, msg.Signer) - k.DeletePendingOwner(ctx) + if err := k.SetOwner(ctx, msg.Signer); err != nil { + return nil, err + } + if err := k.DeletePendingOwner(ctx); err != nil { + return nil, err + } return &types.MsgAcceptOwnershipResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.OwnershipTransferred{ PreviousOwner: owner, @@ -181,7 +195,9 @@ func (k msgServer) AddBurner(ctx context.Context, msg *types.MsgAddBurner) (*typ return nil, errors.New("allowance cannot be negative") } - k.SetBurner(ctx, msg.Burner, msg.Allowance) + if err := k.SetBurner(ctx, msg.Burner, msg.Allowance); err != nil { + return nil, err + } return &types.MsgAddBurnerResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.BurnerAdded{ Address: msg.Burner, @@ -202,7 +218,9 @@ func (k msgServer) RemoveBurner(ctx context.Context, msg *types.MsgRemoveBurner) return nil, fmt.Errorf("%s is not a burner", msg.Burner) } - k.DeleteBurner(ctx, msg.Burner) + if err := k.DeleteBurner(ctx, msg.Burner); err != nil { + return nil, err + } return &types.MsgRemoveBurnerResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.BurnerRemoved{ Address: msg.Burner, @@ -227,7 +245,9 @@ func (k msgServer) SetBurnerAllowance(ctx context.Context, msg *types.MsgSetBurn } allowance := k.GetBurner(ctx, msg.Burner) - k.SetBurner(ctx, msg.Burner, msg.Allowance) + if err := k.SetBurner(ctx, msg.Burner, msg.Allowance); err != nil { + return nil, err + } return &types.MsgSetBurnerAllowanceResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.BurnerUpdated{ Address: msg.Burner, @@ -253,7 +273,9 @@ func (k msgServer) AddMinter(ctx context.Context, msg *types.MsgAddMinter) (*typ return nil, errors.New("allowance cannot be negative") } - k.SetMinter(ctx, msg.Minter, msg.Allowance) + if err := k.SetMinter(ctx, msg.Minter, msg.Allowance); err != nil { + return nil, err + } return &types.MsgAddMinterResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.MinterAdded{ Address: msg.Minter, @@ -274,7 +296,9 @@ func (k msgServer) RemoveMinter(ctx context.Context, msg *types.MsgRemoveMinter) return nil, fmt.Errorf("%s is not a minter", msg.Minter) } - k.DeleteMinter(ctx, msg.Minter) + if err := k.DeleteMinter(ctx, msg.Minter); err != nil { + return nil, err + } return &types.MsgRemoveMinterResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.MinterRemoved{ Address: msg.Minter, @@ -299,7 +323,9 @@ func (k msgServer) SetMinterAllowance(ctx context.Context, msg *types.MsgSetMint } allowance := k.GetMinter(ctx, msg.Minter) - k.SetMinter(ctx, msg.Minter, msg.Allowance) + if err := k.SetMinter(ctx, msg.Minter, msg.Allowance); err != nil { + return nil, err + } return &types.MsgSetMinterAllowanceResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.MinterUpdated{ Address: msg.Minter, @@ -321,7 +347,9 @@ func (k msgServer) AddPauser(ctx context.Context, msg *types.MsgAddPauser) (*typ return nil, fmt.Errorf("%s is already a pauser", msg.Pauser) } - k.SetPauser(ctx, msg.Pauser) + if err := k.SetPauser(ctx, msg.Pauser); err != nil { + return nil, err + } return &types.MsgAddPauserResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.PauserAdded{ Address: msg.Pauser, @@ -341,7 +369,9 @@ func (k msgServer) RemovePauser(ctx context.Context, msg *types.MsgRemovePauser) return nil, fmt.Errorf("%s is not a pauser", msg.Pauser) } - k.DeletePauser(ctx, msg.Pauser) + if err := k.DeletePauser(ctx, msg.Pauser); err != nil { + return nil, err + } return &types.MsgRemovePauserResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.PauserRemoved{ Address: msg.Pauser, @@ -361,7 +391,9 @@ func (k msgServer) AddBlockedChannel(ctx context.Context, msg *types.MsgAddBlock return nil, fmt.Errorf("%s is already blocked", msg.Channel) } - k.SetBlockedChannel(ctx, msg.Channel) + if err := k.SetBlockedChannel(ctx, msg.Channel); err != nil { + return nil, err + } return &types.MsgAddBlockedChannelResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.BlockedChannelAdded{ Channel: msg.Channel, @@ -381,7 +413,9 @@ func (k msgServer) RemoveBlockedChannel(ctx context.Context, msg *types.MsgRemov return nil, fmt.Errorf("%s is not blocked", msg.Channel) } - k.DeleteBlockedChannel(ctx, msg.Channel) + if err := k.DeleteBlockedChannel(ctx, msg.Channel); err != nil { + return nil, err + } return &types.MsgRemoveBlockedChannelResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &types.BlockedChannelRemoved{ Channel: msg.Channel, diff --git a/keeper/msg_server_blocklist.go b/keeper/msg_server_blocklist.go index 3a9e1ed..88822cf 100644 --- a/keeper/msg_server_blocklist.go +++ b/keeper/msg_server_blocklist.go @@ -30,7 +30,9 @@ func (k blocklistMsgServer) TransferOwnership(ctx context.Context, msg *blocklis return nil, blocklist.ErrSameOwner } - k.SetBlocklistPendingOwner(ctx, msg.NewOwner) + if err := k.SetBlocklistPendingOwner(ctx, msg.NewOwner); err != nil { + return nil, err + } return &blocklist.MsgTransferOwnershipResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &blocklist.OwnershipTransferStarted{ PreviousOwner: owner, @@ -48,8 +50,12 @@ func (k blocklistMsgServer) AcceptOwnership(ctx context.Context, msg *blocklist. } owner := k.GetBlocklistOwner(ctx) - k.SetBlocklistOwner(ctx, msg.Signer) - k.DeleteBlocklistPendingOwner(ctx) + if err := k.SetBlocklistOwner(ctx, msg.Signer); err != nil { + return nil, err + } + if err := k.DeleteBlocklistPendingOwner(ctx); err != nil { + return nil, err + } return &blocklist.MsgAcceptOwnershipResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &blocklist.OwnershipTransferred{ PreviousOwner: owner, @@ -72,7 +78,9 @@ func (k blocklistMsgServer) AddToBlocklist(ctx context.Context, msg *blocklist.M return nil, errors.Wrapf(err, "unable to decode account address %s", account) } - k.SetBlockedAddress(ctx, address) + if err := k.SetBlockedAddress(ctx, address); err != nil { + return nil, err + } } return &blocklist.MsgAddToBlocklistResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &blocklist.BlockedAddressesAdded{ @@ -95,7 +103,9 @@ func (k blocklistMsgServer) RemoveFromBlocklist(ctx context.Context, msg *blockl return nil, errors.Wrapf(err, "unable to decode account address %s", account) } - k.DeleteBlockedAddress(ctx, address) + if err := k.DeleteBlockedAddress(ctx, address); err != nil { + return nil, err + } } return &blocklist.MsgRemoveFromBlocklistResponse{}, k.eventService.EventManager(ctx).Emit(ctx, &blocklist.BlockedAddressesRemoved{ diff --git a/keeper/msg_server_blocklist_test.go b/keeper/msg_server_blocklist_test.go index f0b469e..a75aeb6 100644 --- a/keeper/msg_server_blocklist_test.go +++ b/keeper/msg_server_blocklist_test.go @@ -3,7 +3,9 @@ package keeper_test import ( "testing" + "cosmossdk.io/collections" "github.com/ondoprotocol/usdy-noble/v2/keeper" + "github.com/ondoprotocol/usdy-noble/v2/types" "github.com/ondoprotocol/usdy-noble/v2/types/blocklist" "github.com/ondoprotocol/usdy-noble/v2/utils" "github.com/ondoprotocol/usdy-noble/v2/utils/mocks" @@ -21,7 +23,7 @@ func TestBlocklistTransferOwnership(t *testing.T) { // ARRANGE: Set blocklist owner in state. owner := utils.TestAccount() - k.SetBlocklistOwner(ctx, owner.Address) + require.NoError(t, k.SetBlocklistOwner(ctx, owner.Address)) // ACT: Attempt to transfer ownership with invalid signer. _, err = server.TransferOwnership(ctx, &blocklist.MsgTransferOwnership{ @@ -41,6 +43,22 @@ func TestBlocklistTransferOwnership(t *testing.T) { // ARRANGE: Generate a pending owner account. pendingOwner := utils.TestAccount() + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.BlocklistPendingOwner + k.BlocklistPendingOwner = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + blocklist.PendingOwnerKey, "blocklist_pending_owner", collections.StringValue, + ) + + // ACT: Attempt to transfer ownership with failing BlocklistPendingOwner collection store. + _, err = server.TransferOwnership(ctx, &blocklist.MsgTransferOwnership{ + Signer: owner.Address, + NewOwner: pendingOwner.Address, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.BlocklistPendingOwner = tmp + // ACT: Attempt to transfer ownership. _, err = server.TransferOwnership(ctx, &blocklist.MsgTransferOwnership{ Signer: owner.Address, @@ -62,7 +80,7 @@ func TestBlocklistAcceptOwnership(t *testing.T) { // ARRANGE: Set blocklist pending owner in state. pendingOwner := utils.TestAccount() - k.SetBlocklistPendingOwner(ctx, pendingOwner.Address) + require.NoError(t, k.SetBlocklistPendingOwner(ctx, pendingOwner.Address)) // ACT: Attempt to accept ownership with invalid signer. _, err = server.AcceptOwnership(ctx, &blocklist.MsgAcceptOwnership{ @@ -71,6 +89,36 @@ func TestBlocklistAcceptOwnership(t *testing.T) { // ASSERT: The action should've failed due to invalid signer. require.ErrorContains(t, err, blocklist.ErrInvalidPendingOwner.Error()) + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.BlocklistOwner + k.BlocklistOwner = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + blocklist.OwnerKey, "blocklist_owner", collections.StringValue, + ) + + // ACT: Attempt to accept ownership with failing BlocklistOwner collection store. + _, err = server.AcceptOwnership(ctx, &blocklist.MsgAcceptOwnership{ + Signer: pendingOwner.Address, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.BlocklistOwner = tmp + + // ARRANGE: Set up a failing collection store for the attribute delete. + tmp = k.BlocklistPendingOwner + k.BlocklistPendingOwner = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Delete, utils.GetKVStore(ctx, types.ModuleName))), + blocklist.PendingOwnerKey, "blocklist_pending_owner", collections.StringValue, + ) + + // ACT: Attempt to accept ownership with failing BlocklistPendingOwner collection store. + _, err = server.AcceptOwnership(ctx, &blocklist.MsgAcceptOwnership{ + Signer: pendingOwner.Address, + }) + // ASSERT: The action should've failed due to collection store delete error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.BlocklistPendingOwner = tmp + // ACT: Attempt to accept ownership. _, err = server.AcceptOwnership(ctx, &blocklist.MsgAcceptOwnership{ Signer: pendingOwner.Address, @@ -92,7 +140,7 @@ func TestAddToBlocklist(t *testing.T) { // ARRANGE: Set blocklist owner in state. owner := utils.TestAccount() - k.SetBlocklistOwner(ctx, owner.Address) + require.NoError(t, k.SetBlocklistOwner(ctx, owner.Address)) // ACT: Attempt to add to blocklist with invalid signer. _, err = server.AddToBlocklist(ctx, &blocklist.MsgAddToBlocklist{ @@ -112,6 +160,22 @@ func TestAddToBlocklist(t *testing.T) { // ARRANGE: Generate a user account. user := utils.TestAccount() + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.BlockedAddresses + k.BlockedAddresses = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + blocklist.BlockedAddressPrefix, "blocked_addresses", collections.BytesKey, collections.BytesValue, + ) + + // ACT: Attempt to add to blocklist with failing BlockedAddresses collection store. + _, err = server.AddToBlocklist(ctx, &blocklist.MsgAddToBlocklist{ + Signer: owner.Address, + Accounts: []string{user.Address}, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.BlockedAddresses = tmp + // ACT: Attempt to add to blocklist. _, err = server.AddToBlocklist(ctx, &blocklist.MsgAddToBlocklist{ Signer: owner.Address, @@ -133,7 +197,7 @@ func TestRemoveFromBlocklist(t *testing.T) { // ARRANGE: Set blocklist owner in state. owner := utils.TestAccount() - k.SetBlocklistOwner(ctx, owner.Address) + require.NoError(t, k.SetBlocklistOwner(ctx, owner.Address)) // ACT: Attempt to remove from blocklist with invalid signer. _, err = server.RemoveFromBlocklist(ctx, &blocklist.MsgRemoveFromBlocklist{ @@ -163,9 +227,25 @@ func TestRemoveFromBlocklist(t *testing.T) { require.False(t, k.HasBlockedAddress(ctx, user.Bytes)) // ARRANGE: Set user as blocked in state. - k.SetBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, user.Bytes)) require.True(t, k.HasBlockedAddress(ctx, user.Bytes)) + // ARRANGE: Set up a failing collection store for the attribute delete. + tmp := k.BlockedAddresses + k.BlockedAddresses = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Delete, utils.GetKVStore(ctx, types.ModuleName))), + blocklist.BlockedAddressPrefix, "blocked_addresses", collections.BytesKey, collections.BytesValue, + ) + + // ACT: Attempt to remove from blocklist with failing BlockedAddresses collection store. + _, err = server.RemoveFromBlocklist(ctx, &blocklist.MsgRemoveFromBlocklist{ + Signer: owner.Address, + Accounts: []string{user.Address}, + }) + // ASSERT: The action should've failed due to collection store delete error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.BlockedAddresses = tmp + // ACT: Attempt to remove from blocklist. _, err = server.RemoveFromBlocklist(ctx, &blocklist.MsgRemoveFromBlocklist{ Signer: owner.Address, diff --git a/keeper/msg_server_test.go b/keeper/msg_server_test.go index 004a289..1783c97 100644 --- a/keeper/msg_server_test.go +++ b/keeper/msg_server_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "testing" + "cosmossdk.io/collections" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ondoprotocol/usdy-noble/v2/keeper" @@ -24,7 +25,7 @@ func TestBurn(t *testing.T) { // ARRANGE: Set burner in state, with enough allowance for a single burn. burner := utils.TestAccount() - k.SetBurner(ctx, burner.Address, ONE) + require.NoError(t, k.SetBurner(ctx, burner.Address, ONE)) // ACT: Attempt to burn with invalid signer. _, err := server.Burn(ctx, &types.MsgBurn{ @@ -66,6 +67,26 @@ func TestBurn(t *testing.T) { // ARRANGE: Give user 1 $USDY. bank.Balances[user.Address] = sdk.NewCoins(sdk.NewCoin(k.Denom, ONE)) + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Burners + k.Burners = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.BurnerPrefix, "burners", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to burn with failing Burners collection store. + _, err = server.Burn(ctx, &types.MsgBurn{ + Signer: burner.Address, + From: user.Address, + Amount: ONE, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Burners = tmp + + // ARRANGE: Give user 1 $USDY. + bank.Balances[user.Address] = sdk.NewCoins(sdk.NewCoin(k.Denom, ONE)) + // ACT: Attempt to burn. _, err = server.Burn(ctx, &types.MsgBurn{ Signer: burner.Address, @@ -98,7 +119,7 @@ func TestMint(t *testing.T) { // ARRANGE: Set minter in state, with enough allowance for a single mint. minter := utils.TestAccount() - k.SetMinter(ctx, minter.Address, ONE) + require.NoError(t, k.SetMinter(ctx, minter.Address, ONE)) // ACT: Attempt to mint with invalid signer. _, err := server.Mint(ctx, &types.MsgMint{ @@ -118,7 +139,7 @@ func TestMint(t *testing.T) { // ARRANGE: Generate a user account and add to blocklist. user := utils.TestAccount() - k.SetBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, user.Bytes)) // ACT: Attempt to mint to blocked address. _, err = server.Mint(ctx, &types.MsgMint{ @@ -130,7 +151,7 @@ func TestMint(t *testing.T) { require.ErrorContains(t, err, "blocked from receiving") // ARRANGE: Unblock user account. - k.DeleteBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.DeleteBlockedAddress(ctx, user.Bytes)) // ACT: Attempt to mint invalid amount. _, err = server.Mint(ctx, &types.MsgMint{ @@ -141,6 +162,23 @@ func TestMint(t *testing.T) { // ASSERT: The action should've failed due to invalid amount. require.ErrorContains(t, err, "amount must be positive") + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Minters + k.Minters = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.MinterPrefix, "minters", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to mint with failing Minters collection store. + _, err = server.Mint(ctx, &types.MsgMint{ + Signer: minter.Address, + To: user.Address, + Amount: ONE, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Minters = tmp + // ACT: Attempt to mint. _, err = server.Mint(ctx, &types.MsgMint{ Signer: minter.Address, @@ -149,7 +187,7 @@ func TestMint(t *testing.T) { }) // ASSERT: The action should've succeeded. require.NoError(t, err) - require.Equal(t, ONE, bank.Balances[user.Address].AmountOf(k.Denom)) + require.Equal(t, ONE.MulRaw(2), bank.Balances[user.Address].AmountOf(k.Denom)) require.True(t, bank.Balances[types.ModuleName].IsZero()) require.True(t, k.GetMinter(ctx, minter.Address).IsZero()) @@ -169,7 +207,7 @@ func TestPause(t *testing.T) { // ARRANGE: Set pauser in state. pauser := utils.TestAccount() - k.SetPauser(ctx, pauser.Address) + require.NoError(t, k.SetPauser(ctx, pauser.Address)) // ACT: Attempt to pause with invalid signer. _, err := server.Pause(ctx, &types.MsgPause{ @@ -179,6 +217,21 @@ func TestPause(t *testing.T) { require.ErrorContains(t, err, types.ErrInvalidPauser.Error()) require.False(t, k.GetPaused(ctx)) + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Paused + k.Paused = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.PausedKey, "paused", collections.BoolValue, + ) + + // ACT: Attempt to pause with failing Paused collection store. + _, err = server.Pause(ctx, &types.MsgPause{ + Signer: pauser.Address, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Paused = tmp + // ACT: Attempt to pause. _, err = server.Pause(ctx, &types.MsgPause{ Signer: pauser.Address, @@ -201,7 +254,7 @@ func TestUnpause(t *testing.T) { server := keeper.NewMsgServer(k) // ARRANGE: Set paused state to true. - k.SetPaused(ctx, true) + require.NoError(t, k.SetPaused(ctx, true)) // ACT: Attempt to unpause with no owner set. _, err := server.Unpause(ctx, &types.MsgUnpause{}) @@ -211,7 +264,7 @@ func TestUnpause(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to unpause with invalid signer. _, err = server.Unpause(ctx, &types.MsgUnpause{ @@ -221,6 +274,21 @@ func TestUnpause(t *testing.T) { require.ErrorContains(t, err, types.ErrInvalidOwner.Error()) require.True(t, k.GetPaused(ctx)) + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Paused + k.Paused = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.PausedKey, "paused", collections.BoolValue, + ) + + // ACT: Attempt to unpause with failing Paused collection store. + _, err = server.Unpause(ctx, &types.MsgUnpause{ + Signer: owner.Address, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Paused = tmp + // ACT: Attempt to unpause. _, err = server.Unpause(ctx, &types.MsgUnpause{ Signer: owner.Address, @@ -249,7 +317,7 @@ func TestTransferOwnership(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to transfer ownership with invalid signer. _, err = server.TransferOwnership(ctx, &types.MsgTransferOwnership{ @@ -269,6 +337,22 @@ func TestTransferOwnership(t *testing.T) { // ARRANGE: Generate a pending owner account. pendingOwner := utils.TestAccount() + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.PendingOwner + k.PendingOwner = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.PendingOwnerKey, "pending_owner", collections.StringValue, + ) + + // ACT: Attempt to transfer ownership with failing PendingOwner collection store. + _, err = server.TransferOwnership(ctx, &types.MsgTransferOwnership{ + Signer: owner.Address, + NewOwner: pendingOwner.Address, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.PendingOwner = tmp + // ACT: Attempt to transfer ownership. _, err = server.TransferOwnership(ctx, &types.MsgTransferOwnership{ Signer: owner.Address, @@ -290,7 +374,7 @@ func TestAcceptOwnership(t *testing.T) { // ARRANGE: Set pending owner in state. pendingOwner := utils.TestAccount() - k.SetPendingOwner(ctx, pendingOwner.Address) + require.NoError(t, k.SetPendingOwner(ctx, pendingOwner.Address)) // ACT: Attempt to accept ownership with invalid signer. _, err = server.AcceptOwnership(ctx, &types.MsgAcceptOwnership{ @@ -299,6 +383,36 @@ func TestAcceptOwnership(t *testing.T) { // ASSERT: The action should've failed due to invalid signer. require.ErrorContains(t, err, types.ErrInvalidPendingOwner.Error()) + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Owner + k.Owner = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.OwnerKey, "owner", collections.StringValue, + ) + + // ACT: Attempt to accept ownership with failing Owner collection store. + _, err = server.AcceptOwnership(ctx, &types.MsgAcceptOwnership{ + Signer: pendingOwner.Address, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Owner = tmp + + // ARRANGE: Set up a failing collection store for the attribute delete. + tmp = k.PendingOwner + k.PendingOwner = collections.NewItem( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Delete, utils.GetKVStore(ctx, types.ModuleName))), + types.PendingOwnerKey, "pending_owner", collections.StringValue, + ) + + // ACT: Attempt to accept ownership with failing PendingOwner collection store. + _, err = server.AcceptOwnership(ctx, &types.MsgAcceptOwnership{ + Signer: pendingOwner.Address, + }) + // ASSERT: The action should've failed due to collection store delete error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.PendingOwner = tmp + // ACT: Attempt to accept ownership. _, err = server.AcceptOwnership(ctx, &types.MsgAcceptOwnership{ Signer: pendingOwner.Address, @@ -320,7 +434,7 @@ func TestAddBurner(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to add burner with invalid signer. _, err = server.AddBurner(ctx, &types.MsgAddBurner{ @@ -331,7 +445,7 @@ func TestAddBurner(t *testing.T) { // ARRANGE: Generate two burner accounts, add one to state. burner1, burner2 := utils.TestAccount(), utils.TestAccount() - k.SetBurner(ctx, burner2.Address, ONE) + require.NoError(t, k.SetBurner(ctx, burner2.Address, ONE)) // ACT: Attempt to add burner that already exists. _, err = server.AddBurner(ctx, &types.MsgAddBurner{ @@ -351,6 +465,23 @@ func TestAddBurner(t *testing.T) { // ASSERT: The action should've failed due to negative allowance. require.ErrorContains(t, err, "allowance cannot be negative") + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Burners + k.Burners = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.BurnerPrefix, "burners", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to add burner with failing Burners collection store. + _, err = server.AddBurner(ctx, &types.MsgAddBurner{ + Signer: owner.Address, + Burner: burner1.Address, + Allowance: ONE, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Burners = tmp + // ACT: Attempt to add burner. _, err = server.AddBurner(ctx, &types.MsgAddBurner{ Signer: owner.Address, @@ -373,7 +504,7 @@ func TestRemoveBurner(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to remove burner with invalid signer. _, err = server.RemoveBurner(ctx, &types.MsgRemoveBurner{ @@ -394,7 +525,23 @@ func TestRemoveBurner(t *testing.T) { require.ErrorContains(t, err, "is not a burner") // ARRANGE: Set burner in state. - k.SetBurner(ctx, burner.Address, ONE) + require.NoError(t, k.SetBurner(ctx, burner.Address, ONE)) + + // ARRANGE: Set up a failing collection store for the attribute delete. + tmp := k.Burners + k.Burners = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Delete, utils.GetKVStore(ctx, types.ModuleName))), + types.BurnerPrefix, "burners", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to remove burner with failing Burners collection store. + _, err = server.RemoveBurner(ctx, &types.MsgRemoveBurner{ + Signer: owner.Address, + Burner: burner.Address, + }) + // ASSERT: The action should've failed due to collection store delete error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Burners = tmp // ACT: Attempt to remove burner. _, err = server.RemoveBurner(ctx, &types.MsgRemoveBurner{ @@ -417,7 +564,7 @@ func TestSetBurnerAllowance(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to set burner allowance with invalid signer. _, err = server.SetBurnerAllowance(ctx, &types.MsgSetBurnerAllowance{ @@ -439,7 +586,7 @@ func TestSetBurnerAllowance(t *testing.T) { require.ErrorContains(t, err, "is not a burner") // ARRANGE: Set burner in state. - k.SetBurner(ctx, burner.Address, math.ZeroInt()) + require.NoError(t, k.SetBurner(ctx, burner.Address, math.ZeroInt())) // ACT: Attempt to set burner allowance with invalid allowance. _, err = server.SetBurnerAllowance(ctx, &types.MsgSetBurnerAllowance{ @@ -450,6 +597,27 @@ func TestSetBurnerAllowance(t *testing.T) { // ASSERT: The action should've failed due to negative allowance. require.ErrorContains(t, err, "allowance cannot be negative") + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Burners + k.Burners = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.BurnerPrefix, "burners", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to set burner allowance with failing Burners collection store. + _, err = server.SetBurnerAllowance(ctx, &types.MsgSetBurnerAllowance{ + Signer: owner.Address, + Burner: burner.Address, + Allowance: ONE, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Burners = tmp + + // ARRANGE: Set invalid un-decodable burn allowance in state. + key, _ := collections.EncodeKeyWithPrefix(types.BurnerPrefix, collections.StringKey, burner.Address) + utils.GetKVStore(ctx, types.ModuleName).Set(key, []byte("invalid")) + // ACT: Attempt to set burner allowance. _, err = server.SetBurnerAllowance(ctx, &types.MsgSetBurnerAllowance{ Signer: owner.Address, @@ -472,7 +640,7 @@ func TestAddMinter(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to add minter with invalid signer. _, err = server.AddMinter(ctx, &types.MsgAddMinter{ @@ -483,7 +651,7 @@ func TestAddMinter(t *testing.T) { // ARRANGE: Generate two minter accounts, add one to state. minter1, minter2 := utils.TestAccount(), utils.TestAccount() - k.SetMinter(ctx, minter2.Address, ONE) + require.NoError(t, k.SetMinter(ctx, minter2.Address, ONE)) // ACT: Attempt to add minter that already exists. _, err = server.AddMinter(ctx, &types.MsgAddMinter{ @@ -503,6 +671,23 @@ func TestAddMinter(t *testing.T) { // ASSERT: The action should've failed due to negative allowance. require.ErrorContains(t, err, "allowance cannot be negative") + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Minters + k.Minters = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.MinterPrefix, "minters", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to add minter with failing Minters collection store. + _, err = server.AddMinter(ctx, &types.MsgAddMinter{ + Signer: owner.Address, + Minter: minter1.Address, + Allowance: ONE, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Minters = tmp + // ACT: Attempt to add minter. _, err = server.AddMinter(ctx, &types.MsgAddMinter{ Signer: owner.Address, @@ -525,7 +710,7 @@ func TestRemoveMinter(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to remove minter with invalid signer. _, err = server.RemoveMinter(ctx, &types.MsgRemoveMinter{ @@ -546,7 +731,23 @@ func TestRemoveMinter(t *testing.T) { require.ErrorContains(t, err, "is not a minter") // ARRANGE: Set minter in state. - k.SetMinter(ctx, minter.Address, ONE) + require.NoError(t, k.SetMinter(ctx, minter.Address, ONE)) + + // ARRANGE: Set up a failing collection store for the attribute delete. + tmp := k.Minters + k.Minters = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Delete, utils.GetKVStore(ctx, types.ModuleName))), + types.MinterPrefix, "minters", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to remove minter with failing Minters collection store. + _, err = server.RemoveMinter(ctx, &types.MsgRemoveMinter{ + Signer: owner.Address, + Minter: minter.Address, + }) + // ASSERT: The action should've failed due to collection store delete error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Minters = tmp // ACT: Attempt to remove minter. _, err = server.RemoveMinter(ctx, &types.MsgRemoveMinter{ @@ -569,7 +770,7 @@ func TestSetMinterAllowance(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to set minter allowance with invalid signer. _, err = server.SetMinterAllowance(ctx, &types.MsgSetMinterAllowance{ @@ -591,7 +792,7 @@ func TestSetMinterAllowance(t *testing.T) { require.ErrorContains(t, err, "is not a minter") // ARRANGE: Set minters in state. - k.SetMinter(ctx, minter.Address, math.ZeroInt()) + require.NoError(t, k.SetMinter(ctx, minter.Address, math.ZeroInt())) // ACT: Attempt to set minter allowance with invalid allowance. _, err = server.SetMinterAllowance(ctx, &types.MsgSetMinterAllowance{ @@ -602,6 +803,27 @@ func TestSetMinterAllowance(t *testing.T) { // ASSERT: The action should've failed due to negative allowance. require.ErrorContains(t, err, "allowance cannot be negative") + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Minters + k.Minters = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.MinterPrefix, "minters", collections.StringKey, sdk.IntValue, + ) + + // ACT: Attempt to set minter allowance with failing Minters collection store. + _, err = server.SetMinterAllowance(ctx, &types.MsgSetMinterAllowance{ + Signer: owner.Address, + Minter: minter.Address, + Allowance: ONE, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Minters = tmp + + // ARRANGE: Set invalid un-decodable mint allowance in state. + key, _ := collections.EncodeKeyWithPrefix(types.MinterPrefix, collections.StringKey, minter.Address) + utils.GetKVStore(ctx, types.ModuleName).Set(key, []byte("invalid")) + // ACT: Attempt to set minter allowance. _, err = server.SetMinterAllowance(ctx, &types.MsgSetMinterAllowance{ Signer: owner.Address, @@ -624,7 +846,7 @@ func TestAddPauser(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to add pauser with invalid signer. _, err = server.AddPauser(ctx, &types.MsgAddPauser{ @@ -635,7 +857,7 @@ func TestAddPauser(t *testing.T) { // ARRANGE: Generate two pauser accounts, add one to state. pauser1, pauser2 := utils.TestAccount(), utils.TestAccount() - k.SetPauser(ctx, pauser2.Address) + require.NoError(t, k.SetPauser(ctx, pauser2.Address)) // ACT: Attempt to add pauser that already exists. _, err = server.AddPauser(ctx, &types.MsgAddPauser{ @@ -645,6 +867,22 @@ func TestAddPauser(t *testing.T) { // ASSERT: The action should've failed due to existing pauser. require.ErrorContains(t, err, "is already a pauser") + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.Pausers + k.Pausers = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.PauserPrefix, "pausers", collections.StringKey, collections.BytesValue, + ) + + // ACT: Attempt to add pauser with failing Pausers collection store. + _, err = server.AddPauser(ctx, &types.MsgAddPauser{ + Signer: owner.Address, + Pauser: pauser1.Address, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Pausers = tmp + // ACT: Attempt to add pauser. _, err = server.AddPauser(ctx, &types.MsgAddPauser{ Signer: owner.Address, @@ -666,7 +904,7 @@ func TestRemovePauser(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to remove pauser with invalid signer. _, err = server.RemovePauser(ctx, &types.MsgRemovePauser{ @@ -687,7 +925,23 @@ func TestRemovePauser(t *testing.T) { require.ErrorContains(t, err, "is not a pauser") // ARRANGE: Set pauser in state. - k.SetPauser(ctx, pauser.Address) + require.NoError(t, k.SetPauser(ctx, pauser.Address)) + + // ARRANGE: Set up a failing collection store for the attribute delete. + tmp := k.Pausers + k.Pausers = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Delete, utils.GetKVStore(ctx, types.ModuleName))), + types.PauserPrefix, "pausers", collections.StringKey, collections.BytesValue, + ) + + // ACT: Attempt to remove pauser with failing Pausers collection store. + _, err = server.RemovePauser(ctx, &types.MsgRemovePauser{ + Signer: owner.Address, + Pauser: pauser.Address, + }) + // ASSERT: The action should've failed due to collection store delete error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.Pausers = tmp // ACT: Attempt to remove pauser. _, err = server.RemovePauser(ctx, &types.MsgRemovePauser{ @@ -710,7 +964,7 @@ func TestAddBlockedChannel(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to add blocked channel with invalid signer. _, err = server.AddBlockedChannel(ctx, &types.MsgAddBlockedChannel{ @@ -721,7 +975,7 @@ func TestAddBlockedChannel(t *testing.T) { // ARRANGE: Generate two channel, add one to state. channel1, channel2 := "channel-0", "channel-1" - k.SetBlockedChannel(ctx, channel2) + require.NoError(t, k.SetBlockedChannel(ctx, channel2)) // ACT: Attempt to add blocked channel that is blocked. _, err = server.AddBlockedChannel(ctx, &types.MsgAddBlockedChannel{ @@ -731,6 +985,22 @@ func TestAddBlockedChannel(t *testing.T) { // ASSERT: The action should've failed due to blocked channel. require.ErrorContains(t, err, "is already blocked") + // ARRANGE: Set up a failing collection store for the attribute setter. + tmp := k.BlockedChannels + k.BlockedChannels = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Set, utils.GetKVStore(ctx, types.ModuleName))), + types.BlockedChannelPrefix, "blocked_channels", collections.StringKey, collections.BytesValue, + ) + + // ACT: Attempt to add blocked channel with failing BlockedChannels collection store. + _, err = server.AddBlockedChannel(ctx, &types.MsgAddBlockedChannel{ + Signer: owner.Address, + Channel: channel1, + }) + // ASSERT: The action should've failed due to collection store setter error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.BlockedChannels = tmp + // ACT: Attempt to add blocked channel. _, err = server.AddBlockedChannel(ctx, &types.MsgAddBlockedChannel{ Signer: owner.Address, @@ -752,7 +1022,7 @@ func TestRemoveBlockedChannel(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to remove blocked channel with invalid signer. _, err = server.RemoveBlockedChannel(ctx, &types.MsgRemoveBlockedChannel{ @@ -773,7 +1043,23 @@ func TestRemoveBlockedChannel(t *testing.T) { require.ErrorContains(t, err, "is not blocked") // ARRANGE: Set channel in state. - k.SetBlockedChannel(ctx, channel) + require.NoError(t, k.SetBlockedChannel(ctx, channel)) + + // ARRANGE: Set up a failing collection store for the attribute delete. + tmp := k.BlockedChannels + k.BlockedChannels = collections.NewMap( + collections.NewSchemaBuilder(mocks.FailingStore(mocks.Delete, utils.GetKVStore(ctx, types.ModuleName))), + types.BlockedChannelPrefix, "blocked_channels", collections.StringKey, collections.BytesValue, + ) + + // ACT: Attempt to remove blocked channel with failing BlockedChannels collection store. + _, err = server.RemoveBlockedChannel(ctx, &types.MsgRemoveBlockedChannel{ + Signer: owner.Address, + Channel: channel, + }) + // ASSERT: The action should've failed due to collection store delete error. + require.Error(t, err, mocks.ErrorStoreAccess) + k.BlockedChannels = tmp // ACT: Attempt to remove blocked channel. _, err = server.RemoveBlockedChannel(ctx, &types.MsgRemoveBlockedChannel{ diff --git a/keeper/query_server_blocklist_test.go b/keeper/query_server_blocklist_test.go index 623069d..f14ccca 100644 --- a/keeper/query_server_blocklist_test.go +++ b/keeper/query_server_blocklist_test.go @@ -22,7 +22,7 @@ func TestBlocklistOwnerQuery(t *testing.T) { // ARRANGE: Set blocklist owner in state. owner := utils.TestAccount() - k.SetBlocklistOwner(ctx, owner.Address) + require.NoError(t, k.SetBlocklistOwner(ctx, owner.Address)) // ACT: Attempt to query blocklist owner with state. res, err := server.Owner(ctx, &blocklist.QueryOwner{}) @@ -33,7 +33,7 @@ func TestBlocklistOwnerQuery(t *testing.T) { // ARRANGE: Set blocklist pending owner in state. pendingOwner := utils.TestAccount() - k.SetBlocklistPendingOwner(ctx, pendingOwner.Address) + require.NoError(t, k.SetBlocklistPendingOwner(ctx, pendingOwner.Address)) // ACT: Attempt to query blocklist owner with state. res, err = server.Owner(ctx, &blocklist.QueryOwner{}) @@ -62,8 +62,8 @@ func TestBlocklistAddressesQuery(t *testing.T) { // ARRANGE: Set blocklist addresses in state. user1, user2 := utils.TestAccount(), utils.TestAccount() - k.SetBlockedAddress(ctx, user1.Bytes) - k.SetBlockedAddress(ctx, user2.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, user1.Bytes)) + require.NoError(t, k.SetBlockedAddress(ctx, user2.Bytes)) // ACT: Attempt to query blocklist addresses with state. res, err = server.Addresses(ctx, &blocklist.QueryAddresses{}) @@ -100,7 +100,7 @@ func TestBlocklistAddressQuery(t *testing.T) { // ARRANGE: Set blocklist address in state. user := utils.TestAccount() - k.SetBlockedAddress(ctx, user.Bytes) + require.NoError(t, k.SetBlockedAddress(ctx, user.Bytes)) // ACT: Attempt to query blocked state of blocked address. res, err = server.Address(ctx, &blocklist.QueryAddress{ diff --git a/keeper/query_server_test.go b/keeper/query_server_test.go index 14a10af..e8df3f8 100644 --- a/keeper/query_server_test.go +++ b/keeper/query_server_test.go @@ -43,7 +43,7 @@ func TestPausedQuery(t *testing.T) { require.False(t, res.Paused) // ARRANGE: Set paused state to true. - k.SetPaused(ctx, true) + require.NoError(t, k.SetPaused(ctx, true)) // ACT: Attempt to query paused state with state. res, err = server.Paused(ctx, &types.QueryPaused{}) @@ -63,7 +63,7 @@ func TestOwnerQuery(t *testing.T) { // ARRANGE: Set owner in state. owner := utils.TestAccount() - k.SetOwner(ctx, owner.Address) + require.NoError(t, k.SetOwner(ctx, owner.Address)) // ACT: Attempt to query owner with state. res, err := server.Owner(ctx, &types.QueryOwner{}) @@ -74,7 +74,7 @@ func TestOwnerQuery(t *testing.T) { // ARRANGE: Set pending owner in state. pendingOwner := utils.TestAccount() - k.SetPendingOwner(ctx, pendingOwner.Address) + require.NoError(t, k.SetPendingOwner(ctx, pendingOwner.Address)) // ACT: Attempt to query owner with state. res, err = server.Owner(ctx, &types.QueryOwner{}) @@ -101,8 +101,8 @@ func TestBurnersQuery(t *testing.T) { // ARRANGE: Set burners in state. burner1, burner2 := utils.TestAccount(), utils.TestAccount() - k.SetBurner(ctx, burner1.Address, ONE) - k.SetBurner(ctx, burner2.Address, ONE.MulRaw(2)) + require.NoError(t, k.SetBurner(ctx, burner1.Address, ONE)) + require.NoError(t, k.SetBurner(ctx, burner2.Address, ONE.MulRaw(2))) // ACT: Attempt to query burners with state. res, err = server.Burners(ctx, &types.QueryBurners{}) @@ -136,8 +136,8 @@ func TestMintersQuery(t *testing.T) { // ARRANGE: Set minters in state. minter1, minter2 := utils.TestAccount(), utils.TestAccount() - k.SetMinter(ctx, minter1.Address, ONE) - k.SetMinter(ctx, minter2.Address, ONE.MulRaw(2)) + require.NoError(t, k.SetMinter(ctx, minter1.Address, ONE)) + require.NoError(t, k.SetMinter(ctx, minter2.Address, ONE.MulRaw(2))) // ACT: Attempt to query minters with state. res, err = server.Minters(ctx, &types.QueryMinters{}) @@ -171,8 +171,8 @@ func TestPausersQuery(t *testing.T) { // ARRANGE: Set pausers in state. pauser1, pauser2 := utils.TestAccount(), utils.TestAccount() - k.SetPauser(ctx, pauser1.Address) - k.SetPauser(ctx, pauser2.Address) + require.NoError(t, k.SetPauser(ctx, pauser1.Address)) + require.NoError(t, k.SetPauser(ctx, pauser2.Address)) // ACT: Attempt to query pausers with state. res, err = server.Pausers(ctx, &types.QueryPausers{}) @@ -200,8 +200,8 @@ func TestBlockedChannelsQuery(t *testing.T) { // ARRANGE: Set blocked channels in state. channel1, channel2 := "channel-0", "channel-1" - k.SetBlockedChannel(ctx, channel1) - k.SetBlockedChannel(ctx, channel2) + require.NoError(t, k.SetBlockedChannel(ctx, channel1)) + require.NoError(t, k.SetBlockedChannel(ctx, channel2)) // ACT: Attempt to query blocked channels with state. res, err = server.BlockedChannels(ctx, &types.QueryBlockedChannels{}) diff --git a/keeper/state.go b/keeper/state.go index 73f82c4..8629f68 100644 --- a/keeper/state.go +++ b/keeper/state.go @@ -4,211 +4,164 @@ import ( "context" "cosmossdk.io/math" - "cosmossdk.io/store/prefix" - "github.com/cosmos/cosmos-sdk/runtime" "github.com/ondoprotocol/usdy-noble/v2/types" ) // func (k *Keeper) GetPaused(ctx context.Context) bool { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - bz := store.Get(types.PausedKey) - if len(bz) == 1 && bz[0] == 1 { - return true - } else { - return false - } + paused, _ := k.Paused.Get(ctx) + return paused } -func (k *Keeper) SetPaused(ctx context.Context, paused bool) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - if paused { - store.Set(types.PausedKey, []byte{0x1}) - } else { - store.Set(types.PausedKey, []byte{0x0}) - } +func (k *Keeper) SetPaused(ctx context.Context, paused bool) error { + return k.Paused.Set(ctx, paused) } // func (k *Keeper) GetOwner(ctx context.Context) string { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return string(store.Get(types.OwnerKey)) + owner, _ := k.Owner.Get(ctx) + return owner } -func (k *Keeper) SetOwner(ctx context.Context, owner string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Set(types.OwnerKey, []byte(owner)) +func (k *Keeper) SetOwner(ctx context.Context, owner string) error { + return k.Owner.Set(ctx, owner) } // -func (k *Keeper) DeletePendingOwner(ctx context.Context) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Delete(types.PendingOwnerKey) +func (k *Keeper) DeletePendingOwner(ctx context.Context) error { + return k.PendingOwner.Remove(ctx) } func (k *Keeper) GetPendingOwner(ctx context.Context) string { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return string(store.Get(types.PendingOwnerKey)) + pendingOwner, _ := k.PendingOwner.Get(ctx) + return pendingOwner } -func (k *Keeper) SetPendingOwner(ctx context.Context, pendingOwner string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Set(types.PendingOwnerKey, []byte(pendingOwner)) +func (k *Keeper) SetPendingOwner(ctx context.Context, pendingOwner string) error { + return k.PendingOwner.Set(ctx, pendingOwner) } // -func (k *Keeper) DeleteBurner(ctx context.Context, burner string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Delete(types.BurnerKey(burner)) +func (k *Keeper) DeleteBurner(ctx context.Context, burner string) error { + return k.Burners.Remove(ctx, burner) } func (k *Keeper) GetBurner(ctx context.Context, burner string) (allowance math.Int) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - bz := store.Get(types.BurnerKey(burner)) + allowance, err := k.Burners.Get(ctx, burner) + if err != nil { + return math.ZeroInt() + } - _ = allowance.Unmarshal(bz) return } func (k *Keeper) GetBurners(ctx context.Context) (burners []types.Burner) { - adapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(adapter, types.BurnerPrefix) - itr := store.Iterator(nil, nil) - - defer itr.Close() - - for ; itr.Valid(); itr.Next() { - var allowance math.Int - _ = allowance.Unmarshal(itr.Value()) - + _ = k.Burners.Walk(ctx, nil, func(burner string, allowance math.Int) (stop bool, err error) { burners = append(burners, types.Burner{ - Address: string(itr.Key()), + Address: burner, Allowance: allowance, }) - } + + return false, nil + }) return } func (k *Keeper) HasBurner(ctx context.Context, burner string) bool { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return store.Has(types.BurnerKey(burner)) + has, _ := k.Burners.Has(ctx, burner) + return has } -func (k *Keeper) SetBurner(ctx context.Context, burner string, allowance math.Int) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - bz, _ := allowance.Marshal() - store.Set(types.BurnerKey(burner), bz) +func (k *Keeper) SetBurner(ctx context.Context, burner string, allowance math.Int) error { + return k.Burners.Set(ctx, burner, allowance) } // -func (k *Keeper) DeleteMinter(ctx context.Context, minter string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Delete(types.MinterKey(minter)) +func (k *Keeper) DeleteMinter(ctx context.Context, minter string) error { + return k.Minters.Remove(ctx, minter) } func (k *Keeper) GetMinter(ctx context.Context, minter string) (allowance math.Int) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - bz := store.Get(types.MinterKey(minter)) + allowance, err := k.Minters.Get(ctx, minter) + if err != nil { + return math.ZeroInt() + } - _ = allowance.Unmarshal(bz) return } func (k *Keeper) GetMinters(ctx context.Context) (minters []types.Minter) { - adapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(adapter, types.MinterPrefix) - itr := store.Iterator(nil, nil) - - defer itr.Close() - - for ; itr.Valid(); itr.Next() { - var allowance math.Int - _ = allowance.Unmarshal(itr.Value()) - + _ = k.Minters.Walk(ctx, nil, func(minter string, allowance math.Int) (stop bool, err error) { minters = append(minters, types.Minter{ - Address: string(itr.Key()), + Address: minter, Allowance: allowance, }) - } + + return false, nil + }) return } func (k *Keeper) HasMinter(ctx context.Context, minter string) bool { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return store.Has(types.MinterKey(minter)) + has, _ := k.Minters.Has(ctx, minter) + return has } -func (k *Keeper) SetMinter(ctx context.Context, minter string, allowance math.Int) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - bz, _ := allowance.Marshal() - store.Set(types.MinterKey(minter), bz) +func (k *Keeper) SetMinter(ctx context.Context, minter string, allowance math.Int) error { + return k.Minters.Set(ctx, minter, allowance) } // -func (k *Keeper) DeletePauser(ctx context.Context, pauser string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Delete(types.PauserKey(pauser)) +func (k *Keeper) DeletePauser(ctx context.Context, pauser string) error { + return k.Pausers.Remove(ctx, pauser) } func (k *Keeper) GetPausers(ctx context.Context) (pausers []string) { - adapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(adapter, types.PauserPrefix) - itr := store.Iterator(nil, nil) - - defer itr.Close() - - for ; itr.Valid(); itr.Next() { - pausers = append(pausers, string(itr.Key())) - } + _ = k.Pausers.Walk(ctx, nil, func(pauser string, _ []byte) (stop bool, err error) { + pausers = append(pausers, pauser) + return false, nil + }) return } func (k *Keeper) HasPauser(ctx context.Context, pauser string) bool { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return store.Has(types.PauserKey(pauser)) + has, _ := k.Pausers.Has(ctx, pauser) + return has } -func (k *Keeper) SetPauser(ctx context.Context, pauser string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Set(types.PauserKey(pauser), []byte{}) +func (k *Keeper) SetPauser(ctx context.Context, pauser string) error { + return k.Pausers.Set(ctx, pauser, []byte{}) } // -func (k *Keeper) DeleteBlockedChannel(ctx context.Context, channel string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Delete(types.BlockedChannelKey(channel)) +func (k *Keeper) DeleteBlockedChannel(ctx context.Context, channel string) error { + return k.BlockedChannels.Remove(ctx, channel) } func (k *Keeper) GetBlockedChannels(ctx context.Context) (channels []string) { - adapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(adapter, types.BlockedChannelPrefix) - itr := store.Iterator(nil, nil) - - defer itr.Close() - - for ; itr.Valid(); itr.Next() { - channels = append(channels, string(itr.Key())) - } + _ = k.BlockedChannels.Walk(ctx, nil, func(channel string, _ []byte) (stop bool, err error) { + channels = append(channels, channel) + return false, nil + }) return } func (k *Keeper) HasBlockedChannel(ctx context.Context, channel string) bool { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return store.Has(types.BlockedChannelKey(channel)) + has, _ := k.BlockedChannels.Has(ctx, channel) + return has } -func (k *Keeper) SetBlockedChannel(ctx context.Context, channel string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Set(types.BlockedChannelKey(channel), []byte{}) +func (k *Keeper) SetBlockedChannel(ctx context.Context, channel string) error { + return k.BlockedChannels.Set(ctx, channel, []byte{}) } diff --git a/keeper/state_blocklist.go b/keeper/state_blocklist.go index 49a4f97..1613c6f 100644 --- a/keeper/state_blocklist.go +++ b/keeper/state_blocklist.go @@ -2,69 +2,56 @@ package keeper import ( "context" - - "cosmossdk.io/store/prefix" - "github.com/cosmos/cosmos-sdk/runtime" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ondoprotocol/usdy-noble/v2/types/blocklist" ) // func (k *Keeper) GetBlocklistOwner(ctx context.Context) string { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return string(store.Get(blocklist.OwnerKey)) + owner, _ := k.BlocklistOwner.Get(ctx) + return owner } -func (k *Keeper) SetBlocklistOwner(ctx context.Context, owner string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Set(blocklist.OwnerKey, []byte(owner)) +func (k *Keeper) SetBlocklistOwner(ctx context.Context, owner string) error { + return k.BlocklistOwner.Set(ctx, owner) } // -func (k *Keeper) DeleteBlocklistPendingOwner(ctx context.Context) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Delete(blocklist.PendingOwnerKey) +func (k *Keeper) DeleteBlocklistPendingOwner(ctx context.Context) error { + return k.BlocklistPendingOwner.Remove(ctx) } func (k *Keeper) GetBlocklistPendingOwner(ctx context.Context) string { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return string(store.Get(blocklist.PendingOwnerKey)) + pendingOwner, _ := k.BlocklistPendingOwner.Get(ctx) + return pendingOwner } -func (k *Keeper) SetBlocklistPendingOwner(ctx context.Context, pendingOwner string) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Set(blocklist.PendingOwnerKey, []byte(pendingOwner)) +func (k *Keeper) SetBlocklistPendingOwner(ctx context.Context, pendingOwner string) error { + return k.BlocklistPendingOwner.Set(ctx, pendingOwner) } // -func (k *Keeper) DeleteBlockedAddress(ctx context.Context, address []byte) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Delete(blocklist.BlockedAddressKey(address)) +func (k *Keeper) DeleteBlockedAddress(ctx context.Context, address []byte) error { + return k.BlockedAddresses.Remove(ctx, address) } func (k *Keeper) GetBlockedAddresses(ctx context.Context) (addresses []string) { - adapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(adapter, blocklist.BlockedAddressPrefix) - itr := store.Iterator(nil, nil) - - defer itr.Close() + _ = k.BlockedAddresses.Walk(ctx, nil, func(rawAddress []byte, _ []byte) (stop bool, err error) { + address, _ := k.addressCodec.BytesToString(rawAddress) + addresses = append(addresses, address) - for ; itr.Valid(); itr.Next() { - addresses = append(addresses, sdk.AccAddress(itr.Key()).String()) - } + return false, nil + }) return } func (k *Keeper) HasBlockedAddress(ctx context.Context, address []byte) bool { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return store.Has(blocklist.BlockedAddressKey(address)) + has, _ := k.BlockedAddresses.Has(ctx, address) + return has } -func (k *Keeper) SetBlockedAddress(ctx context.Context, address []byte) { - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store.Set(blocklist.BlockedAddressKey(address), []byte{}) +func (k *Keeper) SetBlockedAddress(ctx context.Context, address []byte) error { + return k.BlockedAddresses.Set(ctx, address, []byte{}) } diff --git a/keeper/state_blocklist_test.go b/keeper/state_blocklist_test.go index 3c6c64d..ae59436 100644 --- a/keeper/state_blocklist_test.go +++ b/keeper/state_blocklist_test.go @@ -18,8 +18,8 @@ func TestGetBlockedAddresses(t *testing.T) { // ARRANGE: Set blocklist addresses in state. user1, user2 := utils.TestAccount(), utils.TestAccount() - keeper.SetBlockedAddress(ctx, user1.Bytes) - keeper.SetBlockedAddress(ctx, user2.Bytes) + require.NoError(t, keeper.SetBlockedAddress(ctx, user1.Bytes)) + require.NoError(t, keeper.SetBlockedAddress(ctx, user2.Bytes)) // ACT: Retrieve all blocked addresses. addresses = keeper.GetBlockedAddresses(ctx) diff --git a/types/blocklist/keys.go b/types/blocklist/keys.go index 90f10c8..1df8d91 100644 --- a/types/blocklist/keys.go +++ b/types/blocklist/keys.go @@ -7,7 +7,3 @@ var ( PendingOwnerKey = []byte("blocklist/pending_owner") BlockedAddressPrefix = []byte("blocklist/blocked_address/") ) - -func BlockedAddressKey(address []byte) []byte { - return append(BlockedAddressPrefix, address...) -} diff --git a/types/keys.go b/types/keys.go index 176a4e8..5144b3e 100644 --- a/types/keys.go +++ b/types/keys.go @@ -15,19 +15,3 @@ var ( PauserPrefix = []byte("pauser/") BlockedChannelPrefix = []byte("blocked_channel/") ) - -func BurnerKey(address string) []byte { - return append(BurnerPrefix, []byte(address)...) -} - -func MinterKey(address string) []byte { - return append(MinterPrefix, []byte(address)...) -} - -func PauserKey(address string) []byte { - return append(PauserPrefix, []byte(address)...) -} - -func BlockedChannelKey(channel string) []byte { - return append(BlockedChannelPrefix, []byte(channel)...) -} diff --git a/utils/mocks/store.go b/utils/mocks/store.go new file mode 100644 index 0000000..86d99c1 --- /dev/null +++ b/utils/mocks/store.go @@ -0,0 +1,99 @@ +package mocks + +import ( + "context" + + "cosmossdk.io/core/store" + "cosmossdk.io/errors" + "cosmossdk.io/store/types" + db "github.com/cosmos/cosmos-db" +) + +var ErrorStoreAccess = errors.New("store", 1, "error accessing store") + +type FailingMethod string + +type StoreService struct { + failingMethod FailingMethod + original types.KVStore +} + +type testStore struct { + db db.DB + failingMethod FailingMethod + original types.KVStore +} + +type contextStoreKey struct{} + +const ( + Get FailingMethod = "get" + Has FailingMethod = "has" + Set FailingMethod = "set" + Delete FailingMethod = "delete" + Iterator FailingMethod = "iterator" + ReverseIterator FailingMethod = "reverseIterator" +) + +// FailingStore returns a store.KVStoreService that can be used to test specific errors within collections. +func FailingStore(failingMethod FailingMethod, original types.KVStore) *StoreService { + return &StoreService{failingMethod, original} +} + +func (s StoreService) OpenKVStore(_ context.Context) store.KVStore { + return testStore{ + failingMethod: s.failingMethod, + original: s.original, + } +} + +func (s StoreService) NewStoreContext() context.Context { + kv := db.NewMemDB() + return context.WithValue(context.Background(), contextStoreKey{}, &testStore{kv, s.failingMethod, s.original}) +} + +func (t testStore) Get(key []byte) ([]byte, error) { + if t.failingMethod == Get { + return nil, ErrorStoreAccess + } + return t.original.Get(key), nil +} + +func (t testStore) Has(key []byte) (bool, error) { + if t.failingMethod == Has { + return false, ErrorStoreAccess + } + return t.original.Has(key), nil +} + +func (t testStore) Set(key, value []byte) error { + if t.failingMethod == Set { + return ErrorStoreAccess + } + t.original.Set(key, value) + return nil +} + +func (t testStore) Delete(key []byte) error { + if t.failingMethod == Delete { + return ErrorStoreAccess + } + t.original.Delete(key) + return nil +} + +func (t testStore) Iterator(start, end []byte) (store.Iterator, error) { + if t.failingMethod == Iterator { + return nil, ErrorStoreAccess + } + return t.original.Iterator(start, end), nil +} + +func (t testStore) ReverseIterator(start, end []byte) (store.Iterator, error) { + if t.failingMethod == ReverseIterator { + return nil, ErrorStoreAccess + } + return t.original.ReverseIterator(start, end), nil +} + +var _ store.KVStore = testStore{} diff --git a/utils/store.go b/utils/store.go new file mode 100644 index 0000000..c3c25fa --- /dev/null +++ b/utils/store.go @@ -0,0 +1,12 @@ +package utils + +import ( + "cosmossdk.io/store/rootmulti" + "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GetKVStore retrieves the KVStore for the specified module from the context. +func GetKVStore(ctx sdk.Context, moduleName string) types.KVStore { + return ctx.KVStore(ctx.MultiStore().(*rootmulti.Store).StoreKeysByName()[moduleName]) +}