github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/iavl/iavl_store.go (about) 1 package iavl 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "sync" 8 "time" 9 10 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/cachekv" 11 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/flatkv" 12 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/tracekv" 13 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 14 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 15 "github.com/fibonacci-chain/fbc/libs/iavl" 16 iavlconfig "github.com/fibonacci-chain/fbc/libs/iavl/config" 17 "github.com/fibonacci-chain/fbc/libs/system/trace/persist" 18 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 19 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/merkle" 20 tmkv "github.com/fibonacci-chain/fbc/libs/tendermint/libs/kv" 21 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 22 dbm "github.com/fibonacci-chain/fbc/libs/tm-db" 23 ) 24 25 var ( 26 FlagIavlCacheSize = "iavl-cache-size" 27 28 IavlCacheSize = 1000000 29 ) 30 31 var ( 32 _ types.KVStore = (*Store)(nil) 33 _ types.CommitStore = (*Store)(nil) 34 _ types.CommitKVStore = (*Store)(nil) 35 _ types.Queryable = (*Store)(nil) 36 ) 37 38 // Store Implements types.KVStore and CommitKVStore. 39 type Store struct { 40 tree Tree 41 flatKVStore *flatkv.Store 42 //for upgrade 43 upgradeVersion int64 44 //for time statistics 45 beginTime time.Time 46 } 47 48 func (st *Store) CurrentVersion() int64 { 49 tr := st.tree.(*iavl.MutableTree) 50 return tr.Version() 51 } 52 func (st *Store) StopStoreWithVersion(version int64) { 53 tr := st.tree.(*iavl.MutableTree) 54 tr.StopTree() 55 } 56 func (st *Store) StopStore() { 57 tr := st.tree.(*iavl.MutableTree) 58 tr.StopTree() 59 } 60 61 func (st *Store) GetHeights() map[int64][]byte { 62 return st.tree.GetPersistedRoots() 63 } 64 65 // LoadStore returns an IAVL Store as a CommitKVStore. Internally, it will load the 66 // store's version (id) from the provided DB. An error is returned if the version 67 // fails to load. 68 func LoadStore(db dbm.DB, flatKVDB dbm.DB, id types.CommitID, lazyLoading bool, startVersion int64) (types.CommitKVStore, error) { 69 return LoadStoreWithInitialVersion(db, flatKVDB, id, lazyLoading, uint64(startVersion), uint64(0)) 70 } 71 72 // LoadStoreWithInitialVersion returns an IAVL Store as a CommitKVStore setting its initialVersion 73 // to the one given. Internally, it will load the store's version (id) from the 74 // provided DB. An error is returned if the version fails to load. 75 func LoadStoreWithInitialVersion(db dbm.DB, flatKVDB dbm.DB, id types.CommitID, lazyLoading bool, initialVersion uint64, upgradeVersion uint64) (types.CommitKVStore, error) { 76 tree, err := iavl.NewMutableTreeWithOpts(db, iavlconfig.DynamicConfig.GetIavlCacheSize(), &iavl.Options{InitialVersion: initialVersion, UpgradeVersion: upgradeVersion}) 77 if err != nil { 78 return nil, err 79 } 80 if lazyLoading { 81 _, err = tree.LazyLoadVersion(id.Version) 82 } else { 83 _, err = tree.LoadVersion(id.Version) 84 } 85 86 if err != nil { 87 return nil, err 88 } 89 90 st := &Store{ 91 tree: tree, 92 flatKVStore: flatkv.NewStore(flatKVDB), 93 upgradeVersion: -1, 94 } 95 96 if err = st.ValidateFlatVersion(); err != nil { 97 return nil, err 98 } 99 100 return st, nil 101 } 102 func HasVersion(db dbm.DB, version int64) (bool, error) { 103 tree, err := iavl.NewMutableTreeWithOpts(db, iavlconfig.DynamicConfig.GetIavlCacheSize(), &iavl.Options{InitialVersion: 0}) 104 if err != nil { 105 return false, err 106 } 107 return tree.VersionExistsInDb(version), nil 108 } 109 func GetCommitVersions(db dbm.DB) ([]int64, error) { 110 tree, err := iavl.NewMutableTreeWithOpts(db, iavlconfig.DynamicConfig.GetIavlCacheSize(), &iavl.Options{InitialVersion: 0}) 111 if err != nil { 112 return nil, err 113 } 114 return tree.GetVersions() 115 } 116 117 // UnsafeNewStore returns a reference to a new IAVL Store with a given mutable 118 // IAVL tree reference. It should only be used for testing purposes. 119 // 120 // CONTRACT: The IAVL tree should be fully loaded. 121 // CONTRACT: PruningOptions passed in as argument must be the same as pruning options 122 // passed into iavl.MutableTree 123 func UnsafeNewStore(tree *iavl.MutableTree) *Store { 124 return &Store{ 125 tree: tree, 126 upgradeVersion: -1, 127 } 128 } 129 130 // GetImmutable returns a reference to a new store backed by an immutable IAVL 131 // tree at a specific version (height) without any pruning options. This should 132 // be used for querying and iteration only. If the version does not exist or has 133 // been pruned, an empty immutable IAVL tree will be used. 134 // Any mutable operations executed will result in a panic. 135 func (st *Store) GetImmutable(version int64) (*Store, error) { 136 var iTree *iavl.ImmutableTree 137 var err error 138 if !abci.GetDisableABCIQueryMutex() { 139 if !st.VersionExists(version) { 140 return nil, iavl.ErrVersionDoesNotExist 141 } 142 143 iTree, err = st.tree.GetImmutable(version) 144 if err != nil { 145 return nil, err 146 } 147 } else { 148 iTree, err = st.tree.GetImmutable(version) 149 if err != nil { 150 return nil, iavl.ErrVersionDoesNotExist 151 } 152 } 153 return &Store{ 154 tree: &immutableTree{iTree}, 155 }, nil 156 } 157 158 // GetEmptyImmutable returns an empty immutable IAVL tree 159 func (st *Store) GetEmptyImmutable() *Store { 160 return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}} 161 } 162 163 func (st *Store) CommitterCommit(inputDelta *iavl.TreeDelta) (types.CommitID, *iavl.TreeDelta) { // CommitterCommit 164 flag := false 165 if inputDelta != nil { 166 flag = true 167 st.tree.SetDelta(inputDelta) 168 } 169 ver := st.GetUpgradeVersion() 170 if ver != -1 { 171 st.tree.SetUpgradeVersion(ver) 172 st.SetUpgradeVersion(-1) 173 } 174 hash, version, outputDelta, err := st.tree.SaveVersion(flag) 175 if err != nil { 176 panic(err) 177 } 178 179 // commit to flat kv db 180 st.commitFlatKV(version) 181 182 return types.CommitID{ 183 Version: version, 184 Hash: hash, 185 }, &outputDelta 186 } 187 188 // Implements Committer. 189 func (st *Store) LastCommitID() types.CommitID { 190 return types.CommitID{ 191 Version: st.tree.Version(), 192 Hash: st.tree.Hash(), 193 } 194 } 195 196 func (st *Store) LastCommitVersion() int64 { 197 return st.tree.Version() 198 } 199 200 // SetPruning panics as pruning options should be provided at initialization 201 // since IAVl accepts pruning options directly. 202 func (st *Store) SetPruning(_ types.PruningOptions) { 203 panic("cannot set pruning options on an initialized IAVL store") 204 } 205 206 // VersionExists returns whether or not a given version is stored. 207 func (st *Store) VersionExists(version int64) bool { 208 return st.tree.VersionExists(version) 209 } 210 211 // Implements Store. 212 func (st *Store) GetStoreType() types.StoreType { 213 return types.StoreTypeIAVL 214 } 215 216 // Implements Store. 217 func (st *Store) CacheWrap() types.CacheWrap { 218 stores := cachekv.NewStoreWithPreChangeHandler(st, st.tree.PreChanges) 219 stores.StatisticsCell = st 220 221 return stores 222 } 223 224 // CacheWrapWithTrace implements the Store interface. 225 func (st *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap { 226 return cachekv.NewStore(tracekv.NewStore(st, w, tc)) 227 } 228 229 // Implements types.KVStore. 230 func (st *Store) Set(key, value []byte) { 231 types.AssertValidValue(value) 232 st.tree.Set(key, value) 233 st.setFlatKV(key, value) 234 } 235 236 // Implements types.KVStore. 237 func (st *Store) Get(key []byte) []byte { 238 value := st.getFlatKV(key) 239 if value != nil { 240 return value 241 } 242 value = st.tree.Get(key) 243 if value != nil { 244 st.setFlatKV(key, value) 245 } 246 247 return value 248 } 249 250 // Implements types.KVStore. 251 func (st *Store) Has(key []byte) (exists bool) { 252 if st.hasFlatKV(key) { 253 return true 254 } 255 return st.tree.Has(key) 256 } 257 258 // Implements types.KVStore. 259 func (st *Store) Delete(key []byte) { 260 st.tree.Remove(key) 261 st.deleteFlatKV(key) 262 } 263 264 // DeleteVersions deletes a series of versions from the MutableTree. An error 265 // is returned if any single version is invalid or the delete fails. All writes 266 // happen in a single batch with a single commit. 267 func (st *Store) DeleteVersions(versions ...int64) error { 268 return st.tree.DeleteVersions(versions...) 269 } 270 271 // Implements types.KVStore. 272 func (st *Store) Iterator(start, end []byte) types.Iterator { 273 var iTree *iavl.ImmutableTree 274 275 switch tree := st.tree.(type) { 276 case *immutableTree: 277 iTree = tree.ImmutableTree 278 case *iavl.MutableTree: 279 iTree = tree.ImmutableTree 280 } 281 282 return newIAVLIterator(iTree, start, end, true) 283 } 284 285 // Implements types.KVStore. 286 func (st *Store) ReverseIterator(start, end []byte) types.Iterator { 287 var iTree *iavl.ImmutableTree 288 289 switch tree := st.tree.(type) { 290 case *immutableTree: 291 iTree = tree.ImmutableTree 292 case *iavl.MutableTree: 293 iTree = tree.ImmutableTree 294 } 295 296 return newIAVLIterator(iTree, start, end, false) 297 } 298 299 // Handle gatest the latest height, if height is 0 300 func getHeight(tree Tree, req abci.RequestQuery) int64 { 301 height := req.Height 302 if height == 0 { 303 latest := tree.Version() 304 _, err := tree.GetImmutable(latest - 1) 305 if err == nil { 306 height = latest - 1 307 } else { 308 height = latest 309 } 310 } 311 return height 312 } 313 314 // Query implements ABCI interface, allows queries 315 // 316 // by default we will return from (latest height -1), 317 // as we will have merkle proofs immediately (header height = data height + 1) 318 // If latest-1 is not present, use latest (which must be present) 319 // if you care to have the latest data to see a tx results, you must 320 // explicitly set the height you want to see 321 func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { 322 if tmtypes.HigherThanVenus1(req.Height) { 323 return st.queryWithCM40(req) 324 } 325 if len(req.Data) == 0 { 326 return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrTxDecode, "query cannot be zero length")) 327 } 328 329 // store the height we chose in the response, with 0 being changed to the 330 // latest height 331 res.Height = getHeight(st.tree, req) 332 333 switch req.Path { 334 case "/key": // get by key 335 key := req.Data // data holds the key bytes 336 res.Key = key 337 338 tree, err := st.tree.GetImmutable(res.Height) 339 if err != nil { 340 return sdkerrors.QueryResult(sdkerrors.Wrapf(iavl.ErrVersionDoesNotExist, "request height %d", req.Height)) 341 } 342 343 if req.Prove { 344 value, proof, err := tree.GetWithProof(key) 345 if err != nil { 346 res.Log = err.Error() 347 break 348 } 349 if proof == nil { 350 // Proof == nil implies that the store is empty. 351 if value != nil { 352 panic("unexpected value for an empty proof") 353 } 354 } 355 if value != nil { 356 // value was found 357 res.Value = value 358 res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewValueOp(key, proof).ProofOp()}} 359 } else { 360 // value wasn't found 361 res.Value = nil 362 res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewAbsenceOp(key, proof).ProofOp()}} 363 } 364 } else { 365 _, res.Value = tree.GetWithIndex(key) 366 } 367 368 case "/subspace": 369 var KVs []types.KVPair 370 371 subspace := req.Data 372 res.Key = subspace 373 374 iterator := types.KVStorePrefixIterator(st, subspace) 375 for ; iterator.Valid(); iterator.Next() { 376 KVs = append(KVs, types.KVPair{Key: iterator.Key(), Value: iterator.Value()}) 377 } 378 379 iterator.Close() 380 res.Value = cdc.MustMarshalBinaryLengthPrefixed(KVs) 381 382 default: 383 return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path)) 384 } 385 386 return res 387 } 388 389 func (st *Store) GetDBReadTime() int { 390 return st.tree.GetDBReadTime() 391 } 392 393 func (st *Store) GetDBWriteCount() int { 394 return st.tree.GetDBWriteCount() 395 } 396 397 func (st *Store) GetDBReadCount() int { 398 return st.tree.GetDBReadCount() 399 } 400 401 func (st *Store) GetNodeReadCount() int { 402 return st.tree.GetNodeReadCount() 403 } 404 405 func (st *Store) ResetCount() { 406 st.tree.ResetCount() 407 st.resetFlatKVCount() 408 } 409 410 func (st *Store) StartTiming() { 411 st.beginTime = time.Now() 412 } 413 414 func (st *Store) EndTiming(tag string) { 415 persist.GetStatistics().Accumulate(tag, st.beginTime) 416 } 417 418 //---------------------------------------- 419 420 // Implements types.Iterator. 421 type iavlIterator struct { 422 // Domain 423 start, end []byte 424 425 key []byte // The current key (mutable) 426 value []byte // The current value (mutable) 427 428 // Underlying store 429 tree *iavl.ImmutableTree 430 431 // Channel to push iteration values. 432 iterCh chan tmkv.Pair 433 434 // Close this to release goroutine. 435 quitCh chan struct{} 436 437 // Close this to signal that state is initialized. 438 initCh chan struct{} 439 440 mtx sync.Mutex 441 442 ascending bool // Iteration order 443 444 invalid bool // True once, true forever (mutable) 445 } 446 447 var _ types.Iterator = (*iavlIterator)(nil) 448 449 // newIAVLIterator will create a new iavlIterator. 450 // CONTRACT: Caller must release the iavlIterator, as each one creates a new 451 // goroutine. 452 func newIAVLIterator(tree *iavl.ImmutableTree, start, end []byte, ascending bool) *iavlIterator { 453 iter := &iavlIterator{ 454 tree: tree, 455 start: types.Cp(start), 456 end: types.Cp(end), 457 ascending: ascending, 458 iterCh: make(chan tmkv.Pair), // Set capacity > 0? 459 quitCh: make(chan struct{}), 460 initCh: make(chan struct{}), 461 } 462 go iter.iterateRoutine() 463 go iter.initRoutine() 464 return iter 465 } 466 467 // Run this to funnel items from the tree to iterCh. 468 func (iter *iavlIterator) iterateRoutine() { 469 iter.tree.IterateRange( 470 iter.start, iter.end, iter.ascending, 471 func(key, value []byte) bool { 472 select { 473 case <-iter.quitCh: 474 return true // done with iteration. 475 case iter.iterCh <- tmkv.Pair{Key: key, Value: value}: 476 return false // yay. 477 } 478 }, 479 ) 480 close(iter.iterCh) // done. 481 } 482 483 // Run this to fetch the first item. 484 func (iter *iavlIterator) initRoutine() { 485 iter.receiveNext() 486 close(iter.initCh) 487 } 488 489 // Implements types.Iterator. 490 func (iter *iavlIterator) Domain() (start, end []byte) { 491 return iter.start, iter.end 492 } 493 494 // Implements types.Iterator. 495 func (iter *iavlIterator) Valid() bool { 496 iter.waitInit() 497 iter.mtx.Lock() 498 499 validity := !iter.invalid 500 iter.mtx.Unlock() 501 return validity 502 } 503 504 // Implements types.Iterator. 505 func (iter *iavlIterator) Next() { 506 iter.waitInit() 507 iter.mtx.Lock() 508 iter.assertIsValid(true) 509 510 iter.receiveNext() 511 iter.mtx.Unlock() 512 } 513 514 // Implements types.Iterator. 515 func (iter *iavlIterator) Key() []byte { 516 iter.waitInit() 517 iter.mtx.Lock() 518 iter.assertIsValid(true) 519 520 key := iter.key 521 iter.mtx.Unlock() 522 return key 523 } 524 525 // Implements types.Iterator. 526 func (iter *iavlIterator) Value() []byte { 527 iter.waitInit() 528 iter.mtx.Lock() 529 iter.assertIsValid(true) 530 531 val := iter.value 532 iter.mtx.Unlock() 533 return val 534 } 535 536 // Close closes the IAVL iterator by closing the quit channel and waiting for 537 // the iterCh to finish/close. 538 func (iter *iavlIterator) Close() { 539 close(iter.quitCh) 540 // wait iterCh to close 541 for range iter.iterCh { 542 } 543 } 544 545 // Error performs a no-op. 546 func (iter *iavlIterator) Error() error { 547 return nil 548 } 549 550 //---------------------------------------- 551 552 func (iter *iavlIterator) setNext(key, value []byte) { 553 iter.assertIsValid(false) 554 555 iter.key = key 556 iter.value = value 557 } 558 559 func (iter *iavlIterator) setInvalid() { 560 iter.assertIsValid(false) 561 562 iter.invalid = true 563 } 564 565 func (iter *iavlIterator) waitInit() { 566 <-iter.initCh 567 } 568 569 func (iter *iavlIterator) receiveNext() { 570 kvPair, ok := <-iter.iterCh 571 if ok { 572 iter.setNext(kvPair.Key, kvPair.Value) 573 } else { 574 iter.setInvalid() 575 } 576 } 577 578 // assertIsValid panics if the iterator is invalid. If unlockMutex is true, 579 // it also unlocks the mutex before panicing, to prevent deadlocks in code that 580 // recovers from panics 581 func (iter *iavlIterator) assertIsValid(unlockMutex bool) { 582 if iter.invalid { 583 if unlockMutex { 584 iter.mtx.Unlock() 585 } 586 panic("invalid iterator") 587 } 588 } 589 590 // SetInitialVersion sets the initial version of the IAVL tree. It is used when 591 // starting a new chain at an arbitrary height. 592 func (st *Store) SetInitialVersion(version int64) { 593 st.tree.SetInitialVersion(uint64(version)) 594 } 595 596 // Exports the IAVL store at the given version, returning an iavl.Exporter for the tree. 597 func (st *Store) Export(version int64) (*iavl.Exporter, error) { 598 istore, err := st.GetImmutable(version) 599 if err != nil { 600 return nil, fmt.Errorf("iavl export failed for version %v: %w", version, err) 601 } 602 tree, ok := istore.tree.(*immutableTree) 603 if !ok || tree == nil { 604 return nil, fmt.Errorf("iavl export failed: unable to fetch tree for version %v", version) 605 } 606 return tree.Export(), nil 607 } 608 609 // Import imports an IAVL tree at the given version, returning an iavl.Importer for importing. 610 func (st *Store) Import(version int64) (*iavl.Importer, error) { 611 tree, ok := st.tree.(*iavl.MutableTree) 612 if !ok { 613 return nil, errors.New("iavl import failed: unable to find mutable tree") 614 } 615 return tree.Import(version) 616 } 617 618 func (st *Store) SetUpgradeVersion(version int64) { 619 st.upgradeVersion = version 620 } 621 622 func (st *Store) GetUpgradeVersion() int64 { 623 return st.upgradeVersion 624 }