mukan-ibc/modules/apps/callbacks/ica_test.go
Mukan Erkin Törük 88dd97a9f8
Some checks failed
CodeQL / Analyze (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Has been cancelled
refactor: replace all github.com upstream refs with git.cw.tr/mukan-network
2026-05-11 03:36:22 +03:00

210 lines
6.3 KiB
Go

package ibccallbacks_test
import (
"fmt"
"time"
"github.com/cosmos/gogoproto/proto"
sdkmath "cosmossdk.io/math"
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
stakingtypes "git.cw.tr/mukan-network/mukan-sdk/x/staking/types"
icacontrollertypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/27-interchain-accounts/controller/types"
icahosttypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/27-interchain-accounts/host/types"
icatypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/27-interchain-accounts/types"
"git.cw.tr/mukan-network/mukan-ibc/modules/apps/callbacks/testing/simapp"
"git.cw.tr/mukan-network/mukan-ibc/modules/apps/callbacks/types"
ibctesting "git.cw.tr/mukan-network/mukan-ibc/testing"
)
func (s *CallbacksTestSuite) TestICACallbacks() {
// Destination callbacks are not supported for ICA packets
testCases := []struct {
name string
icaMemo string
expCallback types.CallbackType
expSuccess bool
}{
{
"success: send ica tx with no memo",
"",
"none",
true,
},
{
"success: dest callback",
fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, simapp.SuccessContract),
"none",
true,
},
{
"success: source callback",
fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract),
types.CallbackTypeAcknowledgementPacket,
true,
},
{
"success: source callback with other json fields",
fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, simapp.SuccessContract),
types.CallbackTypeAcknowledgementPacket,
true,
},
{
"success: source callback with malformed json",
fmt.Sprintf(`{"src_callback": {"address": "%s"}, malformed}`, simapp.SuccessContract),
"none",
true,
},
{
"success: source callback with missing address",
`{"src_callback": {"address": ""}}`,
"none",
true,
},
{
"failure: source callback with low gas (panic)",
fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.OogPanicContract),
types.CallbackTypeSendPacket,
false,
},
{
"failure: source callback with low gas (error)",
fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.OogErrorContract),
types.CallbackTypeSendPacket,
false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
icaAddr := s.SetupICATest()
s.ExecuteICATx(icaAddr, tc.icaMemo)
s.AssertHasExecutedExpectedCallback(tc.expCallback, tc.expSuccess)
})
}
}
func (s *CallbacksTestSuite) TestICATimeoutCallbacks() {
// ICA channels are closed after a timeout packet is executed
testCases := []struct {
name string
icaMemo string
expCallback types.CallbackType
expSuccess bool
}{
{
"success: send ica tx timeout with no memo",
"",
"none",
true,
},
{
"success: dest callback",
fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, simapp.SuccessContract),
"none",
true,
},
{
"success: source callback",
fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract),
types.CallbackTypeTimeoutPacket,
true,
},
{
"failure: source callback with low gas (panic)",
fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.OogPanicContract),
types.CallbackTypeSendPacket,
false,
},
{
"failure: source callback with low gas (error)",
fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.OogErrorContract),
types.CallbackTypeSendPacket,
false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
icaAddr := s.SetupICATest()
s.ExecuteICATimeout(icaAddr, tc.icaMemo)
s.AssertHasExecutedExpectedCallback(tc.expCallback, tc.expSuccess)
})
}
}
// ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB
func (s *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string) {
timeoutTimestamp := uint64(s.chainA.GetContext().BlockTime().Add(time.Minute).UnixNano())
icaOwner := s.chainA.SenderAccount.GetAddress().String()
connectionID := s.path.EndpointA.ConnectionID
// build the interchain accounts packet data
packetData := s.buildICAMsgDelegatePacketData(icaAddress, memo)
msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, timeoutTimestamp, packetData)
res, err := s.chainA.SendMsgs(msg)
if err != nil {
return // we return if send packet is rejected
}
packet, err := ibctesting.ParseV1PacketFromEvents(res.GetEvents())
s.Require().NoError(err)
err = s.path.RelayPacket(packet)
s.Require().NoError(err)
}
// ExecuteICATimeout sends and times out an ICA tx
func (s *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string) {
relativeTimeout := uint64(1)
icaOwner := s.chainA.SenderAccount.GetAddress().String()
connectionID := s.path.EndpointA.ConnectionID
// build the interchain accounts packet data
packetData := s.buildICAMsgDelegatePacketData(icaAddress, memo)
msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, relativeTimeout, packetData)
res, err := s.chainA.SendMsgs(msg)
if err != nil {
return // we return if send packet is rejected
}
packet, err := ibctesting.ParseV1PacketFromEvents(res.GetEvents())
s.Require().NoError(err)
// proof query requires up to date client
err = s.path.EndpointA.UpdateClient()
s.Require().NoError(err)
err = s.path.EndpointA.TimeoutPacket(packet)
s.Require().NoError(err)
}
// buildICAMsgDelegatePacketData builds a packetData containing a stakingtypes.MsgDelegate to be executed on chainB
func (s *CallbacksTestSuite) buildICAMsgDelegatePacketData(icaAddress string, memo string) icatypes.InterchainAccountPacketData {
// prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB
validatorAddr := (sdk.ValAddress)(s.chainB.Vals.Validators[0].Address)
msgDelegate := &stakingtypes.MsgDelegate{
DelegatorAddress: icaAddress,
ValidatorAddress: validatorAddr.String(),
Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5000)),
}
// ensure chainB is allowed to execute stakingtypes.MsgDelegate
params := icahosttypes.NewParams(true, []string{sdk.MsgTypeURL(msgDelegate)})
GetSimApp(s.chainB).ICAHostKeeper.SetParams(s.chainB.GetContext(), params)
data, err := icatypes.SerializeCosmosTx(GetSimApp(s.chainA).AppCodec(), []proto.Message{msgDelegate}, icatypes.EncodingProtobuf)
s.Require().NoError(err)
icaPacketData := icatypes.InterchainAccountPacketData{
Type: icatypes.EXECUTE_TX,
Data: data,
Memo: memo,
}
return icaPacketData
}