github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/rootmulti/rootmulti_store.go (about)

     1  package rootmulti
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"path/filepath"
     9  	"sort"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config"
    15  
    16  	sdkmaps "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/internal/maps"
    17  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mem"
    18  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mpt"
    19  	"github.com/fibonacci-chain/fbc/libs/system/trace"
    20  	"github.com/fibonacci-chain/fbc/libs/system/trace/persist"
    21  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/merkle"
    22  
    23  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/cachemulti"
    24  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/dbadapter"
    25  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/flatkv"
    26  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/iavl"
    27  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/tracekv"
    28  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/transient"
    29  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    30  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    31  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    32  	iavltree "github.com/fibonacci-chain/fbc/libs/iavl"
    33  	"github.com/fibonacci-chain/fbc/libs/iavl/config"
    34  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    35  	jsoniter "github.com/json-iterator/go"
    36  
    37  	//"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/merkle"
    38  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/tmhash"
    39  	tmlog "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    40  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    41  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
    42  	"github.com/pkg/errors"
    43  	"github.com/spf13/viper"
    44  )
    45  
    46  var itjs = jsoniter.ConfigCompatibleWithStandardLibrary
    47  
    48  const (
    49  	latestVersionKey      = "s/latest"
    50  	pruneHeightsKey       = "s/pruneheights"
    51  	versionsKey           = "s/versions"
    52  	commitInfoKeyFmt      = "s/%d" // s/<version>
    53  	maxPruneHeightsLength = 100
    54  )
    55  
    56  // Store is composed of many CommitStores. Name contrasts with
    57  // cacheMultiStore which is for cache-wrapping other MultiStores. It implements
    58  // the CommitMultiStore interface.
    59  type Store struct {
    60  	db             dbm.DB
    61  	flatKVDB       dbm.DB
    62  	lastCommitInfo commitInfo
    63  	pruningOpts    types.PruningOptions
    64  	storesParams   map[types.StoreKey]storeParams
    65  	stores         map[types.StoreKey]types.CommitKVStore
    66  	keysByName     map[string]types.StoreKey
    67  	lazyLoading    bool
    68  	pruneHeights   []int64
    69  	versions       []int64
    70  
    71  	traceWriter  io.Writer
    72  	traceContext types.TraceContext
    73  
    74  	interBlockCache types.MultiStorePersistentCache
    75  
    76  	logger tmlog.Logger
    77  
    78  	upgradeVersion int64
    79  
    80  	commitFilters  []types.StoreFilter
    81  	pruneFilters   []types.StoreFilter
    82  	versionFilters []types.VersionFilter
    83  }
    84  
    85  var (
    86  	_ types.CommitMultiStore = (*Store)(nil)
    87  	_ types.Queryable        = (*Store)(nil)
    88  )
    89  
    90  // NewStore returns a reference to a new Store object with the provided DB. The
    91  // store will be created with a PruneNothing pruning strategy by default. After
    92  // a store is created, KVStores must be mounted and finally LoadLatestVersion or
    93  // LoadVersion must be called.
    94  func NewStore(db dbm.DB) *Store {
    95  	var flatKVDB dbm.DB
    96  	if viper.GetBool(flatkv.FlagEnable) {
    97  		flatKVDB = newFlatKVDB()
    98  	}
    99  	ret := &Store{
   100  		db:             db,
   101  		flatKVDB:       flatKVDB,
   102  		pruningOpts:    types.PruneNothing,
   103  		storesParams:   make(map[types.StoreKey]storeParams),
   104  		stores:         make(map[types.StoreKey]types.CommitKVStore),
   105  		keysByName:     make(map[string]types.StoreKey),
   106  		pruneHeights:   make([]int64, 0),
   107  		versions:       make([]int64, 0),
   108  		upgradeVersion: -1,
   109  	}
   110  
   111  	return ret
   112  }
   113  
   114  func newFlatKVDB() dbm.DB {
   115  	rootDir := viper.GetString("home")
   116  	dataDir := filepath.Join(rootDir, "data")
   117  	var err error
   118  	flatKVDB, err := sdk.NewDB("flat", dataDir)
   119  	if err != nil {
   120  		panic(err)
   121  	}
   122  	return flatKVDB
   123  }
   124  
   125  // SetPruning sets the pruning strategy on the root store and all the sub-stores.
   126  // Note, calling SetPruning on the root store prior to LoadVersion or
   127  // LoadLatestVersion performs a no-op as the stores aren't mounted yet.
   128  func (rs *Store) SetPruning(pruningOpts types.PruningOptions) {
   129  	rs.pruningOpts = pruningOpts
   130  }
   131  
   132  // SetLazyLoading sets if the iavl store should be loaded lazily or not
   133  func (rs *Store) SetLazyLoading(lazyLoading bool) {
   134  	rs.lazyLoading = lazyLoading
   135  }
   136  
   137  // Implements Store.
   138  func (rs *Store) GetStoreType() types.StoreType {
   139  	return types.StoreTypeMulti
   140  }
   141  
   142  func (rs *Store) GetStores() map[types.StoreKey]types.CommitKVStore {
   143  	return rs.stores
   144  }
   145  
   146  func (rs *Store) GetVersions() []int64 {
   147  	return rs.versions
   148  }
   149  
   150  func (rs *Store) GetPruningHeights() []int64 {
   151  	return rs.pruneHeights
   152  }
   153  
   154  // Implements CommitMultiStore.
   155  func (rs *Store) MountStoreWithDB(key types.StoreKey, typ types.StoreType, db dbm.DB) {
   156  	if key == nil {
   157  		panic("MountIAVLStore() key cannot be nil")
   158  	}
   159  	if _, ok := rs.storesParams[key]; ok {
   160  		panic(fmt.Sprintf("Store duplicate store key %v", key))
   161  	}
   162  	if _, ok := rs.keysByName[key.Name()]; ok {
   163  		panic(fmt.Sprintf("Store duplicate store key name %v", key))
   164  	}
   165  	rs.storesParams[key] = storeParams{
   166  		key: key,
   167  		typ: typ,
   168  		db:  db,
   169  	}
   170  	rs.keysByName[key.Name()] = key
   171  }
   172  
   173  // GetCommitStore returns a mounted CommitStore for a given StoreKey. If the
   174  // store is wrapped in an inter-block cache, it will be unwrapped before returning.
   175  func (rs *Store) GetCommitStore(key types.StoreKey) types.CommitStore {
   176  	return rs.GetCommitKVStore(key)
   177  }
   178  
   179  // GetCommitKVStore returns a mounted CommitKVStore for a given StoreKey. If the
   180  // store is wrapped in an inter-block cache, it will be unwrapped before returning.
   181  func (rs *Store) GetCommitKVStore(key types.StoreKey) types.CommitKVStore {
   182  	// If the Store has an inter-block cache, first attempt to lookup and unwrap
   183  	// the underlying CommitKVStore by StoreKey. If it does not exist, fallback to
   184  	// the main mapping of CommitKVStores.
   185  	if rs.interBlockCache != nil {
   186  		if store := rs.interBlockCache.Unwrap(key); store != nil {
   187  			return store
   188  		}
   189  	}
   190  
   191  	return rs.stores[key]
   192  }
   193  
   194  // LoadLatestVersionAndUpgrade implements CommitMultiStore
   195  func (rs *Store) LoadLatestVersionAndUpgrade(upgrades *types.StoreUpgrades) error {
   196  	ver := getLatestVersion(rs.db)
   197  	return rs.loadVersion(ver, upgrades)
   198  }
   199  
   200  // LoadVersionAndUpgrade allows us to rename substores while loading an older version
   201  func (rs *Store) LoadVersionAndUpgrade(ver int64, upgrades *types.StoreUpgrades) error {
   202  	return rs.loadVersion(ver, upgrades)
   203  }
   204  
   205  // LoadLatestVersion implements CommitMultiStore.
   206  func (rs *Store) LoadLatestVersion() error {
   207  	ver := getLatestVersion(rs.db)
   208  	return rs.loadVersion(ver, nil)
   209  }
   210  
   211  func (rs *Store) GetLatestVersion() int64 {
   212  	return getLatestVersion(rs.db)
   213  }
   214  
   215  // LoadVersion implements CommitMultiStore.
   216  func (rs *Store) LoadVersion(ver int64) error {
   217  	return rs.loadVersion(ver, nil)
   218  }
   219  
   220  func (rs *Store) GetCommitVersion() (int64, error) {
   221  	var firstSp storeParams
   222  	var firstKey types.StoreKey
   223  	isFindIavlStoreParam := false
   224  	var versions []int64
   225  	var err error
   226  	//find a versions list in one iavl store
   227  	for firstKey, firstSp = range rs.storesParams {
   228  		if firstSp.typ == types.StoreTypeIAVL {
   229  			versions, err = rs.getCommitVersionFromParams(firstSp)
   230  			if err != nil {
   231  				return 0, err
   232  			}
   233  			// ignore not enabled store
   234  			if len(versions) == 0 {
   235  				continue
   236  			}
   237  			isFindIavlStoreParam = true
   238  			break
   239  		}
   240  	}
   241  
   242  	if !isFindIavlStoreParam {
   243  		version := GetLatestStoredMptHeight()
   244  		versions = []int64{int64(version)}
   245  	}
   246  
   247  	//sort the versions list
   248  	sort.Slice(versions, func(i, j int) bool { return versions[i] > versions[j] })
   249  	rs.logger.Info("GetCommitVersion", "iavl:", firstKey.Name(), "versions :", versions)
   250  	//find version in rootmultistore
   251  	for _, version := range versions {
   252  		hasVersion, err := rs.hasVersion(version)
   253  		if err != nil {
   254  			return 0, err
   255  		}
   256  		if hasVersion {
   257  			rs.logger.Info("GetCommitVersion", "version :", version)
   258  			return version, nil
   259  		}
   260  	}
   261  
   262  	return 0, fmt.Errorf("not found any proper version")
   263  }
   264  
   265  // hasVersion means every storesParam in store has this version.
   266  func (rs *Store) hasVersion(targetVersion int64) (bool, error) {
   267  	latestVersion := rs.GetLatestVersion()
   268  	for key, storeParams := range rs.storesParams {
   269  		if storeParams.typ == types.StoreTypeIAVL {
   270  			sName := storeParams.key.Name()
   271  			if evmAccStoreFilter(sName, latestVersion, true) {
   272  				continue
   273  			}
   274  
   275  			// filter block modules {}
   276  			if filter(storeParams.key.Name(), targetVersion, rs.stores[key], rs.commitFilters) {
   277  				continue
   278  			}
   279  
   280  			ok, err := findVersionInSubStores(rs, storeParams, targetVersion)
   281  			if err != nil {
   282  				return false, err
   283  			}
   284  			if !ok {
   285  				rs.logger.Info(fmt.Sprintf("iavl-%s does not have version: %d", key.Name(), targetVersion))
   286  				return false, nil
   287  			}
   288  
   289  		} else if storeParams.typ == types.StoreTypeMPT {
   290  			if !tmtypes.HigherThanMars(targetVersion) {
   291  				continue
   292  			}
   293  			if ok := rs.stores[key].(*mpt.MptStore).HasVersion(targetVersion); !ok {
   294  				rs.logger.Info(fmt.Sprintf("mpt-%s does not have version: %d", key.Name(), targetVersion))
   295  				return false, nil
   296  			}
   297  		}
   298  	}
   299  	return true, nil
   300  }
   301  
   302  // loadSubStoreVersion loads specific version for sub kvstore by given key and storeParams.
   303  func (rs *Store) loadSubStoreVersion(ver int64, key types.StoreKey, storeParams storeParams, upgrades *types.StoreUpgrades, infos map[string]storeInfo) (types.CommitKVStore, error) {
   304  
   305  	commitID := rs.getCommitID(infos, key.Name())
   306  	// Load it
   307  	store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams)
   308  	if err != nil {
   309  		return nil, fmt.Errorf("failed to load %s Store: %v", key.Name(), err)
   310  	}
   311  	// If it has been added, set the initial version
   312  	if upgrades.IsAdded(key.Name()) {
   313  		storeParams.initialVersion = uint64(ver) + 1
   314  	}
   315  
   316  	// If it was deleted, remove all data
   317  	if upgrades.IsDeleted(key.Name()) {
   318  		if err := deleteKVStore(store.(types.KVStore)); err != nil {
   319  			return nil, fmt.Errorf("failed to delete store %s: %v", key.Name(), err)
   320  		}
   321  	} else if oldName := upgrades.RenamedFrom(key.Name()); oldName != "" {
   322  		// handle renames specially
   323  		// make an unregistered key to satify loadCommitStore params
   324  		oldKey := types.NewKVStoreKey(oldName)
   325  		oldParams := storeParams
   326  		oldParams.key = oldKey
   327  
   328  		// load from the old name
   329  		oldStore, err := rs.loadCommitStoreFromParams(oldKey, rs.getCommitID(infos, oldName), oldParams)
   330  		if err != nil {
   331  			return nil, fmt.Errorf("failed to load old Store '%s': %v", oldName, err)
   332  		}
   333  		// move all data
   334  		if err := moveKVStoreData(oldStore.(types.KVStore), store.(types.KVStore)); err != nil {
   335  			return nil, fmt.Errorf("failed to move store %s -> %s: %v", oldName, key.Name(), err)
   336  		}
   337  	}
   338  	return store, nil
   339  }
   340  
   341  // loadSubStoreVersionsAsync uses go-routines to load version async for each sub kvstore and returns kvstore maps
   342  func (rs *Store) loadSubStoreVersionsAsync(ver int64, upgrades *types.StoreUpgrades, infos map[string]storeInfo) (map[types.StoreKey]types.CommitKVStore, map[int64][]byte, error) {
   343  	lock := &sync.Mutex{}
   344  	wg := &sync.WaitGroup{}
   345  	var newStores = make(map[types.StoreKey]types.CommitKVStore)
   346  	roots := make(map[int64][]byte)
   347  	errs := []error{}
   348  	for key, sp := range rs.storesParams {
   349  		if evmAccStoreFilter(key.Name(), ver) {
   350  			continue
   351  		}
   352  		wg.Add(1)
   353  		go func(_key types.StoreKey, _sp storeParams) {
   354  			store, err := rs.loadSubStoreVersion(ver, _key, _sp, upgrades, infos)
   355  			lock.Lock()
   356  			if err != nil {
   357  				errs = append(errs, err)
   358  			} else {
   359  				newStores[_key] = store
   360  			}
   361  			if _sp.typ == types.StoreTypeIAVL {
   362  				if len(roots) == 0 {
   363  					iStore := store.(*iavl.Store)
   364  					roots = iStore.GetHeights()
   365  				}
   366  			}
   367  			lock.Unlock()
   368  			wg.Done()
   369  		}(key, sp)
   370  	}
   371  	wg.Wait()
   372  	if len(errs) != 0 {
   373  		var errStr strings.Builder
   374  		for _, err := range errs {
   375  			errStr.WriteString(fmt.Sprintf("%s\n", err.Error()))
   376  		}
   377  		return nil, nil, fmt.Errorf("failed to load version async, err:%s", errStr.String())
   378  	}
   379  	return newStores, roots, nil
   380  }
   381  
   382  func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {
   383  	var err error
   384  	infos := make(map[string]storeInfo)
   385  	var cInfo commitInfo
   386  	cInfo.Version = tmtypes.GetStartBlockHeight()
   387  
   388  	// load old data if we are not version 0
   389  	if ver != 0 {
   390  		var err error
   391  		cInfo, err = getCommitInfo(rs.db, ver)
   392  		if err != nil {
   393  			return err
   394  		}
   395  
   396  		// convert StoreInfos slice to map
   397  		for _, storeInfo := range cInfo.StoreInfos {
   398  			infos[storeInfo.Name] = storeInfo
   399  		}
   400  
   401  		rs.commitInfoFilter(infos, ver, MptStore)
   402  
   403  		//if upgrade version ne
   404  		callback := func(name string, version int64) {
   405  			ibcInfo := infos[name]
   406  			if ibcInfo.Core.CommitID.Version == 0 {
   407  				ibcInfo.Core.CommitID.Version = version //tmtypes.GetVenus1Height()
   408  				infos[name] = ibcInfo
   409  				for key, param := range rs.storesParams {
   410  					if key.Name() == name {
   411  						param.upgradeVersion = uint64(version)
   412  						rs.storesParams[key] = param
   413  					}
   414  				}
   415  			}
   416  		}
   417  		filterVersion(ver, rs.versionFilters, callback)
   418  	}
   419  
   420  	// load each Store (note this doesn't panic on unmounted keys now)
   421  
   422  	var newStores map[types.StoreKey]types.CommitKVStore
   423  	var roots map[int64][]byte
   424  	loadVersionAsync := viper.GetBool(types.FlagLoadVersionAsync)
   425  	if loadVersionAsync {
   426  		newStores, roots, err = rs.loadSubStoreVersionsAsync(ver, upgrades, infos)
   427  		if err != nil {
   428  			return err
   429  		}
   430  	} else {
   431  		newStores = make(map[types.StoreKey]types.CommitKVStore)
   432  		roots = make(map[int64][]byte)
   433  		for key, sp := range rs.storesParams {
   434  			if evmAccStoreFilter(key.Name(), ver) {
   435  				continue
   436  			}
   437  
   438  			store, err := rs.loadSubStoreVersion(ver, key, sp, upgrades, infos)
   439  			if err != nil {
   440  				return err
   441  			}
   442  			if sp.typ == types.StoreTypeIAVL {
   443  				if len(roots) == 0 {
   444  					iStore := store.(*iavl.Store)
   445  					roots = iStore.GetHeights()
   446  				}
   447  			}
   448  			newStores[key] = store
   449  		}
   450  	}
   451  	//
   452  	rs.lastCommitInfo = cInfo
   453  	rs.stores = newStores
   454  
   455  	err = rs.checkAndResetPruningHeights(roots)
   456  	if err != nil {
   457  		return err
   458  	}
   459  	vs, err := getVersions(rs.db)
   460  	if err != nil {
   461  		return err
   462  	}
   463  	if len(vs) > 0 {
   464  		rs.versions = vs
   465  	}
   466  	if rs.logger != nil {
   467  		rs.logger.Info("loadVersion info", "pruned heights length", len(rs.pruneHeights), "versions", len(rs.versions))
   468  	}
   469  	if len(rs.pruneHeights) > maxPruneHeightsLength {
   470  		return fmt.Errorf("Pruned heights length <%d> exceeds <%d>, "+
   471  			"need to prune them with command "+
   472  			"<fbchaind data prune-compact all --home your_fbchaind_home_directory> before running fbchaind",
   473  			len(rs.pruneHeights), maxPruneHeightsLength)
   474  	}
   475  	return nil
   476  }
   477  
   478  func (rs *Store) checkAndResetPruningHeights(roots map[int64][]byte) error {
   479  
   480  	ph, err := getPruningHeights(rs.db, false)
   481  	if err != nil {
   482  		return err
   483  	}
   484  
   485  	if len(ph) == 0 {
   486  		return nil
   487  	}
   488  
   489  	needReset := false
   490  	var newPh []int64
   491  	for _, h := range ph {
   492  		if _, ok := roots[h]; ok {
   493  			newPh = append(newPh, h)
   494  		} else {
   495  			needReset = true
   496  		}
   497  	}
   498  	rs.pruneHeights = newPh
   499  
   500  	if needReset {
   501  		if rs.logger != nil {
   502  			msg := fmt.Sprintf("Detected pruned heights length <%d>, reset to <%d>",
   503  				len(ph), len(rs.pruneHeights))
   504  			rs.logger.Info(msg)
   505  		}
   506  		batch := rs.db.NewBatch()
   507  		setPruningHeights(batch, newPh)
   508  		batch.Write()
   509  		batch.Close()
   510  	}
   511  
   512  	return nil
   513  }
   514  func (rs *Store) getCommitID(infos map[string]storeInfo, name string) types.CommitID {
   515  	info, ok := infos[name]
   516  	if !ok {
   517  		return types.CommitID{Version: tmtypes.GetStartBlockHeight()}
   518  	}
   519  	return info.Core.CommitID
   520  }
   521  
   522  func deleteKVStore(kv types.KVStore) error {
   523  	// Note that we cannot write while iterating, so load all keys here, delete below
   524  	var keys [][]byte
   525  	itr := kv.Iterator(nil, nil)
   526  	for itr.Valid() {
   527  		keys = append(keys, itr.Key())
   528  		itr.Next()
   529  	}
   530  	itr.Close()
   531  
   532  	for _, k := range keys {
   533  		kv.Delete(k)
   534  	}
   535  	return nil
   536  }
   537  
   538  // we simulate move by a copy and delete
   539  func moveKVStoreData(oldDB types.KVStore, newDB types.KVStore) error {
   540  	// we read from one and write to another
   541  	itr := oldDB.Iterator(nil, nil)
   542  	for itr.Valid() {
   543  		newDB.Set(itr.Key(), itr.Value())
   544  		itr.Next()
   545  	}
   546  	itr.Close()
   547  
   548  	// then delete the old store
   549  	return deleteKVStore(oldDB)
   550  }
   551  
   552  // SetInterBlockCache sets the Store's internal inter-block (persistent) cache.
   553  // When this is defined, all CommitKVStores will be wrapped with their respective
   554  // inter-block cache.
   555  func (rs *Store) SetInterBlockCache(c types.MultiStorePersistentCache) {
   556  	rs.interBlockCache = c
   557  }
   558  
   559  // SetTracer sets the tracer for the MultiStore that the underlying
   560  // stores will utilize to trace operations. A MultiStore is returned.
   561  func (rs *Store) SetTracer(w io.Writer) types.MultiStore {
   562  	rs.traceWriter = w
   563  	return rs
   564  }
   565  
   566  // SetTracingContext updates the tracing context for the MultiStore by merging
   567  // the given context with the existing context by key. Any existing keys will
   568  // be overwritten. It is implied that the caller should update the context when
   569  // necessary between tracing operations. It returns a modified MultiStore.
   570  func (rs *Store) SetTracingContext(tc types.TraceContext) types.MultiStore {
   571  	if rs.traceContext != nil {
   572  		for k, v := range tc {
   573  			rs.traceContext[k] = v
   574  		}
   575  	} else {
   576  		rs.traceContext = tc
   577  	}
   578  
   579  	return rs
   580  }
   581  
   582  // TracingEnabled returns if tracing is enabled for the MultiStore.
   583  func (rs *Store) TracingEnabled() bool {
   584  	return rs.traceWriter != nil
   585  }
   586  
   587  //----------------------------------------
   588  // +CommitStore
   589  
   590  // Implements Committer/CommitStore.
   591  func (rs *Store) LastCommitID() types.CommitID {
   592  	return rs.lastCommitInfo.CommitID()
   593  }
   594  
   595  func (rs *Store) LastCommitVersion() int64 {
   596  	return rs.lastCommitInfo.Version
   597  }
   598  
   599  func (rs *Store) CommitterCommit(*iavltree.TreeDelta) (_ types.CommitID, _ *iavltree.TreeDelta) {
   600  	return
   601  }
   602  
   603  // Implements Committer/CommitStore.
   604  func (rs *Store) CommitterCommitMap(inputDeltaMap iavltree.TreeDeltaMap) (types.CommitID, iavltree.TreeDeltaMap) {
   605  	iavltree.IavlCommitAsyncNoBatch = cfg.DynamicConfig.GetIavlAcNoBatch()
   606  
   607  	previousHeight := rs.lastCommitInfo.Version
   608  	version := previousHeight + 1
   609  
   610  	tsCommitStores := time.Now()
   611  	var outputDeltaMap iavltree.TreeDeltaMap
   612  	rs.lastCommitInfo, outputDeltaMap = commitStores(version, rs.stores, inputDeltaMap, rs.commitFilters)
   613  
   614  	if !iavltree.EnableAsyncCommit {
   615  		// Determine if pruneHeight height needs to be added to the list of heights to
   616  		// be pruned, where pruneHeight = (commitHeight - 1) - KeepRecent.
   617  		if int64(rs.pruningOpts.KeepRecent) < previousHeight {
   618  			pruneHeight := previousHeight - int64(rs.pruningOpts.KeepRecent)
   619  			// We consider this height to be pruned iff:
   620  			//
   621  			// - KeepEvery is zero as that means that all heights should be pruned.
   622  			// - KeepEvery % (height - KeepRecent) != 0 as that means the height is not
   623  			// a 'snapshot' height.
   624  			if rs.pruningOpts.KeepEvery == 0 || pruneHeight%int64(rs.pruningOpts.KeepEvery) != 0 {
   625  				rs.pruneHeights = append(rs.pruneHeights, pruneHeight)
   626  				for k, v := range rs.versions {
   627  					if v == pruneHeight {
   628  						rs.versions = append(rs.versions[:k], rs.versions[k+1:]...)
   629  						break
   630  					}
   631  				}
   632  			}
   633  		}
   634  
   635  		if uint64(len(rs.versions)) > rs.pruningOpts.MaxRetainNum {
   636  			rs.pruneHeights = append(rs.pruneHeights, rs.versions[:uint64(len(rs.versions))-rs.pruningOpts.MaxRetainNum]...)
   637  			rs.versions = rs.versions[uint64(len(rs.versions))-rs.pruningOpts.MaxRetainNum:]
   638  		}
   639  
   640  		// batch prune if the current height is a pruning interval height
   641  		if rs.pruningOpts.Interval > 0 && version%int64(rs.pruningOpts.Interval) == 0 {
   642  			rs.pruneStores()
   643  		}
   644  
   645  		rs.versions = append(rs.versions, version)
   646  	}
   647  	persist.GetStatistics().Accumulate(trace.CommitStores, tsCommitStores)
   648  
   649  	tsFlushMeta := time.Now()
   650  	flushMetadata(rs.db, version, rs.lastCommitInfo, rs.pruneHeights, rs.versions)
   651  	persist.GetStatistics().Accumulate(trace.FlushMeta, tsFlushMeta)
   652  
   653  	return types.CommitID{
   654  		Version: version,
   655  		Hash:    rs.lastCommitInfo.Hash(),
   656  	}, outputDeltaMap
   657  }
   658  
   659  // pruneStores will batch delete a list of heights from each mounted sub-store.
   660  // Afterwards, pruneHeights is reset.
   661  func (rs *Store) pruneStores() {
   662  	pruneCnt := len(rs.pruneHeights)
   663  	if pruneCnt == 0 {
   664  		return
   665  	}
   666  
   667  	if rs.logger != nil {
   668  		rs.logger.Info("pruning start", "pruning-count", pruneCnt, "curr-height", rs.lastCommitInfo.Version+1)
   669  		rs.logger.Debug("pruning", "pruning-heights", rs.pruneHeights)
   670  	}
   671  	defer func() {
   672  		if rs.logger != nil {
   673  			rs.logger.Info("pruning end")
   674  		}
   675  	}()
   676  	stores := rs.getFilterStores(rs.lastCommitInfo.Version)
   677  	//stores = rs.stores
   678  	for key, store := range stores {
   679  		if store.GetStoreType() == types.StoreTypeIAVL {
   680  			sName := key.Name()
   681  
   682  			if evmAccStoreFilter(sName, rs.lastCommitInfo.Version) {
   683  				continue
   684  			}
   685  
   686  			// If the store is wrapped with an inter-block cache, we must first unwrap
   687  			// it to get the underlying IAVL store.
   688  			store = rs.GetCommitKVStore(key)
   689  			if err := store.(*iavl.Store).DeleteVersions(rs.pruneHeights...); err != nil {
   690  				if errCause := errors.Cause(err); errCause != nil && errCause != iavltree.ErrVersionDoesNotExist {
   691  					panic(err)
   692  				}
   693  			}
   694  		}
   695  	}
   696  
   697  	rs.pruneHeights = make([]int64, 0)
   698  }
   699  
   700  func (rs *Store) FlushPruneHeights(pruneHeights []int64, versions []int64) {
   701  	flushMetadata(rs.db, rs.lastCommitInfo.Version, rs.lastCommitInfo, pruneHeights, versions)
   702  }
   703  
   704  // Implements CacheWrapper/Store/CommitStore.
   705  func (rs *Store) CacheWrap() types.CacheWrap {
   706  	return rs.CacheMultiStore().(types.CacheWrap)
   707  }
   708  
   709  // CacheWrapWithTrace implements the CacheWrapper interface.
   710  func (rs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap {
   711  	return rs.CacheWrap()
   712  }
   713  
   714  //----------------------------------------
   715  // +MultiStore
   716  
   717  // CacheMultiStore cache-wraps the multi-store and returns a CacheMultiStore.
   718  // It implements the MultiStore interface.
   719  func (rs *Store) CacheMultiStore() types.CacheMultiStore {
   720  	stores := make(map[types.StoreKey]types.CacheWrapper)
   721  	for k, v := range rs.stores {
   722  		stores[k] = v
   723  	}
   724  
   725  	return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.traceContext)
   726  }
   727  
   728  // CacheMultiStoreWithVersion is analogous to CacheMultiStore except that it
   729  // attempts to load stores at a given version (height). An error is returned if
   730  // any store cannot be loaded. This should only be used for querying and
   731  // iterating at past heights.
   732  func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStore, error) {
   733  	cachedStores := make(map[types.StoreKey]types.CacheWrapper)
   734  	for key, store := range rs.stores {
   735  		switch store.GetStoreType() {
   736  		case types.StoreTypeIAVL:
   737  			// If the store is wrapped with an inter-block cache, we must first unwrap
   738  			// it to get the underlying IAVL store.
   739  			store = rs.GetCommitKVStore(key)
   740  
   741  			if evmAccStoreFilter(key.Name(), version) {
   742  				cachedStores[key] = store.(*iavl.Store).GetEmptyImmutable()
   743  				continue
   744  			}
   745  			// filter block modules {}
   746  			if filter(key.Name(), version, nil, rs.commitFilters) {
   747  				cachedStores[key] = store.(*iavl.Store).GetEmptyImmutable()
   748  				continue
   749  			}
   750  			// Attempt to lazy-load an already saved IAVL store version. If the
   751  			// version does not exist or is pruned, an error should be returned.
   752  			iavlStore, err := store.(*iavl.Store).GetImmutable(version)
   753  			if err != nil {
   754  				return nil, err
   755  			}
   756  
   757  			cachedStores[key] = iavlStore
   758  
   759  		case types.StoreTypeMPT:
   760  			store := rs.GetCommitKVStore(key)
   761  
   762  			mptStore, err := store.(*mpt.MptStore).GetImmutable(version)
   763  			if err != nil {
   764  				return nil, err
   765  			}
   766  
   767  			cachedStores[key] = mptStore
   768  
   769  		default:
   770  			cachedStores[key] = store
   771  		}
   772  	}
   773  
   774  	return cachemulti.NewStore(rs.db, cachedStores, rs.keysByName, rs.traceWriter, rs.traceContext), nil
   775  }
   776  
   777  // GetStore returns a mounted Store for a given StoreKey. If the StoreKey does
   778  // not exist, it will panic. If the Store is wrapped in an inter-block cache, it
   779  // will be unwrapped prior to being returned.
   780  //
   781  // TODO: This isn't used directly upstream. Consider returning the Store as-is
   782  // instead of unwrapping.
   783  func (rs *Store) GetStore(key types.StoreKey) types.Store {
   784  	store := rs.GetCommitKVStore(key)
   785  	if store == nil {
   786  		panic(fmt.Sprintf("store does not exist for key: %s", key.Name()))
   787  	}
   788  
   789  	return store
   790  }
   791  
   792  // GetKVStore returns a mounted KVStore for a given StoreKey. If tracing is
   793  // enabled on the KVStore, a wrapped TraceKVStore will be returned with the root
   794  // store's tracer, otherwise, the original KVStore will be returned.
   795  //
   796  // NOTE: The returned KVStore may be wrapped in an inter-block cache if it is
   797  // set on the root store.
   798  func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore {
   799  	s := rs.stores[key]
   800  	if s == nil {
   801  		panic(fmt.Sprintf("store does not exist for key: %s", key.Name()))
   802  	}
   803  	store := s.(types.KVStore)
   804  
   805  	if rs.TracingEnabled() {
   806  		store = tracekv.NewStore(store, rs.traceWriter, rs.traceContext)
   807  	}
   808  
   809  	return store
   810  }
   811  
   812  // getStoreByName performs a lookup of a StoreKey given a store name typically
   813  // provided in a path. The StoreKey is then used to perform a lookup and return
   814  // a Store. If the Store is wrapped in an inter-block cache, it will be unwrapped
   815  // prior to being returned. If the StoreKey does not exist, nil is returned.
   816  func (rs *Store) getStoreByName(name string) types.Store {
   817  	key := rs.keysByName[name]
   818  	if key == nil {
   819  		return nil
   820  	}
   821  
   822  	return rs.GetCommitKVStore(key)
   823  }
   824  
   825  //---------------------- Query ------------------
   826  
   827  // Query calls substore.Query with the same `req` where `req.Path` is
   828  // modified to remove the substore prefix.
   829  // Ie. `req.Path` here is `/<substore>/<path>`, and trimmed to `/<path>` for the substore.
   830  // TODO: add proof for `multistore -> substore`.
   831  func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery {
   832  	path := req.Path
   833  	storeName, subpath, err := parsePath(path)
   834  	if err != nil {
   835  		return sdkerrors.QueryResult(err)
   836  	}
   837  
   838  	store := rs.getStoreByName(storeName)
   839  	if store == nil {
   840  		return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no such store: %s", storeName))
   841  	}
   842  
   843  	queryable, ok := store.(types.Queryable)
   844  	if !ok {
   845  		return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "store %s (type %T) doesn't support queries", storeName, store))
   846  	}
   847  
   848  	// trim the path and make the query
   849  	req.Path = subpath
   850  	res := queryable.Query(req)
   851  
   852  	if !req.Prove || !RequireProof(subpath) {
   853  		return res
   854  	}
   855  
   856  	if res.Proof == nil || len(res.Proof.Ops) == 0 {
   857  		return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("proof is unexpectedly empty; ensure height has not been pruned. Query log: %s", res.Log)))
   858  	}
   859  
   860  	// If the request's height is the latest height we've committed, then utilize
   861  	// the store's lastCommitInfo as this commit info may not be flushed to disk.
   862  	// Otherwise, we query for the commit info from disk.
   863  	var commitInfo commitInfo
   864  
   865  	if res.Height == rs.lastCommitInfo.Version {
   866  		commitInfo = rs.lastCommitInfo
   867  	} else {
   868  		commitInfo, err = getCommitInfo(rs.db, res.Height)
   869  		if err != nil {
   870  			return sdkerrors.QueryResult(err)
   871  		}
   872  	}
   873  
   874  	if tmtypes.HigherThanVenus1(req.Height) {
   875  		queryIbcProof(&res, &commitInfo, storeName)
   876  	} else {
   877  		// Restore origin path and append proof op.
   878  		res.Proof.Ops = append(res.Proof.Ops, NewMultiStoreProofOp(
   879  			[]byte(storeName),
   880  			NewMultiStoreProof(commitInfo.StoreInfos),
   881  		).ProofOp())
   882  	}
   883  
   884  	// TODO: handle in another TM v0.26 update PR
   885  	// res.Proof = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos)
   886  	return res
   887  }
   888  
   889  // parsePath expects a format like /<storeName>[/<subpath>]
   890  // Must start with /, subpath may be empty
   891  // Returns error if it doesn't start with /
   892  func parsePath(path string) (storeName string, subpath string, err error) {
   893  	if !strings.HasPrefix(path, "/") {
   894  		return storeName, subpath, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid path: %s", path)
   895  	}
   896  
   897  	paths := strings.SplitN(path[1:], "/", 2)
   898  	storeName = paths[0]
   899  
   900  	if len(paths) == 2 {
   901  		subpath = "/" + paths[1]
   902  	}
   903  
   904  	return storeName, subpath, nil
   905  }
   906  
   907  func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID, params storeParams) (types.CommitKVStore, error) {
   908  	var db dbm.DB
   909  
   910  	if params.db != nil {
   911  		db = dbm.NewPrefixDB(params.db, []byte("s/_/"))
   912  	} else {
   913  		prefix := "s/k:" + params.key.Name() + "/"
   914  		db = dbm.NewPrefixDB(rs.db, []byte(prefix))
   915  	}
   916  
   917  	switch params.typ {
   918  	case types.StoreTypeMulti:
   919  		panic("recursive MultiStores not yet supported")
   920  
   921  	case types.StoreTypeIAVL:
   922  		var store types.CommitKVStore
   923  		var err error
   924  		prefix := "s/k:" + params.key.Name() + "/"
   925  		var prefixDB dbm.DB
   926  		if rs.flatKVDB != nil {
   927  			prefixDB = dbm.NewPrefixDB(rs.flatKVDB, []byte(prefix))
   928  		}
   929  		if params.initialVersion == 0 && params.upgradeVersion != 0 {
   930  			store, err = iavl.LoadStoreWithInitialVersion(db, prefixDB, id, rs.lazyLoading, uint64(tmtypes.GetStartBlockHeight()), params.upgradeVersion)
   931  		} else if params.initialVersion == 0 {
   932  			store, err = iavl.LoadStore(db, prefixDB, id, rs.lazyLoading, tmtypes.GetStartBlockHeight())
   933  		} else {
   934  			store, err = iavl.LoadStoreWithInitialVersion(db, prefixDB, id, rs.lazyLoading, params.initialVersion, params.upgradeVersion)
   935  		}
   936  
   937  		if err != nil {
   938  			return nil, err
   939  		}
   940  
   941  		if rs.interBlockCache != nil {
   942  			// Wrap and get a CommitKVStore with inter-block caching. Note, this should
   943  			// only wrap the primary CommitKVStore, not any store that is already
   944  			// cache-wrapped as that will create unexpected behavior.
   945  			store = rs.interBlockCache.GetStoreCache(key, store)
   946  		}
   947  
   948  		return store, err
   949  
   950  	case types.StoreTypeDB:
   951  		return commitDBStoreAdapter{Store: dbadapter.Store{DB: db}}, nil
   952  
   953  	case types.StoreTypeTransient:
   954  		_, ok := key.(*types.TransientStoreKey)
   955  		if !ok {
   956  			return nil, fmt.Errorf("invalid StoreKey for StoreTypeTransient: %s", key.String())
   957  		}
   958  
   959  		return transient.NewStore(), nil
   960  	case types.StoreTypeMemory:
   961  		if _, ok := key.(*types.MemoryStoreKey); !ok {
   962  			return nil, fmt.Errorf("unexpected key type for a MemoryStoreKey; got: %s", key.String())
   963  		}
   964  
   965  		return mem.NewStore(), nil
   966  
   967  	case types.StoreTypeMPT:
   968  		return mpt.NewMptStore(rs.logger, id)
   969  
   970  	default:
   971  		panic(fmt.Sprintf("unrecognized store type %v", params.typ))
   972  	}
   973  }
   974  func (rs *Store) GetDBReadTime() int {
   975  	count := 0
   976  	for _, store := range rs.stores {
   977  		count += store.GetDBReadTime()
   978  	}
   979  	return count
   980  }
   981  func findVersionInSubStores(rs *Store, params storeParams, version int64) (bool, error) {
   982  	var db dbm.DB
   983  
   984  	if params.db != nil {
   985  		db = dbm.NewPrefixDB(params.db, []byte("s/_/"))
   986  	} else {
   987  		prefix := "s/k:" + params.key.Name() + "/"
   988  		db = dbm.NewPrefixDB(rs.db, []byte(prefix))
   989  	}
   990  
   991  	return iavl.HasVersion(db, version)
   992  }
   993  func (rs *Store) getCommitVersionFromParams(params storeParams) ([]int64, error) {
   994  	var db dbm.DB
   995  
   996  	if params.db != nil {
   997  		db = dbm.NewPrefixDB(params.db, []byte("s/_/"))
   998  	} else {
   999  		prefix := "s/k:" + params.key.Name() + "/"
  1000  		db = dbm.NewPrefixDB(rs.db, []byte(prefix))
  1001  	}
  1002  
  1003  	return iavl.GetCommitVersions(db)
  1004  }
  1005  
  1006  func (rs *Store) GetDBWriteCount() int {
  1007  	count := 0
  1008  	for _, store := range rs.stores {
  1009  		count += store.GetDBWriteCount()
  1010  	}
  1011  	return count
  1012  }
  1013  
  1014  func (rs *Store) GetDBReadCount() int {
  1015  	count := 0
  1016  	for _, store := range rs.stores {
  1017  		count += store.GetDBReadCount()
  1018  	}
  1019  	return count
  1020  }
  1021  
  1022  func (rs *Store) GetNodeReadCount() int {
  1023  	count := 0
  1024  	for _, store := range rs.stores {
  1025  		count += store.GetNodeReadCount()
  1026  	}
  1027  	return count
  1028  }
  1029  
  1030  func (rs *Store) ResetCount() {
  1031  	for _, store := range rs.stores {
  1032  		store.ResetCount()
  1033  	}
  1034  }
  1035  
  1036  func (rs *Store) GetFlatKVReadTime() int {
  1037  	rt := 0
  1038  	for _, store := range rs.stores {
  1039  		rt += store.GetFlatKVReadTime()
  1040  	}
  1041  	return rt
  1042  }
  1043  
  1044  func (rs *Store) GetFlatKVWriteTime() int {
  1045  	wt := 0
  1046  	for _, store := range rs.stores {
  1047  		wt += store.GetFlatKVWriteTime()
  1048  	}
  1049  	return wt
  1050  }
  1051  
  1052  func (rs *Store) GetFlatKVReadCount() int {
  1053  	count := 0
  1054  	for _, store := range rs.stores {
  1055  		count += store.GetFlatKVReadCount()
  1056  	}
  1057  	return count
  1058  }
  1059  
  1060  func (rs *Store) GetFlatKVWriteCount() int {
  1061  	count := 0
  1062  	for _, store := range rs.stores {
  1063  		count += store.GetFlatKVWriteCount()
  1064  	}
  1065  	return count
  1066  }
  1067  
  1068  //----------------------------------------
  1069  // storeParams
  1070  
  1071  type storeParams struct {
  1072  	key            types.StoreKey
  1073  	db             dbm.DB
  1074  	typ            types.StoreType
  1075  	initialVersion uint64
  1076  	upgradeVersion uint64
  1077  }
  1078  
  1079  //----------------------------------------
  1080  // commitInfo
  1081  
  1082  // NOTE: Keep commitInfo a simple immutable struct.
  1083  type commitInfo struct {
  1084  
  1085  	// Version
  1086  	Version int64
  1087  
  1088  	// Store info for
  1089  	StoreInfos []storeInfo
  1090  }
  1091  
  1092  // Hash returns the simple merkle root hash of the stores sorted by name.
  1093  func (ci commitInfo) Hash() []byte {
  1094  	if tmtypes.HigherThanVenus1(ci.Version) {
  1095  		return ci.ibcHash()
  1096  	}
  1097  	return ci.originHash()
  1098  }
  1099  
  1100  func (ci commitInfo) originHash() []byte {
  1101  	// TODO: cache to ci.hash []byte
  1102  	m := make(map[string][]byte, len(ci.StoreInfos))
  1103  	for _, storeInfo := range ci.StoreInfos {
  1104  		m[storeInfo.Name] = storeInfo.Hash()
  1105  	}
  1106  	return merkle.SimpleHashFromMap(m)
  1107  }
  1108  
  1109  // Hash returns the simple merkle root hash of the stores sorted by name.
  1110  func (ci commitInfo) ibcHash() []byte {
  1111  	m := ci.toMap()
  1112  	rootHash, _, _ := sdkmaps.ProofsFromMap(m)
  1113  	return rootHash
  1114  }
  1115  
  1116  func (ci commitInfo) CommitID() types.CommitID {
  1117  	return types.CommitID{
  1118  		Version: ci.Version,
  1119  		Hash:    ci.Hash(),
  1120  	}
  1121  }
  1122  
  1123  //----------------------------------------
  1124  // storeInfo
  1125  
  1126  // storeInfo contains the name and core reference for an
  1127  // underlying store.  It is the leaf of the Stores top
  1128  // level simple merkle tree.
  1129  type storeInfo struct {
  1130  	Name string
  1131  	Core storeCore
  1132  }
  1133  
  1134  type storeCore struct {
  1135  	// StoreType StoreType
  1136  	CommitID types.CommitID
  1137  	// ... maybe add more state
  1138  }
  1139  
  1140  // Implements merkle.Hasher.
  1141  func (si storeInfo) Hash() []byte {
  1142  	// Doesn't write Name, since merkle.SimpleHashFromMap() will
  1143  	// include them via the keys.
  1144  	bz := si.Core.CommitID.Hash
  1145  	hasher := tmhash.New()
  1146  
  1147  	_, err := hasher.Write(bz)
  1148  	if err != nil {
  1149  		// TODO: Handle with #870
  1150  		panic(err)
  1151  	}
  1152  
  1153  	return hasher.Sum(nil)
  1154  }
  1155  
  1156  //----------------------------------------
  1157  // Misc.
  1158  
  1159  func getLatestVersion(db dbm.DB) int64 {
  1160  	var latest int64
  1161  	latestBytes, err := db.Get([]byte(latestVersionKey))
  1162  	if err != nil {
  1163  		panic(err)
  1164  	} else if latestBytes == nil {
  1165  		return 0
  1166  	}
  1167  
  1168  	err = cdc.UnmarshalBinaryLengthPrefixed(latestBytes, &latest)
  1169  	if err != nil {
  1170  		panic(err)
  1171  	}
  1172  
  1173  	return latest
  1174  }
  1175  
  1176  type StoreSorts []StoreSort
  1177  
  1178  func (s StoreSorts) Len() int {
  1179  	return len(s)
  1180  }
  1181  
  1182  func (s StoreSorts) Less(i, j int) bool {
  1183  	return s[i].key.Name() < s[j].key.Name()
  1184  }
  1185  
  1186  func (s StoreSorts) Swap(i, j int) {
  1187  	s[i], s[j] = s[j], s[i]
  1188  }
  1189  
  1190  type StoreSort struct {
  1191  	key types.StoreKey
  1192  	v   types.CommitKVStore
  1193  }
  1194  
  1195  // Commits each store and returns a new commitInfo.
  1196  func commitStores(version int64, storeMap map[types.StoreKey]types.CommitKVStore,
  1197  	inputDeltaMap iavltree.TreeDeltaMap, filters []types.StoreFilter) (commitInfo, iavltree.TreeDeltaMap) {
  1198  	var storeInfos []storeInfo
  1199  	outputDeltaMap := iavltree.TreeDeltaMap{}
  1200  
  1201  	// updata commit gap height
  1202  	if iavltree.EnableAsyncCommit {
  1203  		iavltree.UpdateCommitGapHeight(config.DynamicConfig.GetCommitGapHeight())
  1204  	}
  1205  	for key, store := range storeMap {
  1206  		sName := key.Name()
  1207  		if evmAccStoreFilter(sName, version) {
  1208  			continue
  1209  		}
  1210  
  1211  		if !mpt.TrieWriteAhead {
  1212  			if newMptStoreFilter(sName, version) {
  1213  				continue
  1214  			}
  1215  		}
  1216  
  1217  		if filter(key.Name(), version, store, filters) {
  1218  			continue
  1219  		}
  1220  
  1221  		commitID, outputDelta := store.CommitterCommit(inputDeltaMap[key.Name()]) // CommitterCommit
  1222  
  1223  		if store.GetStoreType() == types.StoreTypeTransient {
  1224  			continue
  1225  		}
  1226  
  1227  		// old version, mpt(acc) store, never allowed to participate the process of calculate root hash, or it will lead to SMB!
  1228  		if newMptStoreFilter(sName, version) {
  1229  			continue
  1230  		}
  1231  
  1232  		// evm and acc store should not participate in AppHash calculation process after Mars Height
  1233  		if evmAccStoreFilter(sName, version, true) {
  1234  			continue
  1235  		}
  1236  
  1237  		si := storeInfo{}
  1238  		si.Name = key.Name()
  1239  		si.Core.CommitID = commitID
  1240  		storeInfos = append(storeInfos, si)
  1241  		outputDeltaMap[key.Name()] = outputDelta
  1242  	}
  1243  	return commitInfo{
  1244  		Version:    version,
  1245  		StoreInfos: storeInfos,
  1246  	}, outputDeltaMap
  1247  }
  1248  
  1249  func filter(name string, h int64, st types.CommitKVStore, filters []types.StoreFilter) bool {
  1250  	for _, filter := range filters {
  1251  		if filter(name, h, st) {
  1252  			return true
  1253  		}
  1254  	}
  1255  	return false
  1256  }
  1257  
  1258  func filterVersion(h int64, filters []types.VersionFilter, cb types.VersionCallback) {
  1259  	for _, filter := range filters {
  1260  		if c := filter(h); c != nil {
  1261  			c(cb)
  1262  		}
  1263  	}
  1264  }
  1265  
  1266  // Gets commitInfo from disk.
  1267  func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) {
  1268  	cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver)
  1269  
  1270  	cInfoBytes, err := db.Get([]byte(cInfoKey))
  1271  	if err != nil {
  1272  		return commitInfo{}, fmt.Errorf("failed to get commit info: %v", err)
  1273  	} else if cInfoBytes == nil {
  1274  		return commitInfo{}, fmt.Errorf("failed to get commit info: no data")
  1275  	}
  1276  
  1277  	var cInfo commitInfo
  1278  
  1279  	err = cdc.UnmarshalBinaryLengthPrefixed(cInfoBytes, &cInfo)
  1280  	if err != nil {
  1281  		return commitInfo{}, fmt.Errorf("failed to get Store: %v", err)
  1282  	}
  1283  
  1284  	return cInfo, nil
  1285  }
  1286  
  1287  func setCommitInfo(batch dbm.Batch, version int64, cInfo commitInfo) {
  1288  	cInfoBytes := cdc.MustMarshalBinaryLengthPrefixed(cInfo)
  1289  	cInfoKey := fmt.Sprintf(commitInfoKeyFmt, version)
  1290  	batch.Set([]byte(cInfoKey), cInfoBytes)
  1291  }
  1292  
  1293  func setLatestVersion(batch dbm.Batch, version int64) {
  1294  	latestBytes := cdc.MustMarshalBinaryLengthPrefixed(version)
  1295  	batch.Set([]byte(latestVersionKey), latestBytes)
  1296  }
  1297  
  1298  func setPruningHeights(batch dbm.Batch, pruneHeights []int64) {
  1299  	bz := cdc.MustMarshalBinaryBare(pruneHeights)
  1300  	batch.Set([]byte(pruneHeightsKey), bz)
  1301  }
  1302  
  1303  func SetPruningHeights(db dbm.DB, pruneHeights []int64) {
  1304  	batch := db.NewBatch()
  1305  	setPruningHeights(batch, pruneHeights)
  1306  	batch.Write()
  1307  	batch.Close()
  1308  }
  1309  
  1310  func GetPruningHeights(db dbm.DB) ([]int64, error) {
  1311  	return getPruningHeights(db, true)
  1312  }
  1313  
  1314  func getPruningHeights(db dbm.DB, reportZeroLengthErr bool) ([]int64, error) {
  1315  	bz, err := db.Get([]byte(pruneHeightsKey))
  1316  	if err != nil {
  1317  		return nil, fmt.Errorf("failed to get pruned heights: %w", err)
  1318  	}
  1319  	if len(bz) == 0 {
  1320  		if reportZeroLengthErr {
  1321  			return nil, errors.New("no pruned heights found")
  1322  		} else {
  1323  			return nil, nil
  1324  		}
  1325  	}
  1326  
  1327  	var prunedHeights []int64
  1328  	if err := cdc.UnmarshalBinaryBare(bz, &prunedHeights); err != nil {
  1329  		return nil, fmt.Errorf("failed to unmarshal pruned heights: %w", err)
  1330  	}
  1331  
  1332  	return prunedHeights, nil
  1333  }
  1334  
  1335  func flushMetadata(db dbm.DB, version int64, cInfo commitInfo, pruneHeights []int64, versions []int64) {
  1336  	batch := db.NewBatch()
  1337  	defer batch.Close()
  1338  
  1339  	setCommitInfo(batch, version, cInfo)
  1340  	setLatestVersion(batch, version)
  1341  	setPruningHeights(batch, pruneHeights)
  1342  	setVersions(batch, versions)
  1343  
  1344  	if err := batch.Write(); err != nil {
  1345  		panic(fmt.Errorf("error on batch write %w", err))
  1346  	}
  1347  }
  1348  
  1349  func setVersions(batch dbm.Batch, versions []int64) {
  1350  	bz := cdc.MustMarshalBinaryBare(versions)
  1351  	batch.Set([]byte(versionsKey), bz)
  1352  }
  1353  
  1354  func getVersions(db dbm.DB) ([]int64, error) {
  1355  	bz, err := db.Get([]byte(versionsKey))
  1356  	if err != nil {
  1357  		return nil, fmt.Errorf("failed to get versions: %w", err)
  1358  	}
  1359  
  1360  	if len(bz) == 0 {
  1361  		return nil, nil
  1362  	}
  1363  
  1364  	var versions []int64
  1365  	if err := cdc.UnmarshalBinaryBare(bz, &versions); err != nil {
  1366  		return nil, fmt.Errorf("failed to unmarshal pruned heights: %w", err)
  1367  	}
  1368  
  1369  	return versions, nil
  1370  }
  1371  
  1372  // Snapshot implements snapshottypes.Snapshotter. The snapshot output for a given format must be
  1373  // identical across nodes such that chunks from different sources fit together. If the output for a
  1374  // given format changes (at the byte level), the snapshot format must be bumped - see
  1375  // TestMultistoreSnapshot_Checksum test.
  1376  func (rs *Store) Export(to *Store, initVersion int64) error {
  1377  	curVersion := rs.lastCommitInfo.Version
  1378  	// Collect stores to snapshot (only IAVL stores are supported)
  1379  	type namedStore struct {
  1380  		fromStore *iavl.Store
  1381  		toStore   *iavl.Store
  1382  		name      string
  1383  	}
  1384  	stores := []namedStore{}
  1385  	for key := range rs.stores {
  1386  		switch store := rs.GetCommitKVStore(key).(type) {
  1387  		case *iavl.Store:
  1388  			var toKVStore types.CommitKVStore
  1389  			for toKey, toValue := range to.stores {
  1390  				if key.Name() == toKey.Name() {
  1391  					toKVStore = toValue
  1392  				}
  1393  			}
  1394  			toStore, _ := toKVStore.(*iavl.Store)
  1395  			stores = append(stores, namedStore{name: key.Name(), fromStore: store, toStore: toStore})
  1396  		case *transient.Store:
  1397  			// Non-persisted stores shouldn't be snapshotted
  1398  			continue
  1399  		default:
  1400  			return fmt.Errorf(
  1401  				"don't know how to snapshot store %q of type %T", key.Name(), store)
  1402  		}
  1403  	}
  1404  	sort.Slice(stores, func(i, j int) bool {
  1405  		return strings.Compare(stores[i].name, stores[j].name) == 1
  1406  	})
  1407  
  1408  	// Export each IAVL store. Stores are serialized as a stream of SnapshotItem Protobuf
  1409  	// messages. The first item contains a SnapshotStore with store metadata (i.e. name),
  1410  	// and the following messages contain a SnapshotNode (i.e. an ExportNode). Store changes
  1411  	// are demarcated by new SnapshotStore items.
  1412  	for _, store := range stores {
  1413  		log.Println("--------- export ", store.name, " start ---------")
  1414  		exporter, err := store.fromStore.Export(curVersion)
  1415  		if err != nil {
  1416  			panic(err)
  1417  		}
  1418  		defer exporter.Close()
  1419  
  1420  		importer, err := store.toStore.Import(initVersion)
  1421  		if err != nil {
  1422  			panic(err)
  1423  		}
  1424  		defer importer.Close()
  1425  
  1426  		var totalCnt uint64
  1427  		var totalSize uint64
  1428  		for {
  1429  			node, err := exporter.Next()
  1430  			if err == iavltree.ExportDone {
  1431  				break
  1432  			}
  1433  
  1434  			err = importer.Add(node)
  1435  			if err != nil {
  1436  				panic(err)
  1437  			}
  1438  			nodeSize := len(node.Key) + len(node.Value)
  1439  			totalCnt++
  1440  			totalSize += uint64(nodeSize)
  1441  			if totalCnt%10000 == 0 {
  1442  				log.Println("--------- total node count ", totalCnt, " ---------")
  1443  				log.Println("--------- total node size ", totalSize, " ---------")
  1444  			}
  1445  		}
  1446  
  1447  		exporter.Close()
  1448  		err = importer.Commit()
  1449  		if err != nil {
  1450  			panic(err)
  1451  		}
  1452  		importer.Close()
  1453  		log.Println("--------- export ", store.name, " end ---------")
  1454  	}
  1455  
  1456  	flushMetadata(to.db, initVersion, rs.buildCommitInfo(initVersion), []int64{}, []int64{})
  1457  
  1458  	return nil
  1459  }
  1460  
  1461  func (rs *Store) buildCommitInfo(version int64) commitInfo {
  1462  	storeInfos := []storeInfo{}
  1463  	for key, store := range rs.stores {
  1464  		if store.GetStoreType() == types.StoreTypeTransient {
  1465  			continue
  1466  		}
  1467  		storeInfos = append(storeInfos, storeInfo{
  1468  			Name: key.Name(),
  1469  			Core: storeCore{
  1470  				store.LastCommitID(),
  1471  			},
  1472  		})
  1473  	}
  1474  	return commitInfo{
  1475  		Version:    version,
  1476  		StoreInfos: storeInfos,
  1477  	}
  1478  }
  1479  
  1480  func (src Store) Copy() *Store {
  1481  	dst := &Store{
  1482  		db:           src.db,
  1483  		pruningOpts:  src.pruningOpts,
  1484  		storesParams: make(map[types.StoreKey]storeParams, len(src.storesParams)),
  1485  		stores:       make(map[types.StoreKey]types.CommitKVStore, len(src.stores)),
  1486  		keysByName:   make(map[string]types.StoreKey, len(src.keysByName)),
  1487  		lazyLoading:  src.lazyLoading,
  1488  		pruneHeights: make([]int64, 0),
  1489  		versions:     make([]int64, 0),
  1490  
  1491  		traceWriter:     src.traceWriter,
  1492  		traceContext:    src.traceContext,
  1493  		interBlockCache: src.interBlockCache,
  1494  		upgradeVersion:  src.upgradeVersion,
  1495  	}
  1496  
  1497  	dst.lastCommitInfo = commitInfo{
  1498  		Version:    src.lastCommitInfo.Version,
  1499  		StoreInfos: make([]storeInfo, 0),
  1500  	}
  1501  
  1502  	for _, info := range src.lastCommitInfo.StoreInfos {
  1503  		dst.lastCommitInfo.StoreInfos = append(dst.lastCommitInfo.StoreInfos, info)
  1504  	}
  1505  
  1506  	for key, value := range src.storesParams {
  1507  		dst.storesParams[key] = value
  1508  	}
  1509  
  1510  	for key, value := range src.stores {
  1511  		dst.stores[key] = value
  1512  	}
  1513  
  1514  	for key, value := range src.keysByName {
  1515  		dst.keysByName[key] = value
  1516  	}
  1517  
  1518  	for _, value := range src.pruneHeights {
  1519  		dst.pruneHeights = append(dst.pruneHeights, value)
  1520  	}
  1521  
  1522  	for _, value := range src.versions {
  1523  		dst.versions = append(dst.versions, value)
  1524  	}
  1525  
  1526  	return dst
  1527  }
  1528  func (rs *Store) CurrentVersion() int64 {
  1529  	var currVer int64 = -1
  1530  	for key, store := range rs.stores {
  1531  		var version int64
  1532  		switch store.GetStoreType() {
  1533  		case types.StoreTypeIAVL:
  1534  			sName := key.Name()
  1535  			if evmAccStoreFilter(sName, rs.GetLatestVersion()) {
  1536  				continue
  1537  			}
  1538  			if filter(key.Name(), rs.lastCommitInfo.Version, nil, rs.commitFilters) {
  1539  				continue
  1540  			}
  1541  			s := store.(*iavl.Store)
  1542  			version = s.CurrentVersion()
  1543  		case types.StoreTypeMPT:
  1544  			s := store.(*mpt.MptStore)
  1545  			version = s.CurrentVersion()
  1546  		case types.StoreTypeTransient:
  1547  		default:
  1548  			continue
  1549  		}
  1550  		if currVer == -1 {
  1551  			currVer = version
  1552  			continue
  1553  		}
  1554  		if version < currVer {
  1555  			currVer = version
  1556  		}
  1557  	}
  1558  	return currVer
  1559  }
  1560  func (rs *Store) StopStore() {
  1561  	latestVersion := rs.CurrentVersion()
  1562  	for key, store := range rs.stores {
  1563  		switch store.GetStoreType() {
  1564  		case types.StoreTypeIAVL:
  1565  			sName := key.Name()
  1566  			if evmAccStoreFilter(sName, rs.GetLatestVersion()) {
  1567  				continue
  1568  			}
  1569  			if filter(key.Name(), rs.lastCommitInfo.Version, nil, rs.commitFilters) {
  1570  				continue
  1571  			}
  1572  			s := store.(*iavl.Store)
  1573  			s.StopStoreWithVersion(latestVersion)
  1574  		case types.StoreTypeDB:
  1575  			panic("unexpected db store")
  1576  		case types.StoreTypeMulti:
  1577  			panic("unexpected multi store")
  1578  		case types.StoreTypeMPT:
  1579  			s := store.(*mpt.MptStore)
  1580  			s.StopWithVersion(latestVersion)
  1581  		case types.StoreTypeTransient:
  1582  		default:
  1583  		}
  1584  	}
  1585  
  1586  }
  1587  
  1588  func (rs *Store) SetLogger(log tmlog.Logger) {
  1589  	rs.logger = log.With("module", "root-multi")
  1590  }
  1591  
  1592  // GetLatestStoredMptHeight get latest mpt storage height
  1593  func GetLatestStoredMptHeight() uint64 {
  1594  	db := mpt.InstanceOfMptStore()
  1595  	rst, err := db.TrieDB().DiskDB().Get(mpt.KeyPrefixAccLatestStoredHeight)
  1596  	if err != nil || len(rst) == 0 {
  1597  		return 0
  1598  	}
  1599  	return binary.BigEndian.Uint64(rst)
  1600  }
  1601  
  1602  func (rs *Store) SetUpgradeVersion(version int64) {
  1603  	rs.upgradeVersion = version
  1604  }