github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/iavl/proof.go (about) 1 package iavl 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/gnolang/gno/tm2/pkg/amino" 8 "github.com/gnolang/gno/tm2/pkg/crypto/tmhash" 9 "github.com/gnolang/gno/tm2/pkg/errors" 10 ) 11 12 var ( 13 // ErrInvalidProof is returned by Verify when a proof cannot be validated. 14 ErrInvalidProof = fmt.Errorf("invalid proof") 15 16 // ErrInvalidInputs is returned when the inputs passed to the function are invalid. 17 ErrInvalidInputs = fmt.Errorf("invalid inputs") 18 19 // ErrInvalidRoot is returned when the root passed in does not match the proof's. 20 ErrInvalidRoot = fmt.Errorf("invalid root") 21 ) 22 23 //---------------------------------------- 24 25 // Contract: Left and Right can never both be set. Will result in a empty `[]` roothash 26 type proofInnerNode struct { 27 Height int8 `json:"height"` 28 Size int64 `json:"size"` 29 Version int64 `json:"version"` 30 Left []byte `json:"left"` 31 Right []byte `json:"right"` 32 } 33 34 func (pin proofInnerNode) String() string { 35 return pin.stringIndented("") 36 } 37 38 func (pin proofInnerNode) stringIndented(indent string) string { 39 return fmt.Sprintf(`proofInnerNode{ 40 %s Height: %v 41 %s Size: %v 42 %s Version: %v 43 %s Left: %X 44 %s Right: %X 45 %s}`, 46 indent, pin.Height, 47 indent, pin.Size, 48 indent, pin.Version, 49 indent, pin.Left, 50 indent, pin.Right, 51 indent) 52 } 53 54 func (pin proofInnerNode) Hash(childHash []byte) []byte { 55 hasher := tmhash.New() 56 buf := new(bytes.Buffer) 57 58 err := amino.EncodeVarint8(buf, pin.Height) 59 if err == nil { 60 err = amino.EncodeVarint(buf, pin.Size) 61 } 62 if err == nil { 63 err = amino.EncodeVarint(buf, pin.Version) 64 } 65 66 if len(pin.Left) > 0 && len(pin.Right) > 0 { 67 panic(fmt.Sprintf("both left and right child hashes are set")) 68 } 69 70 if len(pin.Left) == 0 { 71 if err == nil { 72 err = amino.EncodeByteSlice(buf, childHash) 73 } 74 if err == nil { 75 err = amino.EncodeByteSlice(buf, pin.Right) 76 } 77 } else { 78 if err == nil { 79 err = amino.EncodeByteSlice(buf, pin.Left) 80 } 81 if err == nil { 82 err = amino.EncodeByteSlice(buf, childHash) 83 } 84 } 85 if err != nil { 86 panic(fmt.Sprintf("Failed to hash proofInnerNode: %v", err)) 87 } 88 89 hasher.Write(buf.Bytes()) 90 return hasher.Sum(nil) 91 } 92 93 //---------------------------------------- 94 95 type proofLeafNode struct { 96 Key []byte `json:"key"` 97 ValueHash []byte `json:"value"` 98 Version int64 `json:"version"` 99 } 100 101 func (pln proofLeafNode) String() string { 102 return pln.stringIndented("") 103 } 104 105 func (pln proofLeafNode) stringIndented(indent string) string { 106 return fmt.Sprintf(`proofLeafNode{ 107 %s Key: %v 108 %s ValueHash: %X 109 %s Version: %v 110 %s}`, 111 indent, pln.Key, 112 indent, pln.ValueHash, 113 indent, pln.Version, 114 indent) 115 } 116 117 func (pln proofLeafNode) Hash() []byte { 118 hasher := tmhash.New() 119 buf := new(bytes.Buffer) 120 121 err := amino.EncodeVarint8(buf, 0) 122 if err == nil { 123 err = amino.EncodeVarint(buf, 1) 124 } 125 if err == nil { 126 err = amino.EncodeVarint(buf, pln.Version) 127 } 128 if err == nil { 129 err = amino.EncodeByteSlice(buf, pln.Key) 130 } 131 if err == nil { 132 err = amino.EncodeByteSlice(buf, pln.ValueHash) 133 } 134 if err != nil { 135 panic(fmt.Sprintf("Failed to hash proofLeafNode: %v", err)) 136 } 137 hasher.Write(buf.Bytes()) 138 139 return hasher.Sum(nil) 140 } 141 142 //---------------------------------------- 143 144 // If the key does not exist, returns the path to the next leaf left of key (w/ 145 // path), except when key is less than the least item, in which case it returns 146 // a path to the least item. 147 func (node *Node) PathToLeaf(t *ImmutableTree, key []byte) (PathToLeaf, *Node, error) { 148 path := new(PathToLeaf) 149 val, err := node.pathToLeaf(t, key, path) 150 return *path, val, err 151 } 152 153 // pathToLeaf is a helper which recursively constructs the PathToLeaf. 154 // As an optimization the already constructed path is passed in as an argument 155 // and is shared among recursive calls. 156 func (node *Node) pathToLeaf(t *ImmutableTree, key []byte, path *PathToLeaf) (*Node, error) { 157 if node.height == 0 { 158 if bytes.Equal(node.key, key) { 159 return node, nil 160 } 161 return node, errors.New("key does not exist") 162 } 163 164 if bytes.Compare(key, node.key) < 0 { 165 // left side 166 pin := proofInnerNode{ 167 Height: node.height, 168 Size: node.size, 169 Version: node.version, 170 Left: nil, 171 Right: node.getRightNode(t).hash, 172 } 173 *path = append(*path, pin) 174 n, err := node.getLeftNode(t).pathToLeaf(t, key, path) 175 return n, err 176 } 177 // right side 178 pin := proofInnerNode{ 179 Height: node.height, 180 Size: node.size, 181 Version: node.version, 182 Left: node.getLeftNode(t).hash, 183 Right: nil, 184 } 185 *path = append(*path, pin) 186 n, err := node.getRightNode(t).pathToLeaf(t, key, path) 187 return n, err 188 }