merkle.gno
2.35 Kb · 61 lines
1package types
2
3import "strings"
4
5// MerklePath is the path used to verify commitment proofs, which can be an
6// arbitrary structured object (defined by a commitment type).
7// ICS-23 verification supports membership proofs for nested merkle trees.
8// The ICS-24 standard provable keys MUST be stored in the lowest level tree
9// with an optional prefix.
10// The IC24 provable tree may then be stored in a higher level tree(s) that
11// hash up to the root hash stored in the consensus state of the client.
12// Each element of the path represents the key of a merkle tree from the root
13// to the leaf.
14// The elements of the path before the final element must be the path to the
15// tree that contains the ICS24 provable store. Thus, it should remain constant
16// for all ICS24 proofs.
17// The final element of the path is the key of the leaf in the ICS24 provable
18// store, thus IBC core will append the ICS24 path to the final element of the
19// MerklePath stored in the counterparty to create the full path to the leaf
20// for proof verification.
21//
22// Examples:
23// Cosmos SDK:
24// The Cosmos SDK commits to a multi-tree where each store is an IAVL tree and
25// all store hashes are hashed in a simple merkle tree to get the final root
26// hash. Thus, the MerklePath in the counterparty MerklePrefix has the
27// following structure: ["ibc", ""]
28// The core IBC handler will append the ICS24 path to the final element of the
29// MerklePath like so: ["ibc", "{packetCommitmentPath}"] which will then be
30// used for final verification.
31type MerklePath struct {
32 KeyPath [][]byte
33}
34
35func (mp MerklePath) String() string {
36 var strs []string
37 for _, p := range mp.KeyPath {
38 strs = append(strs, string(p))
39 }
40 return "[" + strings.Join(strs, ", ") + "]"
41}
42
43// BuildMerklePath takes the merkle path prefix and an ICS24 path and builds a
44// new path by appending the ICS24 path to the last element of the merkle path
45// prefix.
46func BuildMerklePath(prefix [][]byte, path []byte) MerklePath {
47 prefixLength := len(prefix)
48 if prefixLength == 0 {
49 panic("cannot build merkle path with empty prefix")
50 }
51
52 // copy prefix to avoid modifying the original slice
53 fullPath := make([][]byte, len(prefix))
54 for i, p := range prefix {
55 fullPath[i] = make([]byte, len(p))
56 copy(fullPath[i], p)
57 }
58 // append path to last element
59 fullPath[prefixLength-1] = append(fullPath[prefixLength-1], path...)
60 return MerklePath{KeyPath: fullPath}
61}