Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICS 29: Fee Middleware #276

Merged
merged 87 commits into from
Apr 6, 2022
Merged
Show file tree
Hide file tree
Changes from 86 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
18feadf
scaffolding for 29-fee (#274)
colin-axner Jul 21, 2021
4b9a832
feat: adding proto files for fee payment middleware (#272)
seantking Jul 26, 2021
158a251
fix: removing unncessary fields MsgEscrow & adding query params (#300)
seantking Jul 27, 2021
c63af4a
Merge branch 'main' into ics29-fee-middleware
colin-axner Aug 12, 2021
e3704c6
feat: #258 Register Counterparty Address (#376)
seantking Sep 8, 2021
70c58af
fix: remove comments for imports (#385)
seantking Sep 9, 2021
dd4f8c7
feat: Add handshake logic to ics29 (#307)
AdityaSripal Sep 27, 2021
67bd594
Fee Middleware: Escrow logic (#465)
seantking Nov 5, 2021
405f193
feat: update protos, grpc queries (#488)
charleenfei Nov 10, 2021
8ebbe18
store refund address in IdentifiedPacketFee (#546)
AdityaSripal Nov 18, 2021
d419972
29-Fee: Genesis (#557)
seantking Nov 24, 2021
4dbc83e
feat: adding genesis validation + tests (#561)
seantking Nov 24, 2021
c4dff6c
feat: add incentivised ack proto (#564)
charleenfei Nov 29, 2021
edd11c6
Fee Closing Handshake (#551)
AdityaSripal Nov 29, 2021
885fb9a
Fee Middleware: Add ICS4 wrapper (#562)
seantking Dec 1, 2021
a737132
feat: ics 29 packet callbacks (#357)
charleenfei Dec 21, 2021
53b2f67
Merge branch 'main' of github.com:cosmos/ibc-go into ics29-fee-middle…
colin-axner Jan 12, 2022
e0cc81a
update imports to v3
colin-axner Jan 12, 2022
120fd76
regenerate proto files
colin-axner Jan 12, 2022
0fbc6bb
fix build
colin-axner Jan 12, 2022
dbda885
update ics29 to tip of main (#716)
colin-axner Jan 12, 2022
9285133
fix: event caching for fee distribution (#661)
charleenfei Jan 12, 2022
f3e9f95
ics4 callbacks fee middleware (#580)
seantking Jan 12, 2022
26731ce
chore: making PacketId non nullable (#737)
seantking Jan 18, 2022
764df84
nits: proto spacing + naming (#739)
seantking Jan 20, 2022
d761982
sean/fix-proto-identified-fee-not-null (#746)
seantking Jan 20, 2022
f552fb2
nits: more ics29 nits (#741)
seantking Jan 20, 2022
16e452b
nit: update err syntax (#747)
seantking Jan 20, 2022
b16353e
feat: adding Route, Type, GetSignBytes for all messages (#743)
seantking Jan 21, 2022
b618f02
hygiene: add validate fn for Fee (#748)
seantking Jan 21, 2022
13f77de
fix: app.go (#789)
seantking Jan 26, 2022
6cb4a38
refactor: ics29 json encoded version metadata (#883)
damiannolan Feb 9, 2022
e0161a7
Merge branch 'main' of github.com:cosmos/ibc-go into ics29-fee-middle…
colin-axner Feb 10, 2022
dedbb57
chore: bump ics29 to tip of main (#900)
colin-axner Feb 10, 2022
6f19978
fix: return nil on OnRecvPacket for async pay (#911)
seantking Feb 15, 2022
ea2984b
nit: ics29 comments (#910)
seantking Feb 15, 2022
323c574
Merge branch 'main' into ics29-fee-middleware
colin-axner Feb 15, 2022
fb243c6
chore: Add transfer test for ics29 (#901)
colin-axner Feb 16, 2022
8d226de
refactor: ics29 OnChanOpenInit callback tests now use mock module (#924)
colin-axner Feb 16, 2022
2c1ff0b
feat: allow multiple addrs to incentivize packets (#915)
damiannolan Feb 16, 2022
39ef8d7
chore: remove spec directory from ics29 (#934)
colin-axner Feb 17, 2022
1fb4b5a
refactor: use mock module for ics29 closing handshakes (#926)
colin-axner Feb 17, 2022
9895948
refactor: use mock module for ics29 grpc_query_test.go (#933)
colin-axner Feb 17, 2022
acc699d
refactor: readjust keeper_test.go to use mock module (#930)
colin-axner Feb 17, 2022
9b2d96d
fix: fields for genesis should be non nullable (#938)
seantking Feb 17, 2022
06f2730
refactor: use mock module for ics29 escrow_test.go (#932)
colin-axner Feb 17, 2022
ff15335
refactor: use mock module for ics29 genesis_test.go (#931)
colin-axner Feb 17, 2022
d8b9821
ics29:feat: emit event escrow (#914)
seantking Feb 17, 2022
adc66d2
refactor: OnRecvPacket to use mock module (#927)
colin-axner Feb 18, 2022
4326c14
refactor: ics29 OnChanOpenTry/Ack use mock module for testing instead…
colin-axner Feb 18, 2022
ad7827f
refactor: use mock module for OnAcknowledgePacket callback testing (#…
colin-axner Feb 21, 2022
7c6076f
refactor: OnTimeoutPacket to use mock module (#928)
colin-axner Feb 21, 2022
179c4f4
chore: add packet id arg to EscrowPacketFee (#951)
damiannolan Feb 21, 2022
c14d2b4
chore: remove legacy testing functions (#954)
colin-axner Feb 21, 2022
99db143
fix:ics29: WriteAck update + adding success bool to IncentivizedAck (…
seantking Feb 21, 2022
74afccd
chore: add cli cmd to incentivize existing packet (async) (#965)
colin-axner Feb 22, 2022
6928af7
ics29:fix: counterparty addr must contain channelID (#937)
seantking Feb 22, 2022
6999e10
chore: fix err msg (#971)
colin-axner Feb 22, 2022
4fb6d18
ics29:fix: store source address for query later on WriteAck (#912)
seantking Feb 23, 2022
b02d193
refactor: make fee storage more efficient (#956)
damiannolan Feb 23, 2022
15fa37b
chore: update ics29 genesis state to support multiple packet fees (#957)
damiannolan Feb 23, 2022
9350d53
chore: update MsgPayPacketFeeAsync fields (#979)
damiannolan Feb 24, 2022
f1ba06f
chore: add ParseKeyFeesInEscrow helper function (#998)
colin-axner Feb 24, 2022
fcea26d
chore: update grpc queries to handle multiple fees (#967)
damiannolan Feb 24, 2022
9c508d2
feat: CLI cmd for MsgRegisterCounterpartyAddress (#987)
seantking Feb 24, 2022
7991f79
fix: ics29: switch source with destintion for chan/port IDs (#961)
seantking Feb 25, 2022
9ece5da
test: cleanup 29-fee/types tests (#1006)
damiannolan Feb 25, 2022
f8b4345
feat: grpc query total recv packet fees (#1015)
damiannolan Mar 1, 2022
e51e2c9
chore: switch code ordering (#1025)
colin-axner Mar 1, 2022
5f8fc9f
feat: Add ParseKeyFeeEnabled and rename FeeEnabledKey -> KeyFeeEnable…
colin-axner Mar 1, 2022
4623772
feat: ics29 cli for query total recv fees (#1035)
damiannolan Mar 1, 2022
8d380ba
feat: grpc query total ack fees (#1032)
damiannolan Mar 1, 2022
9137084
feat: grpc query total timeout fees (#1033)
damiannolan Mar 2, 2022
d788adf
feat: adding clis for total ack and timeout queries (#1043)
damiannolan Mar 2, 2022
478db4f
add ParseKeyForwardRelayerAddress function + test (#1046)
charleenfei Mar 2, 2022
71167c4
chore: remove unused ics29 keeper funcs (#1044)
damiannolan Mar 3, 2022
4bf859a
chore: add gRPC for querying incentivized packets for a specific chan…
colin-axner Mar 3, 2022
b33b0a7
add function EscrowAccountHasBalance (#1042)
colin-axner Mar 3, 2022
f3ee8de
feat: ParseKeyCounterpartyRelayer function (#1047)
charleenfei Mar 3, 2022
db88c84
chore: adding queries to cmd builder (#1057)
damiannolan Mar 3, 2022
637652d
chore: update ics29 protodocs (#1055)
damiannolan Mar 4, 2022
4a0e00c
Merge branch 'main' into ics29-fee-middleware
Mar 22, 2022
ab90f07
add counter party channel ID to argument list of on channel open ack …
Mar 22, 2022
3ab2251
ADR 004: Fee module locking in the presence of severe bugs (#1060)
colin-axner Mar 29, 2022
e1cca36
nit: packetID var name (#1214)
seantking Apr 5, 2022
e65e881
Merge branch 'main' into ics29-fee-middleware
Apr 6, 2022
39d4c56
ics29: update with changes from main (#1221)
seantking Apr 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/architecture/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov
| [001](./adr-001-coin-source-tracing.md) | ICS-20 coin denomination format | Accepted, Implemented |
| [002](./adr-002-go-module-versioning.md) | Go module versioning | Accepted |
| [003](./adr-003-ics27-acknowledgement.md) | ICS27 acknowledgement format | Accepted |
| [004](./adr-004-ics29-lock-fee-module.md) | ICS29 module locking upon escrow out of balance | Accepted |
| [015](./adr-015-ibc-packet-receiver.md) | IBC Packet Routing | Accepted |
| [025](./adr-025-ibc-passive-channels.md) | IBC passive channels | Deprecated |
| [026](./adr-026-ibc-client-recovery-mechanisms.md) | IBC client recovery mechansisms | Accepted |
Expand Down
55 changes: 55 additions & 0 deletions docs/architecture/adr-004-ics29-lock-fee-module.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ADR 004: Lock fee module upon escrow out of balance

## Changelog
* 03/03/2022: initial draft

## Status

Accepted

## Context

The fee module maintains an escrow account for all fees escrowed to incentivize packet relays.
It also tracks each packet fee escrowed separately from the escrow account. This is because the escrow account only maintains a total balance. It has no reference for which coins belonged to which packet fee.
In the presence of a severe bug, it is possible the escrow balance will become out of sync with the packet fees marked as escrowed.
The ICS29 module should be capable of elegantly handling such a scenario.

## Decision

We will allow for the ICS29 module to become "locked" if the escrow balance is determined to be out of sync with the packet fees marked as escrowed.
A "locked" fee module will not allow for packet escrows to occur nor will it distribute fees. All IBC callbacks will skip performing fee logic, similar to fee disabled channels.

Manual intervention will be needed to unlock the fee module.

### Sending side

Special behaviour will have to be accounted for in `OnAcknowledgementPacket`. Since the counterparty will continue to send incentivized acknowledgements for fee enabled channels, the acknowledgement will still need to be unmarshalled into an incentivized acknowledgement before calling the underlying application `OnAcknowledgePacket` callback.

When distributing fees, a cached context should be used. If the escrow account balance would become negative, the current state changes should be discarded and the fee module should be locked using the uncached context. This prevents fees from being partially distributed for a given packetID.

### Receiving side

`OnRecvPacket` should remain unaffected by the fee module becoming locked since escrow accounts only affect the sending side.

## Consequences

### Positive

The fee module can be elegantly disabled in the presence of severe bugs.

### Negative

Extra logic is added to account for edge cases which are only possible in the presence of bugs.

### Neutral

## References

Issues:
- [#821](https://github.com/cosmos/ibc-go/issues/821)
- [#860](https://github.com/cosmos/ibc-go/issues/860)

PR's:
- [#1031](https://github.com/cosmos/ibc-go/pull/1031)
- [#1029](https://github.com/cosmos/ibc-go/pull/1029)
- [#1056](https://github.com/cosmos/ibc-go/pull/1056)
1,551 changes: 1,180 additions & 371 deletions docs/ibc/proto-docs.md

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions modules/apps/29-fee/client/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
)

// GetQueryCmd returns the query commands for 29-fee
func GetQueryCmd() *cobra.Command {
queryCmd := &cobra.Command{
Use: "ibc-fee",
Short: "", // TODO
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
}

queryCmd.AddCommand(
GetCmdTotalRecvFees(),
GetCmdTotalAckFees(),
GetCmdTotalTimeoutFees(),
)

return queryCmd
}

// NewTxCmd returns the transaction commands for 29-fee
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: "ibc-fee",
Short: "Transaction subcommand for IBC relayer incentivization",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

txCmd.AddCommand(
NewPayPacketFeeAsyncTxCmd(),
NewRegisterCounterpartyAddress(),
)

return txCmd
}
151 changes: 151 additions & 0 deletions modules/apps/29-fee/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package cli

import (
"fmt"
"strconv"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
"github.com/spf13/cobra"
)

// GetCmdTotalRecvFees returns the command handler for the Query/TotalRecvFees rpc.
func GetCmdTotalRecvFees() *cobra.Command {
cmd := &cobra.Command{
Use: "total-recv-fees [port-id] [channel-id] [sequence]",
Short: "Query the total receive fees for a packet",
Long: "Query the total receive fees for a packet",
Args: cobra.ExactArgs(3),
Example: fmt.Sprintf("%s query ibc-fee total-recv-fees transfer channel-5 100", version.AppName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

portID, channelID := args[0], args[1]
seq, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return err
}

packetID := channeltypes.NewPacketId(channelID, portID, seq)

if err := packetID.Validate(); err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryTotalRecvFeesRequest{
PacketId: packetID,
}

res, err := queryClient.TotalRecvFees(cmd.Context(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdTotalAckFees returns the command handler for the Query/TotalAckFees rpc.
func GetCmdTotalAckFees() *cobra.Command {
cmd := &cobra.Command{
Use: "total-ack-fees [port-id] [channel-id] [sequence]",
Short: "Query the total acknowledgement fees for a packet",
Long: "Query the total acknowledgement fees for a packet",
Args: cobra.ExactArgs(3),
Example: fmt.Sprintf("%s query ibc-fee total-ack-fees transfer channel-5 100", version.AppName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

portID, channelID := args[0], args[1]
seq, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return err
}

packetID := channeltypes.NewPacketId(channelID, portID, seq)

if err := packetID.Validate(); err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryTotalAckFeesRequest{
PacketId: packetID,
}

res, err := queryClient.TotalAckFees(cmd.Context(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdTotalTimeoutFees returns the command handler for the Query/TotalTimeoutFees rpc.
func GetCmdTotalTimeoutFees() *cobra.Command {
cmd := &cobra.Command{
Use: "total-timeout-fees [port-id] [channel-id] [sequence]",
Short: "Query the total timeout fees for a packet",
Long: "Query the total timeout fees for a packet",
Args: cobra.ExactArgs(3),
Example: fmt.Sprintf("%s query ibc-fee total-timeout-fees transfer channel-5 100", version.AppName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

portID, channelID := args[0], args[1]
seq, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return err
}

packetID := channeltypes.NewPacketId(channelID, portID, seq)

if err := packetID.Validate(); err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryTotalTimeoutFeesRequest{
PacketId: packetID,
}

res, err := queryClient.TotalTimeoutFees(cmd.Context(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
124 changes: 124 additions & 0 deletions modules/apps/29-fee/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package cli

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 ibc-fee 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,
}

packetFee := types.NewPacketFee(fee, sender, relayers)
msg := types.NewMsgPayPacketFeeAsync(packetID, packetFee)

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
}

// NewRegisterCounterpartyAddress returns the command to create a MsgRegisterCounterpartyAddress
func NewRegisterCounterpartyAddress() *cobra.Command {
cmd := &cobra.Command{
Use: "register-counterparty [address] [counterparty-address] [channel-id]",
Short: "Register a counterparty relayer address on a given channel.",
Long: strings.TrimSpace(`Register a counterparty relayer address on a given channel.`),
Example: fmt.Sprintf("%s tx ibc-fee register-counterparty cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 channel-0", version.AppName),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgRegisterCounterpartyAddress(args[0], args[1], args[2])

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
Loading