ibc/04-channel: import export GenesisState (#6087)
* ibc/04-channel: import export GenesisState * update tests * add missing genesis fields * genesis tests * keeper tests * update genesis test * typo * rename types * address comments from review * minor updates * typo
This commit is contained in:
parent
6469447d52
commit
2d3a8525b9
|
@ -28,6 +28,7 @@ var (
|
|||
QuerierConnectionChannels = keeper.QuerierConnectionChannels
|
||||
NewChannel = types.NewChannel
|
||||
NewCounterparty = types.NewCounterparty
|
||||
NewIdentifiedChannel = types.NewIdentifiedChannel
|
||||
RegisterCodec = types.RegisterCodec
|
||||
ErrChannelExists = types.ErrChannelExists
|
||||
ErrChannelNotFound = types.ErrChannelNotFound
|
||||
|
@ -50,7 +51,11 @@ var (
|
|||
NewMsgTimeout = types.NewMsgTimeout
|
||||
NewMsgAcknowledgement = types.NewMsgAcknowledgement
|
||||
NewPacket = types.NewPacket
|
||||
NewPacketAckCommitment = types.NewPacketAckCommitment
|
||||
NewPacketSequence = types.NewPacketSequence
|
||||
NewChannelResponse = types.NewChannelResponse
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
NewGenesisState = types.NewGenesisState
|
||||
|
||||
// variable aliases
|
||||
SubModuleCdc = types.SubModuleCdc
|
||||
|
@ -68,6 +73,7 @@ type (
|
|||
Keeper = keeper.Keeper
|
||||
Channel = types.Channel
|
||||
Counterparty = types.Counterparty
|
||||
IdentifiedChannel = types.IdentifiedChannel
|
||||
ClientKeeper = types.ClientKeeper
|
||||
ConnectionKeeper = types.ConnectionKeeper
|
||||
PortKeeper = types.PortKeeper
|
||||
|
@ -82,4 +88,7 @@ type (
|
|||
MsgTimeout = types.MsgTimeout
|
||||
Packet = types.Packet
|
||||
ChannelResponse = types.ChannelResponse
|
||||
PacketAckCommitment = types.PacketAckCommitment
|
||||
PacketSequence = types.PacketSequence
|
||||
GenesisState = types.GenesisState
|
||||
)
|
||||
|
|
|
@ -29,8 +29,8 @@ func QueryPacket(
|
|||
return types.PacketResponse{}, err
|
||||
}
|
||||
|
||||
destPortID := channelRes.Channel.Channel.Counterparty.PortID
|
||||
destChannelID := channelRes.Channel.Channel.Counterparty.ChannelID
|
||||
destPortID := channelRes.Channel.Counterparty.PortID
|
||||
destChannelID := channelRes.Channel.Counterparty.ChannelID
|
||||
|
||||
packet := types.NewPacket(
|
||||
res.Value,
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package channel
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// InitGenesis initializes the ibc channel submodule's state from a provided genesis
|
||||
// state.
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, gs GenesisState) {
|
||||
for _, channel := range gs.Channels {
|
||||
ch := NewChannel(channel.State, channel.Ordering, channel.Counterparty, channel.ConnectionHops, channel.Version)
|
||||
k.SetChannel(ctx, channel.PortID, channel.ID, ch)
|
||||
}
|
||||
for _, ack := range gs.Acknowledgements {
|
||||
k.SetPacketAcknowledgement(ctx, ack.PortID, ack.ChannelID, ack.Sequence, ack.Hash)
|
||||
}
|
||||
for _, commitment := range gs.Commitments {
|
||||
k.SetPacketCommitment(ctx, commitment.PortID, commitment.ChannelID, commitment.Sequence, commitment.Hash)
|
||||
}
|
||||
for _, ss := range gs.SendSequences {
|
||||
k.SetNextSequenceSend(ctx, ss.PortID, ss.ChannelID, ss.Sequence)
|
||||
}
|
||||
for _, rs := range gs.RecvSequences {
|
||||
k.SetNextSequenceRecv(ctx, rs.PortID, rs.ChannelID, rs.Sequence)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportGenesis returns the ibc channel submodule's exported genesis.
|
||||
func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
||||
return GenesisState{
|
||||
Channels: k.GetAllChannels(ctx),
|
||||
Acknowledgements: k.GetAllPacketAcks(ctx),
|
||||
Commitments: k.GetAllPacketCommitments(ctx),
|
||||
SendSequences: k.GetAllPacketSendSeqs(ctx),
|
||||
RecvSequences: k.GetAllPacketRecvSeqs(ctx),
|
||||
}
|
||||
}
|
|
@ -202,9 +202,9 @@ func (k Keeper) ChanOpenAck(
|
|||
}
|
||||
|
||||
// counterparty of the counterparty channel end (i.e self)
|
||||
counterparty := types.NewCounterparty(portID, channelID)
|
||||
expectedCounterparty := types.NewCounterparty(portID, channelID)
|
||||
expectedChannel := types.NewChannel(
|
||||
exported.TRYOPEN, channel.Ordering, counterparty,
|
||||
exported.TRYOPEN, channel.Ordering, expectedCounterparty,
|
||||
counterpartyHops, counterpartyVersion,
|
||||
)
|
||||
|
||||
|
|
|
@ -3,8 +3,11 @@ package keeper
|
|||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
db "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -134,6 +137,90 @@ 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(ibctypes.KeyNextSeqSendPrefix))
|
||||
} else {
|
||||
iterator = sdk.KVStorePrefixIterator(store, []byte(ibctypes.KeyNextSeqRecvPrefix))
|
||||
}
|
||||
|
||||
defer iterator.Close()
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
keySplit := strings.Split(string(iterator.Key()), "/")
|
||||
portID := keySplit[2]
|
||||
channelID := keySplit[4]
|
||||
|
||||
sequence := sdk.BigEndianToUint64(iterator.Value())
|
||||
|
||||
if cb(portID, channelID, sequence) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
ps := types.NewPacketSequence(portID, channelID, nextSendSeq)
|
||||
seqs = append(seqs, ps)
|
||||
return false
|
||||
})
|
||||
return seqs
|
||||
}
|
||||
|
||||
// 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 {
|
||||
ps := types.NewPacketSequence(portID, channelID, nextRecvSeq)
|
||||
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.
|
||||
func (k Keeper) IteratePacketCommitment(ctx sdk.Context, cb func(portID, channelID string, sequence uint64, hash []byte) bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, []byte(ibctypes.KeyPacketCommitmentPrefix))
|
||||
k.iterateHashes(ctx, iterator, cb)
|
||||
}
|
||||
|
||||
// GetAllPacketCommitments returns all stored PacketCommitments objects.
|
||||
func (k Keeper) GetAllPacketCommitments(ctx sdk.Context) (commitments []types.PacketAckCommitment) {
|
||||
k.IteratePacketCommitment(ctx, func(portID, channelID string, sequence uint64, hash []byte) bool {
|
||||
pc := types.NewPacketAckCommitment(portID, channelID, sequence, hash)
|
||||
commitments = append(commitments, pc)
|
||||
return false
|
||||
})
|
||||
return commitments
|
||||
}
|
||||
|
||||
// IteratePacketAcknowledgement provides an iterator over all PacketAcknowledgement objects. For each
|
||||
// aknowledgement, cb will be called. If the cb returns true, the iterator will close
|
||||
// and stop.
|
||||
func (k Keeper) IteratePacketAcknowledgement(ctx sdk.Context, cb func(portID, channelID string, sequence uint64, hash []byte) bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, []byte(ibctypes.KeyPacketAckPrefix))
|
||||
k.iterateHashes(ctx, iterator, cb)
|
||||
}
|
||||
|
||||
// GetAllPacketAcks returns all stored PacketAcknowledgements objects.
|
||||
func (k Keeper) GetAllPacketAcks(ctx sdk.Context) (acks []types.PacketAckCommitment) {
|
||||
k.IteratePacketAcknowledgement(ctx, func(portID, channelID string, sequence uint64, ack []byte) bool {
|
||||
packetAck := types.NewPacketAckCommitment(portID, channelID, sequence, ack)
|
||||
acks = append(acks, packetAck)
|
||||
return false
|
||||
})
|
||||
return acks
|
||||
}
|
||||
|
||||
// IterateChannels provides an iterator over all Channel objects. For each
|
||||
// Channel, cb will be called. If the cb returns true, the iterator will close
|
||||
// and stop.
|
||||
|
@ -145,9 +232,10 @@ func (k Keeper) IterateChannels(ctx sdk.Context, cb func(types.IdentifiedChannel
|
|||
for ; iterator.Valid(); iterator.Next() {
|
||||
var channel types.Channel
|
||||
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &channel)
|
||||
portID, channelID := ibctypes.MustParseChannelPath(string(iterator.Key()))
|
||||
|
||||
if cb(types.IdentifiedChannel{Channel: channel, PortIdentifier: portID, ChannelIdentifier: channelID}) {
|
||||
portID, channelID := ibctypes.MustParseChannelPath(string(iterator.Key()))
|
||||
identifiedChannel := types.NewIdentifiedChannel(portID, channelID, channel)
|
||||
if cb(identifiedChannel) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -171,3 +259,22 @@ func (k Keeper) LookupModuleByChannel(ctx sdk.Context, portID, channelID string)
|
|||
|
||||
return ibctypes.GetModuleOwner(modules), cap, true
|
||||
}
|
||||
|
||||
// common functionality for IteratePacketCommitment and IteratePacketAcknowledgemen
|
||||
func (k Keeper) iterateHashes(ctx sdk.Context, iterator db.Iterator, cb func(portID, channelID string, sequence uint64, hash []byte) bool) {
|
||||
defer iterator.Close()
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
keySplit := strings.Split(string(iterator.Key()), "/")
|
||||
portID := keySplit[2]
|
||||
channelID := keySplit[4]
|
||||
|
||||
sequence, err := strconv.ParseUint(keySplit[len(keySplit)-1], 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if cb(portID, channelID, sequence, iterator.Value()) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,16 +75,11 @@ func (suite *KeeperTestSuite) TestSetChannel() {
|
|||
_, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1)
|
||||
suite.False(found)
|
||||
|
||||
channel := types.Channel{
|
||||
State: exported.OPEN,
|
||||
Ordering: testChannelOrder,
|
||||
Counterparty: types.Counterparty{
|
||||
PortID: testPort2,
|
||||
ChannelID: testChannel2,
|
||||
},
|
||||
ConnectionHops: []string{testConnectionIDA},
|
||||
Version: testChannelVersion,
|
||||
}
|
||||
counterparty2 := types.NewCounterparty(testPort2, testChannel2)
|
||||
channel := types.NewChannel(
|
||||
exported.INIT, testChannelOrder,
|
||||
counterparty2, []string{testConnectionIDA}, testChannelVersion,
|
||||
)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, channel)
|
||||
|
||||
storedChannel, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1)
|
||||
|
@ -98,37 +93,27 @@ func (suite KeeperTestSuite) TestGetAllChannels() {
|
|||
counterparty2 := types.NewCounterparty(testPort2, testChannel2)
|
||||
counterparty3 := types.NewCounterparty(testPort3, testChannel3)
|
||||
|
||||
channel1 := types.Channel{
|
||||
State: exported.INIT,
|
||||
Ordering: testChannelOrder,
|
||||
Counterparty: counterparty3,
|
||||
ConnectionHops: []string{testConnectionIDA},
|
||||
Version: testChannelVersion,
|
||||
}
|
||||
|
||||
channel2 := types.Channel{
|
||||
State: exported.INIT,
|
||||
Ordering: testChannelOrder,
|
||||
Counterparty: counterparty1,
|
||||
ConnectionHops: []string{testConnectionIDA},
|
||||
Version: testChannelVersion,
|
||||
}
|
||||
|
||||
channel3 := types.Channel{
|
||||
State: exported.CLOSED,
|
||||
Ordering: testChannelOrder,
|
||||
Counterparty: counterparty2,
|
||||
ConnectionHops: []string{testConnectionIDA},
|
||||
Version: testChannelVersion,
|
||||
}
|
||||
channel1 := types.NewChannel(
|
||||
exported.INIT, testChannelOrder,
|
||||
counterparty3, []string{testConnectionIDA}, testChannelVersion,
|
||||
)
|
||||
channel2 := types.NewChannel(
|
||||
exported.INIT, testChannelOrder,
|
||||
counterparty1, []string{testConnectionIDA}, testChannelVersion,
|
||||
)
|
||||
channel3 := types.NewChannel(
|
||||
exported.CLOSED, testChannelOrder,
|
||||
counterparty2, []string{testConnectionIDA}, testChannelVersion,
|
||||
)
|
||||
|
||||
expChannels := []types.IdentifiedChannel{
|
||||
{Channel: channel1, PortIdentifier: testPort1, ChannelIdentifier: testChannel1},
|
||||
{Channel: channel2, PortIdentifier: testPort2, ChannelIdentifier: testChannel2},
|
||||
{Channel: channel3, PortIdentifier: testPort3, ChannelIdentifier: testChannel3},
|
||||
types.NewIdentifiedChannel(testPort1, testChannel1, channel1),
|
||||
types.NewIdentifiedChannel(testPort2, testChannel2, channel2),
|
||||
types.NewIdentifiedChannel(testPort3, testChannel3, channel3),
|
||||
}
|
||||
|
||||
ctx := suite.chainB.GetContext()
|
||||
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, channel1)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort2, testChannel2, channel2)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort3, testChannel3, channel3)
|
||||
|
@ -138,6 +123,53 @@ func (suite KeeperTestSuite) TestGetAllChannels() {
|
|||
suite.Require().Equal(expChannels, channels)
|
||||
}
|
||||
|
||||
func (suite KeeperTestSuite) TestGetAllSequences() {
|
||||
seq1 := types.NewPacketSequence(testPort1, testChannel1, 1)
|
||||
seq2 := types.NewPacketSequence(testPort2, testChannel2, 2)
|
||||
|
||||
expSeqs := []types.PacketSequence{seq1, seq2}
|
||||
|
||||
ctx := suite.chainB.GetContext()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
sendSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketSendSeqs(ctx)
|
||||
recvSeqs := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketRecvSeqs(ctx)
|
||||
suite.Require().Len(sendSeqs, 2)
|
||||
suite.Require().Len(recvSeqs, 2)
|
||||
|
||||
suite.Require().Equal(expSeqs, sendSeqs)
|
||||
suite.Require().Equal(expSeqs, recvSeqs)
|
||||
}
|
||||
|
||||
func (suite KeeperTestSuite) TestGetAllCommitmentsAcks() {
|
||||
ack1 := types.NewPacketAckCommitment(testPort1, testChannel1, 1, []byte("ack"))
|
||||
ack2 := types.NewPacketAckCommitment(testPort1, testChannel1, 2, []byte("ack"))
|
||||
comm1 := types.NewPacketAckCommitment(testPort1, testChannel1, 1, []byte("hash"))
|
||||
comm2 := types.NewPacketAckCommitment(testPort1, testChannel1, 2, []byte("hash"))
|
||||
|
||||
expAcks := []types.PacketAckCommitment{ack1, ack2}
|
||||
expCommitments := []types.PacketAckCommitment{comm1, comm2}
|
||||
|
||||
ctx := suite.chainB.GetContext()
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctx, expAcks[i].PortID, expAcks[i].ChannelID, expAcks[i].Sequence, expAcks[i].Hash)
|
||||
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, expCommitments[i].PortID, expCommitments[i].ChannelID, expCommitments[i].Sequence, expCommitments[i].Hash)
|
||||
}
|
||||
|
||||
acks := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketAcks(ctx)
|
||||
commitments := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketCommitments(ctx)
|
||||
suite.Require().Len(acks, 2)
|
||||
suite.Require().Len(commitments, 2)
|
||||
|
||||
suite.Require().Equal(expAcks, acks)
|
||||
suite.Require().Equal(expCommitments, commitments)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSetSequence() {
|
||||
ctx := suite.chainB.GetContext()
|
||||
_, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1)
|
||||
|
|
|
@ -47,7 +47,7 @@ func QuerierConnectionChannels(ctx sdk.Context, req abci.RequestQuery, k Keeper)
|
|||
|
||||
connectionChannels := []types.IdentifiedChannel{}
|
||||
for _, channel := range channels {
|
||||
if channel.Channel.ConnectionHops[0] == params.Connection {
|
||||
if channel.ConnectionHops[0] == params.Connection {
|
||||
connectionChannels = append(connectionChannels, channel)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ type Channel struct {
|
|||
|
||||
// NewChannel creates a new Channel instance
|
||||
func NewChannel(
|
||||
state exported.State, ordering exported.Order, counterparty Counterparty,
|
||||
hops []string, version string,
|
||||
state exported.State, ordering exported.Order,
|
||||
counterparty Counterparty, hops []string, version string,
|
||||
) Channel {
|
||||
return Channel{
|
||||
State: state,
|
||||
|
@ -126,3 +126,40 @@ func (c Counterparty) ValidateBasic() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IdentifiedChannel defines a channel with additional port and channel identifier
|
||||
// fields.
|
||||
type IdentifiedChannel struct {
|
||||
ID string `json:"id" yaml:"id"`
|
||||
PortID string `json:"port_id" yaml:"port_id"`
|
||||
State exported.State `json:"state" yaml:"state"`
|
||||
Ordering exported.Order `json:"ordering" yaml:"ordering"`
|
||||
Counterparty Counterparty `json:"counterparty" yaml:"counterparty"`
|
||||
ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"`
|
||||
Version string `json:"version" yaml:"version "`
|
||||
}
|
||||
|
||||
// NewIdentifiedChannel creates a new IdentifiedChannel instance
|
||||
func NewIdentifiedChannel(portID, channelID string, ch Channel) IdentifiedChannel {
|
||||
return IdentifiedChannel{
|
||||
ID: channelID,
|
||||
PortID: portID,
|
||||
State: ch.State,
|
||||
Ordering: ch.Ordering,
|
||||
Counterparty: ch.Counterparty,
|
||||
ConnectionHops: ch.ConnectionHops,
|
||||
Version: ch.Version,
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateBasic performs a basic validation of the identifiers and channel fields.
|
||||
func (ic IdentifiedChannel) ValidateBasic() error {
|
||||
if err := host.DefaultChannelIdentifierValidator(ic.ID); err != nil {
|
||||
return sdkerrors.Wrap(ErrInvalidChannel, err.Error())
|
||||
}
|
||||
if err := host.DefaultPortIdentifierValidator(ic.PortID); err != nil {
|
||||
return sdkerrors.Wrap(ErrInvalidChannel, err.Error())
|
||||
}
|
||||
channel := NewChannel(ic.State, ic.Ordering, ic.Counterparty, ic.ConnectionHops, ic.Version)
|
||||
return channel.ValidateBasic()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
)
|
||||
|
||||
// PacketAckCommitment defines the genesis type necessary to retrieve and store
|
||||
// acknowlegements.
|
||||
type PacketAckCommitment struct {
|
||||
PortID string `json:"port_id" yaml:"port_id"`
|
||||
ChannelID string `json:"channel_id" yaml:"channel_id"`
|
||||
Sequence uint64 `json:"sequence" yaml:"sequence"`
|
||||
Hash []byte `json:"hash" yaml:"hash"`
|
||||
}
|
||||
|
||||
// NewPacketAckCommitment creates a new PacketAckCommitment instance.
|
||||
func NewPacketAckCommitment(portID, channelID string, seq uint64, hash []byte) PacketAckCommitment {
|
||||
return PacketAckCommitment{
|
||||
PortID: portID,
|
||||
ChannelID: channelID,
|
||||
Sequence: seq,
|
||||
Hash: hash,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate performs basic validation of fields returning an error upon any
|
||||
// failure.
|
||||
func (pa PacketAckCommitment) Validate() error {
|
||||
if len(pa.Hash) == 0 {
|
||||
return errors.New("hash bytes cannot be empty")
|
||||
}
|
||||
return validateGenFields(pa.PortID, pa.ChannelID, pa.Sequence)
|
||||
}
|
||||
|
||||
// PacketSequence defines the genesis type necessary to retrieve and store
|
||||
// next send and receive sequences.
|
||||
type PacketSequence struct {
|
||||
PortID string `json:"port_id" yaml:"port_id"`
|
||||
ChannelID string `json:"channel_id" yaml:"channel_id"`
|
||||
Sequence uint64 `json:"sequence" yaml:"sequence"`
|
||||
}
|
||||
|
||||
// NewPacketSequence creates a new PacketSequences instance.
|
||||
func NewPacketSequence(portID, channelID string, seq uint64) PacketSequence {
|
||||
return PacketSequence{
|
||||
PortID: portID,
|
||||
ChannelID: channelID,
|
||||
Sequence: seq,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate performs basic validation of fields returning an error upon any
|
||||
// failure.
|
||||
func (ps PacketSequence) Validate() error {
|
||||
return validateGenFields(ps.PortID, ps.ChannelID, ps.Sequence)
|
||||
}
|
||||
|
||||
// GenesisState defines the ibc channel submodule's genesis state.
|
||||
type GenesisState struct {
|
||||
Channels []IdentifiedChannel `json:"channels" yaml:"channels"`
|
||||
Acknowledgements []PacketAckCommitment `json:"acknowledgements" yaml:"acknowledgements"`
|
||||
Commitments []PacketAckCommitment `json:"commitments" yaml:"commitments"`
|
||||
SendSequences []PacketSequence `json:"send_sequences" yaml:"send_sequences"`
|
||||
RecvSequences []PacketSequence `json:"recv_sequences" yaml:"recv_sequences"`
|
||||
}
|
||||
|
||||
// NewGenesisState creates a GenesisState instance.
|
||||
func NewGenesisState(
|
||||
channels []IdentifiedChannel, acks, commitments []PacketAckCommitment,
|
||||
sendSeqs, recvSeqs []PacketSequence,
|
||||
) GenesisState {
|
||||
return GenesisState{
|
||||
Channels: channels,
|
||||
Acknowledgements: acks,
|
||||
Commitments: commitments,
|
||||
SendSequences: sendSeqs,
|
||||
RecvSequences: recvSeqs,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultGenesisState returns the ibc channel submodule's default genesis state.
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
Channels: []IdentifiedChannel{},
|
||||
Acknowledgements: []PacketAckCommitment{},
|
||||
Commitments: []PacketAckCommitment{},
|
||||
SendSequences: []PacketSequence{},
|
||||
RecvSequences: []PacketSequence{},
|
||||
}
|
||||
}
|
||||
|
||||
// Validate performs basic genesis state validation returning an error upon any
|
||||
// failure.
|
||||
func (gs GenesisState) Validate() error {
|
||||
for i, channel := range gs.Channels {
|
||||
if err := channel.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid channel %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, ack := range gs.Acknowledgements {
|
||||
if err := ack.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid acknowledgement %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, commitment := range gs.Commitments {
|
||||
if err := commitment.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid commitment %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, ss := range gs.SendSequences {
|
||||
if err := ss.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid send sequence %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, rs := range gs.RecvSequences {
|
||||
if err := rs.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid receive sequence %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateGenFields(portID, channelID string, sequence uint64) error {
|
||||
if err := host.DefaultPortIdentifierValidator(portID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := host.DefaultChannelIdentifierValidator(channelID); err != nil {
|
||||
return err
|
||||
}
|
||||
if sequence == 0 {
|
||||
return errors.New("sequence cannot be 0")
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
|
||||
)
|
||||
|
||||
const (
|
||||
testPort1 = "firstport"
|
||||
testPort2 = "secondport"
|
||||
testConnectionIDA = "connectionidatob"
|
||||
|
||||
testChannel1 = "firstchannel"
|
||||
testChannel2 = "secondchannel"
|
||||
|
||||
testChannelOrder = exported.ORDERED
|
||||
testChannelVersion = "1.0"
|
||||
)
|
||||
|
||||
func TestValidateGenesis(t *testing.T) {
|
||||
counterparty1 := NewCounterparty(testPort1, testChannel1)
|
||||
counterparty2 := NewCounterparty(testPort2, testChannel2)
|
||||
testCases := []struct {
|
||||
name string
|
||||
genState GenesisState
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
genState: DefaultGenesisState(),
|
||||
expPass: true,
|
||||
},
|
||||
{
|
||||
name: "valid genesis",
|
||||
genState: NewGenesisState(
|
||||
[]IdentifiedChannel{
|
||||
NewIdentifiedChannel(
|
||||
testPort1, testChannel1, NewChannel(
|
||||
exported.INIT, testChannelOrder, counterparty2, []string{testConnectionIDA}, testChannelVersion,
|
||||
),
|
||||
),
|
||||
NewIdentifiedChannel(
|
||||
testPort2, testChannel2, NewChannel(
|
||||
exported.INIT, testChannelOrder, counterparty1, []string{testConnectionIDA}, testChannelVersion,
|
||||
),
|
||||
),
|
||||
},
|
||||
[]PacketAckCommitment{
|
||||
NewPacketAckCommitment(testPort2, testChannel2, 1, []byte("ack")),
|
||||
},
|
||||
[]PacketAckCommitment{
|
||||
NewPacketAckCommitment(testPort1, testChannel1, 1, []byte("commit_hash")),
|
||||
},
|
||||
[]PacketSequence{
|
||||
NewPacketSequence(testPort1, testChannel1, 1),
|
||||
},
|
||||
[]PacketSequence{
|
||||
NewPacketSequence(testPort2, testChannel2, 1),
|
||||
},
|
||||
),
|
||||
expPass: true,
|
||||
},
|
||||
{
|
||||
name: "invalid channel",
|
||||
genState: GenesisState{
|
||||
Channels: []IdentifiedChannel{
|
||||
NewIdentifiedChannel(
|
||||
testPort1, "testChannel1", NewChannel(
|
||||
exported.INIT, testChannelOrder, counterparty2, []string{testConnectionIDA}, testChannelVersion,
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid ack",
|
||||
genState: GenesisState{
|
||||
Acknowledgements: []PacketAckCommitment{
|
||||
NewPacketAckCommitment(testPort2, testChannel2, 1, nil),
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid commitment",
|
||||
genState: GenesisState{
|
||||
Commitments: []PacketAckCommitment{
|
||||
NewPacketAckCommitment(testPort1, testChannel1, 1, nil),
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid send seq",
|
||||
genState: GenesisState{
|
||||
SendSequences: []PacketSequence{
|
||||
NewPacketSequence(testPort1, testChannel1, 0),
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid recv seq",
|
||||
genState: GenesisState{
|
||||
RecvSequences: []PacketSequence{
|
||||
NewPacketSequence(testPort1, "testChannel1", 1),
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid recv seq 2",
|
||||
genState: GenesisState{
|
||||
RecvSequences: []PacketSequence{
|
||||
NewPacketSequence("testPort1", testChannel1, 1),
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
err := tc.genState.Validate()
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,12 +16,6 @@ const (
|
|||
QueryConnectionChannels = "connection-channels"
|
||||
)
|
||||
|
||||
type IdentifiedChannel struct {
|
||||
Channel Channel `json:"channel_end" yaml:"channel_end"`
|
||||
PortIdentifier string `json:"port_identifier" yaml:"port_identifier"`
|
||||
ChannelIdentifier string `json:"channel_identifier" yaml:"channel_identifier"`
|
||||
}
|
||||
|
||||
// ChannelResponse defines the client query response for a channel which also
|
||||
// includes a proof,its path and the height from which the proof was retrieved.
|
||||
type ChannelResponse struct {
|
||||
|
@ -36,7 +30,8 @@ func NewChannelResponse(
|
|||
portID, channelID string, channel Channel, proof *merkle.Proof, height int64,
|
||||
) ChannelResponse {
|
||||
return ChannelResponse{
|
||||
Channel: IdentifiedChannel{Channel: channel, PortIdentifier: portID, ChannelIdentifier: channelID},
|
||||
|
||||
Channel: NewIdentifiedChannel(portID, channelID, channel),
|
||||
Proof: commitmenttypes.MerkleProof{Proof: proof},
|
||||
ProofPath: commitmenttypes.NewMerklePath(strings.Split(ibctypes.ChannelPath(portID, channelID), "/")),
|
||||
ProofHeight: uint64(height),
|
||||
|
|
|
@ -4,12 +4,14 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
client "github.com/cosmos/cosmos-sdk/x/ibc/02-client"
|
||||
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
|
||||
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
|
||||
)
|
||||
|
||||
// GenesisState defines the ibc module's genesis state.
|
||||
type GenesisState struct {
|
||||
ClientGenesis client.GenesisState `json:"client_genesis" yaml:"client_genesis"`
|
||||
ConnectionGenesis connection.GenesisState `json:"connection_genesis" yaml:"connection_genesis"`
|
||||
ChannelGenesis channel.GenesisState `json:"channel_genesis" yaml:"channel_genesis"`
|
||||
}
|
||||
|
||||
// DefaultGenesisState returns the ibc module's default genesis state.
|
||||
|
@ -17,6 +19,7 @@ func DefaultGenesisState() GenesisState {
|
|||
return GenesisState{
|
||||
ClientGenesis: client.DefaultGenesisState(),
|
||||
ConnectionGenesis: connection.DefaultGenesisState(),
|
||||
ChannelGenesis: channel.DefaultGenesisState(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +30,11 @@ func (gs GenesisState) Validate() error {
|
|||
return err
|
||||
}
|
||||
|
||||
return gs.ConnectionGenesis.Validate()
|
||||
if err := gs.ConnectionGenesis.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gs.ChannelGenesis.Validate()
|
||||
}
|
||||
|
||||
// InitGenesis initializes the ibc state from a provided genesis
|
||||
|
@ -35,6 +42,7 @@ func (gs GenesisState) Validate() error {
|
|||
func InitGenesis(ctx sdk.Context, k Keeper, gs GenesisState) {
|
||||
client.InitGenesis(ctx, k.ClientKeeper, gs.ClientGenesis)
|
||||
connection.InitGenesis(ctx, k.ConnectionKeeper, gs.ConnectionGenesis)
|
||||
channel.InitGenesis(ctx, k.ChannelKeeper, gs.ChannelGenesis)
|
||||
}
|
||||
|
||||
// ExportGenesis returns the ibc exported genesis.
|
||||
|
@ -42,5 +50,6 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
|||
return GenesisState{
|
||||
ClientGenesis: client.ExportGenesis(ctx, k.ClientKeeper),
|
||||
ConnectionGenesis: connection.ExportGenesis(ctx, k.ConnectionKeeper),
|
||||
ChannelGenesis: channel.ExportGenesis(ctx, k.ChannelKeeper),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
|
||||
connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
|
||||
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
|
||||
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
|
||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
|
@ -50,6 +52,28 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
|
|||
connection.NewConnectionPaths(clientID, []string{ibctypes.ConnectionPath(connectionID)}),
|
||||
},
|
||||
),
|
||||
ChannelGenesis: channel.NewGenesisState(
|
||||
[]channel.IdentifiedChannel{
|
||||
channel.NewIdentifiedChannel(
|
||||
port1, channel1, channel.NewChannel(
|
||||
channelexported.INIT, channelOrder,
|
||||
channel.NewCounterparty(port2, channel2), []string{connectionID}, channelVersion,
|
||||
),
|
||||
),
|
||||
},
|
||||
[]channel.PacketAckCommitment{
|
||||
channel.NewPacketAckCommitment(port2, channel2, 1, []byte("ack")),
|
||||
},
|
||||
[]channel.PacketAckCommitment{
|
||||
channel.NewPacketAckCommitment(port1, channel1, 1, []byte("commit_hash")),
|
||||
},
|
||||
[]channel.PacketSequence{
|
||||
channel.NewPacketSequence(port1, channel1, 1),
|
||||
},
|
||||
[]channel.PacketSequence{
|
||||
channel.NewPacketSequence(port2, channel2, 1),
|
||||
},
|
||||
),
|
||||
},
|
||||
expPass: true,
|
||||
},
|
||||
|
@ -82,6 +106,19 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
|
|||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid channel genesis",
|
||||
genState: ibc.GenesisState{
|
||||
ClientGenesis: client.DefaultGenesisState(),
|
||||
ConnectionGenesis: connection.DefaultGenesisState(),
|
||||
ChannelGenesis: channel.GenesisState{
|
||||
Acknowledgements: []channel.PacketAckCommitment{
|
||||
channel.NewPacketAckCommitment("portID", channel1, 1, []byte("ack")),
|
||||
},
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/store/cachekv"
|
||||
"github.com/cosmos/cosmos-sdk/store/dbadapter"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
|
||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
)
|
||||
|
||||
|
@ -24,6 +25,15 @@ const (
|
|||
connectionID2 = "connectionidtwo"
|
||||
clientID2 = "clientidtwo"
|
||||
|
||||
port1 = "firstport"
|
||||
port2 = "secondport"
|
||||
|
||||
channel1 = "firstchannel"
|
||||
channel2 = "secondchannel"
|
||||
|
||||
channelOrder = channelexported.ORDERED
|
||||
channelVersion = "1.0"
|
||||
|
||||
trustingPeriod time.Duration = time.Hour * 24 * 7 * 2
|
||||
ubdPeriod time.Duration = time.Hour * 24 * 7 * 3
|
||||
maxClockDrift time.Duration = time.Second * 10
|
||||
|
|
|
@ -144,12 +144,6 @@ func KeyChannel(portID, channelID string) []byte {
|
|||
return []byte(ChannelPath(portID, channelID))
|
||||
}
|
||||
|
||||
// KeyChannelCapabilityPath returns the store key for the capability key of a
|
||||
// particular channel binded to a specific port
|
||||
func KeyChannelCapabilityPath(portID, channelID string) []byte {
|
||||
return []byte(ChannelCapabilityPath(portID, channelID))
|
||||
}
|
||||
|
||||
// KeyNextSequenceSend returns the store key for the send sequence of a particular
|
||||
// channel binded to a specific port
|
||||
func KeyNextSequenceSend(portID, channelID string) []byte {
|
||||
|
|
Loading…
Reference in New Issue