2019-02-01 17:03:09 -08:00
|
|
|
package rootmulti
|
2017-12-12 20:13:51 -08:00
|
|
|
|
|
|
|
import (
|
2020-02-06 12:58:32 -08:00
|
|
|
"fmt"
|
2017-12-12 20:13:51 -08:00
|
|
|
"testing"
|
|
|
|
|
2018-06-29 18:10:15 -07:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-06-28 17:54:47 -07:00
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
2019-08-02 06:20:39 -07:00
|
|
|
dbm "github.com/tendermint/tm-db"
|
2018-01-15 17:10:46 -08:00
|
|
|
|
2019-09-10 11:12:38 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/store/iavl"
|
2020-08-11 03:09:16 -07:00
|
|
|
sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps"
|
2019-02-05 10:39:22 -08:00
|
|
|
"github.com/cosmos/cosmos-sdk/store/types"
|
2019-12-27 09:57:54 -08:00
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
2017-12-12 20:13:51 -08:00
|
|
|
)
|
|
|
|
|
2018-07-26 18:24:18 -07:00
|
|
|
func TestStoreType(t *testing.T) {
|
|
|
|
db := dbm.NewMemDB()
|
2019-02-01 17:03:09 -08:00
|
|
|
store := NewStore(db)
|
2019-09-10 11:12:38 -07:00
|
|
|
store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, db)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetCommitKVStore(t *testing.T) {
|
|
|
|
var db dbm.DB = dbm.NewMemDB()
|
2020-06-22 13:31:33 -07:00
|
|
|
ms := newMultiStoreWithMounts(db, types.PruneDefault)
|
2019-09-10 11:12:38 -07:00
|
|
|
err := ms.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
key := ms.keysByName["store1"]
|
|
|
|
|
|
|
|
store1 := ms.GetCommitKVStore(key)
|
|
|
|
require.NotNil(t, store1)
|
|
|
|
require.IsType(t, &iavl.Store{}, store1)
|
2018-07-26 18:24:18 -07:00
|
|
|
|
2019-09-10 11:12:38 -07:00
|
|
|
store2 := ms.GetCommitStore(key)
|
|
|
|
require.NotNil(t, store2)
|
|
|
|
require.IsType(t, &iavl.Store{}, store2)
|
2018-07-26 18:24:18 -07:00
|
|
|
}
|
|
|
|
|
2018-08-21 06:49:06 -07:00
|
|
|
func TestStoreMount(t *testing.T) {
|
|
|
|
db := dbm.NewMemDB()
|
2019-02-01 17:03:09 -08:00
|
|
|
store := NewStore(db)
|
2018-08-21 06:49:06 -07:00
|
|
|
|
2019-02-01 17:03:09 -08:00
|
|
|
key1 := types.NewKVStoreKey("store1")
|
|
|
|
key2 := types.NewKVStoreKey("store2")
|
|
|
|
dup1 := types.NewKVStoreKey("store1")
|
2018-08-21 06:49:06 -07:00
|
|
|
|
2019-02-01 17:03:09 -08:00
|
|
|
require.NotPanics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
|
|
|
|
require.NotPanics(t, func() { store.MountStoreWithDB(key2, types.StoreTypeIAVL, db) })
|
2018-08-21 06:49:06 -07:00
|
|
|
|
2019-02-01 17:03:09 -08:00
|
|
|
require.Panics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
|
2020-03-06 04:28:19 -08:00
|
|
|
require.Panics(t, func() { store.MountStoreWithDB(nil, types.StoreTypeIAVL, db) })
|
2019-02-01 17:03:09 -08:00
|
|
|
require.Panics(t, func() { store.MountStoreWithDB(dup1, types.StoreTypeIAVL, db) })
|
2018-08-21 06:49:06 -07:00
|
|
|
}
|
|
|
|
|
2019-05-28 17:58:33 -07:00
|
|
|
func TestCacheMultiStoreWithVersion(t *testing.T) {
|
|
|
|
var db dbm.DB = dbm.NewMemDB()
|
2020-02-06 12:58:32 -08:00
|
|
|
ms := newMultiStoreWithMounts(db, types.PruneNothing)
|
2019-05-28 17:58:33 -07:00
|
|
|
err := ms.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
commitID := types.CommitID{}
|
|
|
|
checkStore(t, ms, commitID, commitID)
|
|
|
|
|
|
|
|
k, v := []byte("wind"), []byte("blows")
|
|
|
|
|
|
|
|
store1 := ms.getStoreByName("store1").(types.KVStore)
|
|
|
|
store1.Set(k, v)
|
|
|
|
|
|
|
|
cID := ms.Commit()
|
|
|
|
require.Equal(t, int64(1), cID.Version)
|
|
|
|
|
|
|
|
// require failure when given an invalid or pruned version
|
|
|
|
_, err = ms.CacheMultiStoreWithVersion(cID.Version + 1)
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
// require a valid version can be cache-loaded
|
|
|
|
cms, err := ms.CacheMultiStoreWithVersion(cID.Version)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// require a valid key lookup yields the correct value
|
|
|
|
kvStore := cms.GetKVStore(ms.keysByName["store1"])
|
|
|
|
require.NotNil(t, kvStore)
|
|
|
|
require.Equal(t, kvStore.Get(k), v)
|
|
|
|
|
|
|
|
// require we cannot commit (write) to a cache-versioned multi-store
|
|
|
|
require.Panics(t, func() {
|
|
|
|
kvStore.Set(k, []byte("newValue"))
|
|
|
|
cms.Write()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-06-25 10:11:22 -07:00
|
|
|
func TestHashStableWithEmptyCommit(t *testing.T) {
|
|
|
|
var db dbm.DB = dbm.NewMemDB()
|
2020-02-06 12:58:32 -08:00
|
|
|
ms := newMultiStoreWithMounts(db, types.PruneNothing)
|
2019-06-25 10:11:22 -07:00
|
|
|
err := ms.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
commitID := types.CommitID{}
|
|
|
|
checkStore(t, ms, commitID, commitID)
|
|
|
|
|
|
|
|
k, v := []byte("wind"), []byte("blows")
|
|
|
|
|
|
|
|
store1 := ms.getStoreByName("store1").(types.KVStore)
|
|
|
|
store1.Set(k, v)
|
|
|
|
|
|
|
|
cID := ms.Commit()
|
|
|
|
require.Equal(t, int64(1), cID.Version)
|
|
|
|
hash := cID.Hash
|
|
|
|
|
|
|
|
// make an empty commit, it should update version, but not affect hash
|
|
|
|
cID = ms.Commit()
|
|
|
|
require.Equal(t, int64(2), cID.Version)
|
|
|
|
require.Equal(t, hash, cID.Hash)
|
|
|
|
}
|
|
|
|
|
2017-12-12 20:13:51 -08:00
|
|
|
func TestMultistoreCommitLoad(t *testing.T) {
|
2018-04-13 02:04:31 -07:00
|
|
|
var db dbm.DB = dbm.NewMemDB()
|
2020-02-06 12:58:32 -08:00
|
|
|
store := newMultiStoreWithMounts(db, types.PruneNothing)
|
2017-12-12 20:13:51 -08:00
|
|
|
err := store.LoadLatestVersion()
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Nil(t, err)
|
2017-12-12 20:13:51 -08:00
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// New store has empty last commit.
|
2019-02-01 17:03:09 -08:00
|
|
|
commitID := types.CommitID{}
|
2017-12-12 20:13:51 -08:00
|
|
|
checkStore(t, store, commitID, commitID)
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Make sure we can get stores by name.
|
2018-02-02 06:43:03 -08:00
|
|
|
s1 := store.getStoreByName("store1")
|
2018-06-29 18:10:15 -07:00
|
|
|
require.NotNil(t, s1)
|
2018-02-02 06:43:03 -08:00
|
|
|
s3 := store.getStoreByName("store3")
|
2018-06-29 18:10:15 -07:00
|
|
|
require.NotNil(t, s3)
|
2018-02-02 06:43:03 -08:00
|
|
|
s77 := store.getStoreByName("store77")
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Nil(t, s77)
|
2018-01-30 06:30:25 -08:00
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Make a few commits and check them.
|
2017-12-12 20:13:51 -08:00
|
|
|
nCommits := int64(3)
|
|
|
|
for i := int64(0); i < nCommits; i++ {
|
|
|
|
commitID = store.Commit()
|
|
|
|
expectedCommitID := getExpectedCommitID(store, i+1)
|
|
|
|
checkStore(t, store, expectedCommitID, commitID)
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Load the latest multistore again and check version.
|
2020-02-06 12:58:32 -08:00
|
|
|
store = newMultiStoreWithMounts(db, types.PruneNothing)
|
2017-12-12 20:13:51 -08:00
|
|
|
err = store.LoadLatestVersion()
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Nil(t, err)
|
2017-12-12 20:13:51 -08:00
|
|
|
commitID = getExpectedCommitID(store, nCommits)
|
|
|
|
checkStore(t, store, commitID, commitID)
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Commit and check version.
|
2017-12-12 20:13:51 -08:00
|
|
|
commitID = store.Commit()
|
|
|
|
expectedCommitID := getExpectedCommitID(store, nCommits+1)
|
|
|
|
checkStore(t, store, expectedCommitID, commitID)
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Load an older multistore and check version.
|
2017-12-12 20:13:51 -08:00
|
|
|
ver := nCommits - 1
|
2020-02-06 12:58:32 -08:00
|
|
|
store = newMultiStoreWithMounts(db, types.PruneNothing)
|
2017-12-12 20:13:51 -08:00
|
|
|
err = store.LoadVersion(ver)
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Nil(t, err)
|
2017-12-12 20:13:51 -08:00
|
|
|
commitID = getExpectedCommitID(store, ver)
|
|
|
|
checkStore(t, store, commitID, commitID)
|
|
|
|
}
|
|
|
|
|
2019-08-06 05:59:22 -07:00
|
|
|
func TestMultistoreLoadWithUpgrade(t *testing.T) {
|
|
|
|
var db dbm.DB = dbm.NewMemDB()
|
2020-01-22 11:52:56 -08:00
|
|
|
store := newMultiStoreWithMounts(db, types.PruneNothing)
|
2019-08-06 05:59:22 -07:00
|
|
|
err := store.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
// write some data in all stores
|
|
|
|
k1, v1 := []byte("first"), []byte("store")
|
|
|
|
s1, _ := store.getStoreByName("store1").(types.KVStore)
|
|
|
|
require.NotNil(t, s1)
|
|
|
|
s1.Set(k1, v1)
|
|
|
|
|
|
|
|
k2, v2 := []byte("second"), []byte("restore")
|
|
|
|
s2, _ := store.getStoreByName("store2").(types.KVStore)
|
|
|
|
require.NotNil(t, s2)
|
|
|
|
s2.Set(k2, v2)
|
|
|
|
|
|
|
|
k3, v3 := []byte("third"), []byte("dropped")
|
|
|
|
s3, _ := store.getStoreByName("store3").(types.KVStore)
|
|
|
|
require.NotNil(t, s3)
|
|
|
|
s3.Set(k3, v3)
|
|
|
|
|
|
|
|
// do one commit
|
|
|
|
commitID := store.Commit()
|
|
|
|
expectedCommitID := getExpectedCommitID(store, 1)
|
|
|
|
checkStore(t, store, expectedCommitID, commitID)
|
|
|
|
|
|
|
|
ci, err := getCommitInfo(db, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(1), ci.Version)
|
|
|
|
require.Equal(t, 3, len(ci.StoreInfos))
|
|
|
|
checkContains(t, ci.StoreInfos, []string{"store1", "store2", "store3"})
|
|
|
|
|
|
|
|
// Load without changes and make sure it is sensible
|
2020-01-22 11:52:56 -08:00
|
|
|
store = newMultiStoreWithMounts(db, types.PruneNothing)
|
|
|
|
|
2019-08-06 05:59:22 -07:00
|
|
|
err = store.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
commitID = getExpectedCommitID(store, 1)
|
|
|
|
checkStore(t, store, commitID, commitID)
|
|
|
|
|
|
|
|
// let's query data to see it was saved properly
|
|
|
|
s2, _ = store.getStoreByName("store2").(types.KVStore)
|
|
|
|
require.NotNil(t, s2)
|
|
|
|
require.Equal(t, v2, s2.Get(k2))
|
|
|
|
|
|
|
|
// now, let's load with upgrades...
|
2020-01-22 11:52:56 -08:00
|
|
|
restore, upgrades := newMultiStoreWithModifiedMounts(db, types.PruneNothing)
|
2019-08-06 05:59:22 -07:00
|
|
|
err = restore.LoadLatestVersionAndUpgrade(upgrades)
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
// s1 was not changed
|
|
|
|
s1, _ = restore.getStoreByName("store1").(types.KVStore)
|
|
|
|
require.NotNil(t, s1)
|
|
|
|
require.Equal(t, v1, s1.Get(k1))
|
|
|
|
|
|
|
|
// store3 is mounted, but data deleted are gone
|
|
|
|
s3, _ = restore.getStoreByName("store3").(types.KVStore)
|
|
|
|
require.NotNil(t, s3)
|
|
|
|
require.Nil(t, s3.Get(k3)) // data was deleted
|
|
|
|
|
|
|
|
// store2 is no longer mounted
|
|
|
|
st2 := restore.getStoreByName("store2")
|
|
|
|
require.Nil(t, st2)
|
|
|
|
|
|
|
|
// restore2 has the old data
|
|
|
|
rs2, _ := restore.getStoreByName("restore2").(types.KVStore)
|
|
|
|
require.NotNil(t, rs2)
|
|
|
|
require.Equal(t, v2, rs2.Get(k2))
|
|
|
|
|
|
|
|
// store this migrated data, and load it again without migrations
|
|
|
|
migratedID := restore.Commit()
|
|
|
|
require.Equal(t, migratedID.Version, int64(2))
|
|
|
|
|
2020-01-22 11:52:56 -08:00
|
|
|
reload, _ := newMultiStoreWithModifiedMounts(db, types.PruneNothing)
|
2019-08-06 05:59:22 -07:00
|
|
|
err = reload.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.Equal(t, migratedID, reload.LastCommitID())
|
|
|
|
|
|
|
|
// query this new store
|
|
|
|
rl1, _ := reload.getStoreByName("store1").(types.KVStore)
|
|
|
|
require.NotNil(t, rl1)
|
|
|
|
require.Equal(t, v1, rl1.Get(k1))
|
|
|
|
|
|
|
|
rl2, _ := reload.getStoreByName("restore2").(types.KVStore)
|
|
|
|
require.NotNil(t, rl2)
|
|
|
|
require.Equal(t, v2, rl2.Get(k2))
|
|
|
|
|
|
|
|
// check commitInfo in storage
|
|
|
|
ci, err = getCommitInfo(db, 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(2), ci.Version)
|
|
|
|
require.Equal(t, 3, len(ci.StoreInfos), ci.StoreInfos)
|
|
|
|
checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3"})
|
|
|
|
}
|
|
|
|
|
2018-01-30 06:30:25 -08:00
|
|
|
func TestParsePath(t *testing.T) {
|
|
|
|
_, _, err := parsePath("foo")
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Error(t, err)
|
2018-01-30 06:30:25 -08:00
|
|
|
|
|
|
|
store, subpath, err := parsePath("/foo")
|
2018-06-29 18:10:15 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, store, "foo")
|
|
|
|
require.Equal(t, subpath, "")
|
2018-01-30 06:30:25 -08:00
|
|
|
|
|
|
|
store, subpath, err = parsePath("/fizz/bang/baz")
|
2018-06-29 18:10:15 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, store, "fizz")
|
|
|
|
require.Equal(t, subpath, "/bang/baz")
|
2018-01-30 06:30:25 -08:00
|
|
|
|
|
|
|
substore, subsubpath, err := parsePath(subpath)
|
2018-06-29 18:10:15 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, substore, "bang")
|
|
|
|
require.Equal(t, subsubpath, "/baz")
|
2018-01-30 06:30:25 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-02-06 12:58:32 -08:00
|
|
|
func TestMultiStoreRestart(t *testing.T) {
|
|
|
|
db := dbm.NewMemDB()
|
|
|
|
pruning := types.PruningOptions{
|
2020-06-22 13:31:33 -07:00
|
|
|
KeepRecent: 2,
|
|
|
|
KeepEvery: 3,
|
|
|
|
Interval: 1,
|
2020-02-06 12:58:32 -08:00
|
|
|
}
|
|
|
|
multi := newMultiStoreWithMounts(db, pruning)
|
|
|
|
err := multi.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
initCid := multi.LastCommitID()
|
|
|
|
|
|
|
|
k, v := "wind", "blows"
|
|
|
|
k2, v2 := "water", "flows"
|
|
|
|
k3, v3 := "fire", "burns"
|
|
|
|
|
|
|
|
for i := 1; i < 3; i++ {
|
|
|
|
// Set and commit data in one store.
|
|
|
|
store1 := multi.getStoreByName("store1").(types.KVStore)
|
|
|
|
store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, i)))
|
|
|
|
|
|
|
|
// ... and another.
|
|
|
|
store2 := multi.getStoreByName("store2").(types.KVStore)
|
|
|
|
store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, i)))
|
|
|
|
|
|
|
|
// ... and another.
|
|
|
|
store3 := multi.getStoreByName("store3").(types.KVStore)
|
|
|
|
store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, i)))
|
|
|
|
|
|
|
|
multi.Commit()
|
|
|
|
|
|
|
|
cinfo, err := getCommitInfo(multi.db, int64(i))
|
2020-06-22 13:31:33 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(i), cinfo.Version)
|
2020-02-06 12:58:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set and commit data in one store.
|
|
|
|
store1 := multi.getStoreByName("store1").(types.KVStore)
|
|
|
|
store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, 3)))
|
|
|
|
|
|
|
|
// ... and another.
|
|
|
|
store2 := multi.getStoreByName("store2").(types.KVStore)
|
|
|
|
store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, 3)))
|
|
|
|
|
|
|
|
multi.Commit()
|
|
|
|
|
|
|
|
flushedCinfo, err := getCommitInfo(multi.db, 3)
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.NotEqual(t, initCid, flushedCinfo, "CID is different after flush to disk")
|
|
|
|
|
|
|
|
// ... and another.
|
|
|
|
store3 := multi.getStoreByName("store3").(types.KVStore)
|
|
|
|
store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, 3)))
|
|
|
|
|
|
|
|
multi.Commit()
|
|
|
|
|
|
|
|
postFlushCinfo, err := getCommitInfo(multi.db, 4)
|
2020-06-22 13:31:33 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(4), postFlushCinfo.Version, "Commit changed after in-memory commit")
|
2020-02-06 12:58:32 -08:00
|
|
|
|
|
|
|
multi = newMultiStoreWithMounts(db, pruning)
|
|
|
|
err = multi.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
reloadedCid := multi.LastCommitID()
|
2020-06-22 13:31:33 -07:00
|
|
|
require.Equal(t, int64(4), reloadedCid.Version, "Reloaded CID is not the same as last flushed CID")
|
2020-02-06 12:58:32 -08:00
|
|
|
|
|
|
|
// Check that store1 and store2 retained date from 3rd commit
|
|
|
|
store1 = multi.getStoreByName("store1").(types.KVStore)
|
|
|
|
val := store1.Get([]byte(k))
|
|
|
|
require.Equal(t, []byte(fmt.Sprintf("%s:%d", v, 3)), val, "Reloaded value not the same as last flushed value")
|
|
|
|
|
|
|
|
store2 = multi.getStoreByName("store2").(types.KVStore)
|
|
|
|
val2 := store2.Get([]byte(k2))
|
|
|
|
require.Equal(t, []byte(fmt.Sprintf("%s:%d", v2, 3)), val2, "Reloaded value not the same as last flushed value")
|
|
|
|
|
|
|
|
// Check that store3 still has data from last commit even though update happened on 2nd commit
|
|
|
|
store3 = multi.getStoreByName("store3").(types.KVStore)
|
|
|
|
val3 := store3.Get([]byte(k3))
|
2020-06-22 13:31:33 -07:00
|
|
|
require.Equal(t, []byte(fmt.Sprintf("%s:%d", v3, 3)), val3, "Reloaded value not the same as last flushed value")
|
2020-02-06 12:58:32 -08:00
|
|
|
}
|
|
|
|
|
2018-02-02 07:22:49 -08:00
|
|
|
func TestMultiStoreQuery(t *testing.T) {
|
|
|
|
db := dbm.NewMemDB()
|
2020-01-22 11:52:56 -08:00
|
|
|
multi := newMultiStoreWithMounts(db, types.PruneNothing)
|
2018-02-02 07:22:49 -08:00
|
|
|
err := multi.LoadLatestVersion()
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Nil(t, err)
|
2018-02-02 07:22:49 -08:00
|
|
|
|
|
|
|
k, v := []byte("wind"), []byte("blows")
|
|
|
|
k2, v2 := []byte("water"), []byte("flows")
|
|
|
|
// v3 := []byte("is cold")
|
|
|
|
|
|
|
|
cid := multi.Commit()
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Make sure we can get by name.
|
2018-02-02 07:22:49 -08:00
|
|
|
garbage := multi.getStoreByName("bad-name")
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Nil(t, garbage)
|
2018-02-02 07:22:49 -08:00
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Set and commit data in one store.
|
2019-02-01 17:03:09 -08:00
|
|
|
store1 := multi.getStoreByName("store1").(types.KVStore)
|
2018-02-02 07:22:49 -08:00
|
|
|
store1.Set(k, v)
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// ... and another.
|
2019-02-01 17:03:09 -08:00
|
|
|
store2 := multi.getStoreByName("store2").(types.KVStore)
|
2018-02-02 07:22:49 -08:00
|
|
|
store2.Set(k2, v2)
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Commit the multistore.
|
2018-02-02 07:22:49 -08:00
|
|
|
cid = multi.Commit()
|
|
|
|
ver := cid.Version
|
|
|
|
|
2018-08-08 03:27:05 -07:00
|
|
|
// Reload multistore from database
|
2020-01-22 11:52:56 -08:00
|
|
|
multi = newMultiStoreWithMounts(db, types.PruneNothing)
|
2018-08-08 03:27:05 -07:00
|
|
|
err = multi.LoadLatestVersion()
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Test bad path.
|
2018-02-02 07:22:49 -08:00
|
|
|
query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
|
|
|
|
qres := multi.Query(query)
|
2019-12-27 09:57:54 -08:00
|
|
|
require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
|
|
|
|
require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
|
2018-02-02 07:22:49 -08:00
|
|
|
|
|
|
|
query.Path = "h897fy32890rf63296r92"
|
|
|
|
qres = multi.Query(query)
|
2019-12-27 09:57:54 -08:00
|
|
|
require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
|
|
|
|
require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
|
2018-02-02 07:22:49 -08:00
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Test invalid store name.
|
2018-02-02 07:22:49 -08:00
|
|
|
query.Path = "/garbage/key"
|
|
|
|
qres = multi.Query(query)
|
2019-12-27 09:57:54 -08:00
|
|
|
require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code)
|
|
|
|
require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace)
|
2018-02-02 07:22:49 -08:00
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Test valid query with data.
|
2018-02-02 07:22:49 -08:00
|
|
|
query.Path = "/store1/key"
|
|
|
|
qres = multi.Query(query)
|
2019-12-27 09:57:54 -08:00
|
|
|
require.EqualValues(t, 0, qres.Code)
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Equal(t, v, qres.Value)
|
2018-02-02 07:22:49 -08:00
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Test valid but empty query.
|
2018-02-02 07:22:49 -08:00
|
|
|
query.Path = "/store2/key"
|
|
|
|
query.Prove = true
|
|
|
|
qres = multi.Query(query)
|
2019-12-27 09:57:54 -08:00
|
|
|
require.EqualValues(t, 0, qres.Code)
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Nil(t, qres.Value)
|
2018-02-02 07:22:49 -08:00
|
|
|
|
2018-04-13 02:04:31 -07:00
|
|
|
// Test store2 data.
|
2018-02-02 07:22:49 -08:00
|
|
|
query.Data = k2
|
|
|
|
qres = multi.Query(query)
|
2019-12-27 09:57:54 -08:00
|
|
|
require.EqualValues(t, 0, qres.Code)
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Equal(t, v2, qres.Value)
|
2018-02-02 07:22:49 -08:00
|
|
|
}
|
|
|
|
|
2020-06-22 13:31:33 -07:00
|
|
|
func TestMultiStore_Pruning(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
numVersions int64
|
|
|
|
po types.PruningOptions
|
|
|
|
deleted []int64
|
|
|
|
saved []int64
|
|
|
|
}{
|
|
|
|
{"prune nothing", 10, types.PruneNothing, nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
|
|
|
|
{"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}},
|
|
|
|
{"prune some; no batch", 10, types.NewPruningOptions(2, 3, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}},
|
|
|
|
{"prune some; small batch", 10, types.NewPruningOptions(2, 3, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}},
|
|
|
|
{"prune some; large batch", 10, types.NewPruningOptions(2, 3, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
tc := tc
|
|
|
|
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
db := dbm.NewMemDB()
|
|
|
|
ms := newMultiStoreWithMounts(db, tc.po)
|
|
|
|
require.NoError(t, ms.LoadLatestVersion())
|
|
|
|
|
|
|
|
for i := int64(0); i < tc.numVersions; i++ {
|
|
|
|
ms.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range tc.saved {
|
|
|
|
_, err := ms.CacheMultiStoreWithVersion(v)
|
|
|
|
require.NoError(t, err, "expected error when loading height: %d", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range tc.deleted {
|
|
|
|
_, err := ms.CacheMultiStoreWithVersion(v)
|
|
|
|
require.Error(t, err, "expected error when loading height: %d", v)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMultiStore_PruningRestart(t *testing.T) {
|
|
|
|
db := dbm.NewMemDB()
|
|
|
|
ms := newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11))
|
|
|
|
require.NoError(t, ms.LoadLatestVersion())
|
|
|
|
|
|
|
|
// Commit enough to build up heights to prune, where on the next block we should
|
|
|
|
// batch delete.
|
|
|
|
for i := int64(0); i < 10; i++ {
|
|
|
|
ms.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
pruneHeights := []int64{1, 2, 4, 5, 7}
|
|
|
|
|
|
|
|
// ensure we've persisted the current batch of heights to prune to the store's DB
|
|
|
|
ph, err := getPruningHeights(ms.db)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, pruneHeights, ph)
|
|
|
|
|
|
|
|
// "restart"
|
|
|
|
ms = newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11))
|
|
|
|
err = ms.LoadLatestVersion()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, pruneHeights, ms.pruneHeights)
|
|
|
|
|
|
|
|
// commit one more block and ensure the heights have been pruned
|
|
|
|
ms.Commit()
|
|
|
|
require.Empty(t, ms.pruneHeights)
|
|
|
|
|
|
|
|
for _, v := range pruneHeights {
|
|
|
|
_, err := ms.CacheMultiStoreWithVersion(v)
|
|
|
|
require.Error(t, err, "expected error when loading height: %d", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-12 20:13:51 -08:00
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
// utils
|
|
|
|
|
2020-01-22 11:52:56 -08:00
|
|
|
func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store {
|
2019-02-01 17:03:09 -08:00
|
|
|
store := NewStore(db)
|
2020-01-22 11:52:56 -08:00
|
|
|
store.pruningOpts = pruningOpts
|
|
|
|
|
|
|
|
store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil)
|
|
|
|
store.MountStoreWithDB(types.NewKVStoreKey("store2"), types.StoreTypeIAVL, nil)
|
|
|
|
store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil)
|
|
|
|
|
2017-12-12 20:13:51 -08:00
|
|
|
return store
|
|
|
|
}
|
|
|
|
|
2020-01-22 11:52:56 -08:00
|
|
|
func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions) (*Store, *types.StoreUpgrades) {
|
2019-08-06 05:59:22 -07:00
|
|
|
store := NewStore(db)
|
2020-01-22 11:52:56 -08:00
|
|
|
store.pruningOpts = pruningOpts
|
|
|
|
|
|
|
|
store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil)
|
|
|
|
store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil)
|
|
|
|
store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil)
|
2019-08-06 05:59:22 -07:00
|
|
|
|
|
|
|
upgrades := &types.StoreUpgrades{
|
|
|
|
Renamed: []types.StoreRename{{
|
|
|
|
OldKey: "store2",
|
|
|
|
NewKey: "restore2",
|
|
|
|
}},
|
|
|
|
Deleted: []string{"store3"},
|
|
|
|
}
|
2020-01-22 11:52:56 -08:00
|
|
|
|
2019-08-06 05:59:22 -07:00
|
|
|
return store, upgrades
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:03:09 -08:00
|
|
|
func checkStore(t *testing.T, store *Store, expect, got types.CommitID) {
|
2018-06-29 18:10:15 -07:00
|
|
|
require.Equal(t, expect, got)
|
|
|
|
require.Equal(t, expect, store.LastCommitID())
|
2017-12-12 20:13:51 -08:00
|
|
|
}
|
|
|
|
|
2020-08-11 03:09:16 -07:00
|
|
|
func checkContains(t testing.TB, info []types.StoreInfo, wanted []string) {
|
2019-08-06 05:59:22 -07:00
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
for _, want := range wanted {
|
|
|
|
checkHas(t, info, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-11 03:09:16 -07:00
|
|
|
func checkHas(t testing.TB, info []types.StoreInfo, want string) {
|
2019-08-06 05:59:22 -07:00
|
|
|
t.Helper()
|
|
|
|
for _, i := range info {
|
|
|
|
if i.Name == want {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.Fatalf("storeInfo doesn't contain %s", want)
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:03:09 -08:00
|
|
|
func getExpectedCommitID(store *Store, ver int64) types.CommitID {
|
|
|
|
return types.CommitID{
|
2017-12-12 20:13:51 -08:00
|
|
|
Version: ver,
|
2018-01-22 05:44:24 -08:00
|
|
|
Hash: hashStores(store.stores),
|
2017-12-12 20:13:51 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 10:33:32 -07:00
|
|
|
func hashStores(stores map[types.StoreKey]types.CommitKVStore) []byte {
|
2018-11-04 18:28:38 -08:00
|
|
|
m := make(map[string][]byte, len(stores))
|
2018-01-15 17:10:46 -08:00
|
|
|
for key, store := range stores {
|
|
|
|
name := key.Name()
|
2020-08-11 03:09:16 -07:00
|
|
|
m[name] = types.StoreInfo{
|
|
|
|
Name: name,
|
2020-08-14 01:55:54 -07:00
|
|
|
CommitId: store.LastCommitID(),
|
2020-06-03 11:50:22 -07:00
|
|
|
}.GetHash()
|
2017-12-12 20:13:51 -08:00
|
|
|
}
|
2020-08-14 10:58:53 -07:00
|
|
|
return sdkmaps.HashFromMap(m)
|
2017-12-12 20:13:51 -08:00
|
|
|
}
|