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

remaining review comments from #1613 #5539

Merged
merged 17 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
126 changes: 121 additions & 5 deletions e2e/tests/core/04-channel/upgrades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
test "github.com/strangelove-ventures/interchaintest/v8/testutil"
testifysuite "github.com/stretchr/testify/suite"

sdkmath "cosmossdk.io/math"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"

"github.com/cosmos/ibc-go/e2e/testsuite"
Expand Down Expand Up @@ -47,15 +48,35 @@ func (s *ChannelTestSuite) TestChannelUpgrade_WithFeeMiddleware_Succeeds() {
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()

chainAwalletAmount := ibc.WalletAmount{
Address: chainBWallet.FormattedAddress(), // destination address
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
Denom: chainADenom,
Amount: sdkmath.NewInt(testvalues.IBCTransferAmount),
}

var (
chainARelayerWallet, chainBRelayerWallet ibc.Wallet
relayerAStartingBalance int64
testFee = testvalues.DefaultFee(chainADenom)
)

s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")

// trying to create some inflight packets, although they might get relayed before the upgrade starts
t.Run("create inflight transfer packets between chain A and chain B", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
transferTxResp, err := chainA.SendIBCTransfer(ctx, channelA.ChannelID, chainAWallet.KeyName(), chainAwalletAmount, ibc.TransferOptions{})
s.Require().NoError(err)
s.Require().NoError(transferTxResp.Validate(), "chain-a ibc transfer tx is invalid")

transferTxResp = s.Transfer(ctx, chainB, chainBWallet, channelB.PortID, channelB.ChannelID, testvalues.DefaultTransferAmount(chainBDenom), chainBAddress, chainAAddress, s.GetTimeoutHeight(ctx, chainA), 0, "")
s.AssertTxSuccess(transferTxResp)
chainBwalletAmount := ibc.WalletAmount{
Address: chainAWallet.FormattedAddress(), // destination address
Denom: chainBDenom,
Amount: sdkmath.NewInt(testvalues.IBCTransferAmount),
}

transferTxResp, err = chainB.SendIBCTransfer(ctx, channelB.ChannelID, chainBWallet.KeyName(), chainBwalletAmount, ibc.TransferOptions{})
s.Require().NoError(err)
s.Require().NoError(transferTxResp.Validate(), "chain-a ibc transfer tx is invalid")
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
})

