diff --git a/x/ibc/23-commitment/README.md b/x/ibc/23-commitment/README.md new file mode 100644 index 00000000000..61a46b99d8a --- /dev/null +++ b/x/ibc/23-commitment/README.md @@ -0,0 +1,50 @@ +# ICS 23: Commitment + +Package `commitment` defines types and methods to verify other chain's state. The main type is `Store`, containing +proofs that can be verified when the correct value is provided. The spec functions those are directly related to +verification are: + +## Spec + +```typescript +type verifyMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key, value: Value) => bool +type verifyNonMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key) => bool +``` + +## Impl + +### types.go + +`type Proof` implements `spec: type CommitmentProof`. CommitmentProof is an arbitrary object which can be used as +an argument for `spec: verifyMembership` / `spec: verifyNonMembership`, constructed with `spec: createMembershipProof` / +`spec: createNonMembershipProof`. The implementation type `Proof` defines `spec: verify(Non)Membership` as its method +`Verify(Root, []byte) error`, which takes the commitment root and the value bytes argument. The method acts as +`spec: verifyMembership` when the value bytes is not nil, and `spec: verifyNonMembership` if it is nil. + +`type Root` implements `spec: type CommitmentRoot`. + +In Cosmos-SDK implementation, `Root` will be the `AppHash []byte`, and `Proof` will be `merkle.Proof`, which consists +of `SimpleProof` and `IAVLValueProof` + +### store.go + +`Store` assumes that the keys are already known at the time when the transaction is included, so the type `Proof` has +the method `Key() []byte`. The values should also have to be provided in order to verify the proof, but to reduce the +size of the transaction, they are excluded from `Proof` and provided by the application on runtime. + +`NewStore` takes `[]Proof` as its argument, without verifying, since the values are yet unknown. They are stored in +`store.proofs`. + +Proofs can be verified with `store.Prove()` method which takes the key of the proof it will verify and the value +that will be given to the `proof.Verify()`. Verified proofs are stored in `store.verified`. + +### context.go + +All of the ICS internals that requires verification on other chains' state are expected to take `ctx sdk.Context` +argument initialized by `WithStore()`. `WithStore()` sets the `Store` that contains the proofs for the other chain +in the context. Any attept to verify other chain's state without setting `Store` will lead to panic. + +### value.go + +Types in `value.go` is a replication of `store/mapping/*.go`, but only with a single method +`Is(ctx sdk.Context, value T) bool`, which access on the underlying `Store` and performs verification. diff --git a/x/ibc/23-commitment/keypath.go b/x/ibc/23-commitment/keypath.go new file mode 100644 index 00000000000..e3dc62f8af7 --- /dev/null +++ b/x/ibc/23-commitment/keypath.go @@ -0,0 +1,27 @@ +package commitment + +import ( + "github.com/tendermint/tendermint/crypto/merkle" +) + +// Hard coded for now +func SDKPrefix() merkle.KeyPath { + return new(merkle.KeyPath). + AppendKey([]byte("ibc"), merkle.KeyEncodingHex). + AppendKey([]byte{0x00}, merkle.KeyEncodingHex) +} + +func PrefixKeyPath(prefix string, key []byte) (res merkle.KeyPath, err error) { + keys, err := merkle.KeyPathToKeys(prefix) + if err != nil { + return + } + + keys[len(keys)-1] = append(keys[len(keys)], key...) + + for _, key := range keys { + res = res.AppendKey(key, merkle.KeyEncodingHex) + } + + return +} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 94977a9824e..92fad62e277 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -35,7 +35,7 @@ type store struct { } // Proofs must be provided -func Newstore(root Root, proofs []Proof, fullProofs []FullProof) (res store, err error) { +func Newstore(root Root, proofs []Proof) (res store, err error) { res = store{ root: root, proofs: make(map[string]Proof), @@ -46,14 +46,6 @@ func Newstore(root Root, proofs []Proof, fullProofs []FullProof) (res store, err res.proofs[string(proof.Key())] = proof } - for _, proof := range fullProofs { - err = proof.Verify(root) - if err != nil { - return - } - res.verified[string(proof.Proof.Key())] = proof.Value - } - return } @@ -71,7 +63,7 @@ func (store store) Prove(key, value []byte) bool { if !ok { return false } - err := proof.Verify(store.root, key, value) + err := proof.Verify(store.root, value) if err != nil { return false } diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 546fd70825e..5b8cca0a9f5 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -6,14 +6,5 @@ type Root interface{} // XXX: need to separate membership and non membership proof types type Proof interface { Key() []byte - Verify(Root, []byte, []byte) error -} - -type FullProof struct { - Proof Proof - Value []byte -} - -func (proof FullProof) Verify(root Root) error { - return proof.Proof.Verify(root, proof.Proof.Key(), proof.Value) + Verify(Root, []byte) error }