diff --git a/tests/e2e/ibc_callbacks_test.go b/tests/e2e/ibc_callbacks_test.go index fe16b29a4..66a9128af 100644 --- a/tests/e2e/ibc_callbacks_test.go +++ b/tests/e2e/ibc_callbacks_test.go @@ -105,9 +105,9 @@ func TestIBCCallbacks(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { - contractAddrA, _ := chainA.InstantiateContract(codeIDonA, []byte(`{}`)) + contractAddrA := chainA.InstantiateContract(codeIDonA, []byte(`{}`)) require.NotEmpty(t, contractAddrA) - contractAddrB, _ := chainB.InstantiateContract(codeIDonB, []byte(`{}`)) + contractAddrB := chainB.InstantiateContract(codeIDonB, []byte(`{}`)) require.NotEmpty(t, contractAddrB) if spec.contractMsg.Transfer != nil && spec.contractMsg.Transfer.ToAddress == "" { @@ -123,12 +123,12 @@ func TestIBCCallbacks(t *testing.T) { Msg: contractMsgBz, Funds: oneToken, } - result, err := chainA.SendMsgs(&execMsg) + _, err = chainA.SendMsgs(&execMsg) require.NoError(t, err) if spec.expAck { // and the packet is relayed - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // then the contract on chain B should receive a receive callback var response QueryResp @@ -150,7 +150,7 @@ func TestIBCCallbacks(t *testing.T) { assert.Equal(t, []byte(`{"result":"AQ=="}`), response.IBCAckCallbacks[0].Acknowledgement.Data) } else { // and the packet times out - require.NoError(t, wasmibctesting.TimeoutPendingPackets(coord, path, result)) + require.NoError(t, wasmibctesting.TimeoutPendingPackets(coord, &chainA, path)) // then the contract on chain B should not receive anything var response QueryResp @@ -205,7 +205,7 @@ func TestIBCCallbacksWithoutEntrypoints(t *testing.T) { // when the contract on A sends an IBCMsg::Transfer to the contract on B memo := fmt.Sprintf(`{"src_callback":{"address":"%v"},"dest_callback":{"address":"%v"}}`, contractAddrA.String(), contractAddrB.String()) - result := e2e.MustExecViaReflectContract(t, chainA, contractAddrA, wasmvmtypes.CosmosMsg{ + e2e.MustExecViaReflectContract(t, chainA, contractAddrA, wasmvmtypes.CosmosMsg{ IBC: &wasmvmtypes.IBCMsg{ Transfer: &wasmvmtypes.TransferMsg{ ToAddress: contractAddrB.String(), @@ -220,5 +220,5 @@ func TestIBCCallbacksWithoutEntrypoints(t *testing.T) { }) // and the packet is relayed without problems - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) } diff --git a/tests/e2e/ibc_fees_test.go b/tests/e2e/ibc_fees_test.go index 8eba42f58..635b097a2 100644 --- a/tests/e2e/ibc_fees_test.go +++ b/tests/e2e/ibc_fees_test.go @@ -86,14 +86,14 @@ func TestIBCFeesTransfer(t *testing.T) { ibcPayloadMsg := ibctransfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, []sdk.Coin{transferCoin}, actorChainA.String(), receiver.String(), clienttypes.Height{}, uint64(time.Now().Add(time.Minute).UnixNano()), "testing", &ibctransfertypes.Forwarding{Unwind: false, Hops: []ibctransfertypes.Hop{}}) ibcPackageFee := ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) feeMsg := ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibctransfertypes.PortID, path.EndpointA.ChannelID, actorChainA.String(), nil) - result, err := chainA.SendMsgs(feeMsg, ibcPayloadMsg) + _, err = chainA.SendMsgs(feeMsg, ibcPayloadMsg) require.NoError(t, err) pendingIncentivisedPackages := appA.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainA.GetContext(), ibctransfertypes.PortID, path.EndpointA.ChannelID) assert.Len(t, pendingIncentivisedPackages, 1) require.NoError(t, err) // message committed - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // then expBalance := GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, transferCoin.Denom, transferCoin.Amount) @@ -112,14 +112,14 @@ func TestIBCFeesTransfer(t *testing.T) { ibcPayloadMsg = ibctransfertypes.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, []sdk.Coin{transferCoin}, actorChainB.String(), receiver.String(), clienttypes.Height{}, uint64(time.Now().Add(time.Minute).UnixNano()), "more testing", &ibctransfertypes.Forwarding{Unwind: false, Hops: []ibctransfertypes.Hop{}}) ibcPackageFee = ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) feeMsg = ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), nil) - result, err = chainB.SendMsgs(feeMsg, ibcPayloadMsg) + _, err = chainB.SendMsgs(feeMsg, ibcPayloadMsg) require.NoError(t, err) appB := chainB.GetWasmApp() pendingIncentivisedPackages = appB.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainB.GetContext(), ibctransfertypes.PortID, path.EndpointB.ChannelID) assert.Len(t, pendingIncentivisedPackages, 1) // when packages relayed - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // then expBalance = GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, transferCoin.Denom, transferCoin.Amount) @@ -146,11 +146,11 @@ func TestIBCFeesWasm(t *testing.T) { codeID := chainA.StoreCodeFile("./testdata/cw20_base.wasm.gz").CodeID initMsg := []byte(fmt.Sprintf(`{"decimals": 6, "name": "test", "symbol":"ALX", "initial_balances": [{"address": %q,"amount":"100000000"}] }`, actorChainA.String())) - cw20ContractAddr, _ := chainA.InstantiateContract(codeID, initMsg) + cw20ContractAddr := chainA.InstantiateContract(codeID, initMsg) initMsg = []byte(fmt.Sprintf(`{"default_timeout": 360, "gov_contract": %q, "allowlist":[{"contract":%q}]}`, actorChainA.String(), cw20ContractAddr.String())) codeID = chainA.StoreCodeFile("./testdata/cw20_ics20.wasm.gz").CodeID - ibcContractAddr, _ := chainA.InstantiateContract(codeID, initMsg) + ibcContractAddr := chainA.InstantiateContract(codeID, initMsg) ibcContractPortID := chainA.ContractInfo(ibcContractAddr).IBCPortID payee := sdk.AccAddress(bytes.Repeat([]byte{2}, address.Len)) @@ -189,13 +189,13 @@ func TestIBCFeesWasm(t *testing.T) { } ibcPackageFee := ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) feeMsg := ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibcContractPortID, path.EndpointA.ChannelID, actorChainA.String(), nil) - result, err := chainA.SendMsgs(feeMsg, &execMsg) + _, err = chainA.SendMsgs(feeMsg, &execMsg) require.NoError(t, err) pendingIncentivisedPackages := appA.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainA.GetContext(), ibcContractPortID, path.EndpointA.ChannelID) assert.Len(t, pendingIncentivisedPackages, 1) // and packages relayed - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // then // on chain A @@ -221,13 +221,13 @@ func TestIBCFeesWasm(t *testing.T) { ibcPayloadMsg := ibctransfertypes.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, []sdk.Coin{gotBalance}, actorChainB.String(), actorChainA.String(), clienttypes.Height{}, uint64(time.Now().Add(time.Minute).UnixNano()), "even more tests", &ibctransfertypes.Forwarding{Unwind: false, Hops: []ibctransfertypes.Hop{}}) ibcPackageFee = ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) feeMsg = ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), nil) - result, err = chainB.SendMsgs(feeMsg, ibcPayloadMsg) + _, err = chainB.SendMsgs(feeMsg, ibcPayloadMsg) require.NoError(t, err) pendingIncentivisedPackages = appB.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainB.GetContext(), ibctransfertypes.PortID, path.EndpointB.ChannelID) assert.Len(t, pendingIncentivisedPackages, 1) // when packages relayed - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // then // on chain A @@ -257,7 +257,7 @@ func TestIBCFeesReflect(t *testing.T) { codeID := chainA.StoreCodeFile("./testdata/reflect_2_2.wasm").CodeID initMsg := []byte("{}") - reflectContractAddr, _ := chainA.InstantiateContract(codeID, initMsg) + reflectContractAddr := chainA.InstantiateContract(codeID, initMsg) payee := sdk.AccAddress(bytes.Repeat([]byte{2}, address.Len)) oneToken := []wasmvmtypes.Coin{wasmvmtypes.NewCoin(1, sdk.DefaultBondDenom)} @@ -286,7 +286,7 @@ func TestIBCFeesReflect(t *testing.T) { require.NoError(t, err) // when reflect contract on A sends a PayPacketFee msg, followed by a transfer - result, err := ExecViaReflectContract(t, chainA, reflectContractAddr, []wasmvmtypes.CosmosMsg{ + _, err = ExecViaReflectContract(t, chainA, reflectContractAddr, []wasmvmtypes.CosmosMsg{ { IBC: &wasmvmtypes.IBCMsg{ PayPacketFee: &wasmvmtypes.PayPacketFeeMsg{ @@ -340,7 +340,7 @@ func TestIBCFeesReflect(t *testing.T) { require.NoError(t, err) // and packages relayed - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // then // on chain A diff --git a/tests/e2e/ica_test.go b/tests/e2e/ica_test.go index c6c9c1ed7..4b1e500c4 100644 --- a/tests/e2e/ica_test.go +++ b/tests/e2e/ica_test.go @@ -111,10 +111,10 @@ func TestICA(t *testing.T) { } relativeTimeout := uint64(time.Minute.Nanoseconds()) // note this is in nanoseconds msgSendTx := icacontrollertypes.NewMsgSendTx(icaControllerAddr.String(), path.EndpointA.ConnectionID, relativeTimeout, payloadPacket) - result, err := controllerChain.SendNonDefaultSenderMsgs(icaControllerKey, msgSendTx) + _, err = controllerChain.SendNonDefaultSenderMsgs(icaControllerKey, msgSendTx) require.NoError(t, err) - wasmibctesting.RelayAndAckPacket(t, path, result) + wasmibctesting.RelayAndAckPendingPackets(&controllerChain, &hostChain, path) gotBalance := hostChain.Balance(targetAddr, sdk.DefaultBondDenom) assert.Equal(t, sendCoin.String(), gotBalance.String()) diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index 6b74b98b0..eec95a9d6 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -22,7 +22,7 @@ import ( // This instance still expects the old CosmosMsg.Stargate variant instead of the new CosmosMsg.Any. func InstantiateStargateReflectContract(t *testing.T, chain wasmibctesting.WasmTestChain) sdk.AccAddress { codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_1_5.wasm").CodeID - contractAddr, _ := chain.InstantiateContract(codeID, []byte(`{}`)) + contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) require.NotEmpty(t, contractAddr) return contractAddr } @@ -30,7 +30,7 @@ func InstantiateStargateReflectContract(t *testing.T, chain wasmibctesting.WasmT // InstantiateReflectContract stores and instantiates a 2.0 reflect contract instance. func InstantiateReflectContract(t *testing.T, chain wasmibctesting.WasmTestChain) sdk.AccAddress { codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_2_0.wasm").CodeID - contractAddr, _ := chain.InstantiateContract(codeID, []byte(`{}`)) + contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) require.NotEmpty(t, contractAddr) return contractAddr } diff --git a/tests/ibctesting/chain2.go b/tests/ibctesting/chain2.go index a6df375ce..7ca115b2a 100644 --- a/tests/ibctesting/chain2.go +++ b/tests/ibctesting/chain2.go @@ -49,10 +49,27 @@ func (app WasmTestApp) GetTxConfig() client.TxConfig { type WasmTestChain struct { *ibctesting.TestChain + + PendingSendPackets []channeltypes.Packet } func NewWasmTestChain(chain *ibctesting.TestChain) WasmTestChain { - return WasmTestChain{chain} + return WasmTestChain{TestChain: chain, PendingSendPackets: []channeltypes.Packet{}} +} + +func (chain *WasmTestChain) CaptureIBCEvents(result *abci.ExecTxResult) { + toSend, _ := ibctesting.ParsePacketsFromEvents(channeltypes.EventTypeSendPacket, result.Events) + // require.NoError(chain, err) + if len(toSend) > 0 { + // Keep a queue on the chain that we can relay in tests + chain.PendingSendPackets = append(chain.PendingSendPackets, toSend...) + } +} + +func (chain *WasmTestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) { + result, err := chain.TestChain.SendMsgs(msgs...) + chain.CaptureIBCEvents(result) + return result, err } func (chain WasmTestChain) GetWasmApp() *app.WasmApp { @@ -100,7 +117,7 @@ func (chain WasmTestChain) UnwrapExecTXResult(r *abci.ExecTxResult, target proto require.NoError(chain.TB, proto.Unmarshal(wrappedRsp.MsgResponses[0].Value, target)) } -func (chain WasmTestChain) InstantiateContract(codeID uint64, initMsg []byte) (sdk.AccAddress, *abci.ExecTxResult) { +func (chain WasmTestChain) InstantiateContract(codeID uint64, initMsg []byte) sdk.AccAddress { instantiateMsg := &types.MsgInstantiateContract{ Sender: chain.SenderAccount.GetAddress().String(), Admin: chain.SenderAccount.GetAddress().String(), @@ -118,7 +135,7 @@ func (chain WasmTestChain) InstantiateContract(codeID uint64, initMsg []byte) (s a, err := sdk.AccAddressFromBech32(pExecResp.Address) require.NoError(chain.TB, err) - return a, r + return a } // SeedNewContractInstance stores some wasm code and instantiates a new contract on this chain. @@ -131,8 +148,7 @@ func (chain *WasmTestChain) SeedNewContractInstance() sdk.AccAddress { anyAddressStr := chain.SenderAccount.GetAddress().String() initMsg := []byte(fmt.Sprintf(`{"verifier": %q, "beneficiary": %q}`, anyAddressStr, anyAddressStr)) - addr, _ := chain.InstantiateContract(codeID, initMsg) - return addr + return chain.InstantiateContract(codeID, initMsg) } func (chain WasmTestChain) ContractInfo(contractAddr sdk.AccAddress) *types.ContractInfo { @@ -221,34 +237,56 @@ func (chain *WasmTestChain) SmartQuery(contractAddr string, queryMsg, response i return json.Unmarshal(resp.Data, response) } -func RelayAndAckPacket(t *testing.T, path *ibctesting.Path, result *abci.ExecTxResult) { - packet, err := ibctesting.ParsePacketFromEvents(result.Events) - require.NoError(t, err) - err = path.RelayPacket(packet) - require.NoError(t, err) +// RelayAndAckPendingPackets sends pending packages from path.EndpointA to the counterparty chain and acks +func RelayAndAckPendingPackets(chainA *WasmTestChain, chainB *WasmTestChain, path *ibctesting.Path) error { + // get all the packet to relay src->dest + src := path.EndpointA + require.NoError(chainA, src.UpdateClient()) + chainA.Logf("Relay: %d Packets A->B, %d Packets B->A\n", len(chainA.PendingSendPackets), len(chainB.PendingSendPackets)) + for _, v := range chainA.PendingSendPackets { + err := path.RelayPacket(v) + if err != nil { + return err + } + chainA.PendingSendPackets = chainA.PendingSendPackets[1:] + } + + src = path.EndpointB + require.NoError(chainB, src.UpdateClient()) + for _, v := range chainB.PendingSendPackets { + err := path.RelayPacket(v) + if err != nil { + return err + } + chainB.PendingSendPackets = chainB.PendingSendPackets[1:] + } + return nil } // TimeoutPendingPackets returns the package to source chain to let the IBC app revert any operation. // from A to B -func TimeoutPendingPackets(coord *ibctesting.Coordinator, path *ibctesting.Path, result *abci.ExecTxResult) error { +func TimeoutPendingPackets(coord *ibctesting.Coordinator, chainSrc *WasmTestChain, path *ibctesting.Path) error { src := path.EndpointA dest := path.EndpointB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) - require.NoError(coord, err) + toSend := chainSrc.PendingSendPackets + coord.Logf("Timeout %d Packets A->B\n", len(toSend)) require.NoError(coord, src.UpdateClient()) // Increment time and commit block so that 5 second delay period passes between send and receive coord.IncrementTime() coord.CommitBlock(src.Chain, dest.Chain) - // get proof of packet unreceived on dest - packetKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - proofUnreceived, proofHeight := dest.QueryProof(packetKey) - timeoutMsg := channeltypes.NewMsgTimeout(packet, packet.Sequence, proofUnreceived, proofHeight, src.Chain.SenderAccount.GetAddress().String()) - _, err = src.Chain.SendMsgs(timeoutMsg) - if err != nil { - return err + for _, packet := range toSend { + // get proof of packet unreceived on dest + packetKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + proofUnreceived, proofHeight := dest.QueryProof(packetKey) + timeoutMsg := channeltypes.NewMsgTimeout(packet, packet.Sequence, proofUnreceived, proofHeight, src.Chain.SenderAccount.GetAddress().String()) + _, err := chainSrc.SendMsgs(timeoutMsg) + if err != nil { + return err + } } + chainSrc.PendingSendPackets = nil return nil } diff --git a/tests/integration/ibc_integration_test.go b/tests/integration/ibc_integration_test.go index 472955a91..3e4332a13 100644 --- a/tests/integration/ibc_integration_test.go +++ b/tests/integration/ibc_integration_test.go @@ -87,8 +87,8 @@ func TestIBCReflectContract(t *testing.T) { // https://github.com/cosmos/cosmos-sdk/blob/31fdee0228bd6f3e787489c8e4434aabc8facb7d/x/ibc/core/04-channel/keeper/packet.go#L121-L132 // ensure the expected packet was prepared, and relay it - wasmibctesting.RelayAndAckPacket(t, path, result) - wasmibctesting.RelayAndAckPacket(t, path, result) + + wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // let's query the source contract and make sure it registered an address query := ReflectSendQueryMsg{Account: &AccountQuery{ChannelID: path.EndpointA.ChannelID}} @@ -305,7 +305,7 @@ func TestOnIBCPacketReceive(t *testing.T) { initMsg, err := json.Marshal(wasmkeeper.IBCReflectInitMsg{ReflectCodeID: reflectID}) require.NoError(t, err) codeID := chainB.StoreCodeFile("./testdata/ibc_reflect.wasm").CodeID - ibcReflectContractAddr, _ := chainB.InstantiateContract(codeID, initMsg) + ibcReflectContractAddr := chainB.InstantiateContract(codeID, initMsg) // establish IBC channels var ( @@ -323,31 +323,30 @@ func TestOnIBCPacketReceive(t *testing.T) { coord.SetupConnections(path) coord.CreateChannels(path) coord.CommitBlock(chainA.TestChain, chainB.TestChain) - // require.Equal(t, 0, len(chainA.PendingSendPackets)) - // require.Equal(t, 0, len(chainB.PendingSendPackets)) + require.Equal(t, 0, len(chainA.PendingSendPackets)) + require.Equal(t, 0, len(chainB.PendingSendPackets)) // when an ibc packet is sent from chain A to chain B - // capturedAck := mockContractEngine.SubmitIBCPacket(t, path, chainA, myMockContractAddr, spec.packetData) + capturedAck := mockContractEngine.SubmitIBCPacket(t, path, chainA, myMockContractAddr, spec.packetData) coord.CommitBlock(chainA.TestChain, chainB.TestChain) - // require.Equal(t, 1, len(chainA.PendingSendPackets)) - // require.Equal(t, 0, len(chainB.PendingSendPackets)) + require.Equal(t, 1, len(chainA.PendingSendPackets)) + require.Equal(t, 0, len(chainB.PendingSendPackets)) - // err = coord.RelayAndAckPendingPackets(path) - // wasmibctesting.RelayAndAckPacket(t, path, result) + err = wasmibctesting.RelayAndAckPendingPackets(&chainA, &chainB, path) // then if spec.expPacketNotHandled { - // const contractPanicToErrMsg = `recovered: Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: Aborted: panicked at` - // assert.ErrorContains(t, err, contractPanicToErrMsg) - // require.Nil(t, *capturedAck) + const contractPanicToErrMsg = `recovered: Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: Aborted: panicked at` + assert.ErrorContains(t, err, contractPanicToErrMsg) + require.Nil(t, *capturedAck) return } if spec.expAck != nil { - // require.NoError(t, err) - // assert.Equal(t, spec.expAck, *capturedAck, string(*capturedAck)) - // } else { - // require.Nil(t, *capturedAck) + require.NoError(t, err) + assert.Equal(t, spec.expAck, *capturedAck, string(*capturedAck)) + } else { + require.Nil(t, *capturedAck) } }) }