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

     1  package rootmulti
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math"
     7  	"os"
     8  	"os/exec"
     9  	"strings"
    10  	"testing"
    11  
    12  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    13  
    14  	iavltree "github.com/fibonacci-chain/fbc/libs/iavl"
    15  	"github.com/stretchr/testify/assert"
    16  
    17  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    18  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/merkle"
    19  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
    20  	"github.com/stretchr/testify/require"
    21  
    22  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/iavl"
    23  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    24  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    25  )
    26  
    27  func TestStoreType(t *testing.T) {
    28  	db := dbm.NewMemDB()
    29  	store := NewStore(db)
    30  	store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, db)
    31  }
    32  
    33  func TestGetCommitKVStore(t *testing.T) {
    34  	var db dbm.DB = dbm.NewMemDB()
    35  	ms := newMultiStoreWithMounts(db, types.PruneDefault)
    36  	err := ms.LoadLatestVersion()
    37  	require.Nil(t, err)
    38  
    39  	key := ms.keysByName["store1"]
    40  
    41  	store1 := ms.GetCommitKVStore(key)
    42  	require.NotNil(t, store1)
    43  	require.IsType(t, &iavl.Store{}, store1)
    44  
    45  	store2 := ms.GetCommitStore(key)
    46  	require.NotNil(t, store2)
    47  	require.IsType(t, &iavl.Store{}, store2)
    48  }
    49  
    50  func TestStoreMount(t *testing.T) {
    51  	db := dbm.NewMemDB()
    52  	store := NewStore(db)
    53  
    54  	key1 := types.NewKVStoreKey("store1")
    55  	key2 := types.NewKVStoreKey("store2")
    56  	dup1 := types.NewKVStoreKey("store1")
    57  
    58  	require.NotPanics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
    59  	require.NotPanics(t, func() { store.MountStoreWithDB(key2, types.StoreTypeIAVL, db) })
    60  
    61  	require.Panics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
    62  	require.Panics(t, func() { store.MountStoreWithDB(dup1, types.StoreTypeIAVL, db) })
    63  }
    64  
    65  func TestCacheMultiStoreWithVersion(t *testing.T) {
    66  	var db dbm.DB = dbm.NewMemDB()
    67  	ms := newMultiStoreWithMounts(db, types.PruneNothing)
    68  	err := ms.LoadLatestVersion()
    69  	require.Nil(t, err)
    70  
    71  	k, v := []byte("wind"), []byte("blows")
    72  
    73  	store1 := ms.getStoreByName("store1").(types.KVStore)
    74  	store1.Set(k, v)
    75  
    76  	cID, _ := ms.CommitterCommitMap(nil)
    77  	require.Equal(t, int64(1), cID.Version)
    78  
    79  	// require failure when given an invalid or pruned version
    80  	_, err = ms.CacheMultiStoreWithVersion(cID.Version + 1)
    81  	require.Error(t, err)
    82  
    83  	// require a valid version can be cache-loaded
    84  	cms, err := ms.CacheMultiStoreWithVersion(cID.Version)
    85  	require.NoError(t, err)
    86  
    87  	// require a valid key lookup yields the correct value
    88  	kvStore := cms.GetKVStore(ms.keysByName["store1"])
    89  	require.NotNil(t, kvStore)
    90  	require.Equal(t, kvStore.Get(k), v)
    91  
    92  	// require we cannot commit (write) to a cache-versioned multi-store
    93  	require.Panics(t, func() {
    94  		kvStore.Set(k, []byte("newValue"))
    95  		cms.Write()
    96  	})
    97  }
    98  
    99  func TestHashStableWithEmptyCommit(t *testing.T) {
   100  	var db dbm.DB = dbm.NewMemDB()
   101  	ms := newMultiStoreWithMounts(db, types.PruneNothing)
   102  	err := ms.LoadLatestVersion()
   103  	require.Nil(t, err)
   104  
   105  	k, v := []byte("wind"), []byte("blows")
   106  
   107  	store1 := ms.getStoreByName("store1").(types.KVStore)
   108  	store1.Set(k, v)
   109  	cID, _ := ms.CommitterCommitMap(nil)
   110  	require.Equal(t, int64(1), cID.Version)
   111  	hash := cID.Hash
   112  
   113  	// make an empty commit, it should update version, but not affect hash
   114  	cID, _ = ms.CommitterCommitMap(nil)
   115  	require.Equal(t, int64(2), cID.Version)
   116  	require.Equal(t, hash, cID.Hash)
   117  }
   118  
   119  func TestMultistoreCommitLoad(t *testing.T) {
   120  	tmtypes.UnittestOnlySetMilestoneVenus1Height(-1)
   121  	var db dbm.DB = dbm.NewMemDB()
   122  	store := newMultiStoreWithMounts(db, types.PruneNothing)
   123  	err := store.LoadLatestVersion()
   124  	require.Nil(t, err)
   125  
   126  	// New store has empty last commit.
   127  	commitID := types.CommitID{}
   128  
   129  	// Make sure we can get stores by name.
   130  	s1 := store.getStoreByName("store1")
   131  	require.NotNil(t, s1)
   132  	s3 := store.getStoreByName("store3")
   133  	require.NotNil(t, s3)
   134  	s77 := store.getStoreByName("store77")
   135  	require.Nil(t, s77)
   136  
   137  	// Make a few commits and check them.
   138  	nCommits := int64(3)
   139  	for i := int64(0); i < nCommits; i++ {
   140  		commitID, _ = store.CommitterCommitMap(nil)
   141  		expectedCommitID := getExpectedCommitID(store, i+1)
   142  		checkStore(t, store, expectedCommitID, commitID)
   143  	}
   144  
   145  	// Load the latest multistore again and check version.
   146  	store = newMultiStoreWithMounts(db, types.PruneNothing)
   147  	err = store.LoadLatestVersion()
   148  	require.Nil(t, err)
   149  	commitID = getExpectedCommitID(store, nCommits)
   150  	checkStore(t, store, commitID, commitID)
   151  
   152  	// Commit and check version.
   153  	commitID, _ = store.CommitterCommitMap(nil)
   154  	expectedCommitID := getExpectedCommitID(store, nCommits+1)
   155  	checkStore(t, store, expectedCommitID, commitID)
   156  
   157  	// Load an older multistore and check version.
   158  	ver := nCommits - 1
   159  	store = newMultiStoreWithMounts(db, types.PruneNothing)
   160  	err = store.LoadVersion(ver)
   161  	require.Nil(t, err)
   162  	commitID = getExpectedCommitID(store, ver)
   163  	checkStore(t, store, commitID, commitID)
   164  
   165  	// XXX: commit this older version
   166  	commitID, _ = store.CommitterCommitMap(nil)
   167  	expectedCommitID = getExpectedCommitID(store, ver+1)
   168  	checkStore(t, store, expectedCommitID, commitID)
   169  
   170  	// XXX: confirm old commit is overwritten and we have rolled back
   171  	// LatestVersion
   172  	store = newMultiStoreWithMounts(db, types.PruneDefault)
   173  	err = store.LoadLatestVersion()
   174  	require.Nil(t, err)
   175  	commitID = getExpectedCommitID(store, ver+1)
   176  	checkStore(t, store, commitID, commitID)
   177  }
   178  
   179  func TestMultistoreLoadWithUpgrade(t *testing.T) {
   180  	var db dbm.DB = dbm.NewMemDB()
   181  	store := newMultiStoreWithMounts(db, types.PruneNothing)
   182  	err := store.LoadLatestVersion()
   183  	require.Nil(t, err)
   184  
   185  	// write some data in all stores
   186  	k1, v1 := []byte("first"), []byte("store")
   187  	s1, _ := store.getStoreByName("store1").(types.KVStore)
   188  	require.NotNil(t, s1)
   189  	s1.Set(k1, v1)
   190  
   191  	k2, v2 := []byte("second"), []byte("restore")
   192  	s2, _ := store.getStoreByName("store2").(types.KVStore)
   193  	require.NotNil(t, s2)
   194  	s2.Set(k2, v2)
   195  
   196  	k3, v3 := []byte("third"), []byte("dropped")
   197  	s3, _ := store.getStoreByName("store3").(types.KVStore)
   198  	require.NotNil(t, s3)
   199  	s3.Set(k3, v3)
   200  
   201  	s4, _ := store.getStoreByName("store4").(types.KVStore)
   202  	require.Nil(t, s4)
   203  
   204  	// do one commit
   205  	commitID, _ := store.CommitterCommitMap(nil)
   206  	expectedCommitID := getExpectedCommitID(store, 1)
   207  	checkStore(t, store, expectedCommitID, commitID)
   208  
   209  	ci, err := getCommitInfo(db, 1)
   210  	require.NoError(t, err)
   211  	require.Equal(t, int64(1), ci.Version)
   212  	require.Equal(t, 3, len(ci.StoreInfos))
   213  	checkContains(t, ci.StoreInfos, []string{"store1", "store2", "store3"})
   214  
   215  	// Load without changes and make sure it is sensible
   216  	store = newMultiStoreWithMounts(db, types.PruneNothing)
   217  
   218  	err = store.LoadLatestVersion()
   219  	require.Nil(t, err)
   220  	commitID = getExpectedCommitID(store, 1)
   221  	checkStore(t, store, commitID, commitID)
   222  
   223  	// let's query data to see it was saved properly
   224  	s2, _ = store.getStoreByName("store2").(types.KVStore)
   225  	require.NotNil(t, s2)
   226  	require.Equal(t, v2, s2.Get(k2))
   227  
   228  	// now, let's load with upgrades...
   229  	restore, upgrades := newMultiStoreWithModifiedMounts(db, types.PruneNothing)
   230  	err = restore.LoadLatestVersionAndUpgrade(upgrades)
   231  	require.Nil(t, err)
   232  
   233  	// s1 was not changed
   234  	s1, _ = restore.getStoreByName("store1").(types.KVStore)
   235  	require.NotNil(t, s1)
   236  	require.Equal(t, v1, s1.Get(k1))
   237  
   238  	// store3 is mounted, but data deleted are gone
   239  	s3, _ = restore.getStoreByName("store3").(types.KVStore)
   240  	require.NotNil(t, s3)
   241  	require.Nil(t, s3.Get(k3)) // data was deleted
   242  
   243  	// store4 is mounted, with empty data
   244  	s4, _ = restore.getStoreByName("store4").(types.KVStore)
   245  	require.NotNil(t, s4)
   246  
   247  	iterator := s4.Iterator(nil, nil)
   248  
   249  	values := 0
   250  	for ; iterator.Valid(); iterator.Next() {
   251  		values++
   252  	}
   253  	require.Zero(t, values)
   254  
   255  	// write something inside store4
   256  	k4, v4 := []byte("fourth"), []byte("created")
   257  	s4.Set(k4, v4)
   258  
   259  	// store2 is no longer mounted
   260  	st2 := restore.getStoreByName("store2")
   261  	require.Nil(t, st2)
   262  
   263  	// restore2 has the old data
   264  	rs2, _ := restore.getStoreByName("restore2").(types.KVStore)
   265  	require.NotNil(t, rs2)
   266  	require.Equal(t, v2, rs2.Get(k2))
   267  
   268  	// store this migrated data, and load it again without migrations
   269  	migratedID, _ := restore.CommitterCommitMap(nil)
   270  	require.Equal(t, migratedID.Version, int64(2))
   271  
   272  	reload, _ := newMultiStoreWithModifiedMounts(db, types.PruneNothing)
   273  	err = reload.LoadLatestVersion()
   274  	require.Nil(t, err)
   275  	require.Equal(t, migratedID, reload.LastCommitID())
   276  
   277  	// query this new store
   278  	rl1, _ := reload.getStoreByName("store1").(types.KVStore)
   279  	require.NotNil(t, rl1)
   280  	require.Equal(t, v1, rl1.Get(k1))
   281  
   282  	rl2, _ := reload.getStoreByName("restore2").(types.KVStore)
   283  	require.NotNil(t, rl2)
   284  	require.Equal(t, v2, rl2.Get(k2))
   285  
   286  	rl4, _ := reload.getStoreByName("store4").(types.KVStore)
   287  	require.NotNil(t, rl4)
   288  	require.Equal(t, v4, rl4.Get(k4))
   289  
   290  	// check commitInfo in storage
   291  	ci, err = getCommitInfo(db, 2)
   292  	require.NoError(t, err)
   293  	require.Equal(t, int64(2), ci.Version)
   294  	require.Equal(t, 4, len(ci.StoreInfos), ci.StoreInfos)
   295  	checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3", "store4"})
   296  }
   297  
   298  func TestParsePath(t *testing.T) {
   299  	_, _, err := parsePath("foo")
   300  	require.Error(t, err)
   301  
   302  	store, subpath, err := parsePath("/foo")
   303  	require.NoError(t, err)
   304  	require.Equal(t, store, "foo")
   305  	require.Equal(t, subpath, "")
   306  
   307  	store, subpath, err = parsePath("/fizz/bang/baz")
   308  	require.NoError(t, err)
   309  	require.Equal(t, store, "fizz")
   310  	require.Equal(t, subpath, "/bang/baz")
   311  
   312  	substore, subsubpath, err := parsePath(subpath)
   313  	require.NoError(t, err)
   314  	require.Equal(t, substore, "bang")
   315  	require.Equal(t, subsubpath, "/baz")
   316  
   317  }
   318  
   319  // new init commitID for nil, which ibc hash not support
   320  func newInitCommitID() types.CommitID {
   321  	return types.CommitID{
   322  		0,
   323  		nil,
   324  	}
   325  }
   326  func TestMultiStoreRestart(t *testing.T) {
   327  	tmtypes.UnittestOnlySetMilestoneVenus1Height(-1)
   328  	db := dbm.NewMemDB()
   329  	pruning := types.PruningOptions{
   330  		KeepRecent: 2,
   331  		KeepEvery:  3,
   332  		Interval:   1,
   333  	}
   334  	multi := newMultiStoreWithMounts(db, pruning)
   335  	err := multi.LoadLatestVersion()
   336  	require.Nil(t, err)
   337  
   338  	initCid := newInitCommitID()
   339  
   340  	k, v := "wind", "blows"
   341  	k2, v2 := "water", "flows"
   342  	k3, v3 := "fire", "burns"
   343  
   344  	for i := 1; i < 3; i++ {
   345  		// Set and commit data in one store.
   346  		store1 := multi.getStoreByName("store1").(types.KVStore)
   347  		store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, i)))
   348  
   349  		// ... and another.
   350  		store2 := multi.getStoreByName("store2").(types.KVStore)
   351  		store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, i)))
   352  
   353  		// ... and another.
   354  		store3 := multi.getStoreByName("store3").(types.KVStore)
   355  		store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, i)))
   356  
   357  		multi.CommitterCommitMap(nil)
   358  
   359  		cinfo, err := getCommitInfo(multi.db, int64(i))
   360  		require.NoError(t, err)
   361  		require.Equal(t, int64(i), cinfo.Version)
   362  	}
   363  
   364  	// Set and commit data in one store.
   365  	store1 := multi.getStoreByName("store1").(types.KVStore)
   366  	store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, 3)))
   367  
   368  	// ... and another.
   369  	store2 := multi.getStoreByName("store2").(types.KVStore)
   370  	store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, 3)))
   371  
   372  	multi.CommitterCommitMap(nil)
   373  
   374  	flushedCinfo, err := getCommitInfo(multi.db, 3)
   375  	require.Nil(t, err)
   376  	require.NotEqual(t, initCid, flushedCinfo, "CID is different after flush to disk")
   377  
   378  	// ... and another.
   379  	store3 := multi.getStoreByName("store3").(types.KVStore)
   380  	store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, 3)))
   381  
   382  	multi.CommitterCommitMap(nil)
   383  
   384  	postFlushCinfo, err := getCommitInfo(multi.db, 4)
   385  	require.NoError(t, err)
   386  	require.Equal(t, int64(4), postFlushCinfo.Version, "Commit changed after in-memory commit")
   387  
   388  	multi = newMultiStoreWithMounts(db, pruning)
   389  	err = multi.LoadLatestVersion()
   390  	require.Nil(t, err)
   391  
   392  	reloadedCid := multi.LastCommitID()
   393  	require.Equal(t, int64(4), reloadedCid.Version, "Reloaded CID is not the same as last flushed CID")
   394  
   395  	// Check that store1 and store2 retained date from 3rd commit
   396  	store1 = multi.getStoreByName("store1").(types.KVStore)
   397  	val := store1.Get([]byte(k))
   398  	require.Equal(t, []byte(fmt.Sprintf("%s:%d", v, 3)), val, "Reloaded value not the same as last flushed value")
   399  
   400  	store2 = multi.getStoreByName("store2").(types.KVStore)
   401  	val2 := store2.Get([]byte(k2))
   402  	require.Equal(t, []byte(fmt.Sprintf("%s:%d", v2, 3)), val2, "Reloaded value not the same as last flushed value")
   403  
   404  	// Check that store3 still has data from last commit even though update happened on 2nd commit
   405  	store3 = multi.getStoreByName("store3").(types.KVStore)
   406  	val3 := store3.Get([]byte(k3))
   407  	require.Equal(t, []byte(fmt.Sprintf("%s:%d", v3, 3)), val3, "Reloaded value not the same as last flushed value")
   408  }
   409  
   410  func TestMultiStoreQuery(t *testing.T) {
   411  	db := dbm.NewMemDB()
   412  	multi := newMultiStoreWithMounts(db, types.PruneNothing)
   413  	err := multi.LoadLatestVersion()
   414  	require.Nil(t, err)
   415  
   416  	k, v := []byte("wind"), []byte("blows")
   417  	k2, v2 := []byte("water"), []byte("flows")
   418  	// v3 := []byte("is cold")
   419  
   420  	cID, _ := multi.CommitterCommitMap(nil)
   421  
   422  	// Make sure we can get by name.
   423  	garbage := multi.getStoreByName("bad-name")
   424  	require.Nil(t, garbage)
   425  
   426  	// Set and commit data in one store.
   427  	store1 := multi.getStoreByName("store1").(types.KVStore)
   428  	store1.Set(k, v)
   429  
   430  	// ... and another.
   431  	store2 := multi.getStoreByName("store2").(types.KVStore)
   432  	store2.Set(k2, v2)
   433  
   434  	// Commit the multistore.
   435  	cID, _ = multi.CommitterCommitMap(nil)
   436  	ver := cID.Version
   437  
   438  	// Reload multistore from database
   439  	multi = newMultiStoreWithMounts(db, types.PruneNothing)
   440  	err = multi.LoadLatestVersion()
   441  	require.Nil(t, err)
   442  
   443  	// Test bad path.
   444  	query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
   445  	qres := multi.Query(query)
   446  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
   447  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
   448  
   449  	query.Path = "h897fy32890rf63296r92"
   450  	qres = multi.Query(query)
   451  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
   452  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
   453  
   454  	// Test invalid store name.
   455  	query.Path = "/garbage/key"
   456  	qres = multi.Query(query)
   457  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
   458  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
   459  
   460  	// Test valid query with data.
   461  	query.Path = "/store1/key"
   462  	qres = multi.Query(query)
   463  	require.EqualValues(t, 0, qres.Code)
   464  	require.Equal(t, v, qres.Value)
   465  
   466  	// Test valid but empty query.
   467  	query.Path = "/store2/key"
   468  	query.Prove = true
   469  	qres = multi.Query(query)
   470  	require.EqualValues(t, 0, qres.Code)
   471  	require.Nil(t, qres.Value)
   472  
   473  	// Test store2 data.
   474  	query.Data = k2
   475  	qres = multi.Query(query)
   476  	require.EqualValues(t, 0, qres.Code)
   477  	require.Equal(t, v2, qres.Value)
   478  }
   479  
   480  func TestMultiStore_Pruning(t *testing.T) {
   481  	testCases := []struct {
   482  		name        string
   483  		numVersions int64
   484  		po          types.PruningOptions
   485  		deleted     []int64
   486  		saved       []int64
   487  	}{
   488  		{"prune nothing", 10, types.PruneNothing, nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
   489  		{"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4}, []int64{10}},
   490  		{"prune some; no batch", 10, types.NewPruningOptions(2, 3, 1, math.MaxInt64), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}},
   491  		{"prune some; small batch", 10, types.NewPruningOptions(2, 3, 3, math.MaxInt64), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}},
   492  		{"prune some; large batch", 10, types.NewPruningOptions(2, 3, 11, math.MaxInt64), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
   493  	}
   494  
   495  	for _, tc := range testCases {
   496  		tc := tc
   497  
   498  		t.Run(tc.name, func(t *testing.T) {
   499  			db := dbm.NewMemDB()
   500  			ms := newMultiStoreWithMounts(db, tc.po)
   501  			require.NoError(t, ms.LoadLatestVersion())
   502  
   503  			for i := int64(0); i < tc.numVersions; i++ {
   504  				ms.CommitterCommitMap(nil)
   505  			}
   506  
   507  			for _, v := range tc.saved {
   508  				_, err := ms.CacheMultiStoreWithVersion(v)
   509  				require.NoError(t, err, "expected error when loading height: %d", v)
   510  			}
   511  
   512  			for _, v := range tc.deleted {
   513  				_, err := ms.CacheMultiStoreWithVersion(v)
   514  				require.Error(t, err)
   515  			}
   516  		})
   517  	}
   518  }
   519  
   520  func TestMultiStore_PruningRestart(t *testing.T) {
   521  	db := dbm.NewMemDB()
   522  	ms := newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11, math.MaxInt64))
   523  	require.NoError(t, ms.LoadLatestVersion())
   524  
   525  	// Commit enough to build up heights to prune, where on the next block we should
   526  	// batch delete.
   527  	for i := int64(0); i < 10; i++ {
   528  		ms.CommitterCommitMap(nil)
   529  	}
   530  
   531  	pruneHeights := []int64{1, 2, 4, 5, 7}
   532  
   533  	// ensure we've persisted the current batch of heights to prune to the store's DB
   534  	ph, err := getPruningHeights(ms.db, true)
   535  	require.NoError(t, err)
   536  	require.Equal(t, pruneHeights, ph)
   537  
   538  	// "restart"
   539  	ms = newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11, math.MaxInt64))
   540  	err = ms.LoadLatestVersion()
   541  	require.NoError(t, err)
   542  	require.Equal(t, pruneHeights, ms.pruneHeights)
   543  
   544  	// commit one more block and ensure the heights have been pruned
   545  	ms.CommitterCommitMap(nil)
   546  	require.Empty(t, ms.pruneHeights)
   547  
   548  	for _, v := range pruneHeights {
   549  		_, err := ms.CacheMultiStoreWithVersion(v)
   550  		require.Error(t, err)
   551  	}
   552  }
   553  func testMultiStoreDelta(t *testing.T) {
   554  	var db dbm.DB = dbm.NewMemDB()
   555  	ms := newMultiStoreWithMounts(db, types.PruneNothing)
   556  	err := ms.LoadLatestVersion()
   557  	require.Nil(t, err)
   558  
   559  	commitID := types.CommitID{}
   560  	checkStore(t, ms, commitID, commitID)
   561  
   562  	k, v := []byte("wind"), []byte("blows")
   563  	k1, v1 := []byte("key1"), []byte("val1")
   564  	k2, v2 := []byte("key2"), []byte("val2")
   565  
   566  	store1 := ms.getStoreByName("store1").(types.KVStore)
   567  	store1.Set(k, v)
   568  	store1.Set(k1, v1)
   569  	store2 := ms.getStoreByName("store2").(types.KVStore)
   570  	store2.Set(k2, v2)
   571  
   572  	// get deltas
   573  	tmtypes.UploadDelta = true
   574  	tmtypes.DownloadDelta = true
   575  	iavltree.SetProduceDelta(true)
   576  	cID, deltas := ms.CommitterCommitMap(nil)
   577  	require.Equal(t, int64(1), cID.Version)
   578  	assert.NotEmpty(t, deltas)
   579  
   580  	// use deltas
   581  	cID, _ = ms.CommitterCommitMap(deltas)
   582  	require.Equal(t, int64(2), cID.Version)
   583  	//require.Equal(t, deltas, deltas2)
   584  }
   585  func TestMultiStore_Delta(t *testing.T) {
   586  	if os.Getenv("SUB_PROCESS") == "1" {
   587  		testMultiStoreDelta(t)
   588  		return
   589  	}
   590  
   591  	var outb, errb bytes.Buffer
   592  	cmd := exec.Command(os.Args[0], "-test.run=TestMultiStore_Delta")
   593  	cmd.Env = append(os.Environ(), "SUB_PROCESS=1")
   594  	cmd.Stdout = &outb
   595  	cmd.Stderr = &errb
   596  	err := cmd.Run()
   597  	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
   598  		isFailed := false
   599  		if strings.Contains(outb.String(), "FAIL:") ||
   600  			strings.Contains(errb.String(), "FAIL:") {
   601  			fmt.Print(cmd.Stderr)
   602  			fmt.Print(cmd.Stdout)
   603  			isFailed = true
   604  		}
   605  		assert.Equal(t, isFailed, false)
   606  
   607  		return
   608  	}
   609  }
   610  
   611  //-----------------------------------------------------------------------
   612  // utils
   613  
   614  func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store {
   615  	store := NewStore(db)
   616  	store.pruningOpts = pruningOpts
   617  
   618  	store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil)
   619  	store.MountStoreWithDB(types.NewKVStoreKey("store2"), types.StoreTypeIAVL, nil)
   620  	store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil)
   621  
   622  	return store
   623  }
   624  
   625  func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions) (*Store, *types.StoreUpgrades) {
   626  	store := NewStore(db)
   627  	store.pruningOpts = pruningOpts
   628  
   629  	store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil)
   630  	store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil)
   631  	store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil)
   632  	store.MountStoreWithDB(types.NewKVStoreKey("store4"), types.StoreTypeIAVL, nil)
   633  
   634  	upgrades := &types.StoreUpgrades{
   635  		Added: []string{"store4"},
   636  		Renamed: []types.StoreRename{{
   637  			OldKey: "store2",
   638  			NewKey: "restore2",
   639  		}},
   640  		Deleted: []string{"store3"},
   641  	}
   642  
   643  	return store, upgrades
   644  }
   645  
   646  func checkStore(t *testing.T, store *Store, expect, got types.CommitID) {
   647  	require.Equal(t, expect, got)
   648  	require.Equal(t, expect, store.LastCommitID())
   649  }
   650  
   651  func checkContains(t testing.TB, info []storeInfo, wanted []string) {
   652  	t.Helper()
   653  
   654  	for _, want := range wanted {
   655  		checkHas(t, info, want)
   656  	}
   657  }
   658  
   659  func checkHas(t testing.TB, info []storeInfo, want string) {
   660  	t.Helper()
   661  	for _, i := range info {
   662  		if i.Name == want {
   663  			return
   664  		}
   665  	}
   666  	t.Fatalf("storeInfo doesn't contain %s", want)
   667  }
   668  
   669  func getExpectedCommitID(store *Store, ver int64) types.CommitID {
   670  	return types.CommitID{
   671  		Version: ver,
   672  		Hash:    hashStores(store.stores),
   673  	}
   674  }
   675  
   676  func hashStores(stores map[types.StoreKey]types.CommitKVStore) []byte {
   677  	m := make(map[string][]byte, len(stores))
   678  	for key, store := range stores {
   679  		name := key.Name()
   680  		m[name] = storeInfo{
   681  			Name: name,
   682  			Core: storeCore{
   683  				CommitID: store.LastCommitID(),
   684  				// StoreType: store.GetStoreType(),
   685  			},
   686  		}.GetHash()
   687  	}
   688  	return merkle.SimpleHashFromMap(m)
   689  }