x/ibc: proto migration pt 1 (#6097)

* x/ibc: proto migration pt 1

* fix tests

* fixes and godoc

* yaml tags

* rm changelog

* address comments from review

* fix some tests

* fix tests

* add _UNSPECIFIED suffix for default enums

* Update app

* protobuf Any fixes

* use gogoproto

* fix tests

* wrap all messages

* address @alexanderbez comments

* update proto files

Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Aleksandr Bezobchuk <aleks.bezobchuk@gmail.com>
Co-authored-by: Aaron Craelius <aaron@regen.network>
This commit is contained in:
Federico Kunze
2020-05-06 11:17:50 -04:00
committed by GitHub
co-authored by Alexander Bezobchuk Aleksandr Bezobchuk Aaron Craelius
parent bb0a1edf8e
commit d7ebee74e7
84 changed files with 11011 additions and 1443 deletions
+18 -7
View File
@@ -2,12 +2,12 @@ package types
import (
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
)
var SubModuleCdc *codec.Codec
// RegisterCodec registers types declared in this package
// RegisterCodec registers the necessary x/ibc/23-commitment interfaces and concrete types
// on the provided Amino codec. These types are used for Amino JSON serialization.
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterInterface((*exported.Root)(nil), nil)
cdc.RegisterInterface((*exported.Prefix)(nil), nil)
@@ -18,10 +18,21 @@ func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(MerklePrefix{}, "ibc/commitment/MerklePrefix", nil)
cdc.RegisterConcrete(MerklePath{}, "ibc/commitment/MerklePath", nil)
cdc.RegisterConcrete(MerkleProof{}, "ibc/commitment/MerkleProof", nil)
SetSubModuleCodec(cdc)
}
func SetSubModuleCodec(cdc *codec.Codec) {
SubModuleCdc = cdc
var (
amino = codec.New()
// SubModuleCdc references the global x/ibc/23-commitmentl module codec. Note, the codec should
// ONLY be used in certain instances of tests and for JSON encoding as Amino is
// still used for that purpose.
//
// The actual codec used for serialization should be provided to x/ibc/23-commitmentl and
// defined at the application level.
SubModuleCdc = codec.NewHybridCodec(amino, cdctypes.NewInterfaceRegistry())
)
func init() {
RegisterCodec(amino)
amino.Seal()
}
+28
View File
@@ -0,0 +1,28 @@
package types
import (
fmt "fmt"
"net/url"
)
// AppendKey appends a new key to a KeyPath
func (pth KeyPath) AppendKey(key []byte, enc KeyEncoding) KeyPath {
pth.Keys = append(pth.Keys, &Key{name: key, enc: enc})
return pth
}
// String implements the fmt.Stringer interface
func (pth *KeyPath) String() string {
res := ""
for _, key := range pth.Keys {
switch key.enc {
case URL:
res += "/" + url.PathEscape(string(key.name))
case HEX:
res += "/x:" + fmt.Sprintf("%X", key.name)
default:
panic("unexpected key encoding type")
}
}
return res
}
+15 -41
View File
@@ -4,11 +4,11 @@ import (
"errors"
"net/url"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/cosmos/cosmos-sdk/store/rootmulti"
"github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
"github.com/tendermint/tendermint/crypto/merkle"
)
// ICS 023 Merkle Types Implementation
@@ -17,13 +17,7 @@ import (
// Merkle proof implementation of the Proof interface
// Applied on SDK-based IBC implementation
var _ exported.Root = MerkleRoot{}
// MerkleRoot defines a merkle root hash.
// In the Cosmos SDK, the AppHash of a block header becomes the root.
type MerkleRoot struct {
Hash []byte `json:"hash" yaml:"hash"`
}
var _ exported.Root = (*MerkleRoot)(nil)
// NewMerkleRoot constructs a new MerkleRoot
func NewMerkleRoot(hash []byte) MerkleRoot {
@@ -32,28 +26,22 @@ func NewMerkleRoot(hash []byte) MerkleRoot {
}
}
// GetCommitmentType implements RootI interface
func (MerkleRoot) GetCommitmentType() exported.Type {
return exported.Merkle
}
// GetHash implements RootI interface
func (mr MerkleRoot) GetHash() []byte {
return mr.Hash
}
// GetCommitmentType implements RootI interface
func (MerkleRoot) GetCommitmentType() exported.Type {
return exported.Merkle
}
// IsEmpty returns true if the root is empty
func (mr MerkleRoot) IsEmpty() bool {
return len(mr.GetHash()) == 0
}
var _ exported.Prefix = MerklePrefix{}
// MerklePrefix is merkle path prefixed to the key.
// The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...))
type MerklePrefix struct {
KeyPrefix []byte `json:"key_prefix" yaml:"key_prefix"` // byte slice prefixed before the key
}
var _ exported.Prefix = (*MerklePrefix)(nil)
// NewMerklePrefix constructs new MerklePrefix instance
func NewMerklePrefix(keyPrefix []byte) MerklePrefix {
@@ -77,19 +65,13 @@ func (mp MerklePrefix) IsEmpty() bool {
return len(mp.Bytes()) == 0
}
var _ exported.Path = MerklePath{}
// MerklePath is the path used to verify commitment proofs, which can be an arbitrary
// structured object (defined by a commitment type).
type MerklePath struct {
KeyPath merkle.KeyPath `json:"key_path" yaml:"key_path"` // byte slice prefixed before the key
}
var _ exported.Path = (*MerklePath)(nil)
// NewMerklePath creates a new MerklePath instance
func NewMerklePath(keyPathStr []string) MerklePath {
merkleKeyPath := merkle.KeyPath{}
merkleKeyPath := KeyPath{}
for _, keyStr := range keyPathStr {
merkleKeyPath = merkleKeyPath.AppendKey([]byte(keyStr), merkle.KeyEncodingURL)
merkleKeyPath = merkleKeyPath.AppendKey([]byte(keyStr), URL)
}
return MerklePath{
@@ -118,7 +100,7 @@ func (mp MerklePath) Pretty() string {
// IsEmpty returns true if the path is empty
func (mp MerklePath) IsEmpty() bool {
return len(mp.KeyPath) == 0
return len(mp.KeyPath.Keys) == 0
}
// ApplyPrefix constructs a new commitment path from the arguments. It interprets
@@ -138,15 +120,7 @@ func ApplyPrefix(prefix exported.Prefix, path string) (MerklePath, error) {
return NewMerklePath([]string{string(prefix.Bytes()), path}), nil
}
var _ exported.Proof = MerkleProof{}
// MerkleProof is a wrapper type that contains a merkle proof.
// It demonstrates membership or non-membership for an element or set of elements,
// verifiable in conjunction with a known commitment root. Proofs should be
// succinct.
type MerkleProof struct {
Proof *merkle.Proof `json:"proof" yaml:"proof"`
}
var _ exported.Proof = (*MerkleProof)(nil)
// GetCommitmentType implements ProofI
func (MerkleProof) GetCommitmentType() exported.Type {
@@ -175,7 +149,7 @@ func (proof MerkleProof) VerifyNonMembership(root exported.Root, path exported.P
// IsEmpty returns true if the root is empty
func (proof MerkleProof) IsEmpty() bool {
return (proof == MerkleProof{}) || proof.Proof == nil
return proof.Proof.Equal(nil) || proof.Equal(MerkleProof{}) || proof.Proof.Equal(nil) || proof.Proof.Equal(merkle.Proof{})
}
// ValidateBasic checks if the proof is empty.
+2 -2
View File
@@ -53,7 +53,7 @@ func (suite *MerkleTestSuite) TestVerifyMembership() {
root := types.NewMerkleRoot(tc.root)
path := types.NewMerklePath(tc.pathArr)
err := proof.VerifyMembership(root, path, tc.value)
err := proof.VerifyMembership(&root, path, tc.value)
if tc.shouldPass {
// nolint: scopelint
@@ -108,7 +108,7 @@ func (suite *MerkleTestSuite) TestVerifyNonMembership() {
root := types.NewMerkleRoot(tc.root)
path := types.NewMerklePath(tc.pathArr)
err := proof.VerifyNonMembership(root, path)
err := proof.VerifyNonMembership(&root, path)
if tc.shouldPass {
// nolint: scopelint
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
syntax = "proto3";
package cosmos_sdk.x.ibc.commitment.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types";
import "third_party/proto/gogoproto/gogo.proto";
import "third_party/proto/tendermint/crypto/merkle/merkle.proto";
// MerkleRoot defines a merkle root hash.
// In the Cosmos SDK, the AppHash of a block header becomes the root.
message MerkleRoot {
option (gogoproto.goproto_getters) = false;
bytes hash = 1;
}
// MerklePrefix is merkle path prefixed to the key.
// The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...))
message MerklePrefix {
bytes key_prefix = 1 [(gogoproto.moretags) = "yaml:\"key_prefix\""];
}
// MerklePath is the path used to verify commitment proofs, which can be an arbitrary
// structured object (defined by a commitment type).
message MerklePath {
option (gogoproto.goproto_stringer) = false;
KeyPath key_path = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"key_path\""
];
}
// MerkleProof is a wrapper type that contains a merkle proof.
// It demonstrates membership or non-membership for an element or set of elements,
// verifiable in conjunction with a known commitment root. Proofs should be
// succinct.
message MerkleProof {
option (gogoproto.equal) = true;
tendermint.crypto.merkle.Proof proof = 1;
}
// KeyPath defines a slice of keys
message KeyPath {
option (gogoproto.goproto_stringer) = false;
option (gogoproto.goproto_getters) = false;
repeated Key keys = 1;
}
// Key defines a proof Key
message Key {
option (gogoproto.goproto_getters) = false;
bytes name = 1 [(gogoproto.customname) = "name"];
KeyEncoding enc = 2 [(gogoproto.customname) = "enc"];
}
// KeyEncoding defines the encoding format of a key's bytes.
enum KeyEncoding {
option (gogoproto.goproto_enum_stringer) = false;
option (gogoproto.goproto_enum_prefix) = false;
// URL encoding
KEY_ENCODING_URL_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "URL"];
// Hex encoding
KEY_ENCODING_HEX = 1 [(gogoproto.enumvalue_customname) = "HEX"];
}
+2 -1
View File
@@ -9,7 +9,8 @@ import (
// CalculateRoot returns the application Hash at the curretn block height as a commitment
// root for proof verification.
func CalculateRoot(ctx sdk.Context) exported.Root {
return types.NewMerkleRoot(ctx.BlockHeader().AppHash)
root := types.NewMerkleRoot(ctx.BlockHeader().AppHash)
return &root
}
// BatchVerifyMembership verifies a proof that many paths have been set to