Skip to content

Commit

Permalink
Adopt IBC transfer tests for LikeApp
Browse files Browse the repository at this point in the history
Ref #125

Adopts transfer feature test from ibc-go, but test with LikeApp instead of SimApp

Sanity checked that iscn module exists at GetLikeApp and registry name param exists.
  • Loading branch information
elise-ng committed Mar 25, 2022
1 parent cd10d38 commit 2417cf0
Showing 1 changed file with 170 additions and 0 deletions.
170 changes: 170 additions & 0 deletions ibc_tests/transfer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package ibctests

import (
"encoding/json"
"testing"

likeapp "github.com/likecoin/likechain/app"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"

"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/ibc-go/v2/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types"
ibctesting "github.com/cosmos/ibc-go/v2/testing"
)

func SetupTestingLikeApp() (ibctesting.TestingApp, map[string]json.RawMessage) {
defaultNodeHome := "/tmp/.liked-ibc-test"
invCheckPeriod := uint(1)

db := dbm.NewMemDB()
encCdc := likeapp.MakeEncodingConfig()
app := likeapp.NewLikeApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, defaultNodeHome, invCheckPeriod, encCdc, simapp.EmptyAppOptions{})

return app, likeapp.ModuleBasics.DefaultGenesis(encCdc.Marshaler)
}

// Overrides ibc testing suite to use LikeApp for testing instead of SimApp
func init() {
ibctesting.DefaultTestingAppInit = SetupTestingLikeApp
}

// Util for casting TestingApp to LikeApp, Replacement of GetSimApp
// Replace regex /(suite.chain[A,B,C]).GetSimApp\(\)/ with GetLikeApp(suite.T(), $1) in adopted test case
func GetLikeApp(t *testing.T, chain *ibctesting.TestChain) *likeapp.LikeApp {
app, ok := chain.App.(*likeapp.LikeApp)
require.True(t, ok)

return app
}

// Adopted from https://github.com/cosmos/ibc-go/blob/v2.1.0/modules/apps/transfer/transfer_test.go
// Use LikeApp for testing instead of SimApp

type TransferTestSuite struct {
suite.Suite

coordinator *ibctesting.Coordinator

// testing chains used for convenience and readability
chainA *ibctesting.TestChain
chainB *ibctesting.TestChain
chainC *ibctesting.TestChain
}

func (suite *TransferTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3)
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}

func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
path := ibctesting.NewPath(chainA, chainB)
path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort
path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort

return path
}

// constructs a send from chainA to chainB on the established channel/connection
// and sends the same coin back from chainB to chainA.
func (suite *TransferTestSuite) TestHandleMsgTransfer() {
// setup between chainA and chainB
path := NewTransferPath(suite.chainA, suite.chainB)
suite.coordinator.Setup(path)

// originalBalance := GetLikeApp(suite.T(), suite.chainA).BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom)
timeoutHeight := clienttypes.NewHeight(0, 110)

amount, ok := sdk.NewIntFromString("9223372036854775808") // 2^63 (one above int64)
suite.Require().True(ok)
coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount)

// send from chainA to chainB
msg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0)

_, err := suite.chainA.SendMsgs(msg)
suite.Require().NoError(err) // message committed

// relay send
fungibleTokenPacket := types.NewFungibleTokenPacketData(coinToSendToB.Denom, coinToSendToB.Amount.String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0)
ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
err = path.RelayPacket(packet, ack.Acknowledgement())
suite.Require().NoError(err) // relay committed

// check that voucher exists on chain B
voucherDenomTrace := types.ParseDenomTrace(types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), sdk.DefaultBondDenom))
balance := GetLikeApp(suite.T(), suite.chainB).BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())

coinSentFromAToB := types.GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.DefaultBondDenom, amount)
suite.Require().Equal(coinSentFromAToB, balance)

// setup between chainB to chainC
// NOTE:
// pathBtoC.EndpointA = endpoint on chainB
// pathBtoC.EndpointB = endpoint on chainC
pathBtoC := NewTransferPath(suite.chainB, suite.chainC)
suite.coordinator.Setup(pathBtoC)

// send from chainB to chainC
msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, coinSentFromAToB, suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0)

_, err = suite.chainB.SendMsgs(msg)
suite.Require().NoError(err) // message committed

// relay send
// NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment
fullDenomPath := types.GetPrefixedDenom(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, voucherDenomTrace.GetFullDenomPath())
fungibleTokenPacket = types.NewFungibleTokenPacketData(voucherDenomTrace.GetFullDenomPath(), coinSentFromAToB.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String())
packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, timeoutHeight, 0)
err = pathBtoC.RelayPacket(packet, ack.Acknowledgement())
suite.Require().NoError(err) // relay committed

coinSentFromBToC := sdk.NewCoin(types.ParseDenomTrace(fullDenomPath).IBCDenom(), amount)
balance = GetLikeApp(suite.T(), suite.chainC).BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccount.GetAddress(), coinSentFromBToC.Denom)

// check that the balance is updated on chainC
suite.Require().Equal(coinSentFromBToC, balance)

// check that balance on chain B is empty
balance = GetLikeApp(suite.T(), suite.chainB).BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), coinSentFromBToC.Denom)
suite.Require().Zero(balance.Amount.Int64())

// send from chainC back to chainB
msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, coinSentFromBToC, suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0)

_, err = suite.chainC.SendMsgs(msg)
suite.Require().NoError(err) // message committed

// relay send
// NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment
fungibleTokenPacket = types.NewFungibleTokenPacketData(fullDenomPath, coinSentFromBToC.Amount.String(), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, timeoutHeight, 0)
err = pathBtoC.RelayPacket(packet, ack.Acknowledgement())
suite.Require().NoError(err) // relay committed

balance = GetLikeApp(suite.T(), suite.chainB).BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), coinSentFromAToB.Denom)

// check that the balance on chainA returned back to the original state
suite.Require().Equal(coinSentFromAToB, balance)

// check that module account escrow address is empty
escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel())
balance = GetLikeApp(suite.T(), suite.chainB).BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddress, sdk.DefaultBondDenom)
suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt()), balance)

// check that balance on chain B is empty
balance = GetLikeApp(suite.T(), suite.chainC).BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())
suite.Require().Zero(balance.Amount.Int64())
}

func TestTransferTestSuite(t *testing.T) {
suite.Run(t, new(TransferTestSuite))
}

0 comments on commit 2417cf0

Please sign in to comment.