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
745 lines
26 KiB
Go
745 lines
26 KiB
Go
package ante_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
testifysuite "github.com/stretchr/testify/suite"
|
|
|
|
codectypes "git.cw.tr/mukan-network/mukan-sdk/codec/types"
|
|
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
|
|
|
|
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
|
|
channeltypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/types"
|
|
channeltypesv2 "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/v2/types"
|
|
commitmenttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/23-commitment/types"
|
|
host "git.cw.tr/mukan-network/mukan-ibc/modules/core/24-host"
|
|
hostv2 "git.cw.tr/mukan-network/mukan-ibc/modules/core/24-host/v2"
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/ante"
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
|
|
ibctm "git.cw.tr/mukan-network/mukan-ibc/modules/light-clients/07-tendermint"
|
|
ibctesting "git.cw.tr/mukan-network/mukan-ibc/testing"
|
|
"git.cw.tr/mukan-network/mukan-ibc/testing/mock/v2"
|
|
)
|
|
|
|
type AnteTestSuite struct {
|
|
testifysuite.Suite
|
|
|
|
coordinator *ibctesting.Coordinator
|
|
|
|
// testing chains used for convenience and readability
|
|
chainA *ibctesting.TestChain
|
|
chainB *ibctesting.TestChain
|
|
|
|
path *ibctesting.Path
|
|
}
|
|
|
|
// SetupTest creates a coordinator with 2 test chains.
|
|
func (suite *AnteTestSuite) SetupTest() {
|
|
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
|
|
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
|
|
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
|
|
// commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1)
|
|
suite.coordinator.CommitNBlocks(suite.chainA, 2)
|
|
suite.coordinator.CommitNBlocks(suite.chainB, 2)
|
|
suite.path = ibctesting.NewPath(suite.chainA, suite.chainB)
|
|
suite.path.Setup()
|
|
}
|
|
|
|
// TestAnteTestSuite runs all the tests within this package.
|
|
func TestAnteTestSuite(t *testing.T) {
|
|
testifysuite.Run(t, new(AnteTestSuite))
|
|
}
|
|
|
|
// createRecvPacketMessage creates a RecvPacket message for a packet sent from chain A to chain B.
|
|
func (suite *AnteTestSuite) createRecvPacketMessage(isRedundant bool) *channeltypes.MsgRecvPacket {
|
|
sequence, err := suite.path.EndpointA.SendPacket(clienttypes.NewHeight(2, 0), 0, ibctesting.MockPacketData)
|
|
suite.Require().NoError(err)
|
|
|
|
packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequence,
|
|
suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID,
|
|
suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID,
|
|
clienttypes.NewHeight(2, 0), 0)
|
|
|
|
if isRedundant {
|
|
err = suite.path.EndpointB.RecvPacket(packet)
|
|
suite.Require().NoError(err)
|
|
}
|
|
|
|
err = suite.path.EndpointB.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
|
proof, proofHeight := suite.chainA.QueryProof(packetKey)
|
|
|
|
return channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
|
|
}
|
|
|
|
// createRecvPacketMessageV2 creates a V2 RecvPacket message for a packet sent from chain A to chain B.
|
|
func (suite *AnteTestSuite) createRecvPacketMessageV2(isRedundant bool) *channeltypesv2.MsgRecvPacket {
|
|
packet, err := suite.path.EndpointA.MsgSendPacket(suite.chainA.GetTimeoutTimestampSecs(), mock.NewMockPayload(mock.ModuleNameA, mock.ModuleNameB))
|
|
suite.Require().NoError(err)
|
|
|
|
if isRedundant {
|
|
err = suite.path.EndpointB.MsgRecvPacket(packet)
|
|
suite.Require().NoError(err)
|
|
}
|
|
|
|
err = suite.path.EndpointB.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
packetKey := hostv2.PacketCommitmentKey(packet.SourceClient, packet.Sequence)
|
|
proof, proofHeight := suite.chainA.QueryProof(packetKey)
|
|
|
|
return channeltypesv2.NewMsgRecvPacket(packet, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
|
|
}
|
|
|
|
// createAcknowledgementMessage creates an Acknowledgement message for a packet sent from chain B to chain A.
|
|
func (suite *AnteTestSuite) createAcknowledgementMessage(isRedundant bool) sdk.Msg {
|
|
sequence, err := suite.path.EndpointB.SendPacket(clienttypes.NewHeight(2, 0), 0, ibctesting.MockPacketData)
|
|
suite.Require().NoError(err)
|
|
|
|
packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequence,
|
|
suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID,
|
|
suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID,
|
|
clienttypes.NewHeight(2, 0), 0)
|
|
err = suite.path.EndpointA.RecvPacket(packet)
|
|
suite.Require().NoError(err)
|
|
|
|
if isRedundant {
|
|
err = suite.path.EndpointB.AcknowledgePacket(packet, ibctesting.MockAcknowledgement)
|
|
suite.Require().NoError(err)
|
|
}
|
|
|
|
packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
|
proof, proofHeight := suite.chainA.QueryProof(packetKey)
|
|
|
|
return channeltypes.NewMsgAcknowledgement(packet, ibctesting.MockAcknowledgement, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
|
|
}
|
|
|
|
// createAcknowledgementMessageV2 creates a V2 Acknowledgement message for a packet sent from chain B to chain A.
|
|
func (suite *AnteTestSuite) createAcknowledgementMessageV2(isRedundant bool) *channeltypesv2.MsgAcknowledgement {
|
|
packet, err := suite.path.EndpointB.MsgSendPacket(suite.chainB.GetTimeoutTimestampSecs(), mock.NewMockPayload(mock.ModuleNameA, mock.ModuleNameB))
|
|
suite.Require().NoError(err)
|
|
|
|
err = suite.path.EndpointA.MsgRecvPacket(packet)
|
|
suite.Require().NoError(err)
|
|
|
|
ack := channeltypesv2.Acknowledgement{AppAcknowledgements: [][]byte{mock.MockRecvPacketResult.Acknowledgement}}
|
|
if isRedundant {
|
|
err = suite.path.EndpointB.MsgAcknowledgePacket(packet, ack)
|
|
suite.Require().NoError(err)
|
|
}
|
|
|
|
packetKey := hostv2.PacketAcknowledgementKey(packet.DestinationClient, packet.Sequence)
|
|
proof, proofHeight := suite.chainA.QueryProof(packetKey)
|
|
|
|
return channeltypesv2.NewMsgAcknowledgement(packet, ack, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
|
|
}
|
|
|
|
// createTimeoutMessage creates an Timeout message for a packet sent from chain B to chain A.
|
|
func (suite *AnteTestSuite) createTimeoutMessage(isRedundant bool) sdk.Msg {
|
|
height := suite.chainA.LatestCommittedHeader.GetHeight()
|
|
timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1)
|
|
|
|
sequence, err := suite.path.EndpointB.SendPacket(timeoutHeight, 0, ibctesting.MockPacketData)
|
|
suite.Require().NoError(err)
|
|
|
|
suite.coordinator.CommitNBlocks(suite.chainA, 3)
|
|
|
|
err = suite.path.EndpointB.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequence,
|
|
suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID,
|
|
suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID,
|
|
timeoutHeight, 0)
|
|
|
|
if isRedundant {
|
|
err = suite.path.EndpointB.TimeoutPacket(packet)
|
|
suite.Require().NoError(err)
|
|
}
|
|
|
|
packetKey := host.PacketReceiptKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
|
proof, proofHeight := suite.chainA.QueryProof(packetKey)
|
|
|
|
return channeltypes.NewMsgTimeout(packet, sequence, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
|
|
}
|
|
|
|
// createTimeoutMessageV2 creates a V2 Timeout message for a packet sent from chain B to chain A.
|
|
func (suite *AnteTestSuite) createTimeoutMessageV2(isRedundant bool) *channeltypesv2.MsgTimeout {
|
|
timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().Add(time.Second).Unix())
|
|
packet, err := suite.path.EndpointB.MsgSendPacket(timeoutTimestamp, mock.NewMockPayload(mock.ModuleNameA, mock.ModuleNameB))
|
|
suite.Require().NoError(err)
|
|
|
|
suite.coordinator.IncrementTimeBy(time.Hour)
|
|
err = suite.path.EndpointB.UpdateClient()
|
|
suite.Require().NoError(err)
|
|
|
|
if isRedundant {
|
|
err = suite.path.EndpointB.MsgTimeoutPacket(packet)
|
|
suite.Require().NoError(err)
|
|
}
|
|
|
|
packetKey := hostv2.PacketReceiptKey(packet.SourceClient, packet.Sequence)
|
|
proof, proofHeight := suite.chainA.QueryProof(packetKey)
|
|
|
|
return channeltypesv2.NewMsgTimeout(packet, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
|
|
}
|
|
|
|
// createTimeoutOnCloseMessage creates an TimeoutOnClose message for a packet sent from chain B to chain A.
|
|
func (suite *AnteTestSuite) createTimeoutOnCloseMessage(isRedundant bool) sdk.Msg {
|
|
height := suite.chainA.LatestCommittedHeader.GetHeight()
|
|
timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1)
|
|
|
|
sequence, err := suite.path.EndpointB.SendPacket(timeoutHeight, 0, ibctesting.MockPacketData)
|
|
suite.Require().NoError(err)
|
|
suite.path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED })
|
|
|
|
packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequence,
|
|
suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID,
|
|
suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID,
|
|
timeoutHeight, 0)
|
|
|
|
if isRedundant {
|
|
err = suite.path.EndpointB.TimeoutOnClose(packet)
|
|
suite.Require().NoError(err)
|
|
}
|
|
|
|
packetKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
|
proof, proofHeight := suite.chainA.QueryProof(packetKey)
|
|
|
|
channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel())
|
|
closedProof, _ := suite.chainA.QueryProof(channelKey)
|
|
|
|
return channeltypes.NewMsgTimeoutOnClose(packet, 1, proof, closedProof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
|
|
}
|
|
|
|
func (suite *AnteTestSuite) createUpdateClientMessage() sdk.Msg {
|
|
endpoint := suite.path.EndpointB
|
|
|
|
// ensure counterparty has committed state
|
|
endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain)
|
|
|
|
var header exported.ClientMessage
|
|
|
|
switch endpoint.ClientConfig.GetClientType() {
|
|
case exported.Tendermint:
|
|
trustedHeight := endpoint.GetClientLatestHeight()
|
|
header, _ = endpoint.Counterparty.Chain.IBCClientHeader(endpoint.Counterparty.Chain.LatestCommittedHeader, trustedHeight.(clienttypes.Height))
|
|
|
|
default:
|
|
}
|
|
|
|
msg, err := clienttypes.NewMsgUpdateClient(
|
|
endpoint.ClientID, header,
|
|
endpoint.Chain.SenderAccount.GetAddress().String(),
|
|
)
|
|
require.NoError(endpoint.Chain.TB, err)
|
|
|
|
return msg
|
|
}
|
|
|
|
func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() {
|
|
testCases := []struct {
|
|
name string
|
|
malleate func(suite *AnteTestSuite) []sdk.Msg
|
|
expError error
|
|
}{
|
|
{
|
|
"success on one new RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createRecvPacketMessage(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new V2 RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.path.SetupV2()
|
|
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createRecvPacketMessageV2(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new Acknowledgement message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
// the Acknowledgement message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createAcknowledgementMessage(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new V2 Acknowledgement message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.path.SetupV2()
|
|
// the Acknowledgement message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createAcknowledgementMessageV2(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new Timeout message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
// the Timeout message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createTimeoutMessage(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new Timeout V2 message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.path.SetupV2()
|
|
// the Timeout message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createTimeoutMessageV2(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new TimeoutOnClose message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
// the TimeoutOnClose message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createTimeoutOnCloseMessage(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on three new messages of each type",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
var msgs []sdk.Msg
|
|
|
|
// none of the messages of each type has been submitted to the chain yet,
|
|
// the first message is succeed and the next two of each type will be rejected
|
|
// because they are redundant.
|
|
|
|
// from A to B
|
|
for i := 1; i <= 3; i++ {
|
|
msgs = append(msgs, suite.createRecvPacketMessage(false))
|
|
}
|
|
|
|
// from B to A
|
|
for i := 1; i <= 9; i++ {
|
|
switch {
|
|
case i >= 1 && i <= 3:
|
|
msgs = append(msgs, suite.createAcknowledgementMessage(false))
|
|
case i >= 4 && i <= 6:
|
|
msgs = append(msgs, suite.createTimeoutMessage(false))
|
|
case i >= 7 && i <= 9:
|
|
msgs = append(msgs, suite.createTimeoutOnCloseMessage(false))
|
|
}
|
|
}
|
|
return msgs
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on three redundant messages of RecvPacket, Acknowledgement and TimeoutOnClose, and one new Timeout message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
var msgs []sdk.Msg
|
|
|
|
// we pass three messages of RecvPacket, Acknowledgement and TimeoutOnClose that
|
|
// are all redundant (i.e. those messages have already been submitted and
|
|
// processed by the chain). But these messages will not be rejected because the
|
|
// Timeout message is new.
|
|
|
|
// from A to B
|
|
for i := 1; i <= 3; i++ {
|
|
msgs = append(msgs, suite.createRecvPacketMessage(true))
|
|
}
|
|
|
|
// from B to A
|
|
for i := 1; i <= 7; i++ {
|
|
switch {
|
|
case i >= 1 && i <= 3:
|
|
msgs = append(msgs, suite.createAcknowledgementMessage(true))
|
|
case i == 4:
|
|
msgs = append(msgs, suite.createTimeoutMessage(false))
|
|
case i >= 5 && i <= 7:
|
|
msgs = append(msgs, suite.createTimeoutOnCloseMessage(true))
|
|
}
|
|
}
|
|
return msgs
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new message and two redundant messages of each type",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
var msgs []sdk.Msg
|
|
|
|
// For each type there is a new message and two messages that are redundant
|
|
// (i.e. they have been already submitted and processed by the chain). But all
|
|
// the redundant messages will not be rejected because there is a new message
|
|
// of each type.
|
|
|
|
// from A to B
|
|
for i := 1; i <= 3; i++ {
|
|
msgs = append(msgs, suite.createRecvPacketMessage(i != 2))
|
|
}
|
|
|
|
// from B to A
|
|
for i := 1; i <= 9; i++ {
|
|
switch {
|
|
case i >= 1 && i <= 3:
|
|
msgs = append(msgs, suite.createAcknowledgementMessage(i != 2))
|
|
case i >= 4 && i <= 6:
|
|
msgs = append(msgs, suite.createTimeoutMessage(i != 5))
|
|
case i >= 7 && i <= 9:
|
|
msgs = append(msgs, suite.createTimeoutOnCloseMessage(i != 8))
|
|
}
|
|
}
|
|
return msgs
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new UpdateClient message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
return []sdk.Msg{suite.createUpdateClientMessage()}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on three new UpdateClient messages",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
return []sdk.Msg{suite.createUpdateClientMessage(), suite.createUpdateClientMessage(), suite.createUpdateClientMessage()}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on three new Updateclient messages and one new RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
return []sdk.Msg{
|
|
suite.createUpdateClientMessage(),
|
|
suite.createUpdateClientMessage(),
|
|
suite.createUpdateClientMessage(),
|
|
suite.createRecvPacketMessage(false),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on three redundant RecvPacket messages and one SubmitMisbehaviour message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
msgs := []sdk.Msg{suite.createUpdateClientMessage()}
|
|
|
|
for i := 1; i <= 3; i++ {
|
|
msgs = append(msgs, suite.createRecvPacketMessage(true))
|
|
}
|
|
|
|
// append non packet and update message to msgs to ensure multimsg tx should pass
|
|
msgs = append(msgs, &clienttypes.MsgSubmitMisbehaviour{}) //nolint:staticcheck // we're using the deprecated message for testing
|
|
return msgs
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on app callback error, app callbacks are skipped for performance",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.chainB.GetSimApp().IBCMockModule.IBCApp.OnRecvPacket = func(
|
|
ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress,
|
|
) exported.Acknowledgement {
|
|
panic(errors.New("failed OnRecvPacket mock callback"))
|
|
}
|
|
|
|
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createRecvPacketMessage(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"no success on one redundant RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
return []sdk.Msg{suite.createRecvPacketMessage(true)}
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
{
|
|
"no success on one redundant V2 RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.path.SetupV2()
|
|
return []sdk.Msg{suite.createRecvPacketMessageV2(true)}
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
{
|
|
"no success on three redundant messages of each type",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
var msgs []sdk.Msg
|
|
|
|
// from A to B
|
|
for i := 1; i <= 3; i++ {
|
|
msgs = append(msgs, suite.createRecvPacketMessage(true))
|
|
}
|
|
|
|
// from B to A
|
|
for i := 1; i <= 9; i++ {
|
|
switch {
|
|
case i >= 1 && i <= 3:
|
|
msgs = append(msgs, suite.createAcknowledgementMessage(true))
|
|
case i >= 4 && i <= 6:
|
|
msgs = append(msgs, suite.createTimeoutMessage(true))
|
|
case i >= 7 && i <= 9:
|
|
msgs = append(msgs, suite.createTimeoutOnCloseMessage(true))
|
|
}
|
|
}
|
|
return msgs
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
{
|
|
"no success on one new UpdateClient message and three redundant RecvPacket messages",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
msgs := []sdk.Msg{suite.createUpdateClientMessage()}
|
|
|
|
for i := 1; i <= 3; i++ {
|
|
msgs = append(msgs, suite.createRecvPacketMessage(true))
|
|
}
|
|
|
|
return msgs
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
{
|
|
"no success on one new UpdateClient message: invalid client identifier",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
clientMsg, err := codectypes.NewAnyWithValue(&ibctm.Header{})
|
|
suite.Require().NoError(err)
|
|
|
|
msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{ClientId: ibctesting.InvalidID, ClientMessage: clientMsg}}
|
|
return msgs
|
|
},
|
|
clienttypes.ErrClientNotActive,
|
|
},
|
|
{
|
|
"no success on one new UpdateClient message: client module not found",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
clientMsg, err := codectypes.NewAnyWithValue(&ibctm.Header{})
|
|
suite.Require().NoError(err)
|
|
|
|
msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{ClientId: clienttypes.FormatClientIdentifier("08-wasm", 1), ClientMessage: clientMsg}}
|
|
return msgs
|
|
},
|
|
clienttypes.ErrClientNotActive,
|
|
},
|
|
{
|
|
"no success on one new UpdateClient message: no consensus state for trusted height",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
clientMsg, err := codectypes.NewAnyWithValue(&ibctm.Header{TrustedHeight: clienttypes.NewHeight(1, 10000)})
|
|
suite.Require().NoError(err)
|
|
|
|
msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{ClientId: suite.path.EndpointA.ClientID, ClientMessage: clientMsg}}
|
|
return msgs
|
|
},
|
|
clienttypes.ErrConsensusStateNotFound,
|
|
},
|
|
{
|
|
"no success on three new UpdateClient messages and three redundant messages of each type",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
msgs := []sdk.Msg{suite.createUpdateClientMessage(), suite.createUpdateClientMessage(), suite.createUpdateClientMessage()}
|
|
|
|
// from A to B
|
|
for i := 1; i <= 3; i++ {
|
|
msgs = append(msgs, suite.createRecvPacketMessage(true))
|
|
}
|
|
|
|
// from B to A
|
|
for i := 1; i <= 9; i++ {
|
|
switch {
|
|
case i >= 1 && i <= 3:
|
|
msgs = append(msgs, suite.createAcknowledgementMessage(true))
|
|
case i >= 4 && i <= 6:
|
|
msgs = append(msgs, suite.createTimeoutMessage(true))
|
|
case i >= 7 && i <= 9:
|
|
msgs = append(msgs, suite.createTimeoutOnCloseMessage(true))
|
|
}
|
|
}
|
|
return msgs
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
{
|
|
"no success on one new message and one invalid message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
packet := channeltypes.NewPacket(ibctesting.MockPacketData, 2,
|
|
suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID,
|
|
suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID,
|
|
clienttypes.NewHeight(2, 0), 0)
|
|
|
|
return []sdk.Msg{
|
|
suite.createRecvPacketMessage(false),
|
|
channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(1, 1), "signer"),
|
|
}
|
|
},
|
|
commitmenttypes.ErrInvalidProof,
|
|
},
|
|
{
|
|
"no success on one new message and one redundant message in the same block",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
msg := suite.createRecvPacketMessage(false)
|
|
|
|
// We want to be able to run check tx with the non-redundant message without
|
|
// committing it to a block, so that the when check tx runs with the redundant
|
|
// message they are both in the same block
|
|
k := suite.chainB.App.GetIBCKeeper()
|
|
decorator := ante.NewRedundantRelayDecorator(k)
|
|
checkCtx := suite.chainB.GetContext().WithIsCheckTx(true)
|
|
next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil }
|
|
txBuilder := suite.chainB.TxConfig.NewTxBuilder()
|
|
err := txBuilder.SetMsgs([]sdk.Msg{msg}...)
|
|
suite.Require().NoError(err)
|
|
tx := txBuilder.GetTx()
|
|
|
|
_, err = decorator.AnteHandle(checkCtx, tx, false, next)
|
|
suite.Require().NoError(err)
|
|
|
|
return []sdk.Msg{msg}
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
// reset suite
|
|
suite.SetupTest()
|
|
|
|
k := suite.chainB.App.GetIBCKeeper()
|
|
decorator := ante.NewRedundantRelayDecorator(k)
|
|
|
|
msgs := tc.malleate(suite)
|
|
|
|
deliverCtx := suite.chainB.GetContext().WithIsCheckTx(false)
|
|
checkCtx := suite.chainB.GetContext().WithIsCheckTx(true)
|
|
|
|
// create multimsg tx
|
|
txBuilder := suite.chainB.TxConfig.NewTxBuilder()
|
|
err := txBuilder.SetMsgs(msgs...)
|
|
suite.Require().NoError(err)
|
|
tx := txBuilder.GetTx()
|
|
|
|
next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil }
|
|
|
|
_, err = decorator.AnteHandle(deliverCtx, tx, false, next)
|
|
suite.Require().NoError(err, "antedecorator should not error on DeliverTx")
|
|
|
|
_, err = decorator.AnteHandle(checkCtx, tx, false, next)
|
|
if tc.expError == nil {
|
|
suite.Require().NoError(err, "non-strict decorator did not pass as expected")
|
|
} else {
|
|
suite.Require().ErrorIs(err, tc.expError, "non-strict antehandler did not return error as expected")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *AnteTestSuite) TestAnteDecoratorReCheckTx() {
|
|
testCases := []struct {
|
|
name string
|
|
malleate func(suite *AnteTestSuite) []sdk.Msg
|
|
expError error
|
|
}{
|
|
{
|
|
"success on one new RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createRecvPacketMessage(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one new V2 RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.path.SetupV2()
|
|
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createRecvPacketMessageV2(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on one redundant and one new RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
return []sdk.Msg{
|
|
suite.createRecvPacketMessage(true),
|
|
suite.createRecvPacketMessage(false),
|
|
}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on invalid proof (proof checks occur in checkTx)",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
msg := suite.createRecvPacketMessage(false)
|
|
msg.ProofCommitment = []byte("invalid-proof")
|
|
return []sdk.Msg{msg}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"success on app callback error, app callbacks are skipped for performance",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.chainB.GetSimApp().IBCMockModule.IBCApp.OnRecvPacket = func(
|
|
ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress,
|
|
) exported.Acknowledgement {
|
|
panic(errors.New("failed OnRecvPacket mock callback"))
|
|
}
|
|
|
|
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
|
|
return []sdk.Msg{suite.createRecvPacketMessage(false)}
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"no success on one redundant RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
return []sdk.Msg{suite.createRecvPacketMessage(true)}
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
{
|
|
"no success on one redundant V2 RecvPacket message",
|
|
func(suite *AnteTestSuite) []sdk.Msg {
|
|
suite.path.SetupV2()
|
|
return []sdk.Msg{suite.createRecvPacketMessageV2(true)}
|
|
},
|
|
channeltypes.ErrRedundantTx,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
// reset suite
|
|
suite.SetupTest()
|
|
|
|
k := suite.chainB.App.GetIBCKeeper()
|
|
decorator := ante.NewRedundantRelayDecorator(k)
|
|
|
|
msgs := tc.malleate(suite)
|
|
|
|
deliverCtx := suite.chainB.GetContext().WithIsCheckTx(false)
|
|
reCheckCtx := suite.chainB.GetContext().WithIsReCheckTx(true)
|
|
|
|
// create multimsg tx
|
|
txBuilder := suite.chainB.TxConfig.NewTxBuilder()
|
|
err := txBuilder.SetMsgs(msgs...)
|
|
suite.Require().NoError(err)
|
|
tx := txBuilder.GetTx()
|
|
|
|
next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil }
|
|
|
|
_, err = decorator.AnteHandle(deliverCtx, tx, false, next)
|
|
suite.Require().NoError(err, "antedecorator should not error on DeliverTx")
|
|
|
|
_, err = decorator.AnteHandle(reCheckCtx, tx, false, next)
|
|
if tc.expError == nil {
|
|
suite.Require().NoError(err, "non-strict decorator did not pass as expected")
|
|
} else {
|
|
suite.Require().ErrorIs(err, tc.expError, "non-strict antehandler did not return error as expected")
|
|
}
|
|
})
|
|
}
|
|
}
|