Skip to content

Commit

Permalink
feat: IPRPC over IBC: Part 3 - CNS-965: Pending IPRPC IBC fund (#1452)
Browse files Browse the repository at this point in the history
* CNS-965: scaffold param IbcIprpcExpiration

* CNS-965: create pending iprpc fund

* CNS-965: fix unit tests

* CNS-965: move pending iprpc to seperate files and add IsExpired

* CNS-965: renamed to PendingIbcIprpcFund + bug fixes

* CNS-965: unit tests

* CNS-965: remove expired PendingIbcIprpcFunds in begin block

* CNS-965: unit tests

* CNS-965: comment

* CNS-965: divide fund when creating a new pending ibc iprpc fund

* CNS-965: lint fix

* CNS-965: fixes

* CNS-965: add events

* CNS-965: fixes after merge

* CNS-965: revert ibc transfer in case of middleware failure

* CNS-965: pending iprpc pool + reorder code that ibc-transfer is last in middleware

* CNS-965: migrator for IbcIprpcExpiration param

* CNS-965: make expired pending iprpc funds be taken from the pending pool

* CNS-965: small fixes

* feat: IPRPC over IBC: Part 4 - CNS-966: pending ibc iprpc fund query (#1457)

* CNS-966: implemented pending ibc iprpc query + unit test

* CNS-966: fix help section

* feat: IPRPC over IBC: Part 5 - CNS-967: Cover pending IBC IPRPC fund costs (#1470)

* CNS-967: implement cover ibc iprpc funds TX

* CNS-967: make gov module not pay min cost

* CNS-967: unit test

* CNS-967: partial merge from CNS-966

* CNS-967: small fixes

* feat: IPRPC over IBC: Part 6 - CNS-968: IBC middleware testing (#1481)

* CNS-968: add mock transfer keeper and IBC middleware to tester

* CNS-968: change middleware success ack and move create iprpc memo to types

* CNS-968: create ibc transfer helper func for tests and update tests

* CNS-968: lint fix

* feat: IPRPC over IBC: Part 7 - CNS-969 update README (#1482)

* CNS-969: improve comments

* CNS-969: rename param and move event

* CNS-969: update README

* CNS-969: small comment fix
  • Loading branch information
oren-lava authored Jul 8, 2024
1 parent c93cbd9 commit faab38d
Show file tree
Hide file tree
Showing 46 changed files with 3,310 additions and 266 deletions.
1 change: 1 addition & 0 deletions proto/lavanet/lava/rewards/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ message GenesisState {
cosmos.base.v1beta1.Coin min_iprpc_cost = 5 [(gogoproto.nullable) = false];
repeated IprpcReward iprpc_rewards = 6 [(gogoproto.nullable) = false];
uint64 iprpc_rewards_current = 7;
repeated PendingIbcIprpcFund pending_ibc_iprpc_funds = 8 [(gogoproto.nullable) = false];
// this line is used by starport scaffolding # genesis/proto/state
}
9 changes: 9 additions & 0 deletions proto/lavanet/lava/rewards/iprpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,13 @@ message IprpcMemo {
string creator = 1;
string spec = 2;
uint64 duration = 3; // Iprpc fund period in months
}

message PendingIbcIprpcFund {
uint64 index = 1; // unique index
string creator = 2;
string spec = 3;
uint64 duration = 4;
cosmos.base.v1beta1.Coin fund = 5 [(gogoproto.nullable) = false];
uint64 expiry = 6; // expiry timestamp
}
8 changes: 7 additions & 1 deletion proto/lavanet/lava/rewards/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ syntax = "proto3";
package lavanet.lava.rewards;

import "gogoproto/gogo.proto";

import "google/protobuf/duration.proto";
option go_package = "github.com/lavanet/lava/x/rewards/types";

// Params defines the parameters for the module.
Expand Down Expand Up @@ -40,4 +40,10 @@ message Params {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];

google.protobuf.Duration ibc_iprpc_expiration = 7 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "yaml:\"ibc_iprpc_expiration\""
];
}
20 changes: 20 additions & 0 deletions proto/lavanet/lava/rewards/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ service Query {
rpc IprpcSpecReward(QueryIprpcSpecRewardRequest) returns (QueryIprpcSpecRewardResponse) {
option (google.api.http).get = "/lavanet/lava/rewards/iprpc_spec_reward/{spec}";
}

// PendingIbcIprpcFunds queries for a spec's IPRPC reward
rpc PendingIbcIprpcFunds(QueryPendingIbcIprpcFundsRequest) returns (QueryPendingIbcIprpcFundsResponse) {
option (google.api.http).get = "/lavanet/lava/rewards/pending_ibc_iprpc_funds/{filter}";
}
// this line is used by starport scaffolding # 2
}

Expand Down Expand Up @@ -134,4 +139,19 @@ message QueryIprpcSpecRewardResponse {
uint64 current_month_id = 2;
}

// QueryPendingIbcIprpcFundsRequest is request type for the Query/PendingIbcIprpcFund RPC method.
message QueryPendingIbcIprpcFundsRequest {
string filter = 1; // can be an uint64 index, creator name and spec name
}

message PendingIbcIprpcFundInfo {
PendingIbcIprpcFund pending_ibc_iprpc_fund = 1 [(gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin cost = 2 [(gogoproto.nullable) = false]; // equals to min_iprpc_cost * duration
}

// QueryPendingIbcIprpcFundsResponse is response type for the Query/PendingIbcIprpcFund RPC method.
message QueryPendingIbcIprpcFundsResponse {
repeated PendingIbcIprpcFundInfo pending_ibc_iprpc_funds_info = 1 [(gogoproto.nullable) = false];
}

// this line is used by starport scaffolding # 3
9 changes: 9 additions & 0 deletions proto/lavanet/lava/rewards/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ option go_package = "github.com/lavanet/lava/x/rewards/types";
service Msg {
rpc SetIprpcData(MsgSetIprpcData) returns (MsgSetIprpcDataResponse);
rpc FundIprpc(MsgFundIprpc) returns (MsgFundIprpcResponse);
rpc CoverIbcIprpcFundCost(MsgCoverIbcIprpcFundCost) returns (MsgCoverIbcIprpcFundCostResponse);
// this line is used by starport scaffolding # proto/tx/rpc
}

Expand All @@ -37,4 +38,12 @@ message MsgFundIprpc {
message MsgFundIprpcResponse {
}

message MsgCoverIbcIprpcFundCost {
string creator = 1;
uint64 index = 2; // PendingIbcIprpcFund index
}

message MsgCoverIbcIprpcFundCostResponse {
}

// this line is used by starport scaffolding # proto/tx/message
1 change: 1 addition & 0 deletions scripts/test/cli_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ trace lavad q rewards show-iprpc-data > /dev/null
trace lavad q rewards iprpc-provider-reward > /dev/null
trace lavad q rewards iprpc-spec-reward > /dev/null
trace lavad q rewards provider-reward >/dev/null
trace lavad q rewards pending-ibc-iprpc-funds > /dev/null

echo "Testing rewards tx commands"
trace lavad tx rewards fund-iprpc ETH1 4 100000ulava --from alice >/dev/null
Expand Down
37 changes: 28 additions & 9 deletions testutil/common/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types"
testkeeper "github.com/lavanet/lava/testutil/keeper"
"github.com/lavanet/lava/utils"
"github.com/lavanet/lava/utils/lavaslices"
Expand All @@ -25,6 +26,7 @@ import (
pairingtypes "github.com/lavanet/lava/x/pairing/types"
planstypes "github.com/lavanet/lava/x/plans/types"
projectstypes "github.com/lavanet/lava/x/projects/types"
"github.com/lavanet/lava/x/rewards"
rewardstypes "github.com/lavanet/lava/x/rewards/types"
spectypes "github.com/lavanet/lava/x/spec/types"
subscriptiontypes "github.com/lavanet/lava/x/subscription/types"
Expand All @@ -34,10 +36,11 @@ import (
type Tester struct {
T *testing.T

GoCtx context.Context
Ctx sdk.Context
Servers *testkeeper.Servers
Keepers *testkeeper.Keepers
GoCtx context.Context
Ctx sdk.Context
Servers *testkeeper.Servers
Keepers *testkeeper.Keepers
IbcTransfer porttypes.Middleware

accounts map[string]sigs.Account
plans map[string]planstypes.Plan
Expand Down Expand Up @@ -75,11 +78,12 @@ func NewTesterRaw(t *testing.T) *Tester {
servers, keepers, GoCtx := testkeeper.InitAllKeepers(t)

ts := &Tester{
T: t,
GoCtx: GoCtx,
Ctx: sdk.UnwrapSDKContext(GoCtx),
Servers: servers,
Keepers: keepers,
T: t,
GoCtx: GoCtx,
Ctx: sdk.UnwrapSDKContext(GoCtx),
Servers: servers,
Keepers: keepers,
IbcTransfer: rewards.NewIBCMiddleware(keepers.IbcTransfer, keepers.Rewards),

accounts: make(map[string]sigs.Account),
plans: make(map[string]planstypes.Plan),
Expand Down Expand Up @@ -699,6 +703,11 @@ func (ts *Tester) TxRewardsFundIprpc(creator string, spec string, duration uint6
return ts.Servers.RewardsServer.FundIprpc(ts.GoCtx, msg)
}

func (ts *Tester) TxRewardsCoverIbcIprpcFundCost(creator string, index uint64) (*rewardstypes.MsgCoverIbcIprpcFundCostResponse, error) {
msg := rewardstypes.NewMsgCoverIbcIprpcFundCost(creator, index)
return ts.Servers.RewardsServer.CoverIbcIprpcFundCost(ts.GoCtx, msg)
}

// TxCreateValidator: implement 'tx staking createvalidator' and bond its tokens
func (ts *Tester) TxCreateValidator(validator sigs.Account, amount math.Int) {
consensusPowerTokens := ts.Keepers.StakingKeeper.TokensFromConsensusPower(ts.Ctx, 1)
Expand Down Expand Up @@ -969,20 +978,30 @@ func (ts *Tester) QueryRewardsShowIprpcData() (*rewardstypes.QueryShowIprpcDataR
return ts.Keepers.Rewards.ShowIprpcData(ts.GoCtx, msg)
}

// QueryRewardsShowIprpcData implements 'q rewards iprpc-provider-reward-estimation'
func (ts *Tester) QueryRewardsIprpcProviderRewardEstimation(provider string) (*rewardstypes.QueryIprpcProviderRewardEstimationResponse, error) {
msg := &rewardstypes.QueryIprpcProviderRewardEstimationRequest{
Provider: provider,
}
return ts.Keepers.Rewards.IprpcProviderRewardEstimation(ts.GoCtx, msg)
}

// QueryRewardsShowIprpcData implements 'q rewards iprpc-spec-reward'
func (ts *Tester) QueryRewardsIprpcSpecReward(spec string) (*rewardstypes.QueryIprpcSpecRewardResponse, error) {
msg := &rewardstypes.QueryIprpcSpecRewardRequest{
Spec: spec,
}
return ts.Keepers.Rewards.IprpcSpecReward(ts.GoCtx, msg)
}

// QueryRewardsShowIprpcData implements 'q rewards pending-ibc-iprpc-funds'
func (ts *Tester) QueryRewardsPendingIbcIprpcFunds(filter string) (*rewardstypes.QueryPendingIbcIprpcFundsResponse, error) {
msg := &rewardstypes.QueryPendingIbcIprpcFundsRequest{
Filter: filter,
}
return ts.Keepers.Rewards.PendingIbcIprpcFunds(ts.GoCtx, msg)
}

// block/epoch helpers
// QueryRewardsProviderReward implements 'q rewards provider-reward'
func (ts *Tester) QueryRewardsProviderReward(chainID string, provider string) (*rewardstypes.QueryProviderRewardResponse, error) {
Expand Down
9 changes: 9 additions & 0 deletions testutil/keeper/keepers_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
commonconsts "github.com/lavanet/lava/testutil/common/consts"
"github.com/lavanet/lava/utils/sigs"
conflictkeeper "github.com/lavanet/lava/x/conflict/keeper"
Expand Down Expand Up @@ -95,6 +96,7 @@ type Keepers struct {
SlashingKeeper slashingkeeper.Keeper
Rewards rewardskeeper.Keeper
Distribution distributionkeeper.Keeper
IbcTransfer mockIbcTransferKeeper
}

type Servers struct {
Expand All @@ -111,6 +113,7 @@ type Servers struct {
SlashingServer slashingtypes.MsgServer
RewardsServer rewardstypes.MsgServer
DistributionServer distributiontypes.MsgServer
IbcTransferServer ibctransfertypes.MsgServer
}

type KeeperBeginBlockerWithRequest interface {
Expand Down Expand Up @@ -142,6 +145,9 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) {
distributionStoreKey := sdk.NewKVStoreKey(distributiontypes.StoreKey)
stateStore.MountStoreWithDB(distributionStoreKey, storetypes.StoreTypeIAVL, db)

ibctransferStoreKey := sdk.NewKVStoreKey(ibctransfertypes.StoreKey)
stateStore.MountStoreWithDB(ibctransferStoreKey, storetypes.StoreTypeIAVL, db)

stakingStoreKey := sdk.NewKVStoreKey(stakingtypes.StoreKey)
stateStore.MountStoreWithDB(stakingStoreKey, storetypes.StoreTypeIAVL, db)

Expand Down Expand Up @@ -217,6 +223,7 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) {
paramsKeeper.Subspace(rewardstypes.ModuleName)
paramsKeeper.Subspace(distributiontypes.ModuleName)
paramsKeeper.Subspace(dualstakingtypes.ModuleName)
paramsKeeper.Subspace(ibctransfertypes.ModuleName)
// paramsKeeper.Subspace(conflicttypes.ModuleName) //TODO...

epochparamsSubspace, _ := paramsKeeper.GetSubspace(epochstoragetypes.ModuleName)
Expand Down Expand Up @@ -245,11 +252,13 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) {
)

downtimeParamsSubspace, _ := paramsKeeper.GetSubspace(downtimemoduletypes.ModuleName)
ibctransferparamsSubspace, _ := paramsKeeper.GetSubspace(ibctransfertypes.ModuleName)

ks := Keepers{}
ks.TimerStoreKeeper = timerstorekeeper.NewKeeper(cdc)
ks.AccountKeeper = mockAccountKeeper{}
ks.BankKeeper = mockBankKeeper{}
ks.IbcTransfer = NewMockIbcTransferKeeper(ibctransferStoreKey, cdc, ibctransferparamsSubspace, ks.AccountKeeper, ks.BankKeeper)
init_balance()
ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String())
ks.Distribution = distributionkeeper.NewKeeper(cdc, distributionStoreKey, ks.AccountKeeper, ks.BankKeeper, ks.StakingKeeper, authtypes.FeeCollectorName, authtypes.NewModuleAddress(govtypes.ModuleName).String())
Expand Down
103 changes: 103 additions & 0 deletions testutil/keeper/mock_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@ import (
"fmt"
"time"

"cosmossdk.io/math"
tenderminttypes "github.com/cometbft/cometbft/types"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
"github.com/cosmos/ibc-go/v7/modules/core/exported"
)

// account keeper mock
Expand Down Expand Up @@ -156,6 +164,101 @@ func (k mockBankKeeper) BlockedAddr(addr sdk.AccAddress) bool {
return false
}

// Mock IBC transfer keeper
type mockIbcTransferKeeper struct {
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
paramSpace paramstypes.Subspace
authKeeper mockAccountKeeper
bankKeeper mockBankKeeper
}

const (
MockSrcPort = "src"
MockSrcChannel = "srcc"
MockDestPort = "dest"
MockDestChannel = "destc"
)

func NewMockIbcTransferKeeper(storeKey storetypes.StoreKey, cdc codec.BinaryCodec, paramSpace paramstypes.Subspace, authKeeper mockAccountKeeper, bankKeeper mockBankKeeper) mockIbcTransferKeeper {
return mockIbcTransferKeeper{
storeKey: storeKey,
cdc: cdc,
paramSpace: paramSpace,
authKeeper: authKeeper,
bankKeeper: bankKeeper,
}
}

func (k mockIbcTransferKeeper) OnChanOpenInit(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) (string, error) {
return "", nil
}

func (k mockIbcTransferKeeper) OnChanOpenTry(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string) (version string, err error) {
return "", nil
}

func (k mockIbcTransferKeeper) OnChanOpenAck(ctx sdk.Context, portID, channelID string, counterpartyChannelID string, counterpartyVersion string) error {
return nil
}

func (k mockIbcTransferKeeper) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error {
return nil
}

func (k mockIbcTransferKeeper) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error {
return nil
}

func (k mockIbcTransferKeeper) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error {
return nil
}

func (k mockIbcTransferKeeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement {
// get data from packet
var data ibctransfertypes.FungibleTokenPacketData
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
return channeltypes.NewErrorAcknowledgement(err)
}

// parse data
senderAcc, err := sdk.AccAddressFromBech32(data.Sender)
if err != nil {
return channeltypes.NewErrorAcknowledgement(err)
}
receiverAcc, err := sdk.AccAddressFromBech32(data.Receiver)
if err != nil {
return channeltypes.NewErrorAcknowledgement(err)
}
amount, ok := math.NewIntFromString(data.Amount)
if !ok {
return channeltypes.NewErrorAcknowledgement(fmt.Errorf("invalid amount in transfer data: %s", data.Amount))
}

// sub balance from sender in original denom, add balance to receiver (on other chain) with IBC Denom
coins := sdk.NewCoins(sdk.NewCoin(data.Denom, amount))
err = k.bankKeeper.SubFromBalance(senderAcc, coins)
if err != nil {
return channeltypes.NewErrorAcknowledgement(err)
}
ibcCoins := sdk.NewCoins(ibctransfertypes.GetTransferCoin(packet.DestinationPort, packet.DestinationChannel, data.Denom, amount))
err = k.bankKeeper.AddToBalance(receiverAcc, ibcCoins)
if err != nil {
return channeltypes.NewErrorAcknowledgement(err)
}

return channeltypes.NewResultAcknowledgement([]byte{byte(1)})
}

func (k mockIbcTransferKeeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress) error {
return nil
}

func (k mockIbcTransferKeeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error {
return nil
}

// Mock BlockStore
type MockBlockStore struct {
height int64
blockHistory map[int64]*tenderminttypes.Block
Expand Down
14 changes: 14 additions & 0 deletions utils/maps/maps.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package maps

import "encoding/binary"

func FindLargestIntValueInMap[K comparable](myMap map[K]int) (K, int) {
var maxVal int
var maxKey K
Expand All @@ -15,3 +17,15 @@ func FindLargestIntValueInMap[K comparable](myMap map[K]int) (K, int) {

return maxKey, maxVal
}

// GetIDBytes returns the byte representation of the uint64 ID
func GetIDBytes(id uint64) []byte {
bz := make([]byte, 8)
binary.BigEndian.PutUint64(bz, id)
return bz
}

// GetIDFromBytes returns ID in uint64 format from a byte array
func GetIDFromBytes(bz []byte) uint64 {
return binary.BigEndian.Uint64(bz)
}
Loading

0 comments on commit faab38d

Please sign in to comment.