t.Run("execute gov proposal to initiate channel upgrade", func(t *testing.T) {
Expand Down Expand Up @@ -102,7 +123,7 @@ func (s *ChannelTestSuite) TestChannelUpgrade_WithFeeMiddleware_Succeeds() {
s.Require().Equal(true, feeEnabled)
})

t.Run("verify channel B upgraded and has version with ics29", func(t *testing.T) {
t.Run("verify channel B upgraded and is fee enabled", func(t *testing.T) {
channel, err := s.QueryChannel(ctx, chainB, channelB.PortID, channelB.ChannelID)
s.Require().NoError(err)

Expand All @@ -116,6 +137,101 @@ func (s *ChannelTestSuite) TestChannelUpgrade_WithFeeMiddleware_Succeeds() {
s.Require().NoError(err)
s.Require().Equal(true, feeEnabled)
})

t.Run("prune packet acknowledgements", func(t *testing.T) {
// there should be one ack for the packet that we sent before the upgrade
acks, err := s.QueryPacketAcknowledgements(ctx, chainA, channelA.PortID, channelA.ChannelID, []uint64{})
s.Require().NoError(err)
s.Require().Len(acks, 1)
s.Require().Equal(uint64(1), acks[0].Sequence)

pruneAcksTxResponse := s.PruneAcknowledgements(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, uint64(1))
s.AssertTxSuccess(pruneAcksTxResponse)

// after pruning there should not be any acks
acks, err = s.QueryPacketAcknowledgements(ctx, chainA, channelA.PortID, channelA.ChannelID, []uint64{})
s.Require().NoError(err)
s.Require().Empty(acks)
})

t.Run("stop relayer", func(t *testing.T) {
s.StopRelayer(ctx, relayer)
})

t.Run("recover relayer wallets", func(t *testing.T) {
err := s.RecoverRelayerWallets(ctx, relayer)
s.Require().NoError(err)

chainARelayerWallet, chainBRelayerWallet, err = s.GetRelayerWallets(relayer)
s.Require().NoError(err)

relayerAStartingBalance, err = s.GetChainANativeBalance(ctx, chainARelayerWallet)
s.Require().NoError(err)
t.Logf("relayer A user starting with balance: %d", relayerAStartingBalance)
})

s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")

t.Run("register and verify counterparty payee", func(t *testing.T) {
_, chainBRelayerUser := s.GetRelayerUsers(ctx)
resp := s.RegisterCounterPartyPayee(ctx, chainB, chainBRelayerUser, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID, chainBRelayerWallet.FormattedAddress(), chainARelayerWallet.FormattedAddress())
s.AssertTxSuccess(resp)

address, err := s.QueryCounterPartyPayee(ctx, chainB, chainBRelayerWallet.FormattedAddress(), channelA.Counterparty.ChannelID)
s.Require().NoError(err)
s.Require().Equal(chainARelayerWallet.FormattedAddress(), address)
})

t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer)
})

t.Run("send incentivizes packet", func(t *testing.T) {
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
// before adding fees for the packet, there should not be incentivized packets
packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelA.PortID, channelA.ChannelID)
s.Require().NoError(err)
s.Require().Empty(packets)

transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom)

payPacketFeeMsg := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil)
transferMsg := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, transferAmount, chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "")
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
resp := s.BroadcastMessages(ctx, chainA, chainAWallet, payPacketFeeMsg, transferMsg)
s.AssertTxSuccess(resp)
})

t.Run("packets are relayed", func(t *testing.T) {
packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelA.PortID, channelA.ChannelID)
s.Require().NoError(err)
s.Require().Empty(packets)
})

t.Run("tokens are received by walletB", func(t *testing.T) {
actualBalance, err := s.QueryBalance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)

// walletB has received two IBC transfers of value testvalues.IBCTransferAmount since the start of the test.
expected := 2 * testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})

t.Run("timeout fee is refunded", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
s.Require().NoError(err)

// once the relayer has relayed the packets, the timeout fee should be refunded.
// walletA has done to IBC transfers of value testvalues.IBCTransferAmount since the start of the test.
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
expected := testvalues.StartingTokenAmount - 2*testvalues.IBCTransferAmount - testFee.AckFee.AmountOf(chainADenom).Int64() - testFee.RecvFee.AmountOf(chainADenom).Int64()
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
s.Require().Equal(expected, actualBalance)
})

t.Run("relayerA is paid ack and recv fee", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainARelayerWallet)
s.Require().NoError(err)

expected := relayerAStartingBalance + testFee.AckFee.AmountOf(chainADenom).Int64() + testFee.RecvFee.AmountOf(chainADenom).Int64()
s.Require().Equal(expected, actualBalance)
})
}

// TestChannelUpgrade_WithFeeMiddleware_FailsWithTimeoutOnAck tests upgrading a transfer channel to wire up fee middleware but fails on ACK because of timeout
Expand Down
14 changes: 14 additions & 0 deletions e2e/testsuite/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,20 @@ func (s *E2ETestSuite) QueryPacketCommitment(ctx context.Context, chain ibc.Chai
return res.Commitment, nil
}

// QueryPacketAcknowledgements queries the packet acknowledgements on the given chain for the provided channel (optional) list of packet commitment sequences.
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
func (s *E2ETestSuite) QueryPacketAcknowledgements(ctx context.Context, chain ibc.Chain, portID, channelID string, packetCommitmentSequences []uint64) ([]*channeltypes.PacketState, error) {
queryClient := s.GetChainGRCPClients(chain).ChannelQueryClient
res, err := queryClient.PacketAcknowledgements(ctx, &channeltypes.QueryPacketAcknowledgementsRequest{
PortId: portID,
ChannelId: channelID,
PacketCommitmentSequences: packetCommitmentSequences,
})
if err != nil {
return nil, err
}
return res.Acknowledgements, nil
}

