migrate localhost client state to proto (#6925)

* migrate localhost to proto

* localhost returns err on verify consensus state

* fix lint
This commit is contained in:
colin axnér 2020-08-03 15:45:15 +02:00 committed by GitHub
parent 00961f2082
commit 57cd7d62b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 342 additions and 118 deletions

View File

@ -5,7 +5,25 @@ import "gogoproto/gogo.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types";
// MsgCreateClient defines a message to create an IBC client
// MsgCreateClient defines a message to create a localhost client state
message MsgCreateClient {
bytes signer = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
option (gogoproto.goproto_getters) = false;
bytes signer = 1
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
}
// ClientState defines a loopback (localhost) client. It requires (read-only)
// access to keys outside the client prefix.
message ClientState {
option (gogoproto.goproto_getters) = false;
// client id
string id = 1 [(gogoproto.customname) = "ID"];
// self chain ID
string chain_id = 2 [
(gogoproto.customname) = "ChainID",
(gogoproto.moretags) = "yaml:\"chain_id\""
];
// self latest block height
uint64 height = 3;
}

View File

@ -21,19 +21,13 @@ import (
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
var _ clientexported.ClientState = ClientState{}
// ClientState requires (read-only) access to keys outside the client prefix.
type ClientState struct {
ChainID string `json:"chain_id" yaml:"chain_id"`
Height int64 `json:"height" yaml:"height"`
}
var _ clientexported.ClientState = (*ClientState)(nil)
// NewClientState creates a new ClientState instance
func NewClientState(chainID string, height int64) ClientState {
return ClientState{
ChainID: chainID,
Height: height,
Height: uint64(height),
}
}
@ -49,7 +43,7 @@ func (cs ClientState) ClientType() clientexported.ClientType {
// GetLatestHeight returns the latest height stored.
func (cs ClientState) GetLatestHeight() uint64 {
return uint64(cs.Height)
return cs.Height
}
// IsFrozen returns false.
@ -73,45 +67,13 @@ func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec {
return nil
}
// VerifyClientConsensusState verifies a proof of the consensus
// state of the loop-back client.
// VerifyClientConsensusState verifies a proof of the consensus state of the
// Tendermint client stored on the target machine.
// VerifyClientConsensusState returns an error since a local host client does not store consensus
// states.
func (cs ClientState) VerifyClientConsensusState(
store sdk.KVStore,
_ codec.BinaryMarshaler,
aminoCdc *codec.Codec,
_ commitmentexported.Root,
height uint64,
_ string,
consensusHeight uint64,
prefix commitmentexported.Prefix,
_ []byte,
consensusState clientexported.ConsensusState,
sdk.KVStore, codec.BinaryMarshaler, *codec.Codec, commitmentexported.Root,
uint64, string, uint64, commitmentexported.Prefix, []byte, clientexported.ConsensusState,
) error {
path, err := commitmenttypes.ApplyPrefix(prefix, clientexported.ClientTypeLocalHost)
if err != nil {
return err
}
data := store.Get([]byte(path.String()))
if len(data) == 0 {
return sdkerrors.Wrapf(clienttypes.ErrFailedClientConsensusStateVerification, "not found for path %s", path)
}
var prevConsensusState clientexported.ConsensusState
if err := aminoCdc.UnmarshalBinaryBare(data, &prevConsensusState); err != nil {
return err
}
if consensusState != prevConsensusState {
return sdkerrors.Wrapf(
clienttypes.ErrFailedClientConsensusStateVerification,
"consensus state ≠ previous stored consensus state: \n%v\n≠\n%v", consensusState, prevConsensusState,
)
}
return nil
return ErrConsensusStatesNotStored
}
// VerifyConnectionState verifies a proof of the connection state of the

View File

@ -48,41 +48,11 @@ func (suite *LocalhostTestSuite) TestValidate() {
}
func (suite *LocalhostTestSuite) TestVerifyClientConsensusState() {
testCases := []struct {
name string
clientState types.ClientState
prefix commitmenttypes.MerklePrefix
proof []byte
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState("chainID", 10),
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "proof verification failed",
clientState: types.NewClientState("chainID", 10),
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: []byte{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyClientConsensusState(
suite.store, suite.cdc, suite.aminoCdc, nil, height, "chainA", 0, tc.prefix, tc.proof, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
clientState := types.NewClientState("chainID", 10)
err := clientState.VerifyClientConsensusState(
nil, nil, nil, nil, 0, "", 0, nil, nil, nil,
)
suite.Require().Error(err)
}
func (suite *LocalhostTestSuite) TestVerifyConnectionState() {

View File

@ -2,25 +2,42 @@ package types
import (
"github.com/cosmos/cosmos-sdk/codec"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
)
const (
// SubModuleName for the localhost (loopback) client
SubModuleName = "localhost"
)
// SubModuleCdc defines the IBC localhost client codec.
var SubModuleCdc *codec.Codec
func init() {
SubModuleCdc = codec.New()
cryptocodec.RegisterCrypto(SubModuleCdc)
RegisterCodec(SubModuleCdc)
}
// RegisterCodec registers the localhost types
// RegisterCodec registers client state on the provided Amino codec. This type is used for
// Amino JSON serialization.
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(ClientState{}, "ibc/client/localhost/ClientState", nil)
cdc.RegisterConcrete(&MsgCreateClient{}, "ibc/client/localhost/MsgCreateClient", nil)
}
// RegisterInterfaces register the ibc interfaces submodule implementations to protobuf
// Any.
func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgCreateClient{},
)
registry.RegisterImplementations(
(*clientexported.ClientState)(nil),
&ClientState{},
)
}
var (
amino = codec.New()
// SubModuleCdc references the global x/ibc/09-localhost module codec. Note, the codec should
// ONLY be used in certain instances of tests and for JSON encoding.
//
// The actual codec used for serialization should be provided to x/ibc/09-localhost and
// defined at the application level.
SubModuleCdc = codec.NewHybridCodec(amino, cdctypes.NewInterfaceRegistry())
)
func init() {
RegisterCodec(amino)
amino.Seal()
}

View File

@ -0,0 +1,10 @@
package types
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// Localhost sentinel errors
var (
ErrConsensusStatesNotStored = sdkerrors.Register(SubModuleName, 2, "localhost does not store consensus states")
)

View File

@ -0,0 +1,6 @@
package types
const (
// SubModuleName for the localhost (loopback) client
SubModuleName = "localhost"
)

View File

@ -24,7 +24,7 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// MsgCreateClient defines a message to create an IBC client
// MsgCreateClient defines a message to create a localhost client state
type MsgCreateClient struct {
Signer github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=signer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"signer,omitempty"`
}
@ -62,34 +62,79 @@ func (m *MsgCreateClient) XXX_DiscardUnknown() {
var xxx_messageInfo_MsgCreateClient proto.InternalMessageInfo
func (m *MsgCreateClient) GetSigner() github_com_cosmos_cosmos_sdk_types.AccAddress {
if m != nil {
return m.Signer
}
return nil
// ClientState defines a loopback (localhost) client. It requires (read-only)
// access to keys outside the client prefix.
type ClientState struct {
// client id
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// self chain ID
ChainID string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty" yaml:"chain_id"`
// self latest block height
Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
}
func (m *ClientState) Reset() { *m = ClientState{} }
func (m *ClientState) String() string { return proto.CompactTextString(m) }
func (*ClientState) ProtoMessage() {}
func (*ClientState) Descriptor() ([]byte, []int) {
return fileDescriptor_6a04d924e6f8a88e, []int{1}
}
func (m *ClientState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *ClientState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_ClientState.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *ClientState) XXX_Merge(src proto.Message) {
xxx_messageInfo_ClientState.Merge(m, src)
}
func (m *ClientState) XXX_Size() int {
return m.Size()
}
func (m *ClientState) XXX_DiscardUnknown() {
xxx_messageInfo_ClientState.DiscardUnknown(m)
}
var xxx_messageInfo_ClientState proto.InternalMessageInfo
func init() {
proto.RegisterType((*MsgCreateClient)(nil), "ibc.localhost.MsgCreateClient")
proto.RegisterType((*ClientState)(nil), "ibc.localhost.ClientState")
}
func init() { proto.RegisterFile("ibc/localhost/localhost.proto", fileDescriptor_6a04d924e6f8a88e) }
var fileDescriptor_6a04d924e6f8a88e = []byte{
// 200 bytes of a gzipped FileDescriptorProto
// 305 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcd, 0x4c, 0x4a, 0xd6,
0xcf, 0xc9, 0x4f, 0x4e, 0xcc, 0xc9, 0xc8, 0x2f, 0x2e, 0x41, 0xb0, 0xf4, 0x0a, 0x8a, 0xf2, 0x4b,
0xf2, 0x85, 0x78, 0x33, 0x93, 0x92, 0xf5, 0xe0, 0x82, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60,
0x19, 0x7d, 0x10, 0x0b, 0xa2, 0x48, 0x29, 0x86, 0x8b, 0xdf, 0xb7, 0x38, 0xdd, 0xb9, 0x28, 0x35,
0x19, 0x7d, 0x10, 0x0b, 0xa2, 0x48, 0x29, 0x89, 0x8b, 0xdf, 0xb7, 0x38, 0xdd, 0xb9, 0x28, 0x35,
0xb1, 0x24, 0xd5, 0x39, 0x27, 0x33, 0x35, 0xaf, 0x44, 0xc8, 0x93, 0x8b, 0xad, 0x38, 0x33, 0x3d,
0x2f, 0xb5, 0x48, 0x82, 0x51, 0x81, 0x51, 0x83, 0xc7, 0xc9, 0xf0, 0xd7, 0x3d, 0x79, 0xdd, 0xf4,
0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xe4, 0xfc, 0xe2, 0xdc, 0xfc, 0x62,
0x28, 0xa5, 0x5b, 0x9c, 0x92, 0xad, 0x5f, 0x52, 0x59, 0x90, 0x5a, 0xac, 0xe7, 0x98, 0x9c, 0xec,
0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x1c, 0x04, 0x35, 0xc0, 0xc9, 0xff, 0xc4, 0x23, 0x39, 0xc6,
0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39,
0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x4c, 0xf1, 0x1a, 0x58, 0xa1, 0x0f, 0xf2, 0x9a, 0x81, 0xa5,
0x2e, 0xc2, 0x77, 0x60, 0x3b, 0x92, 0xd8, 0xc0, 0xae, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff,
0x0c, 0x82, 0x3a, 0x52, 0xfb, 0x00, 0x00, 0x00,
0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x1c, 0x04, 0x35, 0xc0, 0x8a, 0xa5, 0x63, 0x81, 0x3c, 0x83,
0x52, 0x1d, 0x17, 0x37, 0xc4, 0xe8, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, 0x31, 0x2e, 0xa6, 0xcc,
0x14, 0xb0, 0xd9, 0x9c, 0x4e, 0x6c, 0x8f, 0xee, 0xc9, 0x33, 0x79, 0xba, 0x04, 0x31, 0x65, 0xa6,
0x08, 0x59, 0x72, 0x71, 0x24, 0x67, 0x24, 0x66, 0xe6, 0xc5, 0x67, 0xa6, 0x48, 0x30, 0x81, 0x65,
0xe5, 0x1e, 0xdd, 0x93, 0x67, 0x77, 0x06, 0x89, 0x79, 0xba, 0x7c, 0xba, 0x27, 0xcf, 0x5f, 0x99,
0x98, 0x9b, 0x63, 0xa5, 0x04, 0x53, 0xa4, 0x14, 0xc4, 0x0e, 0x66, 0x7a, 0xa6, 0x08, 0x89, 0x71,
0xb1, 0x65, 0xa4, 0x66, 0xa6, 0x67, 0x94, 0x48, 0x30, 0x2b, 0x30, 0x6a, 0xb0, 0x04, 0x41, 0x79,
0x10, 0xfb, 0x9d, 0xfc, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39,
0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x14,
0xaf, 0xb7, 0x2a, 0xf4, 0x41, 0x01, 0x6c, 0x60, 0xa9, 0x8b, 0x08, 0x63, 0xb0, 0x4f, 0x93, 0xd8,
0xc0, 0x61, 0x67, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x15, 0x37, 0xf6, 0x9e, 0x81, 0x01, 0x00,
0x00,
}
func (m *MsgCreateClient) Marshal() (dAtA []byte, err error) {
@ -122,6 +167,48 @@ func (m *MsgCreateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *ClientState) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ClientState) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Height != 0 {
i = encodeVarintLocalhost(dAtA, i, uint64(m.Height))
i--
dAtA[i] = 0x18
}
if len(m.ChainID) > 0 {
i -= len(m.ChainID)
copy(dAtA[i:], m.ChainID)
i = encodeVarintLocalhost(dAtA, i, uint64(len(m.ChainID)))
i--
dAtA[i] = 0x12
}
if len(m.ID) > 0 {
i -= len(m.ID)
copy(dAtA[i:], m.ID)
i = encodeVarintLocalhost(dAtA, i, uint64(len(m.ID)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintLocalhost(dAtA []byte, offset int, v uint64) int {
offset -= sovLocalhost(v)
base := offset
@ -146,6 +233,26 @@ func (m *MsgCreateClient) Size() (n int) {
return n
}
func (m *ClientState) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.ID)
if l > 0 {
n += 1 + l + sovLocalhost(uint64(l))
}
l = len(m.ChainID)
if l > 0 {
n += 1 + l + sovLocalhost(uint64(l))
}
if m.Height != 0 {
n += 1 + sovLocalhost(uint64(m.Height))
}
return n
}
func sovLocalhost(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@ -239,6 +346,142 @@ func (m *MsgCreateClient) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *ClientState) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocalhost
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ClientState: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ClientState: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocalhost
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthLocalhost
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthLocalhost
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocalhost
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthLocalhost
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthLocalhost
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ChainID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType)
}
m.Height = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocalhost
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Height |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipLocalhost(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthLocalhost
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthLocalhost
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipLocalhost(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0

View File

@ -20,16 +20,14 @@ const (
type LocalhostTestSuite struct {
suite.Suite
aminoCdc *codec.Codec
cdc codec.Marshaler
store sdk.KVStore
cdc codec.Marshaler
store sdk.KVStore
}
func (suite *LocalhostTestSuite) SetupTest() {
isCheckTx := false
app := simapp.Setup(isCheckTx)
suite.aminoCdc = app.Codec()
suite.cdc = app.AppCodec()
ctx := app.BaseApp.NewContext(isCheckTx, abci.Header{Height: 1})
suite.store = app.IBCKeeper.ClientKeeper.ClientStore(ctx, clientexported.ClientTypeLocalHost)

View File

@ -13,7 +13,7 @@ const (
)
var (
_ clientexported.MsgCreateClient = &MsgCreateClient{}
_ clientexported.MsgCreateClient = (*MsgCreateClient)(nil)
)
// NewMsgCreateClient creates a new MsgCreateClient instance