Skip to content

Commit

Permalink
Merge branch 'ics29-fee-middleware' into damian/760-effecient-storage
Browse files Browse the repository at this point in the history
  • Loading branch information
damiannolan authored Feb 23, 2022
2 parents 83719ee + 6999e10 commit 0555a08
Show file tree
Hide file tree
Showing 25 changed files with 455 additions and 152 deletions.
3 changes: 3 additions & 0 deletions docs/ibc/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ It contains the raw acknowledgement bytes, as well as the forward relayer addres
| ----- | ---- | ----- | ----------- |
| `result` | [bytes](#bytes) | | |
| `forward_relayer_address` | [string](#string) | | |
| `underlying_app_success` | [bool](#bool) | | |



Expand Down Expand Up @@ -865,6 +866,7 @@ RegisteredRelayerAddress contains the address and counterparty address for a spe
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | | |
| `counterparty_address` | [string](#string) | | |
| `channel_id` | [string](#string) | | |



Expand Down Expand Up @@ -1076,6 +1078,7 @@ MsgRegisterCounterpartyAddress is the request type for registering the counterpa
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | | |
| `counterparty_address` | [string](#string) | | |
| `channel_id` | [string](#string) | | |



Expand Down
4 changes: 2 additions & 2 deletions modules/apps/29-fee/client/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ func GetQueryCmd() *cobra.Command {
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: "ibc-fee",
Short: "", // TODO
Short: "Transaction subcommand for IBC relayer incentivization",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

txCmd.AddCommand(
// TODO
NewPayPacketFeeAsyncTxCmd(),
)

return txCmd
Expand Down
98 changes: 97 additions & 1 deletion modules/apps/29-fee/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,99 @@
package cli

// TODO
import (
"fmt"
"strconv"
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/spf13/cobra"

"github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
)

const (
flagRecvFee = "recv-fee"
flagAckFee = "ack-fee"
flagTimeoutFee = "timeout-fee"
)

// NewPayPacketFeeAsyncTxCmd returns the command to create a MsgPayPacketFeeAsync
func NewPayPacketFeeAsyncTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "pay-packet-fee [src-port] [src-channel] [sequence]",
Short: "Pay a fee to incentivize an existing IBC packet",
Long: strings.TrimSpace(`Pay a fee to incentivize an existing IBC packet.`),
Example: fmt.Sprintf("%s tx pay-packet-fee transfer channel-0 1 --recv-fee 10stake --ack-fee 10stake --timeout-fee 10stake", version.AppName),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

// NOTE: specifying non-nil relayers is currently unsupported
var relayers []string

sender := clientCtx.GetFromAddress().String()
seq, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return err
}

packetID := channeltypes.NewPacketId(args[1], args[0], seq)

recvFeeStr, err := cmd.Flags().GetString(flagRecvFee)
if err != nil {
return err
}

recvFee, err := sdk.ParseCoinsNormalized(recvFeeStr)
if err != nil {
return err
}

ackFeeStr, err := cmd.Flags().GetString(flagAckFee)
if err != nil {
return err
}

ackFee, err := sdk.ParseCoinsNormalized(ackFeeStr)
if err != nil {
return err
}

timeoutFeeStr, err := cmd.Flags().GetString(flagTimeoutFee)
if err != nil {
return err
}

timeoutFee, err := sdk.ParseCoinsNormalized(timeoutFeeStr)
if err != nil {
return err
}

fee := types.Fee{
RecvFee: recvFee,
AckFee: ackFee,
TimeoutFee: timeoutFee,
}

identifiedPacketFee := types.NewIdentifiedPacketFee(packetID, fee, sender, relayers)

msg := types.NewMsgPayPacketFeeAsync(identifiedPacketFee)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

cmd.Flags().String(flagRecvFee, "", "Fee paid to a relayer for relaying a packet receive.")
cmd.Flags().String(flagAckFee, "", "Fee paid to a relayer for relaying a packet acknowledgement.")
cmd.Flags().String(flagTimeoutFee, "", "Fee paid to a relayer for relaying a packet timeout.")
flags.AddTxFlagsToCmd(cmd)

return cmd
}
6 changes: 3 additions & 3 deletions modules/apps/29-fee/ibc_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (im IBCModule) OnChanOpenAck(
}

if versionMetadata.FeeVersion != types.Version {
return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected counterparty version: %s, got: %s", types.Version, versionMetadata.FeeVersion)
return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected counterparty fee version: %s, got: %s", types.Version, versionMetadata.FeeVersion)
}

// call underlying app's OnChanOpenAck callback with the counterparty app version.
Expand Down Expand Up @@ -196,15 +196,15 @@ func (im IBCModule) OnRecvPacket(

ack := im.app.OnRecvPacket(ctx, packet, relayer)

forwardRelayer, found := im.keeper.GetCounterpartyAddress(ctx, relayer.String())
forwardRelayer, found := im.keeper.GetCounterpartyAddress(ctx, relayer.String(), packet.DestinationChannel)

// incase of async aknowledgement (ack == nil) store the ForwardRelayer address for use later
if ack == nil && found {
im.keeper.SetForwardRelayerAddress(ctx, channeltypes.NewPacketId(packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence()), forwardRelayer)
return nil
}

return types.NewIncentivizedAcknowledgement(forwardRelayer, ack.Acknowledgement())
return types.NewIncentivizedAcknowledgement(forwardRelayer, ack.Acknowledgement(), ack.Success())
}

// OnAcknowledgementPacket implements the IBCModule interface
Expand Down
37 changes: 25 additions & 12 deletions modules/apps/29-fee/ibc_module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
host "github.com/cosmos/ibc-go/v3/modules/core/24-host"
"github.com/cosmos/ibc-go/v3/modules/core/exported"
ibctesting "github.com/cosmos/ibc-go/v3/testing"
ibcmock "github.com/cosmos/ibc-go/v3/testing/mock"
)
Expand Down Expand Up @@ -461,11 +462,18 @@ func (suite *FeeTestSuite) TestOnRecvPacket() {
true,
},
{
"source relayer is empty string",
"async write acknowledgement: ack is nil",
func() {
suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), "")
// setup mock callback
suite.chainB.GetSimApp().FeeMockModule.IBCApp.OnRecvPacket = func(
ctx sdk.Context,
packet channeltypes.Packet,
relayer sdk.AccAddress,
) exported.Acknowledgement {
return nil
}
},
false,
true,
true,
},
{
Expand All @@ -476,6 +484,14 @@ func (suite *FeeTestSuite) TestOnRecvPacket() {
true,
false,
},
{
"forward address is not found",
func() {
suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), "", suite.path.EndpointB.ChannelID)
},
false,
true,
},
}

for _, tc := range testCases {
Expand All @@ -498,7 +514,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() {
cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module)
suite.Require().True(ok)

suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID)

// malleate test case
tc.malleate()
Expand All @@ -509,19 +525,16 @@ func (suite *FeeTestSuite) TestOnRecvPacket() {
case !tc.feeEnabled:
suite.Require().Equal(ibcmock.MockAcknowledgement, result)

case tc.forwardRelayer:
ack := types.IncentivizedAcknowledgement{
Result: ibcmock.MockAcknowledgement.Acknowledgement(),
ForwardRelayerAddress: suite.chainB.SenderAccount.GetAddress().String(),
}
suite.Require().Equal(ack, result)
case tc.forwardRelayer && result == nil:
suite.Require().Equal(nil, result)

case !tc.forwardRelayer:
ack := types.IncentivizedAcknowledgement{
expectedAck := types.IncentivizedAcknowledgement{
Result: ibcmock.MockAcknowledgement.Acknowledgement(),
ForwardRelayerAddress: "",
UnderlyingAppSuccess: true,
}
suite.Require().Equal(ack, result)
suite.Require().Equal(expectedAck, result)
}
})
}
Expand Down
4 changes: 2 additions & 2 deletions modules/apps/29-fee/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) {
k.SetFeeInEscrow(ctx, fee)
}

