github.com/Finschia/finschia-sdk@v0.48.1/store/rootmulti/store_test.go (about)

     1  package rootmulti
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"math/rand"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	dbm "github.com/tendermint/tm-db"
    14  
    15  	"github.com/Finschia/ostracon/libs/log"
    16  	abci "github.com/tendermint/tendermint/abci/types"
    17  
    18  	"github.com/Finschia/finschia-sdk/codec"
    19  	codecTypes "github.com/Finschia/finschia-sdk/codec/types"
    20  	"github.com/Finschia/finschia-sdk/store/cachemulti"
    21  	"github.com/Finschia/finschia-sdk/store/iavl"
    22  	sdkmaps "github.com/Finschia/finschia-sdk/store/internal/maps"
    23  	"github.com/Finschia/finschia-sdk/store/listenkv"
    24  	"github.com/Finschia/finschia-sdk/store/types"
    25  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    26  )
    27  
    28  func TestStoreType(t *testing.T) {
    29  	db := dbm.NewMemDB()
    30  	store := NewStore(db, log.NewNopLogger())
    31  	store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, db)
    32  }
    33  
    34  func TestGetCommitKVStore(t *testing.T) {
    35  	var db dbm.DB = dbm.NewMemDB()
    36  	ms := newMultiStoreWithMounts(db, types.PruneDefault)
    37  	err := ms.LoadLatestVersion()
    38  	require.Nil(t, err)
    39  
    40  	key := ms.keysByName["store1"]
    41  
    42  	store1 := ms.GetCommitKVStore(key)
    43  	require.NotNil(t, store1)
    44  	require.IsType(t, &iavl.Store{}, store1)
    45  
    46  	store2 := ms.GetCommitStore(key)
    47  	require.NotNil(t, store2)
    48  	require.IsType(t, &iavl.Store{}, store2)
    49  }
    50  
    51  func TestStoreMount(t *testing.T) {
    52  	db := dbm.NewMemDB()
    53  	store := NewStore(db, log.NewNopLogger())
    54  
    55  	key1 := types.NewKVStoreKey("store1")
    56  	key2 := types.NewKVStoreKey("store2")
    57  	dup1 := types.NewKVStoreKey("store1")
    58  
    59  	require.NotPanics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
    60  	require.NotPanics(t, func() { store.MountStoreWithDB(key2, types.StoreTypeIAVL, db) })
    61  
    62  	require.Panics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
    63  	require.Panics(t, func() { store.MountStoreWithDB(nil, types.StoreTypeIAVL, db) })
    64  	require.Panics(t, func() { store.MountStoreWithDB(dup1, types.StoreTypeIAVL, db) })
    65  }
    66  
    67  func TestCacheMultiStore(t *testing.T) {
    68  	var db dbm.DB = dbm.NewMemDB()
    69  	ms := newMultiStoreWithMounts(db, types.PruneNothing)
    70  
    71  	cacheMulti := ms.CacheMultiStore()
    72  	require.IsType(t, cachemulti.Store{}, cacheMulti)
    73  }
    74  
    75  func TestCacheMultiStoreWithVersion(t *testing.T) {
    76  	var db dbm.DB = dbm.NewMemDB()
    77  	ms := newMultiStoreWithMounts(db, types.PruneNothing)
    78  	err := ms.LoadLatestVersion()
    79  	require.Nil(t, err)
    80  
    81  	commitID := types.CommitID{}
    82  	checkStore(t, ms, commitID, commitID)
    83  
    84  	k, v := []byte("wind"), []byte("blows")
    85  
    86  	store1 := ms.GetStoreByName("store1").(types.KVStore)
    87  	store1.Set(k, v)
    88  
    89  	cID := ms.Commit()
    90  	require.Equal(t, int64(1), cID.Version)
    91  
    92  	// require no failure when given an invalid or pruned version
    93  	_, err = ms.CacheMultiStoreWithVersion(cID.Version + 1)
    94  	require.NoError(t, err)
    95  
    96  	// require a valid version can be cache-loaded
    97  	cms, err := ms.CacheMultiStoreWithVersion(cID.Version)
    98  	require.NoError(t, err)
    99  
   100  	// require a valid key lookup yields the correct value
   101  	kvStore := cms.GetKVStore(ms.keysByName["store1"])
   102  	require.NotNil(t, kvStore)
   103  	require.Equal(t, kvStore.Get(k), v)
   104  
   105  	// require we cannot commit (write) to a cache-versioned multi-store
   106  	require.Panics(t, func() {
   107  		kvStore.Set(k, []byte("newValue"))
   108  		cms.Write()
   109  	})
   110  }
   111  
   112  func TestHashStableWithEmptyCommit(t *testing.T) {
   113  	var db dbm.DB = dbm.NewMemDB()
   114  	ms := newMultiStoreWithMounts(db, types.PruneNothing)
   115  	err := ms.LoadLatestVersion()
   116  	require.Nil(t, err)
   117  
   118  	commitID := types.CommitID{}
   119  	checkStore(t, ms, commitID, commitID)
   120  
   121  	k, v := []byte("wind"), []byte("blows")
   122  
   123  	store1 := ms.GetStoreByName("store1").(types.KVStore)
   124  	store1.Set(k, v)
   125  
   126  	cID := ms.Commit()
   127  	require.Equal(t, int64(1), cID.Version)
   128  	hash := cID.Hash
   129  
   130  	// make an empty commit, it should update version, but not affect hash
   131  	cID = ms.Commit()
   132  	require.Equal(t, int64(2), cID.Version)
   133  	require.Equal(t, hash, cID.Hash)
   134  }
   135  
   136  func TestMultistoreCommitLoad(t *testing.T) {
   137  	var db dbm.DB = dbm.NewMemDB()
   138  	store := newMultiStoreWithMounts(db, types.PruneNothing)
   139  	err := store.LoadLatestVersion()
   140  	require.Nil(t, err)
   141  
   142  	// New store has empty last commit.
   143  	commitID := types.CommitID{}
   144  	checkStore(t, store, commitID, commitID)
   145  
   146  	// Make sure we can get stores by name.
   147  	s1 := store.GetStoreByName("store1")
   148  	require.NotNil(t, s1)
   149  	s3 := store.GetStoreByName("store3")
   150  	require.NotNil(t, s3)
   151  	s77 := store.GetStoreByName("store77")
   152  	require.Nil(t, s77)
   153  
   154  	// Make a few commits and check them.
   155  	nCommits := int64(3)
   156  	for i := int64(0); i < nCommits; i++ {
   157  		commitID = store.Commit()
   158  		expectedCommitID := getExpectedCommitID(store, i+1)
   159  		checkStore(t, store, expectedCommitID, commitID)
   160  	}
   161  
   162  	// Load the latest multistore again and check version.
   163  	store = newMultiStoreWithMounts(db, types.PruneNothing)
   164  	err = store.LoadLatestVersion()
   165  	require.Nil(t, err)
   166  	commitID = getExpectedCommitID(store, nCommits)
   167  	checkStore(t, store, commitID, commitID)
   168  
   169  	// Commit and check version.
   170  	commitID = store.Commit()
   171  	expectedCommitID := getExpectedCommitID(store, nCommits+1)
   172  	checkStore(t, store, expectedCommitID, commitID)
   173  
   174  	// Load an older multistore and check version.
   175  	ver := nCommits - 1
   176  	store = newMultiStoreWithMounts(db, types.PruneNothing)
   177  	err = store.LoadVersion(ver)
   178  	require.Nil(t, err)
   179  	commitID = getExpectedCommitID(store, ver)
   180  	checkStore(t, store, commitID, commitID)
   181  }
   182  
   183  func TestMultistoreLoadWithUpgrade(t *testing.T) {
   184  	var db dbm.DB = dbm.NewMemDB()
   185  	store := newMultiStoreWithMounts(db, types.PruneNothing)
   186  	err := store.LoadLatestVersion()
   187  	require.Nil(t, err)
   188  
   189  	// write some data in all stores
   190  	k1, v1 := []byte("first"), []byte("store")
   191  	s1, _ := store.GetStoreByName("store1").(types.KVStore)
   192  	require.NotNil(t, s1)
   193  	s1.Set(k1, v1)
   194  
   195  	k2, v2 := []byte("second"), []byte("restore")
   196  	s2, _ := store.GetStoreByName("store2").(types.KVStore)
   197  	require.NotNil(t, s2)
   198  	s2.Set(k2, v2)
   199  
   200  	k3, v3 := []byte("third"), []byte("dropped")
   201  	s3, _ := store.GetStoreByName("store3").(types.KVStore)
   202  	require.NotNil(t, s3)
   203  	s3.Set(k3, v3)
   204  
   205  	s4, _ := store.GetStoreByName("store4").(types.KVStore)
   206  	require.Nil(t, s4)
   207  
   208  	// do one commit
   209  	commitID := store.Commit()
   210  	expectedCommitID := getExpectedCommitID(store, 1)
   211  	checkStore(t, store, expectedCommitID, commitID)
   212  
   213  	ci, err := getCommitInfo(db, 1)
   214  	require.NoError(t, err)
   215  	require.Equal(t, int64(1), ci.Version)
   216  	require.Equal(t, 3, len(ci.StoreInfos))
   217  	checkContains(t, ci.StoreInfos, []string{"store1", "store2", "store3"})
   218  
   219  	// Load without changes and make sure it is sensible
   220  	store = newMultiStoreWithMounts(db, types.PruneNothing)
   221  
   222  	err = store.LoadLatestVersion()
   223  	require.Nil(t, err)
   224  	commitID = getExpectedCommitID(store, 1)
   225  	checkStore(t, store, commitID, commitID)
   226  
   227  	// let's query data to see it was saved properly
   228  	s2, _ = store.GetStoreByName("store2").(types.KVStore)
   229  	require.NotNil(t, s2)
   230  	require.Equal(t, v2, s2.Get(k2))
   231  
   232  	// now, let's load with upgrades...
   233  	restore, upgrades := newMultiStoreWithModifiedMounts(db, types.PruneNothing)
   234  	err = restore.LoadLatestVersionAndUpgrade(upgrades)
   235  	require.Nil(t, err)
   236  
   237  	// s1 was not changed
   238  	s1, _ = restore.GetStoreByName("store1").(types.KVStore)
   239  	require.NotNil(t, s1)
   240  	require.Equal(t, v1, s1.Get(k1))
   241  
   242  	// store3 is mounted, but data deleted are gone
   243  	s3, _ = restore.GetStoreByName("store3").(types.KVStore)
   244  	require.NotNil(t, s3)
   245  	require.Nil(t, s3.Get(k3)) // data was deleted
   246  
   247  	// store4 is mounted, with empty data
   248  	s4, _ = restore.GetStoreByName("store4").(types.KVStore)
   249  	require.NotNil(t, s4)
   250  
   251  	iterator := s4.Iterator(nil, nil)
   252  
   253  	values := 0
   254  	for ; iterator.Valid(); iterator.Next() {
   255  		values += 1
   256  	}
   257  	require.Zero(t, values)
   258  
   259  	require.NoError(t, iterator.Close())
   260  
   261  	// write something inside store4
   262  	k4, v4 := []byte("fourth"), []byte("created")
   263  	s4.Set(k4, v4)
   264  
   265  	// store2 is no longer mounted
   266  	st2 := restore.GetStoreByName("store2")
   267  	require.Nil(t, st2)
   268  
   269  	// restore2 has the old data
   270  	rs2, _ := restore.GetStoreByName("restore2").(types.KVStore)
   271  	require.NotNil(t, rs2)
   272  	require.Equal(t, v2, rs2.Get(k2))
   273  
   274  	// store this migrated data, and load it again without migrations
   275  	migratedID := restore.Commit()
   276  	require.Equal(t, migratedID.Version, int64(2))
   277  
   278  	reload, _ := newMultiStoreWithModifiedMounts(db, types.PruneNothing)
   279  	err = reload.LoadLatestVersion()
   280  	require.Nil(t, err)
   281  	require.Equal(t, migratedID, reload.LastCommitID())
   282  
   283  	// query this new store
   284  	rl1, _ := reload.GetStoreByName("store1").(types.KVStore)
   285  	require.NotNil(t, rl1)
   286  	require.Equal(t, v1, rl1.Get(k1))
   287  
   288  	rl2, _ := reload.GetStoreByName("restore2").(types.KVStore)
   289  	require.NotNil(t, rl2)
   290  	require.Equal(t, v2, rl2.Get(k2))
   291  
   292  	rl4, _ := reload.GetStoreByName("store4").(types.KVStore)
   293  	require.NotNil(t, rl4)
   294  	require.Equal(t, v4, rl4.Get(k4))
   295  
   296  	// check commitInfo in storage
   297  	ci, err = getCommitInfo(db, 2)
   298  	require.NoError(t, err)
   299  	require.Equal(t, int64(2), ci.Version)
   300  	require.Equal(t, 4, len(ci.StoreInfos), ci.StoreInfos)
   301  	checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3", "store4"})
   302  }
   303  
   304  func TestParsePath(t *testing.T) {
   305  	_, _, err := parsePath("foo")
   306  	require.Error(t, err)
   307  
   308  	store, subpath, err := parsePath("/foo")
   309  	require.NoError(t, err)
   310  	require.Equal(t, store, "foo")
   311  	require.Equal(t, subpath, "")
   312  
   313  	store, subpath, err = parsePath("/fizz/bang/baz")
   314  	require.NoError(t, err)
   315  	require.Equal(t, store, "fizz")
   316  	require.Equal(t, subpath, "/bang/baz")
   317  
   318  	substore, subsubpath, err := parsePath(subpath)
   319  	require.NoError(t, err)
   320  	require.Equal(t, substore, "bang")
   321  	require.Equal(t, subsubpath, "/baz")
   322  }
   323  
   324  func TestMultiStoreRestart(t *testing.T) {
   325  	db := dbm.NewMemDB()
   326  	pruning := types.PruningOptions{
   327  		KeepRecent: 2,
   328  		KeepEvery:  3,
   329  		Interval:   1,
   330  	}
   331  	multi := newMultiStoreWithMounts(db, pruning)
   332  	err := multi.LoadLatestVersion()
   333  	require.Nil(t, err)
   334  
   335  	initCid := multi.LastCommitID()
   336  
   337  	k, v := "wind", "blows"
   338  	k2, v2 := "water", "flows"
   339  	k3, v3 := "fire", "burns"
   340  
   341  	for i := 1; i < 3; i++ {
   342  		// Set and commit data in one store.
   343  		store1 := multi.GetStoreByName("store1").(types.KVStore)
   344  		store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, i)))
   345  
   346  		// ... and another.
   347  		store2 := multi.GetStoreByName("store2").(types.KVStore)
   348  		store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, i)))
   349  
   350  		// ... and another.
   351  		store3 := multi.GetStoreByName("store3").(types.KVStore)
   352  		store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, i)))
   353  
   354  		multi.Commit()
   355  
   356  		cinfo, err := getCommitInfo(multi.db, int64(i))
   357  		require.NoError(t, err)
   358  		require.Equal(t, int64(i), cinfo.Version)
   359  	}
   360  
   361  	// Set and commit data in one store.
   362  	store1 := multi.GetStoreByName("store1").(types.KVStore)
   363  	store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, 3)))
   364  
   365  	// ... and another.
   366  	store2 := multi.GetStoreByName("store2").(types.KVStore)
   367  	store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, 3)))
   368  
   369  	multi.Commit()
   370  
   371  	flushedCinfo, err := getCommitInfo(multi.db, 3)
   372  	require.Nil(t, err)
   373  	require.NotEqual(t, initCid, flushedCinfo, "CID is different after flush to disk")
   374  
   375  	// ... and another.
   376  	store3 := multi.GetStoreByName("store3").(types.KVStore)
   377  	store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, 3)))
   378  
   379  	multi.Commit()
   380  
   381  	postFlushCinfo, err := getCommitInfo(multi.db, 4)
   382  	require.NoError(t, err)
   383  	require.Equal(t, int64(4), postFlushCinfo.Version, "Commit changed after in-memory commit")
   384  
   385  	multi = newMultiStoreWithMounts(db, pruning)
   386  	err = multi.LoadLatestVersion()
   387  	require.Nil(t, err)
   388  
   389  	reloadedCid := multi.LastCommitID()
   390  	require.Equal(t, int64(4), reloadedCid.Version, "Reloaded CID is not the same as last flushed CID")
   391  
   392  	// Check that store1 and store2 retained date from 3rd commit
   393  	store1 = multi.GetStoreByName("store1").(types.KVStore)
   394  	val := store1.Get([]byte(k))
   395  	require.Equal(t, []byte(fmt.Sprintf("%s:%d", v, 3)), val, "Reloaded value not the same as last flushed value")
   396  
   397  	store2 = multi.GetStoreByName("store2").(types.KVStore)
   398  	val2 := store2.Get([]byte(k2))
   399  	require.Equal(t, []byte(fmt.Sprintf("%s:%d", v2, 3)), val2, "Reloaded value not the same as last flushed value")
   400  
   401  	// Check that store3 still has data from last commit even though update happened on 2nd commit
   402  	store3 = multi.GetStoreByName("store3").(types.KVStore)
   403  	val3 := store3.Get([]byte(k3))
   404  	require.Equal(t, []byte(fmt.Sprintf("%s:%d", v3, 3)), val3, "Reloaded value not the same as last flushed value")
   405  }
   406  
   407  func TestMultiStoreQuery(t *testing.T) {
   408  	db := dbm.NewMemDB()
   409  	multi := newMultiStoreWithMounts(db, types.PruneNothing)
   410  	err := multi.LoadLatestVersion()
   411  	require.Nil(t, err)
   412  
   413  	k, v := []byte("wind"), []byte("blows")
   414  	k2, v2 := []byte("water"), []byte("flows")
   415  	// v3 := []byte("is cold")
   416  
   417  	cid1 := multi.Commit()
   418  
   419  	// Make sure we can get by name.
   420  	garbage := multi.GetStoreByName("bad-name")
   421  	require.Nil(t, garbage)
   422  
   423  	// Set and commit data in one store.
   424  	store1 := multi.GetStoreByName("store1").(types.KVStore)
   425  	store1.Set(k, v)
   426  
   427  	// ... and another.
   428  	store2 := multi.GetStoreByName("store2").(types.KVStore)
   429  	store2.Set(k2, v2)
   430  
   431  	// Commit the multistore.
   432  	cid2 := multi.Commit()
   433  	ver := cid2.Version
   434  
   435  	// Reload multistore from database
   436  	multi = newMultiStoreWithMounts(db, types.PruneNothing)
   437  	err = multi.LoadLatestVersion()
   438  	require.Nil(t, err)
   439  
   440  	// Test bad path.
   441  	query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
   442  	qres := multi.Query(query)
   443  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
   444  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
   445  
   446  	query.Path = "h897fy32890rf63296r92"
   447  	qres = multi.Query(query)
   448  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
   449  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
   450  
   451  	// Test invalid store name.
   452  	query.Path = "/garbage/key"
   453  	qres = multi.Query(query)
   454  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
   455  	require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
   456  
   457  	// Test valid query with data.
   458  	query.Path = "/store1/key"
   459  	qres = multi.Query(query)
   460  	require.EqualValues(t, 0, qres.Code)
   461  	require.Equal(t, v, qres.Value)
   462  
   463  	// Test valid but empty query.
   464  	query.Path = "/store2/key"
   465  	query.Prove = true
   466  	qres = multi.Query(query)
   467  	require.EqualValues(t, 0, qres.Code)
   468  	require.Nil(t, qres.Value)
   469  
   470  	// Test store2 data.
   471  	query.Data = k2
   472  	qres = multi.Query(query)
   473  	require.EqualValues(t, 0, qres.Code)
   474  	require.Equal(t, v2, qres.Value)
   475  
   476  	// Test proofs latest height
   477  	query.Path = fmt.Sprintf("/%s", proofsPath)
   478  	qres = multi.Query(query)
   479  	require.EqualValues(t, 0, qres.Code)
   480  	require.NotNil(t, qres.ProofOps)
   481  	require.Equal(t, []byte(proofsPath), qres.Key)
   482  	require.Equal(t, cid2.Hash, qres.Value)
   483  	require.Equal(t, cid2.Version, qres.Height)
   484  	require.Equal(t, 3, len(qres.ProofOps.Ops)) // 3 mounted stores
   485  
   486  	// Test proofs second latest height
   487  	query.Height = query.Height - 1
   488  	qres = multi.Query(query)
   489  	require.EqualValues(t, 0, qres.Code)
   490  	require.NotNil(t, qres.ProofOps)
   491  	require.Equal(t, []byte(proofsPath), qres.Key)
   492  	require.Equal(t, cid1.Hash, qres.Value)
   493  	require.Equal(t, cid1.Version, qres.Height)
   494  	require.Equal(t, 3, len(qres.ProofOps.Ops)) // 3 mounted stores
   495  }
   496  
   497  func TestMultiStore_Pruning(t *testing.T) {
   498  	testCases := []struct {
   499  		name        string
   500  		numVersions int64
   501  		po          types.PruningOptions
   502  		deleted     []int64
   503  		saved       []int64
   504  	}{
   505  		{"prune nothing", 10, types.PruneNothing, nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
   506  		{"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}},
   507  		{"prune some; no batch", 10, types.NewPruningOptions(2, 3, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}},
   508  		{"prune some; small batch", 10, types.NewPruningOptions(2, 3, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}},
   509  		{"prune some; large batch", 10, types.NewPruningOptions(2, 3, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
   510  	}
   511  
   512  	for _, tc := range testCases {
   513  		tc := tc
   514  
   515  		t.Run(tc.name, func(t *testing.T) {
   516  			db := dbm.NewMemDB()
   517  			ms := newMultiStoreWithMounts(db, tc.po)
   518  			require.NoError(t, ms.LoadLatestVersion())
   519  
   520  			for i := int64(0); i < tc.numVersions; i++ {
   521  				ms.Commit()
   522  			}
   523  
   524  			for _, v := range tc.saved {
   525  				_, err := ms.CacheMultiStoreWithVersion(v)
   526  				require.NoError(t, err, "expected error when loading height: %d", v)
   527  			}
   528  
   529  			for _, v := range tc.deleted {
   530  				_, err := ms.CacheMultiStoreWithVersion(v)
   531  				// Line: Pruning is async. store/iavl/store.GetImmutable
   532  				// returns an empty tree when the version doesn't exist.
   533  				// However, when it gets caught in between, i.e. version
   534  				// checking is done before, but iavl.GetImmutable is done
   535  				// after pruning, it fails with 'version not exist' error.
   536  				// Simply retry would do.
   537  				if err != nil {
   538  					_, err = ms.CacheMultiStoreWithVersion(v)
   539  				}
   540  				require.NoError(t, err, "expected error when loading height: %d", v)
   541  			}
   542  		})
   543  	}
   544  }
   545  
   546  func TestMultiStore_PruningRestart(t *testing.T) {
   547  	db := dbm.NewMemDB()
   548  	ms := newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11))
   549  	require.NoError(t, ms.LoadLatestVersion())
   550  
   551  	// Commit enough to build up heights to prune, where on the next block we should
   552  	// batch delete.
   553  	for i := int64(0); i < 10; i++ {
   554  		ms.Commit()
   555  	}
   556  
   557  	pruneHeights := []int64{1, 2, 4, 5, 7}
   558  
   559  	// ensure we've persisted the current batch of heights to prune to the store's DB
   560  	ph, err := getPruningHeights(ms.db)
   561  	require.NoError(t, err)
   562  	require.Equal(t, pruneHeights, ph)
   563  
   564  	// "restart"
   565  	ms = newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11))
   566  	err = ms.LoadLatestVersion()
   567  	require.NoError(t, err)
   568  	require.Equal(t, pruneHeights, ms.pruneHeights)
   569  
   570  	// commit one more block and ensure the heights have been pruned
   571  	ms.Commit()
   572  	require.Empty(t, ms.pruneHeights)
   573  
   574  	for _, v := range pruneHeights {
   575  		_, err := ms.CacheMultiStoreWithVersion(v)
   576  		require.NoError(t, err, "expected error when loading height: %d", v)
   577  	}
   578  }
   579  
   580  func assertStoresEqual(t *testing.T, expect, actual types.CommitKVStore, msgAndArgs ...interface{}) {
   581  	assert.Equal(t, expect.LastCommitID(), actual.LastCommitID())
   582  	expectIter := expect.Iterator(nil, nil)
   583  	expectMap := map[string][]byte{}
   584  	for ; expectIter.Valid(); expectIter.Next() {
   585  		expectMap[string(expectIter.Key())] = expectIter.Value()
   586  	}
   587  	require.NoError(t, expectIter.Error())
   588  
   589  	actualIter := expect.Iterator(nil, nil)
   590  	actualMap := map[string][]byte{}
   591  	for ; actualIter.Valid(); actualIter.Next() {
   592  		actualMap[string(actualIter.Key())] = actualIter.Value()
   593  	}
   594  	require.NoError(t, actualIter.Error())
   595  
   596  	assert.Equal(t, expectMap, actualMap, msgAndArgs...)
   597  }
   598  
   599  func TestSetInitialVersion(t *testing.T) {
   600  	db := dbm.NewMemDB()
   601  	multi := newMultiStoreWithMounts(db, types.PruneNothing)
   602  
   603  	require.NoError(t, multi.LoadLatestVersion())
   604  
   605  	multi.SetInitialVersion(5)
   606  	require.Equal(t, int64(5), multi.initialVersion)
   607  
   608  	multi.Commit()
   609  	require.Equal(t, int64(5), multi.LastCommitID().Version)
   610  
   611  	ckvs := multi.GetCommitKVStore(multi.keysByName["store1"])
   612  	iavlStore, ok := ckvs.(*iavl.Store)
   613  	require.True(t, ok)
   614  	require.True(t, iavlStore.VersionExists(5))
   615  }
   616  
   617  func TestAddListenersAndListeningEnabled(t *testing.T) {
   618  	db := dbm.NewMemDB()
   619  	multi := newMultiStoreWithMounts(db, types.PruneNothing)
   620  	testKey := types.NewKVStoreKey("listening_test_key")
   621  	enabled := multi.ListeningEnabled(testKey)
   622  	require.False(t, enabled)
   623  
   624  	multi.AddListeners(testKey, []types.WriteListener{})
   625  	enabled = multi.ListeningEnabled(testKey)
   626  	require.False(t, enabled)
   627  
   628  	mockListener := types.NewStoreKVPairWriteListener(nil, nil)
   629  	multi.AddListeners(testKey, []types.WriteListener{mockListener})
   630  	wrongTestKey := types.NewKVStoreKey("wrong_listening_test_key")
   631  	enabled = multi.ListeningEnabled(wrongTestKey)
   632  	require.False(t, enabled)
   633  
   634  	enabled = multi.ListeningEnabled(testKey)
   635  	require.True(t, enabled)
   636  }
   637  
   638  var (
   639  	interfaceRegistry = codecTypes.NewInterfaceRegistry()
   640  	testMarshaller    = codec.NewProtoCodec(interfaceRegistry)
   641  	testKey1          = []byte{1, 2, 3, 4, 5}
   642  	testValue1        = []byte{5, 4, 3, 2, 1}
   643  	testKey2          = []byte{2, 3, 4, 5, 6}
   644  	testValue2        = []byte{6, 5, 4, 3, 2}
   645  )
   646  
   647  func TestGetListenWrappedKVStore(t *testing.T) {
   648  	buf := new(bytes.Buffer)
   649  	var db dbm.DB = dbm.NewMemDB()
   650  	ms := newMultiStoreWithMounts(db, types.PruneNothing)
   651  	ms.LoadLatestVersion()
   652  	mockListeners := []types.WriteListener{types.NewStoreKVPairWriteListener(buf, testMarshaller)}
   653  	ms.AddListeners(testStoreKey1, mockListeners)
   654  	ms.AddListeners(testStoreKey2, mockListeners)
   655  
   656  	listenWrappedStore1 := ms.GetKVStore(testStoreKey1)
   657  	require.IsType(t, &listenkv.Store{}, listenWrappedStore1)
   658  
   659  	listenWrappedStore1.Set(testKey1, testValue1)
   660  	expectedOutputKVPairSet1, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{
   661  		Key:      testKey1,
   662  		Value:    testValue1,
   663  		StoreKey: testStoreKey1.Name(),
   664  		Delete:   false,
   665  	})
   666  	require.Nil(t, err)
   667  	kvPairSet1Bytes := buf.Bytes()
   668  	buf.Reset()
   669  	require.Equal(t, expectedOutputKVPairSet1, kvPairSet1Bytes)
   670  
   671  	listenWrappedStore1.Delete(testKey1)
   672  	expectedOutputKVPairDelete1, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{
   673  		Key:      testKey1,
   674  		Value:    nil,
   675  		StoreKey: testStoreKey1.Name(),
   676  		Delete:   true,
   677  	})
   678  	require.Nil(t, err)
   679  	kvPairDelete1Bytes := buf.Bytes()
   680  	buf.Reset()
   681  	require.Equal(t, expectedOutputKVPairDelete1, kvPairDelete1Bytes)
   682  
   683  	listenWrappedStore2 := ms.GetKVStore(testStoreKey2)
   684  	require.IsType(t, &listenkv.Store{}, listenWrappedStore2)
   685  
   686  	listenWrappedStore2.Set(testKey2, testValue2)
   687  	expectedOutputKVPairSet2, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{
   688  		Key:      testKey2,
   689  		Value:    testValue2,
   690  		StoreKey: testStoreKey2.Name(),
   691  		Delete:   false,
   692  	})
   693  	kvPairSet2Bytes := buf.Bytes()
   694  	buf.Reset()
   695  	require.Equal(t, expectedOutputKVPairSet2, kvPairSet2Bytes)
   696  
   697  	listenWrappedStore2.Delete(testKey2)
   698  	expectedOutputKVPairDelete2, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{
   699  		Key:      testKey2,
   700  		Value:    nil,
   701  		StoreKey: testStoreKey2.Name(),
   702  		Delete:   true,
   703  	})
   704  	kvPairDelete2Bytes := buf.Bytes()
   705  	buf.Reset()
   706  	require.Equal(t, expectedOutputKVPairDelete2, kvPairDelete2Bytes)
   707  
   708  	unwrappedStore := ms.GetKVStore(testStoreKey3)
   709  	require.IsType(t, &iavl.Store{}, unwrappedStore)
   710  
   711  	unwrappedStore.Set(testKey2, testValue2)
   712  	kvPairSet3Bytes := buf.Bytes()
   713  	buf.Reset()
   714  	require.Equal(t, []byte{}, kvPairSet3Bytes)
   715  
   716  	unwrappedStore.Delete(testKey2)
   717  	kvPairDelete3Bytes := buf.Bytes()
   718  	buf.Reset()
   719  	require.Equal(t, []byte{}, kvPairDelete3Bytes)
   720  }
   721  
   722  func TestCacheWraps(t *testing.T) {
   723  	db := dbm.NewMemDB()
   724  	multi := newMultiStoreWithMounts(db, types.PruneNothing)
   725  
   726  	cacheWrapper := multi.CacheWrap()
   727  	require.IsType(t, cachemulti.Store{}, cacheWrapper)
   728  
   729  	cacheWrappedWithTrace := multi.CacheWrapWithTrace(nil, nil)
   730  	require.IsType(t, cachemulti.Store{}, cacheWrappedWithTrace)
   731  
   732  	cacheWrappedWithListeners := multi.CacheWrapWithListeners(nil, nil)
   733  	require.IsType(t, cachemulti.Store{}, cacheWrappedWithListeners)
   734  }
   735  
   736  func TestTraceConcurrency(t *testing.T) {
   737  	db := dbm.NewMemDB()
   738  	multi := newMultiStoreWithMounts(db, types.PruneNothing)
   739  	err := multi.LoadLatestVersion()
   740  	require.NoError(t, err)
   741  
   742  	b := &bytes.Buffer{}
   743  	key := multi.keysByName["store1"]
   744  	tc := types.TraceContext(map[string]interface{}{"blockHeight": 64})
   745  
   746  	multi.SetTracer(b)
   747  	multi.SetTracingContext(tc)
   748  
   749  	cms := multi.CacheMultiStore()
   750  	store1 := cms.GetKVStore(key)
   751  	cw := store1.CacheWrapWithTrace(b, tc)
   752  	_ = cw
   753  	require.NotNil(t, store1)
   754  
   755  	stop := make(chan struct{})
   756  	stopW := make(chan struct{})
   757  
   758  	go func(stop chan struct{}) {
   759  		for {
   760  			select {
   761  			case <-stop:
   762  				return
   763  			default:
   764  				store1.Set([]byte{1}, []byte{1})
   765  				cms.Write()
   766  			}
   767  		}
   768  	}(stop)
   769  
   770  	go func(stop chan struct{}) {
   771  		for {
   772  			select {
   773  			case <-stop:
   774  				return
   775  			default:
   776  				multi.SetTracingContext(tc)
   777  			}
   778  		}
   779  	}(stopW)
   780  
   781  	time.Sleep(3 * time.Second)
   782  	stop <- struct{}{}
   783  	stopW <- struct{}{}
   784  }
   785  
   786  //-----------------------------------------------------------------------
   787  // utils
   788  
   789  var (
   790  	testStoreKey1 = types.NewKVStoreKey("store1")
   791  	testStoreKey2 = types.NewKVStoreKey("store2")
   792  	testStoreKey3 = types.NewKVStoreKey("store3")
   793  )
   794  
   795  func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store {
   796  	store := NewStore(db, log.NewNopLogger())
   797  	store.pruningOpts = pruningOpts
   798  
   799  	store.MountStoreWithDB(testStoreKey1, types.StoreTypeIAVL, nil)
   800  	store.MountStoreWithDB(testStoreKey2, types.StoreTypeIAVL, nil)
   801  	store.MountStoreWithDB(testStoreKey3, types.StoreTypeIAVL, nil)
   802  
   803  	return store
   804  }
   805  
   806  func newMultiStoreWithMixedMounts(db dbm.DB) *Store {
   807  	store := NewStore(db, log.NewNopLogger())
   808  	store.MountStoreWithDB(types.NewKVStoreKey("iavl1"), types.StoreTypeIAVL, nil)
   809  	store.MountStoreWithDB(types.NewKVStoreKey("iavl2"), types.StoreTypeIAVL, nil)
   810  	store.MountStoreWithDB(types.NewKVStoreKey("iavl3"), types.StoreTypeIAVL, nil)
   811  	store.LoadLatestVersion()
   812  
   813  	return store
   814  }
   815  
   816  func newMultiStoreWithGeneratedData(db dbm.DB, stores uint8, storeKeys uint64) *Store {
   817  	multiStore := NewStore(db, log.NewNopLogger())
   818  	r := rand.New(rand.NewSource(49872768940)) // Fixed seed for deterministic tests
   819  
   820  	keys := []*types.KVStoreKey{}
   821  	for i := uint8(0); i < stores; i++ {
   822  		key := types.NewKVStoreKey(fmt.Sprintf("store%v", i))
   823  		multiStore.MountStoreWithDB(key, types.StoreTypeIAVL, nil)
   824  		keys = append(keys, key)
   825  	}
   826  	multiStore.LoadLatestVersion()
   827  
   828  	for _, key := range keys {
   829  		store := multiStore.stores[key].(*iavl.Store)
   830  		for i := uint64(0); i < storeKeys; i++ {
   831  			k := make([]byte, 8)
   832  			v := make([]byte, 1024)
   833  			binary.BigEndian.PutUint64(k, i)
   834  			_, err := r.Read(v)
   835  			if err != nil {
   836  				panic(err)
   837  			}
   838  			store.Set(k, v)
   839  		}
   840  	}
   841  
   842  	multiStore.Commit()
   843  	multiStore.LoadLatestVersion()
   844  
   845  	return multiStore
   846  }
   847  
   848  func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions) (*Store, *types.StoreUpgrades) {
   849  	store := NewStore(db, log.NewNopLogger())
   850  	store.pruningOpts = pruningOpts
   851  
   852  	store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil)
   853  	store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil)
   854  	store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil)
   855  	store.MountStoreWithDB(types.NewKVStoreKey("store4"), types.StoreTypeIAVL, nil)
   856  
   857  	upgrades := &types.StoreUpgrades{
   858  		Added: []string{"store4"},
   859  		Renamed: []types.StoreRename{{
   860  			OldKey: "store2",
   861  			NewKey: "restore2",
   862  		}},
   863  		Deleted: []string{"store3"},
   864  	}
   865  
   866  	return store, upgrades
   867  }
   868  
   869  func checkStore(t *testing.T, store *Store, expect, got types.CommitID) {
   870  	require.Equal(t, expect, got)
   871  	require.Equal(t, expect, store.LastCommitID())
   872  }
   873  
   874  func checkContains(t testing.TB, info []types.StoreInfo, wanted []string) {
   875  	t.Helper()
   876  
   877  	for _, want := range wanted {
   878  		checkHas(t, info, want)
   879  	}
   880  }
   881  
   882  func checkHas(t testing.TB, info []types.StoreInfo, want string) {
   883  	t.Helper()
   884  	for _, i := range info {
   885  		if i.Name == want {
   886  			return
   887  		}
   888  	}
   889  	t.Fatalf("storeInfo doesn't contain %s", want)
   890  }
   891  
   892  func getExpectedCommitID(store *Store, ver int64) types.CommitID {
   893  	return types.CommitID{
   894  		Version: ver,
   895  		Hash:    hashStores(store.stores),
   896  	}
   897  }
   898  
   899  func hashStores(stores map[types.StoreKey]types.CommitKVStore) []byte {
   900  	m := make(map[string][]byte, len(stores))
   901  	for key, store := range stores {
   902  		name := key.Name()
   903  		m[name] = types.StoreInfo{
   904  			Name:     name,
   905  			CommitId: store.LastCommitID(),
   906  		}.GetHash()
   907  	}
   908  	return sdkmaps.HashFromMap(m)
   909  }
   910  
   911  func TestSetIAVLDIsableFastNode(t *testing.T) {
   912  	db := dbm.NewMemDB()
   913  	multi := newMultiStoreWithMounts(db, types.PruneNothing)
   914  
   915  	multi.SetIAVLDisableFastNode(true)
   916  	require.Equal(t, multi.iavlDisableFastNode, true)
   917  
   918  	multi.SetIAVLDisableFastNode(false)
   919  	require.Equal(t, multi.iavlDisableFastNode, false)
   920  }