Skip to content

Commit

Permalink
x/ibc migrate genesis proto (#6878)
Browse files Browse the repository at this point in the history
* migrated channel genesis types to proto

* connection genesis types migrated to proto

* client proto migration

* failing tests due to tendermint part incomplete

* add genesis test

* x/ibc: ClientState Any

* add genesis test

* suite NotPanics

* comment tests

* update export logic

* refactor

* update test

* fix non-determinism

* castrepeated

* x/ibc: migrate simulations to protobuf

* add proto genesis

* add UnpackInterfaces func to genclientstate

* add unpackinterfaces for consensus states

* formatting

* fix genesis tests

* add modified genesis test

* update comments

* remove localhost register codec

* use app registry

* fix bug

* Update simapp/app.go

* Update x/ibc/02-client/types/genesis.go

* unmarshaler interface

Co-authored-by: Colin Axner <colinaxner@berkeley.edu>
Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>
  • Loading branch information
5 people authored Aug 7, 2020
1 parent 89097a0 commit ceba0cb
Show file tree
Hide file tree
Showing 27 changed files with 3,202 additions and 182 deletions.
46 changes: 46 additions & 0 deletions proto/ibc/channel/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
syntax = "proto3";
package ibc.channel;

option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types";

import "gogoproto/gogo.proto";
import "ibc/channel/channel.proto";

// GenesisState defines the ibc channel submodule's genesis state.
message GenesisState {
repeated IdentifiedChannel channels = 1 [
(gogoproto.casttype) = "IdentifiedChannel",
(gogoproto.nullable) = false
];
repeated PacketAckCommitment acknowledgements = 2 [
(gogoproto.casttype) = "PacketAckCommitment",
(gogoproto.nullable) = false
];
repeated PacketAckCommitment commitments = 3 [(gogoproto.nullable) = false];
repeated PacketSequence send_sequences = 4 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"send_sequences\""
];
repeated PacketSequence recv_sequences = 5 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"recv_sequences\""
];
repeated PacketSequence ack_sequences = 6 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"ack_sequences\""
];
}

// PacketSequence defines the genesis type necessary to retrieve and store
// next send and receive sequences.
message PacketSequence {
string port_id = 1 [
(gogoproto.customname) = "PortID",
(gogoproto.moretags) = "yaml:\"port_id\""
];
string channel_id = 2 [
(gogoproto.customname) = "ChannelID",
(gogoproto.moretags) = "yaml:\"channel_id\""
];
uint64 sequence = 3;
}
41 changes: 41 additions & 0 deletions proto/ibc/client/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
syntax = "proto3";
package ibc.client;

option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types";

import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";

// GenesisClientState defines an identified ClientState as protobuf Any format.
message GenesisClientState {
string client_id = 1 [
(gogoproto.customname) = "ClientID",
(gogoproto.moretags) = "yaml:\"client_id\""
];
google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""];
}

// ClientConsensusStates defines all the stored consensus states for a given client.
message ClientConsensusStates {
string client_id = 1 [
(gogoproto.customname) = "ClientID"
];
repeated google.protobuf.Any consensus_states = 2 [
(gogoproto.moretags) = "yaml:\"consensus_states\""
];
}

// GenesisState defines the ibc client submodule's genesis state.
message GenesisState {
repeated GenesisClientState clients = 1 [
(gogoproto.nullable) = false
];
repeated ClientConsensusStates clients_consensus = 2 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "ClientsConsensusStates",
(gogoproto.moretags) = "yaml:\"clients_consensus\""
];
bool create_localhost = 3 [
(gogoproto.moretags) = "yaml:\"create_localhost\""
];
}
19 changes: 19 additions & 0 deletions proto/ibc/connection/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
syntax = "proto3";
package ibc.connection;

option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types";

import "gogoproto/gogo.proto";
import "ibc/connection/connection.proto";


// GenesisState defines the ibc connection submodule's genesis state.
message GenesisState {
repeated IdentifiedConnection connections = 1 [
(gogoproto.nullable) = false
];
repeated ConnectionPaths client_connection_paths = 2 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"client_connection_paths\""
];
}
28 changes: 28 additions & 0 deletions proto/ibc/types/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
syntax = "proto3";
package ibc.types;

option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/types";

import "gogoproto/gogo.proto";
import "ibc/client/genesis.proto";
import "ibc/connection/genesis.proto";
import "ibc/channel/genesis.proto";

// GenesisState defines the ibc module's genesis state.
message GenesisState {
// ICS002 - Clients genesis state
ibc.client.GenesisState client_genesis = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"client_genesis\""
];
// ICS003 - Connections genesis state
ibc.connection.GenesisState connection_genesis = 2 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"connection_genesis\""
];
// ICS004 - Channel genesis state
ibc.channel.GenesisState channel_genesis = 3 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"channel_genesis\""
];
}
4 changes: 1 addition & 3 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,8 @@ func NewSimApp(
)

// Create IBC Keeper
// TODO: remove amino codec dependency once Tendermint version is upgraded with
// protobuf changes
app.IBCKeeper = ibckeeper.NewKeeper(
app.cdc, appCodec, keys[ibchost.StoreKey], app.StakingKeeper, scopedIBCKeeper,
appCodec, keys[ibchost.StoreKey], app.StakingKeeper, scopedIBCKeeper,
)

