github.com/Finschia/finschia-sdk@v0.48.1/store/internal/maps/maps.go (about) 1 package maps 2 3 import ( 4 "encoding/binary" 5 6 tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" 7 8 "github.com/Finschia/ostracon/crypto/merkle" 9 "github.com/Finschia/ostracon/crypto/tmhash" 10 11 "github.com/Finschia/finschia-sdk/types/kv" 12 ) 13 14 // merkleMap defines a merkle-ized tree from a map. Leave values are treated as 15 // hash(key) | hash(value). Leaves are sorted before Merkle hashing. 16 type merkleMap struct { 17 kvs kv.Pairs 18 sorted bool 19 } 20 21 func newMerkleMap() *merkleMap { 22 return &merkleMap{ 23 kvs: kv.Pairs{}, 24 sorted: false, 25 } 26 } 27 28 // Set creates a kv.Pair from the provided key and value. The value is hashed prior 29 // to creating a kv.Pair. The created kv.Pair is appended to the MerkleMap's slice 30 // of kv.Pairs. Whenever called, the MerkleMap must be resorted. 31 func (sm *merkleMap) set(key string, value []byte) { 32 byteKey := []byte(key) 33 assertValidKey(byteKey) 34 35 sm.sorted = false 36 37 // The value is hashed, so you can check for equality with a cached value (say) 38 // and make a determination to fetch or not. 39 vhash := tmhash.Sum(value) 40 41 sm.kvs.Pairs = append(sm.kvs.Pairs, kv.Pair{ 42 Key: byteKey, 43 Value: vhash, 44 }) 45 } 46 47 // Hash returns the merkle root of items sorted by key. Note, it is unstable. 48 func (sm *merkleMap) hash() []byte { 49 sm.sort() 50 return hashKVPairs(sm.kvs) 51 } 52 53 func (sm *merkleMap) sort() { 54 if sm.sorted { 55 return 56 } 57 58 sm.kvs.Sort() 59 sm.sorted = true 60 } 61 62 // hashKVPairs hashes a kvPair and creates a merkle tree where the leaves are 63 // byte slices. 64 func hashKVPairs(kvs kv.Pairs) []byte { 65 kvsH := make([][]byte, len(kvs.Pairs)) 66 for i, kvp := range kvs.Pairs { 67 kvsH[i] = KVPair(kvp).Bytes() 68 } 69 70 return merkle.HashFromByteSlices(kvsH) 71 } 72 73 // --------------------------------------------- 74 75 // Merkle tree from a map. 76 // Leaves are `hash(key) | hash(value)`. 77 // Leaves are sorted before Merkle hashing. 78 type simpleMap struct { 79 Kvs kv.Pairs 80 sorted bool 81 } 82 83 func newSimpleMap() *simpleMap { 84 return &simpleMap{ 85 Kvs: kv.Pairs{}, 86 sorted: false, 87 } 88 } 89 90 // Set creates a kv pair of the key and the hash of the value, 91 // and then appends it to SimpleMap's kv pairs. 92 func (sm *simpleMap) Set(key string, value []byte) { 93 byteKey := []byte(key) 94 assertValidKey(byteKey) 95 sm.sorted = false 96 97 // The value is hashed, so you can 98 // check for equality with a cached value (say) 99 // and make a determination to fetch or not. 100 vhash := tmhash.Sum(value) 101 102 sm.Kvs.Pairs = append(sm.Kvs.Pairs, kv.Pair{ 103 Key: byteKey, 104 Value: vhash, 105 }) 106 } 107 108 // Hash Merkle root hash of items sorted by key 109 // (UNSTABLE: and by value too if duplicate key). 110 func (sm *simpleMap) Hash() []byte { 111 sm.Sort() 112 return hashKVPairs(sm.Kvs) 113 } 114 115 func (sm *simpleMap) Sort() { 116 if sm.sorted { 117 return 118 } 119 sm.Kvs.Sort() 120 sm.sorted = true 121 } 122 123 // Returns a copy of sorted KVPairs. 124 // NOTE these contain the hashed key and value. 125 func (sm *simpleMap) KVPairs() kv.Pairs { 126 sm.Sort() 127 kvs := kv.Pairs{ 128 Pairs: make([]kv.Pair, len(sm.Kvs.Pairs)), 129 } 130 131 copy(kvs.Pairs, sm.Kvs.Pairs) 132 return kvs 133 } 134 135 //---------------------------------------- 136 137 // A local extension to KVPair that can be hashed. 138 // Key and value are length prefixed and concatenated, 139 // then hashed. 140 type KVPair kv.Pair 141 142 // NewKVPair takes in a key and value and creates a kv.Pair 143 // wrapped in the local extension KVPair 144 func NewKVPair(key, value []byte) KVPair { 145 return KVPair(kv.Pair{ 146 Key: key, 147 Value: value, 148 }) 149 } 150 151 // Bytes returns key || value, with both the 152 // key and value length prefixed. 153 func (kv KVPair) Bytes() []byte { 154 // In the worst case: 155 // * 8 bytes to Uvarint encode the length of the key 156 // * 8 bytes to Uvarint encode the length of the value 157 // So preallocate for the worst case, which will in total 158 // be a maximum of 14 bytes wasted, if len(key)=1, len(value)=1, 159 // but that's going to rare. 160 buf := make([]byte, 8+len(kv.Key)+8+len(kv.Value)) 161 162 // Encode the key, prefixed with its length. 163 nlk := binary.PutUvarint(buf, uint64(len(kv.Key))) 164 nk := copy(buf[nlk:], kv.Key) 165 166 // Encode the value, prefixing with its length. 167 nlv := binary.PutUvarint(buf[nlk+nk:], uint64(len(kv.Value))) 168 nv := copy(buf[nlk+nk+nlv:], kv.Value) 169 170 return buf[:nlk+nk+nlv+nv] 171 } 172 173 // HashFromMap computes a merkle tree from sorted map and returns the merkle 174 // root. 175 func HashFromMap(m map[string][]byte) []byte { 176 mm := newMerkleMap() 177 for k, v := range m { 178 mm.set(k, v) 179 } 180 181 return mm.hash() 182 } 183 184 // ProofsFromMap generates proofs from a map. The keys/values of the map will be used as the keys/values 185 // in the underlying key-value pairs. 186 // The keys are sorted before the proofs are computed. 187 func ProofsFromMap(m map[string][]byte) ([]byte, map[string]*tmcrypto.Proof, []string) { 188 sm := newSimpleMap() 189 for k, v := range m { 190 sm.Set(k, v) 191 } 192 193 sm.Sort() 194 kvs := sm.Kvs 195 kvsBytes := make([][]byte, len(kvs.Pairs)) 196 for i, kvp := range kvs.Pairs { 197 kvsBytes[i] = KVPair(kvp).Bytes() 198 } 199 200 rootHash, proofList := merkle.ProofsFromByteSlices(kvsBytes) 201 proofs := make(map[string]*tmcrypto.Proof) 202 keys := make([]string, len(proofList)) 203 204 for i, kvp := range kvs.Pairs { 205 proofs[string(kvp.Key)] = proofList[i].ToProto() 206 keys[i] = string(kvp.Key) 207 } 208 209 return rootHash, proofs, keys 210 } 211 212 func assertValidKey(key []byte) { 213 if len(key) == 0 { 214 panic("key is nil") 215 } 216 }