From 7cb306829e09029a960a9398c546a7ee6e5a38a3 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 22 Nov 2022 16:14:10 +0000 Subject: [PATCH] Allow zero proof height packet recv ack timeout (#2781) --- modules/core/04-channel/types/msgs.go | 12 - modules/core/04-channel/types/msgs_test.go | 4 - .../06-solomachine/client_state.go | 3 - .../06-solomachine/client_state_test.go | 13 +- .../06-solomachine/solomachine_test.go | 96 ++++- testing/solomachine.go | 328 ++++++++++++------ 6 files changed, 318 insertions(+), 138 deletions(-) diff --git a/modules/core/04-channel/types/msgs.go b/modules/core/04-channel/types/msgs.go index b5a16b3b3e4..6792d82a478 100644 --- a/modules/core/04-channel/types/msgs.go +++ b/modules/core/04-channel/types/msgs.go @@ -323,9 +323,6 @@ func (msg MsgRecvPacket) ValidateBasic() error { if len(msg.ProofCommitment) == 0 { return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") } - if msg.ProofHeight.IsZero() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero") - } _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) @@ -372,9 +369,6 @@ func (msg MsgTimeout) ValidateBasic() error { if len(msg.ProofUnreceived) == 0 { return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty unreceived proof") } - if msg.ProofHeight.IsZero() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero") - } if msg.NextSequenceRecv == 0 { return sdkerrors.Wrap(sdkerrors.ErrInvalidSequence, "next sequence receive cannot be 0") } @@ -423,9 +417,6 @@ func (msg MsgTimeoutOnClose) ValidateBasic() error { if len(msg.ProofClose) == 0 { return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof of closed counterparty channel end") } - if msg.ProofHeight.IsZero() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero") - } _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) @@ -467,9 +458,6 @@ func (msg MsgAcknowledgement) ValidateBasic() error { if len(msg.ProofAcked) == 0 { return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "cannot submit an empty proof") } - if msg.ProofHeight.IsZero() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero") - } if len(msg.Acknowledgement) == 0 { return sdkerrors.Wrap(ErrInvalidAcknowledgement, "ack bytes cannot be empty") } diff --git a/modules/core/04-channel/types/msgs_test.go b/modules/core/04-channel/types/msgs_test.go index b14c5886383..661e17eefa7 100644 --- a/modules/core/04-channel/types/msgs_test.go +++ b/modules/core/04-channel/types/msgs_test.go @@ -315,7 +315,6 @@ func (suite *TypesTestSuite) TestMsgRecvPacketValidateBasic() { expPass bool }{ {"success", types.NewMsgRecvPacket(packet, suite.proof, height, addr), true}, - {"proof height is zero", types.NewMsgRecvPacket(packet, suite.proof, clienttypes.ZeroHeight(), addr), false}, {"proof contain empty proof", types.NewMsgRecvPacket(packet, emptyProof, height, addr), false}, {"missing signer address", types.NewMsgRecvPacket(packet, suite.proof, height, emptyAddr), false}, {"invalid packet", types.NewMsgRecvPacket(invalidPacket, suite.proof, height, addr), false}, @@ -351,7 +350,6 @@ func (suite *TypesTestSuite) TestMsgTimeoutValidateBasic() { expPass bool }{ {"success", types.NewMsgTimeout(packet, 1, suite.proof, height, addr), true}, - {"proof height must be > 0", types.NewMsgTimeout(packet, 1, suite.proof, clienttypes.ZeroHeight(), addr), false}, {"seq 0", types.NewMsgTimeout(packet, 0, suite.proof, height, addr), false}, {"missing signer address", types.NewMsgTimeout(packet, 1, suite.proof, height, emptyAddr), false}, {"cannot submit an empty proof", types.NewMsgTimeout(packet, 1, emptyProof, height, addr), false}, @@ -383,7 +381,6 @@ func (suite *TypesTestSuite) TestMsgTimeoutOnCloseValidateBasic() { {"seq 0", types.NewMsgTimeoutOnClose(packet, 0, suite.proof, suite.proof, height, addr), false}, {"empty proof", types.NewMsgTimeoutOnClose(packet, 1, emptyProof, suite.proof, height, addr), false}, {"empty proof close", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, emptyProof, height, addr), false}, - {"proof height is zero", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, clienttypes.ZeroHeight(), addr), false}, {"signer address is empty", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, emptyAddr), false}, {"invalid packet", types.NewMsgTimeoutOnClose(invalidPacket, 1, suite.proof, suite.proof, height, addr), false}, } @@ -410,7 +407,6 @@ func (suite *TypesTestSuite) TestMsgAcknowledgementValidateBasic() { expPass bool }{ {"success", types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, height, addr), true}, - {"proof height must be > 0", types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, clienttypes.ZeroHeight(), addr), false}, {"empty ack", types.NewMsgAcknowledgement(packet, nil, suite.proof, height, addr), false}, {"missing signer address", types.NewMsgAcknowledgement(packet, packet.GetData(), suite.proof, height, emptyAddr), false}, {"cannot submit an empty proof", types.NewMsgAcknowledgement(packet, packet.GetData(), emptyProof, height, addr), false}, diff --git a/modules/light-clients/06-solomachine/client_state.go b/modules/light-clients/06-solomachine/client_state.go index ded76f9617d..e24b0bb7890 100644 --- a/modules/light-clients/06-solomachine/client_state.go +++ b/modules/light-clients/06-solomachine/client_state.go @@ -46,9 +46,6 @@ func (cs ClientState) GetTimestampAtHeight( cdc codec.BinaryCodec, height exported.Height, ) (uint64, error) { - if !cs.GetLatestHeight().EQ(height) { - return 0, sdkerrors.Wrapf(ErrInvalidSequence, "not latest height (%s)", height) - } return cs.ConsensusState.Timestamp, nil } diff --git a/modules/light-clients/06-solomachine/client_state_test.go b/modules/light-clients/06-solomachine/client_state_test.go index 14c7361753d..534dbc6ac81 100644 --- a/modules/light-clients/06-solomachine/client_state_test.go +++ b/modules/light-clients/06-solomachine/client_state_test.go @@ -345,7 +345,7 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() { ) commitmentBz := channeltypes.CommitPacket(suite.chainA.Codec, packet) - path = sm.GetPacketCommitmentPath(ibctesting.MockPort, ibctesting.FirstChannelID) + path = sm.GetPacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) signBytes = solomachine.SignBytes{ Sequence: sm.Sequence, Timestamp: sm.Time, @@ -372,7 +372,7 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() { { "success: packet acknowledgement verification", func() { - path = sm.GetPacketAcknowledgementPath(ibctesting.MockPort, ibctesting.FirstChannelID) + path = sm.GetPacketAcknowledgementPath(ibctesting.MockPort, ibctesting.FirstChannelID, 1) signBytes = solomachine.SignBytes{ Sequence: sm.Sequence, Timestamp: sm.Time, @@ -399,7 +399,7 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() { { "success: packet receipt verification", func() { - path = sm.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID) + path = sm.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID, 1) signBytes = solomachine.SignBytes{ Sequence: sm.Sequence, Timestamp: sm.Time, @@ -608,7 +608,7 @@ func (suite *SoloMachineTestSuite) TestVerifyNonMembership() { { "success: packet receipt absence verification", func() { - path = suite.solomachine.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID) + path = suite.solomachine.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID, 1) signBytes = solomachine.SignBytes{ Sequence: sm.GetHeight().GetRevisionHeight(), Timestamp: sm.Time, @@ -794,11 +794,6 @@ func (suite *SoloMachineTestSuite) TestGetTimestampAtHeight() { expValue: suite.solomachine.ClientState().ConsensusState.Timestamp, expPass: true, }, - { - name: "get timestamp at height not exists", - clientState: suite.solomachine.ClientState(), - height: suite.solomachine.ClientState().GetLatestHeight().Increment(), - }, } for i, tc := range testCases { diff --git a/modules/light-clients/06-solomachine/solomachine_test.go b/modules/light-clients/06-solomachine/solomachine_test.go index f5c590bfed8..5d27e2edf8e 100644 --- a/modules/light-clients/06-solomachine/solomachine_test.go +++ b/modules/light-clients/06-solomachine/solomachine_test.go @@ -2,6 +2,7 @@ package solomachine_test import ( "testing" + "time" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" @@ -11,10 +12,17 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v6/modules/core/24-host" "github.com/cosmos/ibc-go/v6/modules/core/exported" solomachine "github.com/cosmos/ibc-go/v6/modules/light-clients/06-solomachine" ibctesting "github.com/cosmos/ibc-go/v6/testing" + "github.com/cosmos/ibc-go/v6/testing/mock" +) + +var ( + channelIDSolomachine = "channel-on-solomachine" // channelID generated on solo machine side ) type SoloMachineTestSuite struct { @@ -46,7 +54,7 @@ func TestSoloMachineTestSuite(t *testing.T) { suite.Run(t, new(SoloMachineTestSuite)) } -func (suite *SoloMachineTestSuite) TestSolomachineSetup() { +func (suite *SoloMachineTestSuite) SetupSolomachine() string { clientID := suite.solomachine.CreateClient(suite.chainA) connectionID := suite.solomachine.ConnOpenInit(suite.chainA, clientID) @@ -65,11 +73,97 @@ func (suite *SoloMachineTestSuite) TestSolomachineSetup() { // open confirm is not necessary as the solo machine implementation is mocked + return channelID +} + +func (suite *SoloMachineTestSuite) TestRecvPacket() { + channelID := suite.SetupSolomachine() + + packet := channeltypes.NewPacket( + mock.MockPacketData, + 1, + mock.PortID, + channelIDSolomachine, + mock.PortID, + channelID, + clienttypes.ZeroHeight(), + uint64(suite.chainA.GetContext().BlockTime().Add(time.Hour).UnixNano()), + ) + + // send packet is not necessary as the solo machine implementation is mocked + + suite.solomachine.RecvPacket(suite.chainA, packet) + + // close init is not necessary as the solomachine implementation is mocked + + suite.solomachine.ChanCloseConfirm(suite.chainA, channelID) +} + +func (suite *SoloMachineTestSuite) TestAcknowledgePacket() { + channelID := suite.SetupSolomachine() + + packet := channeltypes.NewPacket( + mock.MockPacketData, + 1, + mock.PortID, + channelID, + mock.PortID, + channelIDSolomachine, + clienttypes.ZeroHeight(), + uint64(suite.chainA.GetContext().BlockTime().Add(time.Hour).UnixNano()), + ) + + suite.solomachine.SendPacket(suite.chainA, packet) + + // recv packet is not necessary as the solo machine implementation is mocked + + suite.solomachine.AcknowledgePacket(suite.chainA, packet) + // close init is not necessary as the solomachine implementation is mocked suite.solomachine.ChanCloseConfirm(suite.chainA, channelID) } +func (suite *SoloMachineTestSuite) TestTimeout() { + channelID := suite.SetupSolomachine() + + packet := channeltypes.NewPacket( + mock.MockPacketData, + 1, + mock.PortID, + channelID, + mock.PortID, + channelIDSolomachine, + clienttypes.ZeroHeight(), + 1, + ) + + suite.solomachine.SendPacket(suite.chainA, packet) + + suite.solomachine.TimeoutPacket(suite.chainA, packet) + + suite.solomachine.ChanCloseConfirm(suite.chainA, channelID) +} + +func (suite *SoloMachineTestSuite) TestTimeoutOnClose() { + channelID := suite.SetupSolomachine() + + packet := channeltypes.NewPacket( + mock.MockPacketData, + 1, + mock.PortID, + channelID, + mock.PortID, + channelIDSolomachine, + clienttypes.ZeroHeight(), + 1, + ) + + suite.solomachine.SendPacket(suite.chainA, packet) + + suite.solomachine.TimeoutPacketOnClose(suite.chainA, packet, channelID) +} + func (suite *SoloMachineTestSuite) GetSequenceFromStore() uint64 { bz := suite.store.Get(host.ClientStateKey()) suite.Require().NotNil(bz) diff --git a/testing/solomachine.go b/testing/solomachine.go index 497aa623b7c..c1ff12f2a12 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -129,6 +129,121 @@ func (solo *Solomachine) CreateClient(chain *TestChain) string { return clientID } +// CreateHeader generates a new private/public key pair and creates the +// necessary signature to construct a valid solo machine header. +// A new diversifier will be used as well +func (solo *Solomachine) CreateHeader(newDiversifier string) *solomachine.Header { + // generate new private keys and signature for header + newPrivKeys, newPubKeys, newPubKey := GenerateKeys(solo.t, uint64(len(solo.PrivateKeys))) + + publicKey, err := codectypes.NewAnyWithValue(newPubKey) + require.NoError(solo.t, err) + + data := &solomachine.HeaderData{ + NewPubKey: publicKey, + NewDiversifier: newDiversifier, + } + + dataBz, err := solo.cdc.Marshal(data) + require.NoError(solo.t, err) + + signBytes := &solomachine.SignBytes{ + Sequence: solo.Sequence, + Timestamp: solo.Time, + Diversifier: solo.Diversifier, + Path: []byte{}, + Data: dataBz, + } + + bz, err := solo.cdc.Marshal(signBytes) + require.NoError(solo.t, err) + + sig := solo.GenerateSignature(bz) + + header := &solomachine.Header{ + Sequence: solo.Sequence, + Timestamp: solo.Time, + Signature: sig, + NewPublicKey: publicKey, + NewDiversifier: newDiversifier, + } + + // assumes successful header update + solo.Sequence++ + solo.PrivateKeys = newPrivKeys + solo.PublicKeys = newPubKeys + solo.PublicKey = newPubKey + solo.Diversifier = newDiversifier + + return header +} + +// CreateMisbehaviour constructs testing misbehaviour for the solo machine client +// by signing over two different data bytes at the same sequence. +func (solo *Solomachine) CreateMisbehaviour() *solomachine.Misbehaviour { + merklePath := solo.GetClientStatePath("counterparty") + path, err := solo.cdc.Marshal(&merklePath) + require.NoError(solo.t, err) + + data, err := solo.cdc.Marshal(solo.ClientState()) + require.NoError(solo.t, err) + + signBytes := &solomachine.SignBytes{ + Sequence: solo.Sequence, + Timestamp: solo.Time, + Diversifier: solo.Diversifier, + Path: path, + Data: data, + } + + bz, err := solo.cdc.Marshal(signBytes) + require.NoError(solo.t, err) + + sig := solo.GenerateSignature(bz) + signatureOne := solomachine.SignatureAndData{ + Signature: sig, + Path: path, + Data: data, + Timestamp: solo.Time, + } + + // misbehaviour signaturess can have different timestamps + solo.Time++ + + merklePath = solo.GetConsensusStatePath("counterparty", clienttypes.NewHeight(0, 1)) + path, err = solo.cdc.Marshal(&merklePath) + require.NoError(solo.t, err) + + data, err = solo.cdc.Marshal(solo.ConsensusState()) + require.NoError(solo.t, err) + + signBytes = &solomachine.SignBytes{ + Sequence: solo.Sequence, + Timestamp: solo.Time, + Diversifier: solo.Diversifier, + Path: path, + Data: data, + } + + bz, err = solo.cdc.Marshal(signBytes) + require.NoError(solo.t, err) + + sig = solo.GenerateSignature(bz) + signatureTwo := solomachine.SignatureAndData{ + Signature: sig, + Path: path, + Data: data, + Timestamp: solo.Time, + } + + return &solomachine.Misbehaviour{ + ClientId: solo.ClientID, + Sequence: solo.Sequence, + SignatureOne: &signatureOne, + SignatureTwo: &signatureTwo, + } +} + // ConnOpenInit initializes a connection on the provided chain given a solo machine clientID. func (solo *Solomachine) ConnOpenInit(chain *TestChain, clientID string) string { msgConnOpenInit := connectiontypes.NewMsgConnectionOpenInit( @@ -217,7 +332,7 @@ func (solo *Solomachine) ChanOpenAck(chain *TestChain, channelID string) { // ChanCloseConfirm performs the channel close confirm handshake step on the tendermint chain for the associated // solo machine client. func (solo *Solomachine) ChanCloseConfirm(chain *TestChain, channelID string) { - proofInit := solo.GenerateChanCloseInitProof(channelID) + proofInit := solo.GenerateChanClosedProof(channelID) msgChanCloseConfirm := channeltypes.NewMsgChannelCloseConfirm( mock.PortID, channelID, @@ -231,119 +346,74 @@ func (solo *Solomachine) ChanCloseConfirm(chain *TestChain, channelID string) { require.NotNil(solo.t, res) } -// CreateHeader generates a new private/public key pair and creates the -// necessary signature to construct a valid solo machine header. -// A new diversifier will be used as well -func (solo *Solomachine) CreateHeader(newDiversifier string) *solomachine.Header { - // generate new private keys and signature for header - newPrivKeys, newPubKeys, newPubKey := GenerateKeys(solo.t, uint64(len(solo.PrivateKeys))) - - publicKey, err := codectypes.NewAnyWithValue(newPubKey) - require.NoError(solo.t, err) - - data := &solomachine.HeaderData{ - NewPubKey: publicKey, - NewDiversifier: newDiversifier, - } - - dataBz, err := solo.cdc.Marshal(data) - require.NoError(solo.t, err) - - signBytes := &solomachine.SignBytes{ - Sequence: solo.Sequence, - Timestamp: solo.Time, - Diversifier: solo.Diversifier, - Path: []byte{}, - Data: dataBz, - } - - bz, err := solo.cdc.Marshal(signBytes) - require.NoError(solo.t, err) - - sig := solo.GenerateSignature(bz) - - header := &solomachine.Header{ - Sequence: solo.Sequence, - Timestamp: solo.Time, - Signature: sig, - NewPublicKey: publicKey, - NewDiversifier: newDiversifier, - } - - // assumes successful header update - solo.Sequence++ - solo.PrivateKeys = newPrivKeys - solo.PublicKeys = newPubKeys - solo.PublicKey = newPubKey - solo.Diversifier = newDiversifier - - return header +// SendPacket mocks sending a packet by setting a packet commitment directly. +func (solo *Solomachine) SendPacket(chain *TestChain, packet channeltypes.Packet) { + commitmentHash := channeltypes.CommitPacket(chain.Codec, packet) + chain.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitmentHash) } -// CreateMisbehaviour constructs testing misbehaviour for the solo machine client -// by signing over two different data bytes at the same sequence. -func (solo *Solomachine) CreateMisbehaviour() *solomachine.Misbehaviour { - merklePath := solo.GetClientStatePath("counterparty") - path, err := solo.cdc.Marshal(&merklePath) - require.NoError(solo.t, err) +// RecvPacket creates a commitment proof and broadcasts a new MsgRecvPacket. +func (solo *Solomachine) RecvPacket(chain *TestChain, packet channeltypes.Packet) { + proofCommitment := solo.GenerateCommitmentProof(packet) + msgRecvPacket := channeltypes.NewMsgRecvPacket( + packet, + proofCommitment, + clienttypes.ZeroHeight(), + chain.SenderAccount.GetAddress().String(), + ) - data, err := solo.cdc.Marshal(solo.ClientState()) + res, err := chain.SendMsgs(msgRecvPacket) require.NoError(solo.t, err) + require.NotNil(solo.t, res) +} - signBytes := &solomachine.SignBytes{ - Sequence: solo.Sequence, - Timestamp: solo.Time, - Diversifier: solo.Diversifier, - Path: path, - Data: data, - } +// AcknowledgePacket creates an acknowledgement proof and broadcasts a MsgAcknowledgement. +func (solo *Solomachine) AcknowledgePacket(chain *TestChain, packet channeltypes.Packet) { + proofAck := solo.GenerateAcknowledgementProof(packet) + msgAcknowledgement := channeltypes.NewMsgAcknowledgement( + packet, mock.MockAcknowledgement.Acknowledgement(), + proofAck, + clienttypes.ZeroHeight(), + chain.SenderAccount.GetAddress().String(), + ) - bz, err := solo.cdc.Marshal(signBytes) + res, err := chain.SendMsgs(msgAcknowledgement) require.NoError(solo.t, err) + require.NotNil(solo.t, res) +} - sig := solo.GenerateSignature(bz) - signatureOne := solomachine.SignatureAndData{ - Signature: sig, - Path: path, - Data: data, - Timestamp: solo.Time, - } - - // misbehaviour signaturess can have different timestamps - solo.Time++ - - merklePath = solo.GetConsensusStatePath("counterparty", clienttypes.NewHeight(0, 1)) - path, err = solo.cdc.Marshal(&merklePath) - require.NoError(solo.t, err) +// TimeoutPacket creates a unreceived packet proof and broadcasts a MsgTimeout. +func (solo *Solomachine) TimeoutPacket(chain *TestChain, packet channeltypes.Packet) { + proofUnreceived := solo.GenerateReceiptAbsenceProof(packet) + msgTimeout := channeltypes.NewMsgTimeout( + packet, + 1, // nextSequenceRecv is unused for UNORDERED channels + proofUnreceived, + clienttypes.ZeroHeight(), + chain.SenderAccount.GetAddress().String(), + ) - data, err = solo.cdc.Marshal(solo.ConsensusState()) + res, err := chain.SendMsgs(msgTimeout) require.NoError(solo.t, err) + require.NotNil(solo.t, res) +} - signBytes = &solomachine.SignBytes{ - Sequence: solo.Sequence, - Timestamp: solo.Time, - Diversifier: solo.Diversifier, - Path: path, - Data: data, - } +// TimeoutPacket creates a channel closed and unreceived packet proof and broadcasts a MsgTimeoutOnClose. +func (solo *Solomachine) TimeoutPacketOnClose(chain *TestChain, packet channeltypes.Packet, channelID string) { + proofClosed := solo.GenerateChanClosedProof(channelID) + proofUnreceived := solo.GenerateReceiptAbsenceProof(packet) + msgTimeout := channeltypes.NewMsgTimeoutOnClose( + packet, + 1, // nextSequenceRecv is unused for UNORDERED channels + proofUnreceived, + proofClosed, + clienttypes.ZeroHeight(), + chain.SenderAccount.GetAddress().String(), + ) - bz, err = solo.cdc.Marshal(signBytes) + res, err := chain.SendMsgs(msgTimeout) require.NoError(solo.t, err) - - sig = solo.GenerateSignature(bz) - signatureTwo := solomachine.SignatureAndData{ - Signature: sig, - Path: path, - Data: data, - Timestamp: solo.Time, - } - - return &solomachine.Misbehaviour{ - ClientId: solo.ClientID, - Sequence: solo.Sequence, - SignatureOne: &signatureOne, - SignatureTwo: &signatureTwo, - } + require.NotNil(solo.t, res) } // GenerateSignature uses the stored private keys to generate a signature @@ -474,9 +544,9 @@ func (solo *Solomachine) GenerateChanOpenTryProof(counterpartyChannelID string) return solo.GenerateProof(signBytes) } -// GenerateChanCloseInitProof generates the proofInit required for the channel close confirm handshake step. +// GenerateChanClosedProof generates a channel closed proof. // The channelID provided represents the channelID created on the counterparty chain, that is the tendermint chain. -func (solo *Solomachine) GenerateChanCloseInitProof(counterpartyChannelID string) []byte { +func (solo *Solomachine) GenerateChanClosedProof(counterpartyChannelID string) []byte { counterparty := channeltypes.NewCounterparty(mock.PortID, counterpartyChannelID) channel := channeltypes.NewChannel(channeltypes.CLOSED, channeltypes.UNORDERED, counterparty, []string{connectionIDSolomachine}, mock.Version) @@ -494,6 +564,46 @@ func (solo *Solomachine) GenerateChanCloseInitProof(counterpartyChannelID string return solo.GenerateProof(signBytes) } +// GenerateCommitmentProof generates a commitment proof for the provided packet. +func (solo *Solomachine) GenerateCommitmentProof(packet channeltypes.Packet) []byte { + commitment := channeltypes.CommitPacket(solo.cdc, packet) + + signBytes := &solomachine.SignBytes{ + Sequence: solo.Sequence, + Timestamp: solo.Time, + Diversifier: solo.Diversifier, + Path: []byte(solo.GetPacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()).String()), + Data: commitment, + } + + return solo.GenerateProof(signBytes) +} + +// GenerateAcknowledgementProof generates an acknowledgement proof. +func (solo *Solomachine) GenerateAcknowledgementProof(packet channeltypes.Packet) []byte { + signBytes := &solomachine.SignBytes{ + Sequence: solo.Sequence, + Timestamp: solo.Time, + Diversifier: solo.Diversifier, + Path: []byte(solo.GetPacketAcknowledgementPath(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()).String()), + Data: channeltypes.CommitAcknowledgement(mock.MockAcknowledgement.Acknowledgement()), + } + + return solo.GenerateProof(signBytes) +} + +// GenerateReceiptAbsenceProof generates a receipt absence proof for the provided packet. +func (solo *Solomachine) GenerateReceiptAbsenceProof(packet channeltypes.Packet) []byte { + signBytes := &solomachine.SignBytes{ + Sequence: solo.Sequence, + Timestamp: solo.Time, + Diversifier: solo.Diversifier, + Path: []byte(solo.GetPacketReceiptPath(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()).String()), + Data: nil, + } + return solo.GenerateProof(signBytes) +} + // GetClientStatePath returns the commitment path for the client state. func (solo *Solomachine) GetClientStatePath(counterpartyClientIdentifier string) commitmenttypes.MerklePath { path, err := commitmenttypes.ApplyPrefix(prefix, commitmenttypes.NewMerklePath(host.FullClientStatePath(counterpartyClientIdentifier))) @@ -529,8 +639,8 @@ func (solo *Solomachine) GetChannelStatePath(portID, channelID string) commitmen } // GetPacketCommitmentPath returns the commitment path for a packet commitment. -func (solo *Solomachine) GetPacketCommitmentPath(portID, channelID string) commitmenttypes.MerklePath { - commitmentPath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, solo.Sequence)) +func (solo *Solomachine) GetPacketCommitmentPath(portID, channelID string, sequence uint64) commitmenttypes.MerklePath { + commitmentPath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence)) path, err := commitmenttypes.ApplyPrefix(prefix, commitmentPath) require.NoError(solo.t, err) @@ -538,8 +648,8 @@ func (solo *Solomachine) GetPacketCommitmentPath(portID, channelID string) commi } // GetPacketAcknowledgementPath returns the commitment path for a packet acknowledgement. -func (solo *Solomachine) GetPacketAcknowledgementPath(portID, channelID string) commitmenttypes.MerklePath { - ackPath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, solo.Sequence)) +func (solo *Solomachine) GetPacketAcknowledgementPath(portID, channelID string, sequence uint64) commitmenttypes.MerklePath { + ackPath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence)) path, err := commitmenttypes.ApplyPrefix(prefix, ackPath) require.NoError(solo.t, err) @@ -548,8 +658,8 @@ func (solo *Solomachine) GetPacketAcknowledgementPath(portID, channelID string) // GetPacketReceiptPath returns the commitment path for a packet receipt // and an absent receipts. -func (solo *Solomachine) GetPacketReceiptPath(portID, channelID string) commitmenttypes.MerklePath { - receiptPath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, solo.Sequence)) +func (solo *Solomachine) GetPacketReceiptPath(portID, channelID string, sequence uint64) commitmenttypes.MerklePath { + receiptPath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, sequence)) path, err := commitmenttypes.ApplyPrefix(prefix, receiptPath) require.NoError(solo.t, err)