Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit c0b7072

Browse files
boojamyaagouinxlab
authored
Merge #86: Backports #78, #80, #81 into v6
* Fix same bool being used for all 3 (#81) * fix: middleware panic upon receiving amount that is not int64; added test (#78) resolves #77 * Fix: Allows timeout field to accept both uint64 and string durations (#80) * timeout accetps both string and time.duration * feedback * handle invalid unmarshalls * Update router/ibc_middleware.go Co-authored-by: Andrew Gouin <andrew@gouin.io> * add test case for empty valid json --------- Co-authored-by: Andrew Gouin <andrew@gouin.io> * make compliant with ibc-go version and fix lint * remove unused make test command * regen protos * add lint check to CI --------- Co-authored-by: Andrew Gouin <andrew@gouin.io> Co-authored-by: Max Kupriianov <max@kc.vc>
1 parent 6e26c54 commit c0b7072

File tree

9 files changed

+281
-72
lines changed

9 files changed

+281
-72
lines changed

.github/workflows/golangci.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: golangci-lint
2+
on:
3+
push:
4+
tags:
5+
- v*
6+
branches:
7+
- master
8+
- main
9+
pull_request:
10+
permissions:
11+
contents: read
12+
# Optional: allow read access to pull request. Use with `only-new-issues` option.
13+
# pull-requests: read
14+
jobs:
15+
golangci:
16+
name: lint
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/setup-go@v3
20+
with:
21+
go-version: 1.19
22+
- uses: actions/checkout@v3
23+
- name: golangci-lint
24+
uses: golangci/golangci-lint-action@v3
25+
with:
26+
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
27+
version: latest

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ go.sum: go.mod
176176
###############################################################################
177177

178178
test: test-unit
179-
test-all: test-unit test-ledger-mock test-race test-cover
179+
test-all: test-unit test-ledger-mock test-race
180180

181181
TEST_PACKAGES=./...
182182
TEST_TARGETS := test-unit test-unit-amino test-unit-proto test-ledger-mock test-race test-ledger test-race

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ replace (
88
)
99

1010
require (
11+
cosmossdk.io/errors v1.0.0-beta.7
1112
github.com/armon/go-metrics v0.4.1
1213
github.com/cosmos/cosmos-sdk v0.46.9
1314
github.com/cosmos/ibc-go/v6 v6.1.0
@@ -26,7 +27,6 @@ require (
2627
)
2728

2829
require (
29-
cosmossdk.io/errors v1.0.0-beta.7 // indirect
3030
cosmossdk.io/math v1.0.0-beta.4 // indirect
3131
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
3232
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect

router/ibc_middleware.go

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strings"
77
"time"
88

9+
errorsmod "cosmossdk.io/errors"
910
"github.com/armon/go-metrics"
1011
sdk "github.com/cosmos/cosmos-sdk/types"
1112
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -119,6 +120,18 @@ func getDenomForThisChain(port, channel, counterpartyPort, counterpartyChannel,
119120
return transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom()
120121
}
121122

123+
// getBoolFromAny returns the bool value is any is a valid bool, otherwise false.
124+
func getBoolFromAny(value any) bool {
125+
if value == nil {
126+
return false
127+
}
128+
boolVal, ok := value.(bool)
129+
if !ok {
130+
return false
131+
}
132+
return boolVal
133+
}
134+
122135
// OnRecvPacket checks the memo field on this packet and if the metadata inside's root key indicates this packet
123136
// should be handled by the swap middleware it attempts to perform a swap. If the swap is successful
124137
// the underlying application's OnRecvPacket callback is invoked, an ack error is returned otherwise.
@@ -136,40 +149,28 @@ func (im IBCMiddleware) OnRecvPacket(
136149
"sequence", packet.Sequence,
137150
"src-channel", packet.SourceChannel, "src-port", packet.SourcePort,
138151
"dst-channel", packet.DestinationChannel, "dst-port", packet.DestinationPort,
139-
"amount", data.Amount, "denom", data.Denom,
152+
"amount", data.Amount, "denom", data.Denom, "memo", data.Memo,
140153
)
141154

142-
m := &types.PacketMetadata{}
143-
err := json.Unmarshal([]byte(data.Memo), m)
144-
if err != nil || m.Forward == nil {
155+
d := make(map[string]interface{})
156+
err := json.Unmarshal([]byte(data.Memo), &d)
157+
if err != nil || d["forward"] == nil {
145158
// not a packet that should be forwarded
146159
im.keeper.Logger(ctx).Debug("packetForwardMiddleware OnRecvPacket forward metadata does not exist")
147160
return im.app.OnRecvPacket(ctx, packet, relayer)
148161
}
162+
m := &types.PacketMetadata{}
163+
err = json.Unmarshal([]byte(data.Memo), m)
164+
if err != nil {
165+
return channeltypes.NewErrorAcknowledgement(fmt.Errorf("packetForwardMiddleware error parsing forward metadata, %s", err))
166+
}
149167

150168
metadata := m.Forward
151169

152-
var processed, nonrefundable, disableDenomComposition bool
153170
goCtx := ctx.Context()
154-
p := goCtx.Value(types.ProcessedKey{})
155-
nr := goCtx.Value(types.NonrefundableKey{})
156-
ddc := goCtx.Value(types.DisableDenomCompositionKey{})
157-
158-
if p != nil {
159-
if pb, ok := p.(bool); ok {
160-
processed = pb
161-
}
162-
}
163-
if nr != nil {
164-
if nrb, ok := p.(bool); ok {
165-
nonrefundable = nrb
166-
}
167-
}
168-
if ddc != nil {
169-
if ddcb, ok := p.(bool); ok {
170-
disableDenomComposition = ddcb
171-
}
172-
}
171+
processed := getBoolFromAny(goCtx.Value(types.ProcessedKey{}))
172+
nonrefundable := getBoolFromAny(goCtx.Value(types.NonrefundableKey{}))
173+
disableDenomComposition := getBoolFromAny(goCtx.Value(types.DisableDenomCompositionKey{}))
173174

174175
if err := metadata.Validate(); err != nil {
175176
return channeltypes.NewErrorAcknowledgement(err)
@@ -203,10 +204,9 @@ func (im IBCMiddleware) OnRecvPacket(
203204

204205
token := sdk.NewCoin(denomOnThisChain, amountInt)
205206

206-
var timeout time.Duration
207-
if metadata.Timeout.Nanoseconds() > 0 {
208-
timeout = metadata.Timeout
209-
} else {
207+
timeout := time.Duration(metadata.Timeout)
208+
209+
if timeout.Nanoseconds() <= 0 {
210210
timeout = im.forwardTimeout
211211
}
212212

@@ -254,7 +254,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket(
254254

255255
var ack channeltypes.Acknowledgement
256256
if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil {
257-
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err)
257+
return errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err)
258258
}
259259

260260
inFlightPacket := im.keeper.GetAndClearInFlightPacket(ctx, packet.SourceChannel, packet.SourcePort, packet.Sequence)

router/keeper/keeper.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strings"
77
"time"
88

9+
errorsmod "cosmossdk.io/errors"
910
"github.com/armon/go-metrics"
1011
"github.com/cosmos/cosmos-sdk/codec"
1112
storetypes "github.com/cosmos/cosmos-sdk/store/types"
@@ -98,9 +99,9 @@ func (k *Keeper) WriteAcknowledgementForForwardedPacket(
9899
ack channeltypes.Acknowledgement,
99100
) error {
100101
// Lookup module by channel capability
101-
_, cap, err := k.channelKeeper.LookupModuleByChannel(ctx, inFlightPacket.RefundPortId, inFlightPacket.RefundChannelId)
102+
_, chanCap, err := k.channelKeeper.LookupModuleByChannel(ctx, inFlightPacket.RefundPortId, inFlightPacket.RefundChannelId)
102103
if err != nil {
103-
return sdkerrors.Wrap(err, "could not retrieve module from port-id")
104+
return errorsmod.Wrap(err, "could not retrieve module from port-id")
104105
}
105106

106107
// for forwarded packets, the funds were moved into an escrow account if the denom originated on this chain.
@@ -113,7 +114,7 @@ func (k *Keeper) WriteAcknowledgementForForwardedPacket(
113114
ackResult := fmt.Sprintf("packet forward failed after point of no return: %s", ack.GetError())
114115
newAck := channeltypes.NewResultAcknowledgement([]byte(ackResult))
115116

116-
return k.ics4Wrapper.WriteAcknowledgement(ctx, cap, channeltypes.Packet{
117+
return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, channeltypes.Packet{
117118
Data: inFlightPacket.PacketData,
118119
Sequence: inFlightPacket.RefundSequence,
119120
SourcePort: inFlightPacket.PacketSrcPortId,
@@ -181,7 +182,7 @@ func (k *Keeper) WriteAcknowledgementForForwardedPacket(
181182
}
182183
}
183184

184-
return k.ics4Wrapper.WriteAcknowledgement(ctx, cap, channeltypes.Packet{
185+
return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, channeltypes.Packet{
185186
Data: inFlightPacket.PacketData,
186187
Sequence: inFlightPacket.RefundSequence,
187188
SourcePort: inFlightPacket.PacketSrcPortId,
@@ -223,7 +224,7 @@ func (k *Keeper) ForwardTransferPacket(
223224
k.Logger(ctx).Error("packetForwardMiddleware error funding community pool",
224225
"error", err,
225226
)
226-
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
227+
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
227228
}
228229
}
229230

@@ -236,7 +237,7 @@ func (k *Keeper) ForwardTransferPacket(
236237
k.Logger(ctx).Error("packetForwardMiddleware error marshaling next as JSON",
237238
"error", err,
238239
)
239-
return sdkerrors.Wrapf(sdkerrors.ErrJSONMarshal, err.Error())
240+
return errorsmod.Wrapf(sdkerrors.ErrJSONMarshal, err.Error())
240241
}
241242
memo = string(memoBz)
242243
}
@@ -270,7 +271,7 @@ func (k *Keeper) ForwardTransferPacket(
270271
"amount", packetCoin.Amount.String(), "denom", packetCoin.Denom,
271272
"error", err,
272273
)
273-
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
274+
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
274275
}
275276

276277
// Store the following information in keeper:
@@ -304,11 +305,13 @@ func (k *Keeper) ForwardTransferPacket(
304305
store.Set(key, bz)
305306

306307
defer func() {
307-
telemetry.SetGaugeWithLabels(
308-
[]string{"tx", "msg", "ibc", "transfer"},
309-
float32(token.Amount.Int64()),
310-
[]metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, token.Denom)},
311-
)
308+
if token.Amount.IsInt64() {
309+
telemetry.SetGaugeWithLabels(
310+
[]string{"tx", "msg", "ibc", "transfer"},
311+
float32(token.Amount.Int64()),
312+
[]metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, token.Denom)},
313+
)
314+
}
312315

313316
telemetry.IncrCounterWithLabels(
314317
[]string{"ibc", types.ModuleName, "send"},

router/module_test.go

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import (
1818
)
1919

2020
var (
21-
testDenom = "uatom"
22-
testAmount = "100"
21+
testDenom = "uatom"
22+
testAmount = "100"
23+
testAmount256 = "100000000000000000000"
2324

2425
testSourcePort = "transfer"
2526
testSourceChannel = "channel-10"
@@ -65,6 +66,36 @@ func transferPacket(t *testing.T, receiver string, metadata any) channeltypes.Pa
6566
}
6667
}
6768

69+
func transferPacket256(t *testing.T, receiver string, metadata any) channeltypes.Packet {
70+
t.Helper()
71+
transferPacket := transfertypes.FungibleTokenPacketData{
72+
Denom: testDenom,
73+
Amount: testAmount256,
74+
Receiver: receiver,
75+
}
76+
77+
if metadata != nil {
78+
if mStr, ok := metadata.(string); ok {
79+
transferPacket.Memo = mStr
80+
} else {
81+
memo, err := json.Marshal(metadata)
82+
require.NoError(t, err)
83+
transferPacket.Memo = string(memo)
84+
}
85+
}
86+
87+
transferData, err := transfertypes.ModuleCdc.MarshalJSON(&transferPacket)
88+
require.NoError(t, err)
89+
90+
return channeltypes.Packet{
91+
SourcePort: testSourcePort,
92+
SourceChannel: testSourceChannel,
93+
DestinationPort: testDestinationPort,
94+
DestinationChannel: testDestinationChannel,
95+
Data: transferData,
96+
}
97+
}
98+
6899
func TestOnRecvPacket_EmptyPacket(t *testing.T) {
69100
ctl := gomock.NewController(t)
70101
defer ctl.Finish()
@@ -139,6 +170,33 @@ func TestOnRecvPacket_NoForward(t *testing.T) {
139170
require.Equal(t, "test", string(expectedAck.GetResult()))
140171
}
141172

173+
func TestOnRecvPacket_NoMemo(t *testing.T) {
174+
ctl := gomock.NewController(t)
175+
defer ctl.Finish()
176+
setup := test.NewTestSetup(t, ctl)
177+
ctx := setup.Initializer.Ctx
178+
cdc := setup.Initializer.Marshaler
179+
forwardMiddleware := setup.ForwardMiddleware
180+
181+
// Test data
182+
senderAccAddr := test.AccAddress()
183+
packet := transferPacket(t, "cosmos16plylpsgxechajltx9yeseqexzdzut9g8vla4k", "{}")
184+
185+
// Expected mocks
186+
gomock.InOrder(
187+
setup.Mocks.IBCModuleMock.EXPECT().OnRecvPacket(ctx, packet, senderAccAddr).
188+
Return(channeltypes.NewResultAcknowledgement([]byte("test"))),
189+
)
190+
191+
ack := forwardMiddleware.OnRecvPacket(ctx, packet, senderAccAddr)
192+
require.True(t, ack.Success())
193+
194+
expectedAck := &channeltypes.Acknowledgement{}
195+
err := cdc.UnmarshalJSON(ack.Acknowledgement(), expectedAck)
196+
require.NoError(t, err)
197+
require.Equal(t, "test", string(expectedAck.GetResult()))
198+
}
199+
142200
func TestOnRecvPacket_RecvPacketFailed(t *testing.T) {
143201
ctl := gomock.NewController(t)
144202
defer ctl.Finish()
@@ -229,6 +287,73 @@ func TestOnRecvPacket_ForwardNoFee(t *testing.T) {
229287
require.NoError(t, err)
230288
}
231289

290+
func TestOnRecvPacket_ForwardAmountInt256(t *testing.T) {
291+
var err error
292+
ctl := gomock.NewController(t)
293+
defer ctl.Finish()
294+
setup := test.NewTestSetup(t, ctl)
295+
ctx := setup.Initializer.Ctx
296+
cdc := setup.Initializer.Marshaler
297+
forwardMiddleware := setup.ForwardMiddleware
298+
299+
// Test data
300+
const (
301+
hostAddr = "cosmos1vzxkv3lxccnttr9rs0002s93sgw72h7ghukuhs"
302+
destAddr = "cosmos16plylpsgxechajltx9yeseqexzdzut9g8vla4k"
303+
port = "transfer"
304+
channel = "channel-0"
305+
)
306+
denom := makeIBCDenom(testDestinationPort, testDestinationChannel, testDenom)
307+
senderAccAddr := test.AccAddress()
308+
309+
amount256, ok := sdk.NewIntFromString(testAmount256)
310+
require.True(t, ok)
311+
312+
testCoin := sdk.NewCoin(denom, amount256)
313+
packetOrig := transferPacket256(t, hostAddr, &types.PacketMetadata{
314+
Forward: &types.ForwardMetadata{
315+
Receiver: destAddr,
316+
Port: port,
317+
Channel: channel,
318+
},
319+
})
320+
packetFwd := transferPacket256(t, destAddr, nil)
321+
322+
acknowledgement := channeltypes.NewResultAcknowledgement([]byte("test"))
323+
successAck := cdc.MustMarshalJSON(&acknowledgement)
324+
325+
// Expected mocks
326+
gomock.InOrder(
327+
setup.Mocks.IBCModuleMock.EXPECT().OnRecvPacket(ctx, packetOrig, senderAccAddr).
328+
Return(acknowledgement),
329+
330+
setup.Mocks.TransferKeeperMock.EXPECT().Transfer(
331+
sdk.WrapSDKContext(ctx),
332+
transfertypes.NewMsgTransfer(
333+
port,
334+
channel,
335+
testCoin,
336+
hostAddr,
337+
destAddr,
338+
keeper.DefaultTransferPacketTimeoutHeight,
339+
uint64(ctx.BlockTime().UnixNano())+uint64(keeper.DefaultForwardTransferPacketTimeoutTimestamp.Nanoseconds()),
340+
"",
341+
),
342+
).Return(&transfertypes.MsgTransferResponse{Sequence: 0}, nil),
343+
344+
setup.Mocks.IBCModuleMock.EXPECT().OnAcknowledgementPacket(ctx, packetFwd, successAck, senderAccAddr).
345+
Return(nil),
346+
)
347+
348+
// chain B with router module receives packet and forwards. ack should be nil so that it is not written yet.
349+
ack := forwardMiddleware.OnRecvPacket(ctx, packetOrig, senderAccAddr)
350+
require.Nil(t, ack)
351+
352+
// ack returned from chain C
353+
err = forwardMiddleware.OnAcknowledgementPacket(ctx, packetFwd, successAck, senderAccAddr)
354+
require.NoError(t, err)
355+
}
356+
232357
func TestOnRecvPacket_ForwardWithFee(t *testing.T) {
233358
var err error
234359
ctl := gomock.NewController(t)

0 commit comments

Comments
 (0)