for _, addr := range state.RegisteredRelayers {
k.SetCounterpartyAddress(ctx, addr.Address, addr.CounterpartyAddress)
for _, relayer := range state.RegisteredRelayers {
k.SetCounterpartyAddress(ctx, relayer.Address, relayer.CounterpartyAddress, relayer.ChannelId)
}

for _, forwardAddr := range state.ForwardRelayers {
Expand Down
5 changes: 3 additions & 2 deletions modules/apps/29-fee/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func (suite *KeeperTestSuite) TestInitGenesis() {
{
Address: sender,
CounterpartyAddress: counterparty,
ChannelId: ibctesting.FirstChannelID,
},
},
}
Expand All @@ -59,7 +60,7 @@ func (suite *KeeperTestSuite) TestInitGenesis() {
suite.Require().True(isEnabled)

// check relayers
addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainA.GetContext(), sender)
addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainA.GetContext(), sender, ibctesting.FirstChannelID)
suite.Require().True(found)
suite.Require().Equal(genesisState.RegisteredRelayers[0].CounterpartyAddress, addr)
}
Expand All @@ -84,7 +85,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() {
sender := suite.chainA.SenderAccount.GetAddress().String()
counterparty := suite.chainB.SenderAccount.GetAddress().String()
// set counterparty address
suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty)
suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID)

// set forward relayer address
suite.chainA.GetSimApp().IBCFeeKeeper.SetForwardRelayerAddress(suite.chainA.GetContext(), packetID, sender)
Expand Down
11 changes: 6 additions & 5 deletions modules/apps/29-fee/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,15 @@ func (k Keeper) DisableAllChannels(ctx sdk.Context) {

// SetCounterpartyAddress maps the destination chain relayer address to the source relayer address
// The receiving chain must store the mapping from: address -> counterpartyAddress for the given channel
func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress string) {
func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) {
store := ctx.KVStore(k.storeKey)
store.Set(types.KeyRelayerAddress(address), []byte(counterpartyAddress))
store.Set(types.KeyCounterpartyRelayer(address, channelID), []byte(counterpartyAddress))
}