// Create Transfer Keepers
Expand Down
16 changes: 13 additions & 3 deletions x/ibc/02-client/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,22 @@ import (
// state.
func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) {
for _, client := range gs.Clients {
k.SetClientState(ctx, client.ClientID, client.ClientState)
k.SetClientType(ctx, client.ClientID, client.ClientState.ClientType())
cs, ok := client.ClientState.GetCachedValue().(exported.ClientState)
if !ok {
panic("invalid client state")
}
k.SetClientState(ctx, client.ClientID, cs)
k.SetClientType(ctx, client.ClientID, cs.ClientType())
}

for _, cs := range gs.ClientsConsensus {
for _, consState := range cs.ConsensusStates {
k.SetClientConsensusState(ctx, cs.ClientID, consState.GetHeight(), consState)
consensusState, ok := consState.GetCachedValue().(exported.ConsensusState)
if !ok {
panic("invalid consensus state")
}

k.SetClientConsensusState(ctx, cs.ClientID, consensusState.GetHeight(), consensusState)
}
}

Expand Down
47 changes: 17 additions & 30 deletions x/ibc/02-client/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/tendermint/tendermint/libs/log"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
Expand Down Expand Up @@ -118,51 +119,37 @@ func (k Keeper) IterateConsensusStates(ctx sdk.Context, cb func(clientID string,
// GetAllGenesisClients returns all the clients in state with their client ids returned as GenesisClientState
func (k Keeper) GetAllGenesisClients(ctx sdk.Context) (genClients []types.GenesisClientState) {
k.IterateClients(ctx, func(clientID string, cs exported.ClientState) bool {
gc := types.GenesisClientState{
ClientID: clientID,
ClientState: cs,
}
genClients = append(genClients, gc)
genClients = append(genClients, types.NewGenesisClientState(clientID, cs))
return false
})
return
}

// GetAllConsensusStates returns all stored client consensus states.
// NOTE: non deterministic.
func (k Keeper) GetAllConsensusStates(ctx sdk.Context) (clientConsStates []types.ClientConsensusStates) {
var clientIDs []string
// create map to add consensus states to the existing clients
cons := make(map[string][]exported.ConsensusState)
func (k Keeper) GetAllConsensusStates(ctx sdk.Context) types.ClientsConsensusStates {
clientConsStates := make(types.ClientsConsensusStates, 0)
mapClientIDToConsStateIdx := make(map[string]int)

k.IterateConsensusStates(ctx, func(clientID string, cs exported.ConsensusState) bool {
consensusStates, ok := cons[clientID]
if !ok {
clientIDs = append(clientIDs, clientID)
cons[clientID] = []exported.ConsensusState{cs}
anyClientState := types.MustPackConsensusState(cs)

idx, ok := mapClientIDToConsStateIdx[clientID]
if ok {
clientConsStates[idx].ConsensusStates = append(clientConsStates[idx].ConsensusStates, anyClientState)
return false
}

cons[clientID] = append(consensusStates, cs)
return false
})

// create ClientConsensusStates in the same order of iteration to prevent non-determinism
for len(clientIDs) > 0 {
id := clientIDs[len(clientIDs)-1]
consensusStates, ok := cons[id]
if !ok {
panic(fmt.Sprintf("consensus states from client id %s not found", id))
clientConsState := types.ClientConsensusStates{
ClientID: clientID,
ConsensusStates: []*codectypes.Any{anyClientState},
}

clientConsState := types.NewClientConsensusStates(id, consensusStates)
clientConsStates = append(clientConsStates, clientConsState)
mapClientIDToConsStateIdx[clientID] = len(clientConsStates) - 1
return false
})

// remove the last element
clientIDs = clientIDs[:len(clientIDs)-1]
}

return clientConsStates
return clientConsStates.Sort()
}

// HasClientConsensusState returns if keeper has a ConsensusState for a particular
Expand Down
43 changes: 19 additions & 24 deletions x/ibc/02-client/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,35 +223,30 @@ func (suite KeeperTestSuite) TestConsensusStateHelpers() {
}

func (suite KeeperTestSuite) TestGetAllConsensusStates() {
expConsensus := []types.ClientConsensusStates{
types.NewClientConsensusStates(
testClientID,
[]exported.ConsensusState{
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.consensusState.GetHeight(), nil,
),
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp.Add(time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash")), suite.consensusState.GetHeight()+1, nil,
),
},
expConsensus := []exported.ConsensusState{
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.consensusState.GetHeight(), nil,
),
types.NewClientConsensusStates(
testClientID2,
[]exported.ConsensusState{
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp.Add(2*time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash_2")), suite.consensusState.GetHeight()+2, nil,
),
},
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp.Add(time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash")), suite.consensusState.GetHeight()+1, nil,
),
}

for i := range expConsensus {
for _, cons := range expConsensus[i].ConsensusStates {
suite.keeper.SetClientConsensusState(suite.ctx, expConsensus[i].ClientID, cons.GetHeight(), cons)
}
expConsensus2 := []exported.ConsensusState{
ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp.Add(2*time.Minute), commitmenttypes.NewMerkleRoot([]byte("app_hash_2")), suite.consensusState.GetHeight()+2, nil,
),
}

expAnyConsensus := types.ClientsConsensusStates{
types.NewClientConsensusStates(testClientID, expConsensus),
types.NewClientConsensusStates(testClientID2, expConsensus2),
}.Sort()

suite.keeper.SetClientConsensusState(suite.ctx, testClientID, expConsensus[0].GetHeight(), expConsensus[0])
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, expConsensus[1].GetHeight(), expConsensus[1])
suite.keeper.SetClientConsensusState(suite.ctx, testClientID2, expConsensus2[0].GetHeight(), expConsensus2[0])

consStates := suite.keeper.GetAllConsensusStates(suite.ctx)
suite.Require().Len(consStates, len(expConsensus))
suite.Require().Equal(expConsensus, consStates)
suite.Require().Equal(expAnyConsensus, consStates, "%s \n\n%s", expAnyConsensus, consStates)
}
19 changes: 11 additions & 8 deletions x/ibc/02-client/simulation/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,32 @@ import (
"bytes"
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)

// ClientUnmarshaler defines an interface for unmarshaling ICS02 interfaces.
type ClientUnmarshaler interface {
MustUnmarshalClientState([]byte) exported.ClientState
MustUnmarshalConsensusState([]byte) exported.ConsensusState
}

// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding client type.
func NewDecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) (string, bool) {
func NewDecodeStore(cdc ClientUnmarshaler, kvA, kvB kv.Pair) (string, bool) {
switch {
case bytes.HasPrefix(kvA.Key, host.KeyClientStorePrefix) && bytes.HasSuffix(kvA.Key, host.KeyClientState()):
var clientStateA, clientStateB exported.ClientState
cdc.MustUnmarshalBinaryBare(kvA.Value, &clientStateA)
cdc.MustUnmarshalBinaryBare(kvB.Value, &clientStateB)
clientStateA := cdc.MustUnmarshalClientState(kvA.Value)
clientStateB := cdc.MustUnmarshalClientState(kvB.Value)
return fmt.Sprintf("ClientState A: %v\nClientState B: %v", clientStateA, clientStateB), true

case bytes.HasPrefix(kvA.Key, host.KeyClientStorePrefix) && bytes.HasSuffix(kvA.Key, host.KeyClientType()):
return fmt.Sprintf("Client type A: %s\nClient type B: %s", string(kvA.Value), string(kvB.Value)), true

case bytes.HasPrefix(kvA.Key, host.KeyClientStorePrefix) && bytes.Contains(kvA.Key, []byte("consensusState")):
var consensusStateA, consensusStateB exported.ConsensusState
cdc.MustUnmarshalBinaryBare(kvA.Value, &consensusStateA)
cdc.MustUnmarshalBinaryBare(kvB.Value, &consensusStateB)
consensusStateA := cdc.MustUnmarshalConsensusState(kvA.Value)
consensusStateB := cdc.MustUnmarshalConsensusState(kvB.Value)
return fmt.Sprintf("ConsensusState A: %v\nConsensusState B: %v", consensusStateA, consensusStateB), true

default:
Expand Down
11 changes: 5 additions & 6 deletions x/ibc/02-client/simulation/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,29 @@ import (

func TestDecodeStore(t *testing.T) {
app := simapp.Setup(false)
cdc := app.Codec()
clientID := "clientidone"

clientState := ibctmtypes.ClientState{
clientState := &ibctmtypes.ClientState{
FrozenHeight: 10,
}

consState := ibctmtypes.ConsensusState{
consState := &ibctmtypes.ConsensusState{
Height: 10,
Timestamp: time.Now().UTC(),
}

kvPairs := kv.Pairs{
kv.Pair{
Key: host.FullKeyClientPath(clientID, host.KeyClientState()),
Value: cdc.MustMarshalBinaryBare(clientState),
Value: app.IBCKeeper.ClientKeeper.MustMarshalClientState(clientState),
},
kv.Pair{
Key: host.FullKeyClientPath(clientID, host.KeyClientType()),
Value: []byte(exported.Tendermint.String()),
},
kv.Pair{
Key: host.FullKeyClientPath(clientID, host.KeyConsensusState(10)),
Value: cdc.MustMarshalBinaryBare(consState),
Value: app.IBCKeeper.ClientKeeper.MustMarshalConsensusState(consState),
},
kv.Pair{
Key: []byte{0x99},
Expand All @@ -60,7 +59,7 @@ func TestDecodeStore(t *testing.T) {
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
res, found := simulation.NewDecodeStore(cdc, kvPairs[i], kvPairs[i])
res, found := simulation.NewDecodeStore(app.IBCKeeper.ClientKeeper, kvPairs[i], kvPairs[i])
if i == len(tests)-1 {
require.False(t, found, string(kvPairs[i].Key))
require.Empty(t, res, string(kvPairs[i].Key))
Expand Down
Loading

0 comments on commit ceba0cb

Please sign in to comment.