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  }