github.com/Finschia/finschia-sdk@v0.49.1/store/iavl/store.go (about)

     1  package iavl
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"time"
     8  
     9  	"github.com/Finschia/ostracon/libs/log"
    10  	ics23 "github.com/confio/ics23/go"
    11  	"github.com/cosmos/iavl"
    12  	abci "github.com/tendermint/tendermint/abci/types"
    13  	tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
    14  	dbm "github.com/tendermint/tm-db"
    15  
    16  	"github.com/Finschia/finschia-sdk/store/cachekv"
    17  	"github.com/Finschia/finschia-sdk/store/listenkv"
    18  	"github.com/Finschia/finschia-sdk/store/tracekv"
    19  	"github.com/Finschia/finschia-sdk/store/types"
    20  	"github.com/Finschia/finschia-sdk/telemetry"
    21  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    22  	"github.com/Finschia/finschia-sdk/types/kv"
    23  )
    24  
    25  const (
    26  	// DefaultIAVLCacheSize is default Iavl cache units size. 1 unit is 128 byte
    27  	// default 64MB
    28  	DefaultIAVLCacheSize = 1024 * 512
    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  	_ types.StoreWithInitialVersion = (*Store)(nil)
    37  )
    38  
    39  // Store Implements types.KVStore and CommitKVStore.
    40  type Store struct {
    41  	tree Tree
    42  }
    43  
    44  // LoadStore returns an IAVL Store as a CommitKVStore. Internally, it will load the
    45  // store's version (id) from the provided DB. An error is returned if the version
    46  // fails to load, or if called with a positive version on an empty tree.
    47  func LoadStore(db dbm.DB, logger log.Logger, key types.StoreKey, id types.CommitID, lazyLoading bool, cacheSize int, disableFastNode bool) (types.CommitKVStore, error) {
    48  	return LoadStoreWithInitialVersion(db, logger, key, id, lazyLoading, 0, cacheSize, disableFastNode)
    49  }
    50  
    51  // LoadStoreWithInitialVersion returns an IAVL Store as a CommitKVStore setting its initialVersion
    52  // to the one given. Internally, it will load the store's version (id) from the
    53  // provided DB. An error is returned if the version fails to load, or if called with a positive
    54  // version on an empty tree.
    55  func LoadStoreWithInitialVersion(db dbm.DB, logger log.Logger, key types.StoreKey, id types.CommitID, lazyLoading bool, initialVersion uint64, cacheSize int, disableFastNode bool) (types.CommitKVStore, error) {
    56  	tree, err := iavl.NewMutableTreeWithOpts(db, cacheSize, &iavl.Options{InitialVersion: initialVersion}, disableFastNode)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	isUpgradeable, err := tree.IsUpgradeable()
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	if isUpgradeable && logger != nil {
    67  		logger.Info(
    68  			"Upgrading IAVL storage for faster queries + execution on live state. This may take a while",
    69  			"store_key", key.String(),
    70  			"version", initialVersion,
    71  			"commit", fmt.Sprintf("%X", id),
    72  			"is_lazy", lazyLoading,
    73  		)
    74  	}
    75  
    76  	if lazyLoading {
    77  		_, err = tree.LazyLoadVersion(id.Version)
    78  	} else {
    79  		_, err = tree.LoadVersion(id.Version)
    80  	}
    81  
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	if logger != nil {
    87  		logger.Debug("Finished loading IAVL tree")
    88  	}
    89  
    90  	return &Store{
    91  		tree: tree,
    92  	}, nil
    93  }
    94  
    95  // UnsafeNewStore returns a reference to a new IAVL Store with a given mutable
    96  // IAVL tree reference. It should only be used for testing purposes.
    97  //
    98  // CONTRACT: The IAVL tree should be fully loaded.
    99  // CONTRACT: PruningOptions passed in as argument must be the same as pruning options
   100  // passed into iavl.MutableTree
   101  func UnsafeNewStore(tree *iavl.MutableTree) *Store {
   102  	return &Store{
   103  		tree: tree,
   104  	}
   105  }
   106  
   107  // GetImmutable returns a reference to a new store backed by an immutable IAVL
   108  // tree at a specific version (height) without any pruning options. This should
   109  // be used for querying and iteration only. If the version does not exist or has
   110  // been pruned, an empty immutable IAVL tree will be used.
   111  // Any mutable operations executed will result in a panic.
   112  func (st *Store) GetImmutable(version int64) (*Store, error) {
   113  	if !st.VersionExists(version) {
   114  		return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, nil
   115  	}
   116  
   117  	iTree, err := st.tree.GetImmutable(version)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	return &Store{
   123  		tree: &immutableTree{iTree},
   124  	}, nil
   125  }
   126  
   127  // Commit commits the current store state and returns a CommitID with the new
   128  // version and hash.
   129  func (st *Store) Commit() types.CommitID {
   130  	defer telemetry.MeasureSince(time.Now(), "store", "iavl", "commit")
   131  
   132  	hash, version, err := st.tree.SaveVersion()
   133  	if err != nil {
   134  		panic(err)
   135  	}
   136  
   137  	return types.CommitID{
   138  		Version: version,
   139  		Hash:    hash,
   140  	}
   141  }
   142  
   143  // LastCommitID implements Committer.
   144  func (st *Store) LastCommitID() types.CommitID {
   145  	hash, err := st.tree.Hash()
   146  	if err != nil {
   147  		panic(err)
   148  	}
   149  
   150  	return types.CommitID{
   151  		Version: st.tree.Version(),
   152  		Hash:    hash,
   153  	}
   154  }
   155  
   156  // SetPruning panics as pruning options should be provided at initialization
   157  // since IAVl accepts pruning options directly.
   158  func (st *Store) SetPruning(_ types.PruningOptions) {
   159  	panic("cannot set pruning options on an initialized IAVL store")
   160  }
   161  
   162  // SetPruning panics as pruning options should be provided at initialization
   163  // since IAVl accepts pruning options directly.
   164  func (st *Store) GetPruning() types.PruningOptions {
   165  	panic("cannot get pruning options on an initialized IAVL store")
   166  }
   167  
   168  // VersionExists returns whether or not a given version is stored.
   169  func (st *Store) VersionExists(version int64) bool {
   170  	return st.tree.VersionExists(version)
   171  }
   172  
   173  // GetAllVersions returns all versions in the iavl tree
   174  func (st *Store) GetAllVersions() []int {
   175  	return st.tree.(*iavl.MutableTree).AvailableVersions()
   176  }
   177  
   178  // Implements Store.
   179  func (st *Store) GetStoreType() types.StoreType {
   180  	return types.StoreTypeIAVL
   181  }
   182  
   183  // Implements Store.
   184  func (st *Store) CacheWrap() types.CacheWrap {
   185  	return cachekv.NewStore(st)
   186  }
   187  
   188  // CacheWrapWithTrace implements the Store interface.
   189  func (st *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
   190  	return cachekv.NewStore(tracekv.NewStore(st, w, tc))
   191  }
   192  
   193  // CacheWrapWithListeners implements the CacheWrapper interface.
   194  func (st *Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap {
   195  	return cachekv.NewStore(listenkv.NewStore(st, storeKey, listeners))
   196  }
   197  
   198  // Implements types.KVStore.
   199  func (st *Store) Set(key, value []byte) {
   200  	types.AssertValidKey(key)
   201  	types.AssertValidValue(value)
   202  	_, err := st.tree.Set(key, value)
   203  	if err != nil {
   204  		panic(err)
   205  	}
   206  }
   207  
   208  // Implements types.KVStore.
   209  func (st *Store) Get(key []byte) []byte {
   210  	defer telemetry.MeasureSince(time.Now(), "store", "iavl", "get")
   211  	value, err := st.tree.Get(key)
   212  	if err != nil {
   213  		panic(err)
   214  	}
   215  	return value
   216  }
   217  
   218  // Implements types.KVStore.
   219  func (st *Store) Has(key []byte) (exists bool) {
   220  	defer telemetry.MeasureSince(time.Now(), "store", "iavl", "has")
   221  	has, err := st.tree.Has(key)
   222  	if err != nil {
   223  		panic(err)
   224  	}
   225  	return has
   226  }
   227  
   228  // Implements types.KVStore.
   229  func (st *Store) Delete(key []byte) {
   230  	defer telemetry.MeasureSince(time.Now(), "store", "iavl", "delete")
   231  	_, _, err := st.tree.Remove(key)
   232  	if err != nil {
   233  		panic(err)
   234  	}
   235  }
   236  
   237  // DeleteVersions deletes a series of versions from the MutableTree. An error
   238  // is returned if any single version is invalid or the delete fails. All writes
   239  // happen in a single batch with a single commit.
   240  func (st *Store) DeleteVersions(versions ...int64) error {
   241  	return st.tree.DeleteVersions(versions...)
   242  }
   243  
   244  // LoadVersionForOverwriting attempts to load a tree at a previously committed
   245  // version, or the latest version below it. Any versions greater than targetVersion will be deleted.
   246  func (st *Store) LoadVersionForOverwriting(targetVersion int64) (int64, error) {
   247  	return st.tree.LoadVersionForOverwriting(targetVersion)
   248  }
   249  
   250  // Implements types.KVStore.
   251  func (st *Store) Iterator(start, end []byte) types.Iterator {
   252  	iterator, err := st.tree.Iterator(start, end, true)
   253  	if err != nil {
   254  		panic(err)
   255  	}
   256  	return iterator
   257  }
   258  
   259  // Implements types.KVStore.
   260  func (st *Store) ReverseIterator(start, end []byte) types.Iterator {
   261  	iterator, err := st.tree.Iterator(start, end, false)
   262  	if err != nil {
   263  		panic(err)
   264  	}
   265  	return iterator
   266  }
   267  
   268  // SetInitialVersion sets the initial version of the IAVL tree. It is used when
   269  // starting a new chain at an arbitrary height.
   270  func (st *Store) SetInitialVersion(version int64) {
   271  	st.tree.SetInitialVersion(uint64(version))
   272  }
   273  
   274  // Exports the IAVL store at the given version, returning an iavl.Exporter for the tree.
   275  func (st *Store) Export(version int64) (*iavl.Exporter, error) {
   276  	istore, err := st.GetImmutable(version)
   277  	if err != nil {
   278  		return nil, fmt.Errorf("iavl export failed for version %v: %w", version, err)
   279  	}
   280  	tree, ok := istore.tree.(*immutableTree)
   281  	if !ok || tree == nil {
   282  		return nil, fmt.Errorf("iavl export failed: unable to fetch tree for version %v", version)
   283  	}
   284  	return tree.Export(), nil
   285  }
   286  
   287  // Import imports an IAVL tree at the given version, returning an iavl.Importer for importing.
   288  func (st *Store) Import(version int64) (*iavl.Importer, error) {
   289  	tree, ok := st.tree.(*iavl.MutableTree)
   290  	if !ok {
   291  		return nil, errors.New("iavl import failed: unable to find mutable tree")
   292  	}
   293  	return tree.Import(version)
   294  }
   295  
   296  // Handle gatest the latest height, if height is 0
   297  func getHeight(tree Tree, req abci.RequestQuery) int64 {
   298  	height := req.Height
   299  	if height == 0 {
   300  		latest := tree.Version()
   301  		if tree.VersionExists(latest - 1) {
   302  			height = latest - 1
   303  		} else {
   304  			height = latest
   305  		}
   306  	}
   307  	return height
   308  }
   309  
   310  // Query implements ABCI interface, allows queries
   311  //
   312  // by default we will return from (latest height -1),
   313  // as we will have merkle proofs immediately (header height = data height + 1)
   314  // If latest-1 is not present, use latest (which must be present)
   315  // if you care to have the latest data to see a tx results, you must
   316  // explicitly set the height you want to see
   317  func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
   318  	defer telemetry.MeasureSince(time.Now(), "store", "iavl", "query")
   319  
   320  	if len(req.Data) == 0 {
   321  		return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrTxDecode, "query cannot be zero length"))
   322  	}
   323  
   324  	tree := st.tree
   325  
   326  	// store the height we chose in the response, with 0 being changed to the
   327  	// latest height
   328  	res.Height = getHeight(tree, req)
   329  
   330  	switch req.Path {
   331  	case "/key": // get by key
   332  		key := req.Data // data holds the key bytes
   333  
   334  		res.Key = key
   335  		if !st.VersionExists(res.Height) {
   336  			res.Log = iavl.ErrVersionDoesNotExist.Error()
   337  			break
   338  		}
   339  
   340  		value, err := tree.GetVersioned(key, res.Height)
   341  		if err != nil {
   342  			panic(err)
   343  		}
   344  		res.Value = value
   345  
   346  		if !req.Prove {
   347  			break
   348  		}
   349  
   350  		// Continue to prove existence/absence of value
   351  		// Must convert store.Tree to iavl.MutableTree with given version to use in CreateProof
   352  		iTree, err := tree.GetImmutable(res.Height)
   353  		if err != nil {
   354  			// sanity check: If value for given version was retrieved, immutable tree must also be retrievable
   355  			panic(fmt.Sprintf("version exists in store but could not retrieve corresponding versioned tree in store, %s", err.Error()))
   356  		}
   357  		mtree := &iavl.MutableTree{
   358  			ImmutableTree: iTree,
   359  		}
   360  
   361  		// get proof from tree and convert to merkle.Proof before adding to result
   362  		res.ProofOps = getProofFromTree(mtree, req.Data, res.Value != nil)
   363  
   364  	case "/subspace":
   365  		pairs := kv.Pairs{
   366  			Pairs: make([]kv.Pair, 0),
   367  		}
   368  
   369  		subspace := req.Data
   370  		res.Key = subspace
   371  
   372  		iterator := types.KVStorePrefixIterator(st, subspace)
   373  		for ; iterator.Valid(); iterator.Next() {
   374  			pairs.Pairs = append(pairs.Pairs, kv.Pair{Key: iterator.Key(), Value: iterator.Value()})
   375  		}
   376  		iterator.Close()
   377  
   378  		bz, err := pairs.Marshal()
   379  		if err != nil {
   380  			panic(fmt.Errorf("failed to marshal KV pairs: %w", err))
   381  		}
   382  
   383  		res.Value = bz
   384  
   385  	default:
   386  		return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path))
   387  	}
   388  
   389  	return res
   390  }
   391  
   392  // Takes a MutableTree, a key, and a flag for creating existence or absence proof and returns the
   393  // appropriate merkle.Proof. Since this must be called after querying for the value, this function should never error
   394  // Thus, it will panic on error rather than returning it
   395  func getProofFromTree(tree *iavl.MutableTree, key []byte, exists bool) *tmcrypto.ProofOps {
   396  	var (
   397  		commitmentProof *ics23.CommitmentProof
   398  		err             error
   399  	)
   400  
   401  	if exists {
   402  		// value was found
   403  		commitmentProof, err = tree.GetMembershipProof(key)
   404  		if err != nil {
   405  			// sanity check: If value was found, membership proof must be creatable
   406  			panic(fmt.Sprintf("unexpected value for empty proof: %s", err.Error()))
   407  		}
   408  	} else {
   409  		// value wasn't found
   410  		commitmentProof, err = tree.GetNonMembershipProof(key)
   411  		if err != nil {
   412  			// sanity check: If value wasn't found, nonmembership proof must be creatable
   413  			panic(fmt.Sprintf("unexpected error for nonexistence proof: %s", err.Error()))
   414  		}
   415  	}
   416  
   417  	op := types.NewIavlCommitmentOp(key, commitmentProof)
   418  	return &tmcrypto.ProofOps{Ops: []tmcrypto.ProofOp{op.ProofOp()}}
   419  }
   420  
   421  //----------------------------------------
   422  
   423  // Implements types.Iterator.
   424  type iavlIterator struct {
   425  	dbm.Iterator
   426  }
   427  
   428  var _ types.Iterator = (*iavlIterator)(nil)