Add ibc-reflect test
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package wasm_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
wasmvm "github.com/CosmWasm/wasmvm/v2"
|
||||
@@ -249,6 +251,92 @@ func TestOnIBCPacketReceive(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIBCAsyncAck(t *testing.T) {
|
||||
// given 2 chains with a mock on chain A to control the IBC flow
|
||||
// and the ibc-reflect contract on chain B
|
||||
// when the no_ack package is relayed
|
||||
// then the contract does not produce an ack
|
||||
// and
|
||||
// when the async_ack message is executed on chain B
|
||||
// then the contract produces the ack
|
||||
|
||||
mockContractEngine := NewCaptureAckTestContractEngine()
|
||||
chainAOpts := []wasmkeeper.Option{
|
||||
wasmkeeper.WithWasmEngine(mockContractEngine),
|
||||
}
|
||||
var (
|
||||
coord = wasmibctesting.NewCoordinator(t, 2, chainAOpts)
|
||||
chainA = coord.GetChain(wasmibctesting.GetChainID(1))
|
||||
chainB = coord.GetChain(wasmibctesting.GetChainID(2))
|
||||
)
|
||||
// setup chain A contract metadata for mock
|
||||
myMockContractAddr := chainA.SeedNewContractInstance() // setups env but uses mock contract
|
||||
|
||||
// setup chain B contracts
|
||||
reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect_1_5.wasm").CodeID
|
||||
initMsg, err := json.Marshal(wasmkeeper.IBCReflectInitMsg{ReflectCodeID: reflectID})
|
||||
require.NoError(t, err)
|
||||
codeID := chainB.StoreCodeFile("./keeper/testdata/ibc_reflect.wasm").CodeID
|
||||
ibcReflectContractAddr := chainB.InstantiateContract(codeID, initMsg)
|
||||
|
||||
// establish IBC channels
|
||||
var (
|
||||
sourcePortID = chainA.ContractInfo(myMockContractAddr).IBCPortID
|
||||
counterpartPortID = chainB.ContractInfo(ibcReflectContractAddr).IBCPortID
|
||||
path = wasmibctesting.NewPath(chainA, chainB)
|
||||
)
|
||||
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
||||
PortID: sourcePortID, Version: "ibc-reflect-v1", Order: channeltypes.UNORDERED,
|
||||
}
|
||||
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
||||
PortID: counterpartPortID, Version: "ibc-reflect-v1", Order: channeltypes.UNORDERED,
|
||||
}
|
||||
|
||||
coord.SetupConnections(path)
|
||||
coord.CreateChannels(path)
|
||||
coord.CommitBlock(chainA, chainB)
|
||||
require.Equal(t, 0, len(chainA.PendingSendPackets))
|
||||
require.Equal(t, 0, len(chainB.PendingSendPackets))
|
||||
|
||||
// when the "no_ack" ibc packet is sent from chain A to chain B
|
||||
capturedAck := mockContractEngine.SubmitIBCPacket(t, path, chainA, myMockContractAddr, []byte(`{"no_ack":{}}`))
|
||||
coord.CommitBlock(chainA, chainB)
|
||||
|
||||
require.Equal(t, 1, len(chainA.PendingSendPackets))
|
||||
require.Equal(t, 0, len(chainB.PendingSendPackets))
|
||||
|
||||
// we don't expect an ack yet
|
||||
err = path.RelayPacketWithoutAck(chainA.PendingSendPackets[0], nil)
|
||||
noAckPacket := chainA.PendingSendPackets[0]
|
||||
chainA.PendingSendPackets = []channeltypes.Packet{}
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, *capturedAck)
|
||||
|
||||
// when the "async_ack" ibc packet is sent from chain A to chain B
|
||||
destChannel := path.EndpointB.ChannelID
|
||||
packetSeq := 1
|
||||
ackData := base64.StdEncoding.EncodeToString([]byte("my ack"))
|
||||
ack := fmt.Sprintf(`{"data":"%s", "success": true}`, ackData)
|
||||
msg := fmt.Sprintf(`{"async_ack":{"channel_id":"%s","packet_sequence": "%d", "ack": %s}}`, destChannel, packetSeq, ack)
|
||||
res, err := chainB.SendMsgs(&types.MsgExecuteContract{
|
||||
Sender: chainB.SenderAccount.GetAddress().String(),
|
||||
Contract: ibcReflectContractAddr.String(),
|
||||
Msg: []byte(msg),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// relay the ack
|
||||
err = path.EndpointA.UpdateClient()
|
||||
require.NoError(t, err)
|
||||
acknowledgement, err := wasmibctesting.ParseAckFromEvents(res.GetEvents())
|
||||
require.NoError(t, err)
|
||||
err = path.EndpointA.AcknowledgePacket(noAckPacket, acknowledgement)
|
||||
require.NoError(t, err)
|
||||
|
||||
// now ack for the no_ack packet should have arrived
|
||||
require.Equal(t, []byte("my ack"), *capturedAck)
|
||||
}
|
||||
|
||||
// mock to submit an ibc data package from given chain and capture the ack
|
||||
type captureAckTestContractEngine struct {
|
||||
*wasmtesting.MockWasmEngine
|
||||
|
||||
@@ -89,6 +89,57 @@ func (path *Path) RelayPacket(packet channeltypes.Packet, _ []byte) error {
|
||||
return fmt.Errorf("packet commitment does not exist on either endpoint for provided packet")
|
||||
}
|
||||
|
||||
// RelayPacketWithoutAck attempts to relay the packet first on EndpointA and then on EndpointB
|
||||
// if EndpointA does not contain a packet commitment for that packet. An error is returned
|
||||
// if a relay step fails or the packet commitment does not exist on either endpoint.
|
||||
// In contrast to RelayPacket, this function does not acknowledge the packet and expects it to have no acknowledgement yet.
|
||||
// It is useful for testing async acknowledgement.
|
||||
func (path *Path) RelayPacketWithoutAck(packet channeltypes.Packet, _ []byte) error {
|
||||
pc := path.EndpointA.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
||||
if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointA.Chain.App.AppCodec(), packet)) {
|
||||
|
||||
// packet found, relay from A to B
|
||||
if err := path.EndpointB.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := path.EndpointB.RecvPacketWithResult(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = ParseAckFromEvents(res.GetEvents())
|
||||
if err == nil {
|
||||
return fmt.Errorf("tried to relay packet without ack but got ack")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
pc = path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
||||
if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointB.Chain.App.AppCodec(), packet)) {
|
||||
|
||||
// packet found, relay B to A
|
||||
if err := path.EndpointA.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := path.EndpointA.RecvPacketWithResult(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = ParseAckFromEvents(res.GetEvents())
|
||||
if err == nil {
|
||||
return fmt.Errorf("tried to relay packet without ack but got ack")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("packet commitment does not exist on either endpoint for provided packet")
|
||||
}
|
||||
|
||||
// SendMsg delivers the provided messages to the chain. The counterparty
|
||||
// client is updated with the new source consensus state.
|
||||
func (path *Path) SendMsg(msgs ...sdk.Msg) error {
|
||||
|
||||
Reference in New Issue
Block a user