// QueryUpgradeError queries the upgrade error on the given chain for the provided channel.
func (s *E2ETestSuite) QueryUpgradeError(ctx context.Context, chain ibc.Chain, portID, channelID string) (channeltypes.ErrorReceipt, error) {
queryClient := s.GetChainGRCPClients(chain).ChannelQueryClient
Expand Down
12 changes: 12 additions & 0 deletions e2e/testsuite/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,15 @@ func (s *E2ETestSuite) PayPacketFeeAsync(
msg := feetypes.NewMsgPayPacketFeeAsync(packetID, packetFee)
return s.BroadcastMessages(ctx, chain, user, msg)
}

// PruneAcknowledgements broadcasts a MsgPruneAcknowledgements message.
func (s *E2ETestSuite) PruneAcknowledgements(
ctx context.Context,
chain ibc.Chain,
user ibc.Wallet,
portID, channelID string,
limit uint64,
) sdk.TxResponse {
msg := channeltypes.NewMsgPruneAcknowledgements(portID, channelID, limit, user.FormattedAddress())
return s.BroadcastMessages(ctx, chain, user, msg)
}
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,33 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() {
}
}

// OnChanUpgradeTry callback returns error on controller chains
func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() {
suite.SetupTest() // reset
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)

err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

// call application callback directly
module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID)
suite.Require().NoError(err)

app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module)
suite.Require().True(ok)
cbs, ok := app.(porttypes.UpgradableModule)
suite.Require().True(ok)

version, err := cbs.OnChanUpgradeTry(
suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID,
path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.Version,
)
suite.Require().Error(err)
suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow)
suite.Require().Equal("", version)
}

func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() {
var (
path *ibctesting.Path
Expand Down
52 changes: 52 additions & 0 deletions modules/apps/27-interchain-accounts/host/ibc_module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,33 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() {
}
}

// OnChanUpgradeInit callback returns error on host chains
func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() {
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)

err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

// call application callback directly
module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID)
suite.Require().NoError(err)

app, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module)
suite.Require().True(ok)
cbs, ok := app.(porttypes.UpgradableModule)
suite.Require().True(ok)

version, err := cbs.OnChanUpgradeInit(
suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID,
path.EndpointB.ChannelConfig.Order, []string{path.EndpointB.ConnectionID}, path.EndpointB.ChannelConfig.Version,
)

suite.Require().Error(err)
suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow)
suite.Require().Equal("", version)
}

func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() {
testCases := []struct {
name string
Expand Down Expand Up @@ -672,6 +699,31 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() {
}
}

// OnChanUpgradeAck callback returns error on host chains
func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() {
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)

err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

// call application callback directly
module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID)
suite.Require().NoError(err)

app, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module)
suite.Require().True(ok)
cbs, ok := app.(porttypes.UpgradableModule)
suite.Require().True(ok)

err = cbs.OnChanUpgradeAck(
suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.Version,
)

suite.Require().Error(err)
suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow)
}

func (suite *InterchainAccountsTestSuite) fundICAWallet(ctx sdk.Context, portID string, amount sdk.Coins) {
interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(ctx, ibctesting.FirstConnectionID, portID)
suite.Require().True(found)
Expand Down
4 changes: 3 additions & 1 deletion modules/core/04-channel/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,9 @@ func NewMsgChannelUpgradeCancel(
}
}

// ValidateBasic implements sdk.Msg
// ValidateBasic implements sdk.Msg. No checks are done for ErrorReceipt and ProofErrorReceipt
// since they are not required if the current channel state is not in FLUSHCOMPLETE and the signer
// is the designated authority (e.g. the governance module).
func (msg MsgChannelUpgradeCancel) ValidateBasic() error {
if err := host.PortIdentifierValidator(msg.PortId); err != nil {
return errorsmod.Wrap(err, "invalid port ID")
Expand Down
Loading