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:
co-authored by
Alexander Bezobchuk
Aleksandr Bezobchuk
Aaron Craelius
parent
bb0a1edf8e
commit
d7ebee74e7
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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"];
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user