From 3fc211d86dc183e3debaa67009a753d2cce999a9 Mon Sep 17 00:00:00 2001 From: Amit Yadav Date: Tue, 19 Dec 2023 15:26:55 +0530 Subject: [PATCH] add host chain storage and tests --- x/yield/client/cli/tx_register_host_chain.go | 8 +- x/yield/keeper/host_chain.go | 102 ++++++++++++++++++ x/yield/keeper/host_chain_test.go | 86 +++++++++++++++ .../keeper/msg_server_register_host_chain.go | 2 +- x/yield/types/ica_account.go | 4 +- x/yield/types/keys.go | 5 + x/yield/types/message_register_host_chain.go | 8 +- 7 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 x/yield/keeper/host_chain.go create mode 100644 x/yield/keeper/host_chain_test.go diff --git a/x/yield/client/cli/tx_register_host_chain.go b/x/yield/client/cli/tx_register_host_chain.go index 98346f74..dac44fa8 100644 --- a/x/yield/client/cli/tx_register_host_chain.go +++ b/x/yield/client/cli/tx_register_host_chain.go @@ -23,19 +23,19 @@ func CmdRegisterHostChain() *cobra.Command { return err } - connectionId := args[0] + connectionID := args[0] hostDenom := args[1] bech32prefix := args[2] ibcDenom := args[3] - channelId := args[4] + channelID := args[4] msg := types.NewMsgRegisterHostChain( clientCtx.GetFromAddress().String(), - connectionId, + connectionID, bech32prefix, hostDenom, ibcDenom, - channelId, + channelID, ) if err := msg.ValidateBasic(); err != nil { return err diff --git a/x/yield/keeper/host_chain.go b/x/yield/keeper/host_chain.go new file mode 100644 index 00000000..e8e198a7 --- /dev/null +++ b/x/yield/keeper/host_chain.go @@ -0,0 +1,102 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + errorsmod "cosmossdk.io/errors" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/sideprotocol/side/x/yield/types" +) + +// SetHostChain set a specific hostChain in the store +func (k Keeper) SetHostChain(ctx sdk.Context, hostChain types.HostChain) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.HostChainKey)) + b := k.cdc.MustMarshal(&hostChain) + store.Set([]byte(hostChain.ChainId), b) +} + +// GetHostChain returns a hostChain from its id +func (k Keeper) GetHostChain(ctx sdk.Context, chainID string) (val types.HostChain, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.HostChainKey)) + b := store.Get([]byte(chainID)) + if b == nil { + return val, false + } + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +// GetHostChainFromHostDenom returns a HostChain from a HostDenom +func (k Keeper) GetHostChainFromHostDenom(ctx sdk.Context, denom string) (*types.HostChain, error) { + var matchChain types.HostChain + k.IterateHostChains(ctx, func(ctx sdk.Context, index int64, chainInfo types.HostChain) error { + if chainInfo.HostDenom == denom { + matchChain = chainInfo + return nil + } + return nil + }) + if matchChain.ChainId != "" { + return &matchChain, nil + } + return nil, errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "No HostChain for %s found", denom) +} + +// GetHostChainFromTransferChannelID returns a HostChain from a transfer channel ID +func (k Keeper) GetHostChainFromTransferChannelID(ctx sdk.Context, channelID string) (hostChain types.HostChain, found bool) { + for _, hostChain := range k.GetAllHostChain(ctx) { + if hostChain.TransferChannelId == channelID { + return hostChain, true + } + } + return types.HostChain{}, false +} + +// RemoveHostChain removes a hostChain from the store +func (k Keeper) RemoveHostChain(ctx sdk.Context, chainID string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.HostChainKey)) + store.Delete([]byte(chainID)) +} + +// GetAllHostChain returns all hostChain +func (k Keeper) GetAllHostChain(ctx sdk.Context) (list []types.HostChain) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.HostChainKey)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var val types.HostChain + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + + return +} + +// IterateHostChains iterates chains +func (k Keeper) IterateHostChains(ctx sdk.Context, fn func(ctx sdk.Context, index int64, zoneInfo types.HostChain) error) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.HostChainKey)) + + iterator := sdk.KVStorePrefixIterator(store, nil) + defer iterator.Close() + + i := int64(0) + + for ; iterator.Valid(); iterator.Next() { + k.Logger(ctx).Debug(fmt.Sprintf("Iterating hostChain %d", i)) + zone := types.HostChain{} + k.cdc.MustUnmarshal(iterator.Value(), &zone) + + error := fn(ctx, i, zone) + + if error != nil { + break + } + i++ + } +} diff --git a/x/yield/keeper/host_chain_test.go b/x/yield/keeper/host_chain_test.go new file mode 100644 index 00000000..2e2fd5d8 --- /dev/null +++ b/x/yield/keeper/host_chain_test.go @@ -0,0 +1,86 @@ +package keeper_test + +import ( + "strconv" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + keepertest "github.com/sideprotocol/side/testutil/keeper" + "github.com/sideprotocol/side/testutil/nullify" + "github.com/sideprotocol/side/x/yield/keeper" + "github.com/sideprotocol/side/x/yield/types" +) + +func createNHostChain(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.HostChain { + items := make([]types.HostChain, n) + for i := range items { + items[i].ChainId = strconv.Itoa(i) + keeper.SetHostChain(ctx, items[i]) + } + return items +} + +func TestHostChainGet(t *testing.T) { + keeper, ctx := keepertest.YieldKeeper(t) + items := createNHostChain(keeper, ctx, 10) + for _, item := range items { + got, found := keeper.GetHostChain(ctx, item.ChainId) + require.True(t, found) + require.Equal(t, + nullify.Fill(&item), + nullify.Fill(&got), + ) + } +} + +func TestHostChainRemove(t *testing.T) { + keeper, ctx := keepertest.YieldKeeper(t) + items := createNHostChain(keeper, ctx, 10) + for _, item := range items { + keeper.RemoveHostChain(ctx, item.ChainId) + _, found := keeper.GetHostChain(ctx, item.ChainId) + require.False(t, found) + } +} + +func TestHostChainGetAll(t *testing.T) { + keeper, ctx := keepertest.YieldKeeper(t) + items := createNHostChain(keeper, ctx, 10) + require.ElementsMatch(t, + nullify.Fill(items), + nullify.Fill(keeper.GetAllHostChain(ctx)), + ) +} + +// func (s *KeeperTestSuite) TestGetHostChainFromTransferChannelID() { +// // Store 5 host chains +// expectedHostChains := map[string]types.HostChain{} +// for i := 0; i < 5; i++ { +// chainId := fmt.Sprintf("chain-%d", i) +// channelId := fmt.Sprintf("channel-%d", i) + +// HostChain := types.HostChain{ +// ChainId: chainId, +// TransferChannelId: channelId, +// } +// s.App.StakeibcKeeper.SetHostChain(s.Ctx, HostChain) +// expectedHostChains[channelId] = HostChain +// } + +// // Look up each host chain by the channel ID +// for i := 0; i < 5; i++ { +// channelId := fmt.Sprintf("channel-%d", i) + +// expectedHostChain := expectedHostChains[channelId] +// actualHostChain, found := s.App.StakeibcKeeper.GetHostChainFromTransferChannelID(s.Ctx, channelId) + +// s.Require().True(found, "found host chain %d", i) +// s.Require().Equal(expectedHostChain.ChainId, actualHostChain.ChainId, "host chain %d chain-id", i) +// } + +// // Lookup a non-existent host chain - should not be found +// _, found := s.App.StakeibcKeeper.GetHostChainFromTransferChannelID(s.Ctx, "fake_channel") +// s.Require().False(found, "fake channel should not be found") +// } diff --git a/x/yield/keeper/msg_server_register_host_chain.go b/x/yield/keeper/msg_server_register_host_chain.go index 0059a1d2..dd1459d5 100644 --- a/x/yield/keeper/msg_server_register_host_chain.go +++ b/x/yield/keeper/msg_server_register_host_chain.go @@ -64,7 +64,7 @@ func (k msgServer) RegisterHostChain(goCtx context.Context, msg *types.MsgRegist } } - hc := &types.HostChain{ + hc := types.HostChain{ ChainId: chainID, Bech32Prefix: msg.Bech32Prefix, ConnectionId: msg.ConnectionId, diff --git a/x/yield/types/ica_account.go b/x/yield/types/ica_account.go index 151b0a86..cb57ce32 100644 --- a/x/yield/types/ica_account.go +++ b/x/yield/types/ica_account.go @@ -1,5 +1,5 @@ package types -func FormatICAAccountOwner(chainId string, accountType string) (result string) { - return chainId + "." + accountType +func FormatICAAccountOwner(chainID string, accountType string) (result string) { + return chainID + "." + accountType } diff --git a/x/yield/types/keys.go b/x/yield/types/keys.go index befdfc79..40efe16a 100644 --- a/x/yield/types/keys.go +++ b/x/yield/types/keys.go @@ -17,3 +17,8 @@ const ( func KeyPrefix(p string) []byte { return []byte(p) } + +const ( + // Host chain keys prefix the HostChain structs + HostChainKey = "HostChain-value-" +) diff --git a/x/yield/types/message_register_host_chain.go b/x/yield/types/message_register_host_chain.go index b5f8a31c..7f98c647 100644 --- a/x/yield/types/message_register_host_chain.go +++ b/x/yield/types/message_register_host_chain.go @@ -11,19 +11,19 @@ var _ sdk.Msg = &MsgRegisterHostChain{} func NewMsgRegisterHostChain( creator string, - connectionId string, + connectionID string, bech32prefix string, hostDenom string, ibcDenom string, - transferChannelId string, + transferChannelID string, ) *MsgRegisterHostChain { return &MsgRegisterHostChain{ Creator: creator, - ConnectionId: connectionId, + ConnectionId: connectionID, Bech32Prefix: bech32prefix, HostDenom: hostDenom, IbcDenom: ibcDenom, - TransferChannelId: transferChannelId, + TransferChannelId: transferChannelID, } }