github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/mutable_ibc_adapter.go (about) 1 package iavl 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 7 ics23 "github.com/confio/ics23/go" 8 ) 9 10 func (t *ImmutableTree) GetMembershipProof(key []byte) (*ics23.CommitmentProof, error) { 11 exist, err := createExistenceProof(t, key) 12 if err != nil { 13 return nil, err 14 } 15 proof := &ics23.CommitmentProof{ 16 Proof: &ics23.CommitmentProof_Exist{ 17 Exist: exist, 18 }, 19 } 20 return proof, nil 21 } 22 23 // convertExistenceProof will convert the given proof into a valid 24 // existence proof, if that's what it is. 25 // 26 // This is the simplest case of the range proof and we will focus on 27 // demoing compatibility here 28 func convertExistenceProof(p *RangeProof, key, value []byte) (*ics23.ExistenceProof, error) { 29 if len(p.Leaves) != 1 { 30 return nil, fmt.Errorf("existence proof requires RangeProof to have exactly one leaf") 31 } 32 return &ics23.ExistenceProof{ 33 Key: key, 34 Value: value, 35 Leaf: convertLeafOp(p.Leaves[0].Version), 36 Path: convertInnerOps(p.LeftPath), 37 }, nil 38 } 39 40 func convertLeafOp(version int64) *ics23.LeafOp { 41 var varintBuf [binary.MaxVarintLen64]byte 42 // this is adapted from iavl/proof.go:proofLeafNode.Hash() 43 prefix := convertVarIntToBytes(0, varintBuf) 44 prefix = append(prefix, convertVarIntToBytes(1, varintBuf)...) 45 prefix = append(prefix, convertVarIntToBytes(version, varintBuf)...) 46 47 return &ics23.LeafOp{ 48 Hash: ics23.HashOp_SHA256, 49 PrehashValue: ics23.HashOp_SHA256, 50 Length: ics23.LengthOp_VAR_PROTO, 51 Prefix: prefix, 52 } 53 } 54 55 // we cannot get the proofInnerNode type, so we need to do the whole path in one function 56 func convertInnerOps(path PathToLeaf) []*ics23.InnerOp { 57 steps := make([]*ics23.InnerOp, 0, len(path)) 58 59 // lengthByte is the length prefix prepended to each of the sha256 sub-hashes 60 var lengthByte byte = 0x20 61 62 var varintBuf [binary.MaxVarintLen64]byte 63 64 // we need to go in reverse order, iavl starts from root to leaf, 65 // we want to go up from the leaf to the root 66 for i := len(path) - 1; i >= 0; i-- { 67 // this is adapted from iavl/proof.go:proofInnerNode.Hash() 68 prefix := convertVarIntToBytes(int64(path[i].Height), varintBuf) 69 prefix = append(prefix, convertVarIntToBytes(path[i].Size, varintBuf)...) 70 prefix = append(prefix, convertVarIntToBytes(path[i].Version, varintBuf)...) 71 72 var suffix []byte 73 if len(path[i].Left) > 0 { 74 // length prefixed left side 75 prefix = append(prefix, lengthByte) 76 prefix = append(prefix, path[i].Left...) 77 // prepend the length prefix for child 78 prefix = append(prefix, lengthByte) 79 } else { 80 // prepend the length prefix for child 81 prefix = append(prefix, lengthByte) 82 // length-prefixed right side 83 suffix = []byte{lengthByte} 84 suffix = append(suffix, path[i].Right...) 85 } 86 87 op := &ics23.InnerOp{ 88 Hash: ics23.HashOp_SHA256, 89 Prefix: prefix, 90 Suffix: suffix, 91 } 92 steps = append(steps, op) 93 } 94 return steps 95 } 96 97 func convertVarIntToBytes(orig int64, buf [binary.MaxVarintLen64]byte) []byte { 98 n := binary.PutVarint(buf[:], orig) 99 return buf[:n] 100 } 101 102 /* 103 GetNonMembershipProof will produce a CommitmentProof that the given key doesn't exist in the iavl tree. 104 If the key exists in the tree, this will return an error. 105 */ 106 func (t *ImmutableTree) GetNonMembershipProof(key []byte) (*ics23.CommitmentProof, error) { 107 // idx is one node right of what we want.... 108 idx, val := t.GetWithIndex(key) 109 if val != nil { 110 return nil, fmt.Errorf("cannot create NonExistanceProof when Key in State") 111 } 112 113 var err error 114 nonexist := &ics23.NonExistenceProof{ 115 Key: key, 116 } 117 118 if idx >= 1 { 119 leftkey, _ := t.GetByIndex(idx - 1) 120 nonexist.Left, err = createExistenceProof(t, leftkey) 121 if err != nil { 122 return nil, err 123 } 124 } 125 126 // this will be nil if nothing right of the queried key 127 rightkey, _ := t.GetByIndex(idx) 128 if rightkey != nil { 129 nonexist.Right, err = createExistenceProof(t, rightkey) 130 if err != nil { 131 return nil, err 132 } 133 } 134 135 proof := &ics23.CommitmentProof{ 136 Proof: &ics23.CommitmentProof_Nonexist{ 137 Nonexist: nonexist, 138 }, 139 } 140 return proof, nil 141 } 142 143 func createExistenceProof(tree *ImmutableTree, key []byte) (*ics23.ExistenceProof, error) { 144 value, proof, err := tree.GetWithProof2(key) 145 if err != nil { 146 return nil, err 147 } 148 if value == nil { 149 return nil, fmt.Errorf("cannot create ExistanceProof when Key not in State") 150 } 151 return convertExistenceProof(proof, key, value) 152 }