x/ibc: constrain acks processing order (#6244)
* x/ibc: constrain acks processing order * test * address @AdityaSripal comments * address @colin-axner comments * address @alexanderbez comments
This commit is contained in:
parent
0db51de37a
commit
ca20a39962
|
@ -40,7 +40,11 @@ func (k Keeper) SendTransfer(
|
|||
// get the next sequence
|
||||
sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel)
|
||||
if !found {
|
||||
return channeltypes.ErrSequenceSendNotFound
|
||||
return sdkerrors.Wrapf(
|
||||
channeltypes.ErrSequenceSendNotFound,
|
||||
"source port: %s, source channel: %s", sourcePort, sourceChannel,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
return k.createOutgoingPacket(ctx, sequence, sourcePort, sourceChannel, destinationPort, destinationChannel, destHeight, amount, sender, receiver)
|
||||
|
|
|
@ -23,6 +23,9 @@ func InitGenesis(ctx sdk.Context, k Keeper, gs GenesisState) {
|
|||
for _, rs := range gs.RecvSequences {
|
||||
k.SetNextSequenceRecv(ctx, rs.PortID, rs.ChannelID, rs.Sequence)
|
||||
}
|
||||
for _, as := range gs.AckSequences {
|
||||
k.SetNextSequenceAck(ctx, as.PortID, as.ChannelID, as.Sequence)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportGenesis returns the ibc channel submodule's exported genesis.
|
||||
|
@ -33,5 +36,6 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
|||
Commitments: k.GetAllPacketCommitments(ctx),
|
||||
SendSequences: k.GetAllPacketSendSeqs(ctx),
|
||||
RecvSequences: k.GetAllPacketRecvSeqs(ctx),
|
||||
AckSequences: k.GetAllPacketAckSeqs(ctx),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ func (k Keeper) ChanOpenInit(
|
|||
|
||||
k.SetNextSequenceSend(ctx, portID, channelID, 1)
|
||||
k.SetNextSequenceRecv(ctx, portID, channelID, 1)
|
||||
k.SetNextSequenceAck(ctx, portID, channelID, 1)
|
||||
|
||||
k.Logger(ctx).Info(fmt.Sprintf("channel (port-id: %s, channel-id: %s) state updated: NONE -> INIT", portID, channelID))
|
||||
return capKey, nil
|
||||
|
@ -155,6 +156,7 @@ func (k Keeper) ChanOpenTry(
|
|||
|
||||
k.SetNextSequenceSend(ctx, portID, channelID, 1)
|
||||
k.SetNextSequenceRecv(ctx, portID, channelID, 1)
|
||||
k.SetNextSequenceAck(ctx, portID, channelID, 1)
|
||||
|
||||
k.Logger(ctx).Info(fmt.Sprintf("channel (port-id: %s, channel-id: %s) state updated: NONE -> TRYOPEN", portID, channelID))
|
||||
return capKey, nil
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -76,7 +75,7 @@ func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return binary.BigEndian.Uint64(bz), true
|
||||
return sdk.BigEndianToUint64(bz), true
|
||||
}
|
||||
|
||||
// SetNextSequenceSend sets a channel's next send sequence to the store
|
||||
|
@ -94,7 +93,7 @@ func (k Keeper) GetNextSequenceRecv(ctx sdk.Context, portID, channelID string) (
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return binary.BigEndian.Uint64(bz), true
|
||||
return sdk.BigEndianToUint64(bz), true
|
||||
}
|
||||
|
||||
// SetNextSequenceRecv sets a channel's next receive sequence to the store
|
||||
|
@ -104,6 +103,24 @@ func (k Keeper) SetNextSequenceRecv(ctx sdk.Context, portID, channelID string, s
|
|||
store.Set(host.KeyNextSequenceRecv(portID, channelID), bz)
|
||||
}
|
||||
|
||||
// GetNextSequenceAck gets a channel's next ack sequence from the store
|
||||
func (k Keeper) GetNextSequenceAck(ctx sdk.Context, portID, channelID string) (uint64, bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(host.KeyNextSequenceAck(portID, channelID))
|
||||
if bz == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return sdk.BigEndianToUint64(bz), true
|
||||
}
|
||||
|
||||
// SetNextSequenceAck sets a channel's next ack sequence to the store
|
||||
func (k Keeper) SetNextSequenceAck(ctx sdk.Context, portID, channelID string, sequence uint64) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := sdk.Uint64ToBigEndian(sequence)
|
||||
store.Set(host.KeyNextSequenceAck(portID, channelID), bz)
|
||||
}
|
||||
|
||||
// GetPacketCommitment gets the packet commitment hash from the store
|
||||
func (k Keeper) GetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) []byte {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
@ -138,23 +155,17 @@ func (k Keeper) GetPacketAcknowledgement(ctx sdk.Context, portID, channelID stri
|
|||
return bz, true
|
||||
}
|
||||
|
||||
// IteratePacketSequence provides an iterator over all send and receive sequences. For each
|
||||
// sequence, cb will be called. If the cb returns true, the iterator will close
|
||||
// and stop.
|
||||
func (k Keeper) IteratePacketSequence(ctx sdk.Context, send bool, cb func(portID, channelID string, sequence uint64) bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
var iterator db.Iterator
|
||||
if send {
|
||||
iterator = sdk.KVStorePrefixIterator(store, []byte(host.KeyNextSeqSendPrefix))
|
||||
} else {
|
||||
iterator = sdk.KVStorePrefixIterator(store, []byte(host.KeyNextSeqRecvPrefix))
|
||||
}
|
||||
|
||||
// IteratePacketSequence provides an iterator over all send, receive or ack sequences.
|
||||
// For each sequence, cb will be called. If the cb returns true, the iterator
|
||||
// will close and stop.
|
||||
func (k Keeper) IteratePacketSequence(ctx sdk.Context, iterator db.Iterator, cb func(portID, channelID string, sequence uint64) bool) {
|
||||
defer iterator.Close()
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
keySplit := strings.Split(string(iterator.Key()), "/")
|
||||
portID := keySplit[2]
|
||||
channelID := keySplit[4]
|
||||
portID, channelID, err := host.ParseChannelPath(string(iterator.Key()))
|
||||
if err != nil {
|
||||
// return if the key is not a channel key
|
||||
return
|
||||
}
|
||||
|
||||
sequence := sdk.BigEndianToUint64(iterator.Value())
|
||||
|
||||
|
@ -166,7 +177,9 @@ func (k Keeper) IteratePacketSequence(ctx sdk.Context, send bool, cb func(portID
|
|||
|
||||
// GetAllPacketSendSeqs returns all stored next send sequences.
|
||||
func (k Keeper) GetAllPacketSendSeqs(ctx sdk.Context) (seqs []types.PacketSequence) {
|
||||
k.IteratePacketSequence(ctx, true, func(portID, channelID string, nextSendSeq uint64) bool {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, []byte(host.KeyNextSeqSendPrefix))
|
||||
k.IteratePacketSequence(ctx, iterator, func(portID, channelID string, nextSendSeq uint64) bool {
|
||||
ps := types.NewPacketSequence(portID, channelID, nextSendSeq)
|
||||
seqs = append(seqs, ps)
|
||||
return false
|
||||
|
@ -176,7 +189,9 @@ func (k Keeper) GetAllPacketSendSeqs(ctx sdk.Context) (seqs []types.PacketSequen
|
|||
|
||||
// GetAllPacketRecvSeqs returns all stored next recv sequences.
|
||||
func (k Keeper) GetAllPacketRecvSeqs(ctx sdk.Context) (seqs []types.PacketSequence) {
|
||||
k.IteratePacketSequence(ctx, false, func(portID, channelID string, nextRecvSeq uint64) bool {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, []byte(host.KeyNextSeqRecvPrefix))
|
||||
k.IteratePacketSequence(ctx, iterator, func(portID, channelID string, nextRecvSeq uint64) bool {
|
||||
ps := types.NewPacketSequence(portID, channelID, nextRecvSeq)
|
||||
seqs = append(seqs, ps)
|
||||
return false
|
||||
|
@ -184,6 +199,18 @@ func (k Keeper) GetAllPacketRecvSeqs(ctx sdk.Context) (seqs []types.PacketSequen
|
|||
return seqs
|
||||
}
|
||||
|
||||
// GetAllPacketAckSeqs returns all stored next acknowledgements sequences.
|
||||
func (k Keeper) GetAllPacketAckSeqs(ctx sdk.Context) (seqs []types.PacketSequence) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, []byte(host.KeyNextSeqAckPrefix))
|
||||
k.IteratePacketSequence(ctx, iterator, func(portID, channelID string, nextAckSeq uint64) bool {
|
||||
ps := types.NewPacketSequence(portID, channelID, nextAckSeq)
|
||||
seqs = append(seqs, ps)
|
||||
return false
|
||||
})
|
||||
return seqs
|
||||
}
|
||||
|
||||
// IteratePacketCommitment provides an iterator over all PacketCommitment objects. For each
|
||||
// aknowledgement, cb will be called. If the cb returns true, the iterator will close
|
||||
// and stop.
|
||||
|
|
|
@ -131,15 +131,19 @@ func (suite KeeperTestSuite) TestGetAllSequences() {
|
|||
for _, seq := range expSeqs {
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, seq.PortID, seq.ChannelID, seq.Sequence)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctx, seq.PortID, seq.ChannelID, seq.Sequence)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(ctx, seq.PortID, seq.ChannelID, seq.Sequence)
|
||||
}
|
||||
|
||||
sendSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketSendSeqs(ctx)
|
||||
recvSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketRecvSeqs(ctx)
|
||||
ackSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketAckSeqs(ctx)
|
||||
suite.Require().Len(sendSeqs, 2)
|
||||
suite.Require().Len(recvSeqs, 2)
|
||||
suite.Require().Len(ackSeqs, 2)
|
||||
|
||||
suite.Require().Equal(expSeqs, sendSeqs)
|
||||
suite.Require().Equal(expSeqs, recvSeqs)
|
||||
suite.Require().Equal(expSeqs, ackSeqs)
|
||||
}
|
||||
|
||||
func (suite KeeperTestSuite) TestGetAllCommitmentsAcks() {
|
||||
|
@ -175,9 +179,13 @@ func (suite *KeeperTestSuite) TestSetSequence() {
|
|||
_, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, testPort1, testChannel1)
|
||||
suite.False(found)
|
||||
|
||||
nextSeqSend, nextSeqRecv := uint64(10), uint64(10)
|
||||
_, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, testPort1, testChannel1)
|
||||
suite.False(found)
|
||||
|
||||
nextSeqSend, nextSeqRecv, nextSeqAck := uint64(10), uint64(10), uint64(10)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, testPort1, testChannel1, nextSeqSend)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctx, testPort1, testChannel1, nextSeqRecv)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(ctx, testPort1, testChannel1, nextSeqAck)
|
||||
|
||||
storedNextSeqSend, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1)
|
||||
suite.True(found)
|
||||
|
@ -186,6 +194,10 @@ func (suite *KeeperTestSuite) TestSetSequence() {
|
|||
storedNextSeqRecv, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1)
|
||||
suite.True(found)
|
||||
suite.Equal(nextSeqRecv, storedNextSeqRecv)
|
||||
|
||||
storedNextSeqAck, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceAck(ctx, testPort1, testChannel1)
|
||||
suite.True(found)
|
||||
suite.Equal(nextSeqAck, storedNextSeqAck)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestPackageCommitment() {
|
||||
|
|
|
@ -99,7 +99,10 @@ func (k Keeper) SendPacket(
|
|||
|
||||
nextSequenceSend, found := k.GetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel())
|
||||
if !found {
|
||||
return types.ErrSequenceSendNotFound
|
||||
return sdkerrors.Wrapf(
|
||||
types.ErrSequenceSendNotFound,
|
||||
"source port: %s, source channel: %s", packet.GetSourcePort(), packet.GetSourceChannel(),
|
||||
)
|
||||
}
|
||||
|
||||
if packet.GetSequence() != nextSequenceSend {
|
||||
|
@ -247,7 +250,10 @@ func (k Keeper) PacketExecuted(
|
|||
if channel.Ordering == types.ORDERED {
|
||||
nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel())
|
||||
if !found {
|
||||
return types.ErrSequenceReceiveNotFound
|
||||
return sdkerrors.Wrapf(
|
||||
types.ErrSequenceReceiveNotFound,
|
||||
"destination port: %s, destination channel: %s", packet.GetDestPort(), packet.GetDestChannel(),
|
||||
)
|
||||
}
|
||||
|
||||
if packet.GetSequence() != nextSequenceRecv {
|
||||
|
@ -352,6 +358,25 @@ func (k Keeper) AcknowledgePacket(
|
|||
return nil, sdkerrors.Wrap(err, "invalid acknowledgement on counterparty chain")
|
||||
}
|
||||
|
||||
if channel.Ordering == types.ORDERED {
|
||||
nextSequenceAck, found := k.GetNextSequenceAck(ctx, packet.GetDestPort(), packet.GetDestChannel())
|
||||
if !found {
|
||||
return nil, sdkerrors.Wrapf(
|
||||
types.ErrSequenceAckNotFound,
|
||||
"destination port: %s, destination channel: %s", packet.GetDestPort(), packet.GetDestChannel(),
|
||||
)
|
||||
}
|
||||
|
||||
if packet.GetSequence() != nextSequenceAck {
|
||||
return nil, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInvalidSequence,
|
||||
"packet sequence ≠ next ack sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceAck,
|
||||
)
|
||||
}
|
||||
|
||||
k.SetNextSequenceAck(ctx, packet.GetDestPort(), packet.GetDestChannel(), nextSequenceAck+1)
|
||||
}
|
||||
|
||||
// log that a packet has been acknowledged
|
||||
k.Logger(ctx).Info(fmt.Sprintf("packet acknowledged: %v", packet))
|
||||
|
||||
|
|
|
@ -275,6 +275,7 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
|
|||
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, types.OPEN, types.ORDERED, testConnectionIDB)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet))
|
||||
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort2, testChannel2, 1, types.CommitAcknowledgement(ack))
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(suite.chainB.GetContext(), counterparty.GetPortID(), counterparty.GetChannelID(), 1)
|
||||
}, true},
|
||||
{"channel not found", func() {}, false},
|
||||
{"channel not open", func() {
|
||||
|
@ -309,6 +310,29 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
|
|||
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet))
|
||||
}, false},
|
||||
{"next ack sequence not found", func() {
|
||||
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
|
||||
suite.chainB.CreateClient(suite.chainA)
|
||||
suite.chainA.CreateClient(suite.chainB)
|
||||
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
|
||||
suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connection.OPEN)
|
||||
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
|
||||
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, types.OPEN, types.ORDERED, testConnectionIDB)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet))
|
||||
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort2, testChannel2, 1, types.CommitAcknowledgement(ack))
|
||||
}, false},
|
||||
{"next ack sequence mismatch", func() {
|
||||
packet = types.NewPacket(mockSuccessPacket{}.GetBytes(), 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID(), timeoutHeight, disabledTimeoutTimestamp)
|
||||
suite.chainB.CreateClient(suite.chainA)
|
||||
suite.chainA.CreateClient(suite.chainB)
|
||||
suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connection.OPEN)
|
||||
suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connection.OPEN)
|
||||
suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, types.OPEN, types.ORDERED, testConnectionIDA)
|
||||
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, types.OPEN, types.ORDERED, testConnectionIDB)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet))
|
||||
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort2, testChannel2, 1, types.CommitAcknowledgement(ack))
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(suite.chainB.GetContext(), counterparty.GetPortID(), counterparty.GetChannelID(), 10)
|
||||
}, false},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
|
@ -322,12 +346,11 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
|
|||
proof, proofHeight := queryProof(suite.chainA, packetKey)
|
||||
|
||||
ctx := suite.chainB.GetContext()
|
||||
packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, proof, proofHeight+1)
|
||||
if tc.expPass {
|
||||
packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, proof, proofHeight+1)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().NotNil(packetOut)
|
||||
} else {
|
||||
packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, proof, proofHeight+1)
|
||||
suite.Require().Error(err)
|
||||
suite.Require().Nil(packetOut)
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ var (
|
|||
ErrChannelCapabilityNotFound = sdkerrors.Register(SubModuleName, 9, "channel capability not found")
|
||||
ErrSequenceSendNotFound = sdkerrors.Register(SubModuleName, 10, "sequence send not found")
|
||||
ErrSequenceReceiveNotFound = sdkerrors.Register(SubModuleName, 11, "sequence receive not found")
|
||||
ErrInvalidPacket = sdkerrors.Register(SubModuleName, 12, "invalid packet")
|
||||
ErrPacketTimeout = sdkerrors.Register(SubModuleName, 13, "packet timeout")
|
||||
ErrTooManyConnectionHops = sdkerrors.Register(SubModuleName, 14, "too many connection hops")
|
||||
ErrAcknowledgementTooLong = sdkerrors.Register(SubModuleName, 15, "acknowledgement too long")
|
||||
ErrSequenceAckNotFound = sdkerrors.Register(SubModuleName, 12, "sequence acknowledgement not found")
|
||||
ErrInvalidPacket = sdkerrors.Register(SubModuleName, 13, "invalid packet")
|
||||
ErrPacketTimeout = sdkerrors.Register(SubModuleName, 14, "packet timeout")
|
||||
ErrTooManyConnectionHops = sdkerrors.Register(SubModuleName, 15, "too many connection hops")
|
||||
ErrAcknowledgementTooLong = sdkerrors.Register(SubModuleName, 16, "acknowledgement too long")
|
||||
)
|
||||
|
|
|
@ -65,12 +65,13 @@ type GenesisState struct {
|
|||
Commitments []PacketAckCommitment `json:"commitments" yaml:"commitments"`
|
||||
SendSequences []PacketSequence `json:"send_sequences" yaml:"send_sequences"`
|
||||
RecvSequences []PacketSequence `json:"recv_sequences" yaml:"recv_sequences"`
|
||||
AckSequences []PacketSequence `json:"ack_sequences" yaml:"ack_sequences"`
|
||||
}
|
||||
|
||||
// NewGenesisState creates a GenesisState instance.
|
||||
func NewGenesisState(
|
||||
channels []IdentifiedChannel, acks, commitments []PacketAckCommitment,
|
||||
sendSeqs, recvSeqs []PacketSequence,
|
||||
sendSeqs, recvSeqs, ackSeqs []PacketSequence,
|
||||
) GenesisState {
|
||||
return GenesisState{
|
||||
Channels: channels,
|
||||
|
@ -78,6 +79,7 @@ func NewGenesisState(
|
|||
Commitments: commitments,
|
||||
SendSequences: sendSeqs,
|
||||
RecvSequences: recvSeqs,
|
||||
AckSequences: ackSeqs,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,6 +91,7 @@ func DefaultGenesisState() GenesisState {
|
|||
Commitments: []PacketAckCommitment{},
|
||||
SendSequences: []PacketSequence{},
|
||||
RecvSequences: []PacketSequence{},
|
||||
AckSequences: []PacketSequence{},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,6 +128,12 @@ func (gs GenesisState) Validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
for i, as := range gs.AckSequences {
|
||||
if err := as.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid acknowledgement sequence %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@ func TestValidateGenesis(t *testing.T) {
|
|||
[]PacketSequence{
|
||||
NewPacketSequence(testPort2, testChannel2, 1),
|
||||
},
|
||||
[]PacketSequence{
|
||||
NewPacketSequence(testPort2, testChannel2, 1),
|
||||
},
|
||||
),
|
||||
expPass: true,
|
||||
},
|
||||
|
@ -119,6 +122,15 @@ func TestValidateGenesis(t *testing.T) {
|
|||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid ack seq",
|
||||
genState: GenesisState{
|
||||
AckSequences: []PacketSequence{
|
||||
NewPacketSequence(testPort1, "(testChannel1)", 1),
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
|
@ -2,7 +2,6 @@ package host
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -31,6 +30,7 @@ const (
|
|||
KeyChannelCapabilityPrefix = "capabilities"
|
||||
KeyNextSeqSendPrefix = "seqSends"
|
||||
KeyNextSeqRecvPrefix = "seqRecvs"
|
||||
KeyNextSeqAckPrefix = "seqAcks"
|
||||
KeyPacketCommitmentPrefix = "commitments"
|
||||
KeyPacketAckPrefix = "acks"
|
||||
)
|
||||
|
@ -129,6 +129,11 @@ func NextSequenceRecvPath(portID, channelID string) string {
|
|||
return fmt.Sprintf("%s/", KeyNextSeqRecvPrefix) + channelPath(portID, channelID) + "/nextSequenceRecv"
|
||||
}
|
||||
|
||||
// NextSequenceAckPath defines the next acknowledgement sequence counter store path
|
||||
func NextSequenceAckPath(portID, channelID string) string {
|
||||
return fmt.Sprintf("%s/", KeyNextSeqAckPrefix) + channelPath(portID, channelID) + "/nextSequenceAck"
|
||||
}
|
||||
|
||||
// PacketCommitmentPath defines the commitments to packet data fields store path
|
||||
func PacketCommitmentPath(portID, channelID string, sequence uint64) string {
|
||||
return fmt.Sprintf("%s/", KeyPacketCommitmentPrefix) + channelPath(portID, channelID) + fmt.Sprintf("/packets/%d", sequence)
|
||||
|
@ -156,6 +161,12 @@ func KeyNextSequenceRecv(portID, channelID string) []byte {
|
|||
return []byte(NextSequenceRecvPath(portID, channelID))
|
||||
}
|
||||
|
||||
// KeyNextSequenceAck returns the store key for the acknowledgement sequence of
|
||||
// a particular channel binded to a specific port.
|
||||
func KeyNextSequenceAck(portID, channelID string) []byte {
|
||||
return []byte(NextSequenceAckPath(portID, channelID))
|
||||
}
|
||||
|
||||
// KeyPacketCommitment returns the store key of under which a packet commitment
|
||||
// is stored
|
||||
func KeyPacketCommitment(portID, channelID string, sequence uint64) []byte {
|
||||
|
@ -172,19 +183,6 @@ func channelPath(portID, channelID string) string {
|
|||
return fmt.Sprintf("ports/%s/channels/%s", portID, channelID)
|
||||
}
|
||||
|
||||
func MustParseChannelPath(path string) (string, string) {
|
||||
split := strings.Split(path, "/")
|
||||
if len(split) != 5 {
|
||||
panic("cannot parse channel path")
|
||||
}
|
||||
|
||||
if split[1] != "ports" || split[3] != "channels" {
|
||||
panic("cannot parse channel path")
|
||||
}
|
||||
|
||||
return split[2], split[4]
|
||||
}
|
||||
|
||||
// ICS05
|
||||
// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#store-paths
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package host
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RemovePath is an util function to remove a path from a set.
|
||||
func RemovePath(paths []string, path string) ([]string, bool) {
|
||||
for i, p := range paths {
|
||||
|
@ -9,3 +14,28 @@ func RemovePath(paths []string, path string) ([]string, bool) {
|
|||
}
|
||||
return paths, false
|
||||
}
|
||||
|
||||
// ParseChannelPath returns the port and channel ID from a full path. It returns
|
||||
// an error if the provided path is invalid,
|
||||
func ParseChannelPath(path string) (string, string, error) {
|
||||
split := strings.Split(path, "/")
|
||||
if len(split) < 5 {
|
||||
return "", "", fmt.Errorf("cannot parse channel path %s", path)
|
||||
}
|
||||
|
||||
if split[1] != "ports" || split[3] != "channels" {
|
||||
return "", "", fmt.Errorf("cannot parse channel path %s", path)
|
||||
}
|
||||
|
||||
return split[2], split[4], nil
|
||||
}
|
||||
|
||||
// MustParseChannelPath returns the port and channel ID from a full path. Panics
|
||||
// if the provided path is invalid
|
||||
func MustParseChannelPath(path string) (string, string) {
|
||||
portID, channelID, err := ParseChannelPath(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return portID, channelID
|
||||
}
|
||||
|
|
|
@ -74,6 +74,9 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
|
|||
[]channel.PacketSequence{
|
||||
channel.NewPacketSequence(port2, channel2, 1),
|
||||
},
|
||||
[]channel.PacketSequence{
|
||||
channel.NewPacketSequence(port2, channel2, 1),
|
||||
},
|
||||
),
|
||||
},
|
||||
expPass: true,
|
||||
|
|
Loading…
Reference in New Issue