// GetCounterpartyAddress gets the relayer counterparty address given a destination relayer address
func (k Keeper) GetCounterpartyAddress(ctx sdk.Context, address string) (string, bool) {
func (k Keeper) GetCounterpartyAddress(ctx sdk.Context, address, channelID string) (string, bool) {
store := ctx.KVStore(k.storeKey)
key := types.KeyRelayerAddress(address)
key := types.KeyCounterpartyRelayer(address, channelID)

if !store.Has(key) {
return "", false
Expand All @@ -156,7 +156,7 @@ func (k Keeper) GetCounterpartyAddress(ctx sdk.Context, address string) (string,
// GetAllRelayerAddresses returns all registered relayer addresses
func (k Keeper) GetAllRelayerAddresses(ctx sdk.Context) []types.RegisteredRelayerAddress {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(types.RelayerAddressKeyPrefix))
iterator := sdk.KVStorePrefixIterator(store, []byte(types.CounterpartyRelayerAddressKeyPrefix))
defer iterator.Close()

var registeredAddrArr []types.RegisteredRelayerAddress
Expand All @@ -166,6 +166,7 @@ func (k Keeper) GetAllRelayerAddresses(ctx sdk.Context) []types.RegisteredRelaye
addr := types.RegisteredRelayerAddress{
Address: keySplit[1],
CounterpartyAddress: string(iterator.Value()),
ChannelId: keySplit[2],
}

registeredAddrArr = append(registeredAddrArr, addr)
Expand Down
3 changes: 2 additions & 1 deletion modules/apps/29-fee/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,13 @@ func (suite *KeeperTestSuite) TestGetAllRelayerAddresses() {
sender := suite.chainA.SenderAccount.GetAddress().String()
counterparty := suite.chainB.SenderAccount.GetAddress().String()

suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty)
suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID)

expectedAddr := []types.RegisteredRelayerAddress{
{
Address: sender,
CounterpartyAddress: counterparty,
ChannelId: ibctesting.FirstChannelID,
},
}

Expand Down
2 changes: 1 addition & 1 deletion modules/apps/29-fee/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.Ms
ctx := sdk.UnwrapSDKContext(goCtx)

k.SetCounterpartyAddress(
ctx, msg.Address, msg.CounterpartyAddress,
ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId,
)

k.Logger(ctx).Info("Registering counterparty address for relayer.", "Address:", msg.Address, "Counterparty Address:", msg.CounterpartyAddress)
Expand Down
5 changes: 3 additions & 2 deletions modules/apps/29-fee/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper_test
import (
"github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
ibctesting "github.com/cosmos/ibc-go/v3/testing"
)

func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() {
Expand Down Expand Up @@ -35,14 +36,14 @@ func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() {
sender = suite.chainA.SenderAccount.GetAddress().String()
counterparty = suite.chainB.SenderAccount.GetAddress().String()
tc.malleate()
msg := types.NewMsgRegisterCounterpartyAddress(sender, counterparty)
msg := types.NewMsgRegisterCounterpartyAddress(sender, counterparty, ibctesting.FirstChannelID)

_, err := suite.chainA.SendMsgs(msg)

if tc.expPass {
suite.Require().NoError(err) // message committed

counterpartyAddress, _ := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(ctx, suite.chainA.SenderAccount.GetAddress().String())
counterpartyAddress, _ := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(ctx, suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID)
suite.Require().Equal(counterparty, counterpartyAddress)
} else {
suite.Require().Error(err)
Expand Down
9 changes: 7 additions & 2 deletions modules/apps/29-fee/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ func (k Keeper) SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability,

// WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function
// ICS29 WriteAcknowledgement is used for asynchronous acknowledgements
func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement []byte) error {
func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error {
if !k.IsFeeEnabled(ctx, packet.GetDestPort(), packet.GetDestChannel()) {
// ics4Wrapper may be core IBC or higher-level middleware
return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, acknowledgement)
}

// retrieve the forward relayer that was stored in `onRecvPacket`
packetId := channeltypes.NewPacketId(packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence())
relayer, _ := k.GetForwardRelayerAddress(ctx, packetId)

k.DeleteForwardRelayerAddress(ctx, packetId)

ack := types.NewIncentivizedAcknowledgement(relayer, acknowledgement)
ack := types.NewIncentivizedAcknowledgement(relayer, acknowledgement.Acknowledgement(), acknowledgement.Success())

// ics4Wrapper may be core IBC or higher-level middleware
return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack)
Expand Down
Loading

0 comments on commit 0555a08

Please sign in to comment.