github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/store/iavl/store.go (about) 1 package iavl 2 3 import ( 4 goerrors "errors" 5 "fmt" 6 "sync" 7 8 "github.com/gnolang/gno/tm2/pkg/amino" 9 abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" 10 "github.com/gnolang/gno/tm2/pkg/crypto/merkle" 11 dbm "github.com/gnolang/gno/tm2/pkg/db" 12 "github.com/gnolang/gno/tm2/pkg/errors" 13 "github.com/gnolang/gno/tm2/pkg/iavl" 14 "github.com/gnolang/gno/tm2/pkg/std" 15 16 "github.com/gnolang/gno/tm2/pkg/store/cache" 17 serrors "github.com/gnolang/gno/tm2/pkg/store/errors" 18 "github.com/gnolang/gno/tm2/pkg/store/types" 19 ) 20 21 const ( 22 defaultIAVLCacheSize = 10000 23 ) 24 25 // Implements store.CommitStoreConstructor. 26 func StoreConstructor(db dbm.DB, opts types.StoreOptions) types.CommitStore { 27 tree := iavl.NewMutableTree(db, defaultIAVLCacheSize) 28 store := UnsafeNewStore(tree, opts) 29 return store 30 } 31 32 // ---------------------------------------- 33 34 var ( 35 _ types.Store = (*Store)(nil) 36 _ types.CommitStore = (*Store)(nil) 37 _ types.Queryable = (*Store)(nil) 38 ) 39 40 // Store Implements types.Store and CommitStore. 41 type Store struct { 42 tree Tree 43 opts types.StoreOptions 44 } 45 46 func UnsafeNewStore(tree *iavl.MutableTree, opts types.StoreOptions) *Store { 47 st := &Store{ 48 tree: tree, 49 opts: opts, 50 } 51 return st 52 } 53 54 // GetImmutable returns a reference to a new store backed by an immutable IAVL 55 // tree at a specific version (height) without any pruning options. This should 56 // be used for querying and iteration only. If the version does not exist or has 57 // been pruned, an error will be returned. Any mutable operations executed will 58 // result in a panic. 59 func (st *Store) GetImmutable(version int64) (*Store, error) { 60 if !st.VersionExists(version) { 61 return nil, iavl.ErrVersionDoesNotExist 62 } 63 64 iTree, err := st.tree.GetImmutable(version) 65 if err != nil { 66 return nil, err 67 } 68 69 opts := st.opts 70 opts.Immutable = true 71 72 return &Store{ 73 tree: &immutableTree{iTree}, 74 opts: opts, 75 }, nil 76 } 77 78 // Implements Committer. 79 func (st *Store) Commit() types.CommitID { 80 // Save a new version. 81 hash, version, err := st.tree.SaveVersion() 82 if err != nil { 83 // TODO: Do we want to extend Commit to allow returning errors? 84 panic(err) 85 } 86 87 // Release an old version of history, if not a sync waypoint. 88 previous := version - 1 89 if st.opts.KeepRecent < previous { 90 toRelease := previous - st.opts.KeepRecent 91 if st.opts.KeepEvery == 0 || toRelease%st.opts.KeepEvery != 0 { 92 err := st.tree.DeleteVersion(toRelease) 93 if errCause := errors.Cause(err); errCause != nil && !goerrors.Is(errCause, iavl.ErrVersionDoesNotExist) { 94 panic(err) 95 } 96 } 97 } 98 99 return types.CommitID{ 100 Version: version, 101 Hash: hash, 102 } 103 } 104 105 // Implements Committer. 106 func (st *Store) LastCommitID() types.CommitID { 107 return types.CommitID{ 108 Version: st.tree.Version(), 109 Hash: st.tree.Hash(), 110 } 111 } 112 113 // Implements Committer. 114 func (st *Store) GetStoreOptions() types.StoreOptions { 115 return st.opts 116 } 117 118 // Implements Committer. 119 func (st *Store) SetStoreOptions(opts2 types.StoreOptions) { 120 st.opts = opts2 121 } 122 123 // Implements Committer. 124 func (st *Store) LoadLatestVersion() error { 125 version := st.tree.LatestVersion() 126 return st.LoadVersion(version) 127 } 128 129 // Implements Committer. 130 func (st *Store) LoadVersion(ver int64) error { 131 if st.opts.Immutable { 132 immutTree, err := st.tree.(*iavl.MutableTree).GetImmutable(ver) 133 if err != nil { 134 return err 135 } else { 136 st.tree = &immutableTree{immutTree} 137 return nil 138 } 139 } else { 140 if st.opts.LazyLoad { 141 _, err := st.tree.(*iavl.MutableTree).LazyLoadVersion(ver) 142 return err 143 } else { 144 _, err := st.tree.(*iavl.MutableTree).LoadVersion(ver) 145 return err 146 } 147 } 148 } 149 150 // VersionExists returns whether or not a given version is stored. 151 func (st *Store) VersionExists(version int64) bool { 152 return st.tree.VersionExists(version) 153 } 154 155 // Implements Store. 156 func (st *Store) CacheWrap() types.Store { 157 return cache.New(st) 158 } 159 160 // Implements Store. 161 func (st *Store) Write() { 162 panic("unexpected .Write() on iavl.Store. Hash()?") 163 } 164 165 // Implements types.Store. 166 func (st *Store) Set(key, value []byte) { 167 types.AssertValidValue(value) 168 st.tree.Set(key, value) 169 } 170 171 // Implements types.Store. 172 func (st *Store) Get(key []byte) (value []byte) { 173 _, v := st.tree.Get(key) 174 return v 175 } 176 177 // Implements types.Store. 178 func (st *Store) Has(key []byte) (exists bool) { 179 return st.tree.Has(key) 180 } 181 182 // Implements types.Store. 183 func (st *Store) Delete(key []byte) { 184 st.tree.Remove(key) 185 } 186 187 // Implements types.Store. 188 func (st *Store) Iterator(start, end []byte) types.Iterator { 189 var iTree *iavl.ImmutableTree 190 191 switch tree := st.tree.(type) { 192 case *immutableTree: 193 iTree = tree.ImmutableTree 194 case *iavl.MutableTree: 195 iTree = tree.ImmutableTree 196 } 197 198 return newIAVLIterator(iTree, start, end, true) 199 } 200 201 // Implements types.Store. 202 func (st *Store) ReverseIterator(start, end []byte) types.Iterator { 203 var iTree *iavl.ImmutableTree 204 205 switch tree := st.tree.(type) { 206 case *immutableTree: 207 iTree = tree.ImmutableTree 208 case *iavl.MutableTree: 209 iTree = tree.ImmutableTree 210 } 211 212 return newIAVLIterator(iTree, start, end, false) 213 } 214 215 // Handle gatest the latest height, if height is 0 216 func getHeight(tree Tree, req abci.RequestQuery) int64 { 217 height := req.Height 218 if height == 0 { 219 latest := tree.Version() 220 if tree.VersionExists(latest - 1) { 221 height = latest - 1 222 } else { 223 height = latest 224 } 225 } 226 return height 227 } 228 229 // Query implements ABCI interface, allows queries 230 // 231 // by default we will return from (latest height -1), 232 // as we will have merkle proofs immediately (header height = data height + 1) 233 // If latest-1 is not present, use latest (which must be present) 234 // if you care to have the latest data to see a tx results, you must 235 // explicitly set the height you want to see 236 func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { 237 if len(req.Data) == 0 { 238 msg := "Query cannot be zero length" 239 res.Error = serrors.ErrTxDecode(msg) 240 return 241 } 242 243 tree := st.tree 244 245 // store the height we chose in the response, with 0 being changed to the 246 // latest height 247 res.Height = getHeight(tree, req) 248 249 switch req.Path { 250 case "/key": // get by key 251 key := req.Data // data holds the key bytes 252 253 res.Key = key 254 if !st.VersionExists(res.Height) { 255 res.Log = errors.Wrap(iavl.ErrVersionDoesNotExist, "").Error() 256 break 257 } 258 259 if req.Prove { 260 value, proof, err := tree.GetVersionedWithProof(key, res.Height) 261 if err != nil { 262 res.Log = err.Error() 263 break 264 } 265 if proof == nil { 266 // Proof == nil implies that the store is empty. 267 if value != nil { 268 panic("unexpected value for an empty proof") 269 } 270 } 271 if value != nil { 272 // value was found 273 res.Value = value 274 res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLValueOp(key, proof).ProofOp()}} 275 } else { 276 // value wasn't found 277 res.Value = nil 278 res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLAbsenceOp(key, proof).ProofOp()}} 279 } 280 } else { 281 _, res.Value = tree.GetVersioned(key, res.Height) 282 } 283 284 case "/subspace": 285 var KVs []types.KVPair 286 287 subspace := req.Data 288 res.Key = subspace 289 290 iterator := types.PrefixIterator(st, subspace) 291 for ; iterator.Valid(); iterator.Next() { 292 KVs = append(KVs, types.KVPair{Key: iterator.Key(), Value: iterator.Value()}) 293 } 294 295 iterator.Close() 296 res.Value = amino.MustMarshalSized(KVs) 297 298 default: 299 msg := fmt.Sprintf("Unexpected Query path: %v", req.Path) 300 res.Error = serrors.ErrUnknownRequest(msg) 301 return 302 } 303 304 return 305 } 306 307 // ---------------------------------------- 308 309 // Implements types.Iterator. 310 type iavlIterator struct { 311 // Underlying store 312 tree *iavl.ImmutableTree 313 314 // Domain 315 start, end []byte 316 317 // Iteration order 318 ascending bool 319 320 // Channel to push iteration values. 321 iterCh chan std.KVPair 322 323 // Close this to release goroutine. 324 quitCh chan struct{} 325 326 // Close this to signal that state is initialized. 327 initCh chan struct{} 328 329 // ---------------------------------------- 330 // What follows are mutable state. 331 mtx sync.Mutex 332 333 invalid bool // True once, true forever 334 key []byte // The current key 335 value []byte // The current value 336 } 337 338 var _ types.Iterator = (*iavlIterator)(nil) 339 340 // newIAVLIterator will create a new iavlIterator. 341 // CONTRACT: Caller must release the iavlIterator, as each one creates a new 342 // goroutine. 343 func newIAVLIterator(tree *iavl.ImmutableTree, start, end []byte, ascending bool) *iavlIterator { 344 iter := &iavlIterator{ 345 tree: tree, 346 start: types.Cp(start), 347 end: types.Cp(end), 348 ascending: ascending, 349 iterCh: make(chan std.KVPair), // Set capacity > 0? 350 quitCh: make(chan struct{}), 351 initCh: make(chan struct{}), 352 } 353 go iter.iterateRoutine() 354 go iter.initRoutine() 355 return iter 356 } 357 358 // Run this to funnel items from the tree to iterCh. 359 func (iter *iavlIterator) iterateRoutine() { 360 iter.tree.IterateRange( 361 iter.start, iter.end, iter.ascending, 362 func(key, value []byte) bool { 363 select { 364 case <-iter.quitCh: 365 return true // done with iteration. 366 case iter.iterCh <- std.KVPair{Key: key, Value: value}: 367 return false // yay. 368 } 369 }, 370 ) 371 close(iter.iterCh) // done. 372 } 373 374 // Run this to fetch the first item. 375 func (iter *iavlIterator) initRoutine() { 376 iter.receiveNext() 377 close(iter.initCh) 378 } 379 380 // Implements types.Iterator. 381 func (iter *iavlIterator) Domain() (start, end []byte) { 382 return iter.start, iter.end 383 } 384 385 // Implements types.Iterator. 386 func (iter *iavlIterator) Valid() bool { 387 iter.waitInit() 388 iter.mtx.Lock() 389 390 validity := !iter.invalid 391 iter.mtx.Unlock() 392 return validity 393 } 394 395 // Implements types.Iterator. 396 func (iter *iavlIterator) Next() { 397 iter.waitInit() 398 iter.mtx.Lock() 399 iter.assertIsValid(true) 400 401 iter.receiveNext() 402 iter.mtx.Unlock() 403 } 404 405 // Implements types.Iterator. 406 func (iter *iavlIterator) Key() []byte { 407 iter.waitInit() 408 iter.mtx.Lock() 409 iter.assertIsValid(true) 410 411 key := iter.key 412 iter.mtx.Unlock() 413 return key 414 } 415 416 // Implements types.Iterator. 417 func (iter *iavlIterator) Value() []byte { 418 iter.waitInit() 419 iter.mtx.Lock() 420 iter.assertIsValid(true) 421 422 val := iter.value 423 iter.mtx.Unlock() 424 return val 425 } 426 427 // Implements types.Iterator. 428 func (iter *iavlIterator) Close() { 429 close(iter.quitCh) 430 } 431 432 // ---------------------------------------- 433 434 func (iter *iavlIterator) setNext(key, value []byte) { 435 iter.assertIsValid(false) 436 437 iter.key = key 438 iter.value = value 439 } 440 441 func (iter *iavlIterator) setInvalid() { 442 iter.assertIsValid(false) 443 444 iter.invalid = true 445 } 446 447 func (iter *iavlIterator) waitInit() { 448 <-iter.initCh 449 } 450 451 func (iter *iavlIterator) receiveNext() { 452 kvPair, ok := <-iter.iterCh 453 if ok { 454 iter.setNext(kvPair.Key, kvPair.Value) 455 } else { 456 iter.setInvalid() 457 } 458 } 459 460 // assertIsValid panics if the iterator is invalid. If unlockMutex is true, 461 // it also unlocks the mutex before panicking, to prevent deadlocks in code that 462 // recovers from panics 463 func (iter *iavlIterator) assertIsValid(unlockMutex bool) { 464 if iter.invalid { 465 if unlockMutex { 466 iter.mtx.Unlock() 467 } 468 panic("invalid iterator") 469 } 470 }