Add state sync support (#7166)
* Add state sync support * fix incorrect test tempdir * proto: move and update Protobuf schemas * proto: lint fixes * comment tweaks * don't use type aliasing * don't call .Error() when logging errors * use create terminology instead of take for snapshots * reuse chunk hasher * simplify key encoding code * track chunk index in Manager * add restoreDone message for Manager * add a ready channel to Snapshotter.Restore() * add comment on streaming IO API * use sdkerrors for error handling * fix incorrect error * tweak changelog * syntax fix * update test code after merge
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package iavl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
@@ -212,6 +213,28 @@ func (st *Store) SetInitialVersion(version int64) {
|
||||
st.tree.SetInitialVersion(uint64(version))
|
||||
}
|
||||
|
||||
// Exports the IAVL store at the given version, returning an iavl.Exporter for the tree.
|
||||
func (st *Store) Export(version int64) (*iavl.Exporter, error) {
|
||||
istore, err := st.GetImmutable(version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("iavl export failed for version %v: %w", version, err)
|
||||
}
|
||||
tree, ok := istore.tree.(*immutableTree)
|
||||
if !ok || tree == nil {
|
||||
return nil, fmt.Errorf("iavl export failed: unable to fetch tree for version %v", version)
|
||||
}
|
||||
return tree.Export(), nil
|
||||
}
|
||||
|
||||
// Import imports an IAVL tree at the given version, returning an iavl.Importer for importing.
|
||||
func (st *Store) Import(version int64) (*iavl.Importer, error) {
|
||||
tree, ok := st.tree.(*iavl.MutableTree)
|
||||
if !ok {
|
||||
return nil, errors.New("iavl import failed: unable to find mutable tree")
|
||||
}
|
||||
return tree.Import(version)
|
||||
}
|
||||
|
||||
// Handle gatest the latest height, if height is 0
|
||||
func getHeight(tree Tree, req abci.RequestQuery) int64 {
|
||||
height := req.Height
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
package rootmulti
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
iavltree "github.com/cosmos/iavl"
|
||||
protoio "github.com/gogo/protobuf/io"
|
||||
gogotypes "github.com/gogo/protobuf/types"
|
||||
"github.com/pkg/errors"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/snapshots"
|
||||
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
|
||||
"github.com/cosmos/cosmos-sdk/store/cachemulti"
|
||||
"github.com/cosmos/cosmos-sdk/store/dbadapter"
|
||||
"github.com/cosmos/cosmos-sdk/store/iavl"
|
||||
@@ -26,6 +33,11 @@ const (
|
||||
latestVersionKey = "s/latest"
|
||||
pruneHeightsKey = "s/pruneheights"
|
||||
commitInfoKeyFmt = "s/%d" // s/<version>
|
||||
|
||||
// Do not change chunk size without new snapshot format (must be uniform across nodes)
|
||||
snapshotChunkSize = uint64(10e6)
|
||||
snapshotBufferSize = int(snapshotChunkSize)
|
||||
snapshotMaxItemSize = int(64e6) // SDK has no key/value size limit, so we set an arbitrary limit
|
||||
)
|
||||
|
||||
// Store is composed of many CommitStores. Name contrasts with
|
||||
@@ -68,6 +80,11 @@ func NewStore(db dbm.DB) *Store {
|
||||
}
|
||||
}
|
||||
|
||||
// GetPruning fetches the pruning strategy from the root store.
|
||||
func (rs *Store) GetPruning() types.PruningOptions {
|
||||
return rs.pruningOpts
|
||||
}
|
||||
|
||||
// SetPruning sets the pruning strategy on the root store and all the sub-stores.
|
||||
// Note, calling SetPruning on the root store prior to LoadVersion or
|
||||
// LoadLatestVersion performs a no-op as the stores aren't mounted yet.
|
||||
@@ -550,6 +567,237 @@ func parsePath(path string) (storeName string, subpath string, err error) {
|
||||
return storeName, subpath, nil
|
||||
}
|
||||
|
||||
//---------------------- Snapshotting ------------------
|
||||
|
||||
// Snapshot implements snapshottypes.Snapshotter. The snapshot output for a given format must be
|
||||
// identical across nodes such that chunks from different sources fit together. If the output for a
|
||||
// given format changes (at the byte level), the snapshot format must be bumped - see
|
||||
// TestMultistoreSnapshot_Checksum test.
|
||||
func (rs *Store) Snapshot(height uint64, format uint32) (<-chan io.ReadCloser, error) {
|
||||
if format != snapshottypes.CurrentFormat {
|
||||
return nil, sdkerrors.Wrapf(snapshottypes.ErrUnknownFormat, "format %v", format)
|
||||
}
|
||||
if height == 0 {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "cannot snapshot height 0")
|
||||
}
|
||||
if height > uint64(rs.LastCommitID().Version) {
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "cannot snapshot future height %v", height)
|
||||
}
|
||||
|
||||
// Collect stores to snapshot (only IAVL stores are supported)
|
||||
type namedStore struct {
|
||||
*iavl.Store
|
||||
name string
|
||||
}
|
||||
stores := []namedStore{}
|
||||
for key := range rs.stores {
|
||||
switch store := rs.GetCommitKVStore(key).(type) {
|
||||
case *iavl.Store:
|
||||
stores = append(stores, namedStore{name: key.Name(), Store: store})
|
||||
case *transient.Store, *mem.Store:
|
||||
// Non-persisted stores shouldn't be snapshotted
|
||||
continue
|
||||
default:
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic,
|
||||
"don't know how to snapshot store %q of type %T", key.Name(), store)
|
||||
}
|
||||
}
|
||||
sort.Slice(stores, func(i, j int) bool {
|
||||
return strings.Compare(stores[i].name, stores[j].name) == -1
|
||||
})
|
||||
|
||||
// Spawn goroutine to generate snapshot chunks and pass their io.ReadClosers through a channel
|
||||
ch := make(chan io.ReadCloser)
|
||||
go func() {
|
||||
// Set up a stream pipeline to serialize snapshot nodes:
|
||||
// ExportNode -> delimited Protobuf -> zlib -> buffer -> chunkWriter -> chan io.ReadCloser
|
||||
chunkWriter := snapshots.NewChunkWriter(ch, snapshotChunkSize)
|
||||
defer chunkWriter.Close()
|
||||
bufWriter := bufio.NewWriterSize(chunkWriter, snapshotBufferSize)
|
||||
defer func() {
|
||||
if err := bufWriter.Flush(); err != nil {
|
||||
chunkWriter.CloseWithError(err)
|
||||
}
|
||||
}()
|
||||
zWriter, err := zlib.NewWriterLevel(bufWriter, 7)
|
||||
if err != nil {
|
||||
chunkWriter.CloseWithError(sdkerrors.Wrap(err, "zlib failure"))
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := zWriter.Close(); err != nil {
|
||||
chunkWriter.CloseWithError(err)
|
||||
}
|
||||
}()
|
||||
protoWriter := protoio.NewDelimitedWriter(zWriter)
|
||||
defer func() {
|
||||
if err := protoWriter.Close(); err != nil {
|
||||
chunkWriter.CloseWithError(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Export each IAVL store. Stores are serialized as a stream of SnapshotItem Protobuf
|
||||
// messages. The first item contains a SnapshotStore with store metadata (i.e. name),
|
||||
// and the following messages contain a SnapshotNode (i.e. an ExportNode). Store changes
|
||||
// are demarcated by new SnapshotStore items.
|
||||
for _, store := range stores {
|
||||
exporter, err := store.Export(int64(height))
|
||||
if err != nil {
|
||||
chunkWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
defer exporter.Close()
|
||||
err = protoWriter.WriteMsg(&types.SnapshotItem{
|
||||
Item: &types.SnapshotItem_Store{
|
||||
Store: &types.SnapshotStoreItem{
|
||||
Name: store.name,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
chunkWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
node, err := exporter.Next()
|
||||
if err == iavltree.ExportDone {
|
||||
break
|
||||
} else if err != nil {
|
||||
chunkWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
err = protoWriter.WriteMsg(&types.SnapshotItem{
|
||||
Item: &types.SnapshotItem_IAVL{
|
||||
IAVL: &types.SnapshotIAVLItem{
|
||||
Key: node.Key,
|
||||
Value: node.Value,
|
||||
Height: int32(node.Height),
|
||||
Version: node.Version,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
chunkWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
exporter.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// Restore implements snapshottypes.Snapshotter.
|
||||
func (rs *Store) Restore(
|
||||
height uint64, format uint32, chunks <-chan io.ReadCloser, ready chan<- struct{},
|
||||
) error {
|
||||
if format != snapshottypes.CurrentFormat {
|
||||
return sdkerrors.Wrapf(snapshottypes.ErrUnknownFormat, "format %v", format)
|
||||
}
|
||||
if height == 0 {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "cannot restore snapshot at height 0")
|
||||
}
|
||||
if height > math.MaxInt64 {
|
||||
return sdkerrors.Wrapf(snapshottypes.ErrInvalidMetadata,
|
||||
"snapshot height %v cannot exceed %v", height, math.MaxInt64)
|
||||
}
|
||||
|
||||
// Signal readiness. Must be done before the readers below are set up, since the zlib
|
||||
// reader reads from the stream on initialization, potentially causing deadlocks.
|
||||
if ready != nil {
|
||||
close(ready)
|
||||
}
|
||||
|
||||
// Set up a restore stream pipeline
|
||||
// chan io.ReadCloser -> chunkReader -> zlib -> delimited Protobuf -> ExportNode
|
||||
chunkReader := snapshots.NewChunkReader(chunks)
|
||||
defer chunkReader.Close()
|
||||
zReader, err := zlib.NewReader(chunkReader)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "zlib failure")
|
||||
}
|
||||
defer zReader.Close()
|
||||
protoReader := protoio.NewDelimitedReader(zReader, snapshotMaxItemSize)
|
||||
defer protoReader.Close()
|
||||
|
||||
// Import nodes into stores. The first item is expected to be a SnapshotItem containing
|
||||
// a SnapshotStoreItem, telling us which store to import into. The following items will contain
|
||||
// SnapshotNodeItem (i.e. ExportNode) until we reach the next SnapshotStoreItem or EOF.
|
||||
var importer *iavltree.Importer
|
||||
for {
|
||||
item := &types.SnapshotItem{}
|
||||
err := protoReader.ReadMsg(item)
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return sdkerrors.Wrap(err, "invalid protobuf message")
|
||||
}
|
||||
|
||||
switch item := item.Item.(type) {
|
||||
case *types.SnapshotItem_Store:
|
||||
if importer != nil {
|
||||
err = importer.Commit()
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "IAVL commit failed")
|
||||
}
|
||||
importer.Close()
|
||||
}
|
||||
store, ok := rs.getStoreByName(item.Store.Name).(*iavl.Store)
|
||||
if !ok || store == nil {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrLogic, "cannot import into non-IAVL store %q", item.Store.Name)
|
||||
}
|
||||
importer, err = store.Import(int64(height))
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "import failed")
|
||||
}
|
||||
defer importer.Close()
|
||||
|
||||
case *types.SnapshotItem_IAVL:
|
||||
if importer == nil {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "received IAVL node item before store item")
|
||||
}
|
||||
if item.IAVL.Height > math.MaxInt8 {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrLogic, "node height %v cannot exceed %v",
|
||||
item.IAVL.Height, math.MaxInt8)
|
||||
}
|
||||
node := &iavltree.ExportNode{
|
||||
Key: item.IAVL.Key,
|
||||
Value: item.IAVL.Value,
|
||||
Height: int8(item.IAVL.Height),
|
||||
Version: item.IAVL.Version,
|
||||
}
|
||||
// Protobuf does not differentiate between []byte{} as nil, but fortunately IAVL does
|
||||
// not allow nil keys nor nil values for leaf nodes, so we can always set them to empty.
|
||||
if node.Key == nil {
|
||||
node.Key = []byte{}
|
||||
}
|
||||
if node.Height == 0 && node.Value == nil {
|
||||
node.Value = []byte{}
|
||||
}
|
||||
err := importer.Add(node)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "IAVL node import failed")
|
||||
}
|
||||
|
||||
default:
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrLogic, "unknown snapshot item %T", item)
|
||||
}
|
||||
}
|
||||
|
||||
if importer != nil {
|
||||
err := importer.Commit()
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "IAVL commit failed")
|
||||
}
|
||||
importer.Close()
|
||||
}
|
||||
|
||||
flushMetadata(rs.db, int64(height), rs.buildCommitInfo(int64(height)), []int64{})
|
||||
return rs.LoadLatestVersion()
|
||||
}
|
||||
|
||||
func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID, params storeParams) (types.CommitKVStore, error) {
|
||||
var db dbm.DB
|
||||
|
||||
@@ -602,6 +850,23 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *Store) buildCommitInfo(version int64) *types.CommitInfo {
|
||||
storeInfos := []types.StoreInfo{}
|
||||
for key, store := range rs.stores {
|
||||
if store.GetStoreType() == types.StoreTypeTransient {
|
||||
continue
|
||||
}
|
||||
storeInfos = append(storeInfos, types.StoreInfo{
|
||||
Name: key.Name(),
|
||||
CommitId: store.LastCommitID(),
|
||||
})
|
||||
}
|
||||
return &types.CommitInfo{
|
||||
Version: version,
|
||||
StoreInfos: storeInfos,
|
||||
}
|
||||
}
|
||||
|
||||
type storeParams struct {
|
||||
key types.StoreKey
|
||||
db dbm.DB
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
package rootmulti
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
|
||||
"github.com/cosmos/cosmos-sdk/store/iavl"
|
||||
sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps"
|
||||
"github.com/cosmos/cosmos-sdk/store/types"
|
||||
@@ -505,6 +514,120 @@ func TestMultiStore_PruningRestart(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultistoreSnapshot_Checksum(t *testing.T) {
|
||||
// Chunks from different nodes must fit together, so all nodes must produce identical chunks.
|
||||
// This checksum test makes sure that the byte stream remains identical. If the test fails
|
||||
// without having changed the data (e.g. because the Protobuf or zlib encoding changes),
|
||||
// snapshottypes.CurrentFormat must be bumped.
|
||||
store := newMultiStoreWithGeneratedData(dbm.NewMemDB(), 5, 10000)
|
||||
version := uint64(store.LastCommitID().Version)
|
||||
|
||||
testcases := []struct {
|
||||
format uint32
|
||||
chunkHashes []string
|
||||
}{
|
||||
{1, []string{
|
||||
"503e5b51b657055b77e88169fadae543619368744ad15f1de0736c0a20482f24",
|
||||
"e1a0daaa738eeb43e778aefd2805e3dd720798288a410b06da4b8459c4d8f72e",
|
||||
"aa048b4ee0f484965d7b3b06822cf0772cdcaad02f3b1b9055e69f2cb365ef3c",
|
||||
"7921eaa3ed4921341e504d9308a9877986a879fe216a099c86e8db66fcba4c63",
|
||||
"a4a864e6c02c9fca5837ec80dc84f650b25276ed7e4820cf7516ced9f9901b86",
|
||||
"ca2879ac6e7205d257440131ba7e72bef784cd61642e32b847729e543c1928b9",
|
||||
}},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
tc := tc
|
||||
t.Run(fmt.Sprintf("Format %v", tc.format), func(t *testing.T) {
|
||||
chunks, err := store.Snapshot(version, tc.format)
|
||||
require.NoError(t, err)
|
||||
hashes := []string{}
|
||||
for chunk := range chunks {
|
||||
hasher := sha256.New()
|
||||
_, err := io.Copy(hasher, chunk)
|
||||
require.NoError(t, err)
|
||||
hashes = append(hashes, hex.EncodeToString(hasher.Sum(nil)))
|
||||
}
|
||||
assert.Equal(t, tc.chunkHashes, hashes,
|
||||
"Snapshot output for format %v has changed", tc.format)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultistoreSnapshot_Errors(t *testing.T) {
|
||||
store := newMultiStoreWithMixedMountsAndBasicData(dbm.NewMemDB())
|
||||
|
||||
testcases := map[string]struct {
|
||||
height uint64
|
||||
format uint32
|
||||
expectType error
|
||||
}{
|
||||
"0 height": {0, snapshottypes.CurrentFormat, nil},
|
||||
"0 format": {1, 0, snapshottypes.ErrUnknownFormat},
|
||||
"unknown height": {9, snapshottypes.CurrentFormat, nil},
|
||||
"unknown format": {1, 9, snapshottypes.ErrUnknownFormat},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
_, err := store.Snapshot(tc.height, tc.format)
|
||||
require.Error(t, err)
|
||||
if tc.expectType != nil {
|
||||
assert.True(t, errors.Is(err, tc.expectType))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultistoreRestore_Errors(t *testing.T) {
|
||||
store := newMultiStoreWithMixedMounts(dbm.NewMemDB())
|
||||
|
||||
testcases := map[string]struct {
|
||||
height uint64
|
||||
format uint32
|
||||
expectType error
|
||||
}{
|
||||
"0 height": {0, snapshottypes.CurrentFormat, nil},
|
||||
"0 format": {1, 0, snapshottypes.ErrUnknownFormat},
|
||||
"unknown format": {1, 9, snapshottypes.ErrUnknownFormat},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err := store.Restore(tc.height, tc.format, nil, nil)
|
||||
require.Error(t, err)
|
||||
if tc.expectType != nil {
|
||||
assert.True(t, errors.Is(err, tc.expectType))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultistoreSnapshotRestore(t *testing.T) {
|
||||
source := newMultiStoreWithMixedMountsAndBasicData(dbm.NewMemDB())
|
||||
target := newMultiStoreWithMixedMounts(dbm.NewMemDB())
|
||||
version := uint64(source.LastCommitID().Version)
|
||||
require.EqualValues(t, 3, version)
|
||||
|
||||
chunks, err := source.Snapshot(version, snapshottypes.CurrentFormat)
|
||||
require.NoError(t, err)
|
||||
ready := make(chan struct{})
|
||||
err = target.Restore(version, snapshottypes.CurrentFormat, chunks, ready)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, struct{}{}, <-ready)
|
||||
|
||||
assert.Equal(t, source.LastCommitID(), target.LastCommitID())
|
||||
for key, sourceStore := range source.stores {
|
||||
targetStore := target.getStoreByName(key.Name()).(types.CommitKVStore)
|
||||
switch sourceStore.GetStoreType() {
|
||||
case types.StoreTypeTransient:
|
||||
assert.False(t, targetStore.Iterator(nil, nil).Valid(),
|
||||
"transient store %v not empty", key.Name())
|
||||
default:
|
||||
assertStoresEqual(t, sourceStore, targetStore, "store %q not equal", key.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetInitialVersion(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
multi := newMultiStoreWithMounts(db, types.PruneNothing)
|
||||
@@ -516,6 +639,73 @@ func TestSetInitialVersion(t *testing.T) {
|
||||
require.Equal(t, int64(5), multi.LastCommitID().Version)
|
||||
}
|
||||
|
||||
func BenchmarkMultistoreSnapshot100K(b *testing.B) {
|
||||
benchmarkMultistoreSnapshot(b, 10, 10000)
|
||||
}
|
||||
|
||||
func BenchmarkMultistoreSnapshot1M(b *testing.B) {
|
||||
benchmarkMultistoreSnapshot(b, 10, 100000)
|
||||
}
|
||||
|
||||
func BenchmarkMultistoreSnapshotRestore100K(b *testing.B) {
|
||||
benchmarkMultistoreSnapshotRestore(b, 10, 10000)
|
||||
}
|
||||
|
||||
func BenchmarkMultistoreSnapshotRestore1M(b *testing.B) {
|
||||
benchmarkMultistoreSnapshotRestore(b, 10, 100000)
|
||||
}
|
||||
|
||||
func benchmarkMultistoreSnapshot(b *testing.B, stores uint8, storeKeys uint64) {
|
||||
b.StopTimer()
|
||||
source := newMultiStoreWithGeneratedData(dbm.NewMemDB(), stores, storeKeys)
|
||||
version := source.LastCommitID().Version
|
||||
require.EqualValues(b, 1, version)
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
target := NewStore(dbm.NewMemDB())
|
||||
for key := range source.stores {
|
||||
target.MountStoreWithDB(key, types.StoreTypeIAVL, nil)
|
||||
}
|
||||
err := target.LoadLatestVersion()
|
||||
require.NoError(b, err)
|
||||
require.EqualValues(b, 0, target.LastCommitID().Version)
|
||||
|
||||
chunks, err := source.Snapshot(uint64(version), snapshottypes.CurrentFormat)
|
||||
require.NoError(b, err)
|
||||
for reader := range chunks {
|
||||
_, err := io.Copy(ioutil.Discard, reader)
|
||||
require.NoError(b, err)
|
||||
err = reader.Close()
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkMultistoreSnapshotRestore(b *testing.B, stores uint8, storeKeys uint64) {
|
||||
b.StopTimer()
|
||||
source := newMultiStoreWithGeneratedData(dbm.NewMemDB(), stores, storeKeys)
|
||||
version := uint64(source.LastCommitID().Version)
|
||||
require.EqualValues(b, 1, version)
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
target := NewStore(dbm.NewMemDB())
|
||||
for key := range source.stores {
|
||||
target.MountStoreWithDB(key, types.StoreTypeIAVL, nil)
|
||||
}
|
||||
err := target.LoadLatestVersion()
|
||||
require.NoError(b, err)
|
||||
require.EqualValues(b, 0, target.LastCommitID().Version)
|
||||
|
||||
chunks, err := source.Snapshot(version, snapshottypes.CurrentFormat)
|
||||
require.NoError(b, err)
|
||||
err = target.Restore(version, snapshottypes.CurrentFormat, chunks, nil)
|
||||
require.NoError(b, err)
|
||||
require.Equal(b, source.LastCommitID(), target.LastCommitID())
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// utils
|
||||
|
||||
@@ -530,6 +720,75 @@ func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store
|
||||
return store
|
||||
}
|
||||
|
||||
func newMultiStoreWithMixedMounts(db dbm.DB) *Store {
|
||||
store := NewStore(db)
|
||||
store.MountStoreWithDB(types.NewKVStoreKey("iavl1"), types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(types.NewKVStoreKey("iavl2"), types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(types.NewKVStoreKey("iavl3"), types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(types.NewTransientStoreKey("trans1"), types.StoreTypeTransient, nil)
|
||||
store.LoadLatestVersion()
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func newMultiStoreWithMixedMountsAndBasicData(db dbm.DB) *Store {
|
||||
store := newMultiStoreWithMixedMounts(db)
|
||||
store1 := store.getStoreByName("iavl1").(types.CommitKVStore)
|
||||
store2 := store.getStoreByName("iavl2").(types.CommitKVStore)
|
||||
trans1 := store.getStoreByName("trans1").(types.KVStore)
|
||||
|
||||
store1.Set([]byte("a"), []byte{1})
|
||||
store1.Set([]byte("b"), []byte{1})
|
||||
store2.Set([]byte("X"), []byte{255})
|
||||
store2.Set([]byte("A"), []byte{101})
|
||||
trans1.Set([]byte("x1"), []byte{91})
|
||||
store.Commit()
|
||||
|
||||
store1.Set([]byte("b"), []byte{2})
|
||||
store1.Set([]byte("c"), []byte{3})
|
||||
store2.Set([]byte("B"), []byte{102})
|
||||
store.Commit()
|
||||
|
||||
store2.Set([]byte("C"), []byte{103})
|
||||
store2.Delete([]byte("X"))
|
||||
trans1.Set([]byte("x2"), []byte{92})
|
||||
store.Commit()
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func newMultiStoreWithGeneratedData(db dbm.DB, stores uint8, storeKeys uint64) *Store {
|
||||
multiStore := NewStore(db)
|
||||
r := rand.New(rand.NewSource(49872768940)) // Fixed seed for deterministic tests
|
||||
|
||||
keys := []*types.KVStoreKey{}
|
||||
for i := uint8(0); i < stores; i++ {
|
||||
key := types.NewKVStoreKey(fmt.Sprintf("store%v", i))
|
||||
multiStore.MountStoreWithDB(key, types.StoreTypeIAVL, nil)
|
||||
keys = append(keys, key)
|
||||
}
|
||||
multiStore.LoadLatestVersion()
|
||||
|
||||
for _, key := range keys {
|
||||
store := multiStore.stores[key].(*iavl.Store)
|
||||
for i := uint64(0); i < storeKeys; i++ {
|
||||
k := make([]byte, 8)
|
||||
v := make([]byte, 1024)
|
||||
binary.BigEndian.PutUint64(k, i)
|
||||
_, err := r.Read(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
store.Set(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
multiStore.Commit()
|
||||
multiStore.LoadLatestVersion()
|
||||
|
||||
return multiStore
|
||||
}
|
||||
|
||||
func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions) (*Store, *types.StoreUpgrades) {
|
||||
store := NewStore(db)
|
||||
store.pruningOpts = pruningOpts
|
||||
@@ -549,6 +808,25 @@ func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions
|
||||
return store, upgrades
|
||||
}
|
||||
|
||||
func assertStoresEqual(t *testing.T, expect, actual types.CommitKVStore, msgAndArgs ...interface{}) {
|
||||
assert.Equal(t, expect.LastCommitID(), actual.LastCommitID())
|
||||
expectIter := expect.Iterator(nil, nil)
|
||||
expectMap := map[string][]byte{}
|
||||
for ; expectIter.Valid(); expectIter.Next() {
|
||||
expectMap[string(expectIter.Key())] = expectIter.Value()
|
||||
}
|
||||
require.NoError(t, expectIter.Error())
|
||||
|
||||
actualIter := expect.Iterator(nil, nil)
|
||||
actualMap := map[string][]byte{}
|
||||
for ; actualIter.Valid(); actualIter.Next() {
|
||||
actualMap[string(actualIter.Key())] = actualIter.Value()
|
||||
}
|
||||
require.NoError(t, actualIter.Error())
|
||||
|
||||
assert.Equal(t, expectMap, actualMap, msgAndArgs...)
|
||||
}
|
||||
|
||||
func checkStore(t *testing.T, store *Store, expect, got types.CommitID) {
|
||||
require.Equal(t, expect, got)
|
||||
require.Equal(t, expect, store.LastCommitID())
|
||||
|
||||
@@ -0,0 +1,953 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: cosmos/base/store/v1beta1/snapshot.proto
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// SnapshotItem is an item contained in a rootmulti.Store snapshot.
|
||||
type SnapshotItem struct {
|
||||
// item is the specific type of snapshot item.
|
||||
//
|
||||
// Types that are valid to be assigned to Item:
|
||||
// *SnapshotItem_Store
|
||||
// *SnapshotItem_IAVL
|
||||
Item isSnapshotItem_Item `protobuf_oneof:"item"`
|
||||
}
|
||||
|
||||
func (m *SnapshotItem) Reset() { *m = SnapshotItem{} }
|
||||
func (m *SnapshotItem) String() string { return proto.CompactTextString(m) }
|
||||
func (*SnapshotItem) ProtoMessage() {}
|
||||
func (*SnapshotItem) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9c55879db4cc4502, []int{0}
|
||||
}
|
||||
func (m *SnapshotItem) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *SnapshotItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_SnapshotItem.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *SnapshotItem) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SnapshotItem.Merge(m, src)
|
||||
}
|
||||
func (m *SnapshotItem) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *SnapshotItem) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SnapshotItem.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SnapshotItem proto.InternalMessageInfo
|
||||
|
||||
type isSnapshotItem_Item interface {
|
||||
isSnapshotItem_Item()
|
||||
MarshalTo([]byte) (int, error)
|
||||
Size() int
|
||||
}
|
||||
|
||||
type SnapshotItem_Store struct {
|
||||
Store *SnapshotStoreItem `protobuf:"bytes,1,opt,name=store,proto3,oneof" json:"store,omitempty"`
|
||||
}
|
||||
type SnapshotItem_IAVL struct {
|
||||
IAVL *SnapshotIAVLItem `protobuf:"bytes,2,opt,name=iavl,proto3,oneof" json:"iavl,omitempty"`
|
||||
}
|
||||
|
||||
func (*SnapshotItem_Store) isSnapshotItem_Item() {}
|
||||
func (*SnapshotItem_IAVL) isSnapshotItem_Item() {}
|
||||
|
||||
func (m *SnapshotItem) GetItem() isSnapshotItem_Item {
|
||||
if m != nil {
|
||||
return m.Item
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SnapshotItem) GetStore() *SnapshotStoreItem {
|
||||
if x, ok := m.GetItem().(*SnapshotItem_Store); ok {
|
||||
return x.Store
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SnapshotItem) GetIAVL() *SnapshotIAVLItem {
|
||||
if x, ok := m.GetItem().(*SnapshotItem_IAVL); ok {
|
||||
return x.IAVL
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// XXX_OneofWrappers is for the internal use of the proto package.
|
||||
func (*SnapshotItem) XXX_OneofWrappers() []interface{} {
|
||||
return []interface{}{
|
||||
(*SnapshotItem_Store)(nil),
|
||||
(*SnapshotItem_IAVL)(nil),
|
||||
}
|
||||
}
|
||||
|
||||
// SnapshotStoreItem contains metadata about a snapshotted store.
|
||||
type SnapshotStoreItem struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (m *SnapshotStoreItem) Reset() { *m = SnapshotStoreItem{} }
|
||||
func (m *SnapshotStoreItem) String() string { return proto.CompactTextString(m) }
|
||||
func (*SnapshotStoreItem) ProtoMessage() {}
|
||||
func (*SnapshotStoreItem) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9c55879db4cc4502, []int{1}
|
||||
}
|
||||
func (m *SnapshotStoreItem) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *SnapshotStoreItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_SnapshotStoreItem.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *SnapshotStoreItem) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SnapshotStoreItem.Merge(m, src)
|
||||
}
|
||||
func (m *SnapshotStoreItem) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *SnapshotStoreItem) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SnapshotStoreItem.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SnapshotStoreItem proto.InternalMessageInfo
|
||||
|
||||
func (m *SnapshotStoreItem) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// SnapshotIAVLItem is an exported IAVL node.
|
||||
type SnapshotIAVLItem struct {
|
||||
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"`
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) Reset() { *m = SnapshotIAVLItem{} }
|
||||
func (m *SnapshotIAVLItem) String() string { return proto.CompactTextString(m) }
|
||||
func (*SnapshotIAVLItem) ProtoMessage() {}
|
||||
func (*SnapshotIAVLItem) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9c55879db4cc4502, []int{2}
|
||||
}
|
||||
func (m *SnapshotIAVLItem) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *SnapshotIAVLItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_SnapshotIAVLItem.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *SnapshotIAVLItem) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SnapshotIAVLItem.Merge(m, src)
|
||||
}
|
||||
func (m *SnapshotIAVLItem) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *SnapshotIAVLItem) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SnapshotIAVLItem.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SnapshotIAVLItem proto.InternalMessageInfo
|
||||
|
||||
func (m *SnapshotIAVLItem) GetKey() []byte {
|
||||
if m != nil {
|
||||
return m.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) GetValue() []byte {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) GetVersion() int64 {
|
||||
if m != nil {
|
||||
return m.Version
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) GetHeight() int32 {
|
||||
if m != nil {
|
||||
return m.Height
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*SnapshotItem)(nil), "cosmos.base.store.v1beta1.SnapshotItem")
|
||||
proto.RegisterType((*SnapshotStoreItem)(nil), "cosmos.base.store.v1beta1.SnapshotStoreItem")
|
||||
proto.RegisterType((*SnapshotIAVLItem)(nil), "cosmos.base.store.v1beta1.SnapshotIAVLItem")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("cosmos/base/store/v1beta1/snapshot.proto", fileDescriptor_9c55879db4cc4502)
|
||||
}
|
||||
|
||||
var fileDescriptor_9c55879db4cc4502 = []byte{
|
||||
// 324 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xc1, 0x4a, 0xc3, 0x30,
|
||||
0x18, 0xc7, 0x1b, 0xd7, 0x4d, 0xfd, 0xdc, 0x61, 0x86, 0x21, 0xd5, 0x43, 0x1d, 0xbb, 0x58, 0x50,
|
||||
0x13, 0xa6, 0x4f, 0x60, 0xf1, 0xb0, 0xa1, 0xa7, 0x0c, 0x3c, 0x78, 0x4b, 0x67, 0x68, 0xcb, 0xd6,
|
||||
0x65, 0x2c, 0x59, 0x61, 0x6f, 0xe1, 0x6b, 0xf8, 0x26, 0x1e, 0x77, 0xf4, 0x24, 0xd2, 0xbd, 0x88,
|
||||
0x24, 0xe9, 0x2e, 0x8a, 0xe0, 0xa9, 0xdf, 0xbf, 0xfc, 0xfe, 0xbf, 0x7c, 0xf0, 0x41, 0x34, 0x91,
|
||||
0xaa, 0x90, 0x8a, 0x26, 0x5c, 0x09, 0xaa, 0xb4, 0x5c, 0x0a, 0x5a, 0x0e, 0x12, 0xa1, 0xf9, 0x80,
|
||||
0xaa, 0x39, 0x5f, 0xa8, 0x4c, 0x6a, 0xb2, 0x58, 0x4a, 0x2d, 0xf1, 0xa9, 0x23, 0x89, 0x21, 0x89,
|
||||
0x25, 0x49, 0x4d, 0x9e, 0x75, 0x53, 0x99, 0x4a, 0x4b, 0x51, 0x33, 0xb9, 0x42, 0xff, 0x0d, 0x41,
|
||||
0x7b, 0x5c, 0x3b, 0x46, 0x5a, 0x14, 0xf8, 0x1e, 0x9a, 0xb6, 0x17, 0xa0, 0x1e, 0x8a, 0x8e, 0x6e,
|
||||
0xae, 0xc8, 0x9f, 0x46, 0xb2, 0xeb, 0x8d, 0xcd, 0x5f, 0x53, 0x1e, 0x7a, 0xcc, 0x95, 0xf1, 0x03,
|
||||
0xf8, 0x39, 0x2f, 0x67, 0xc1, 0x9e, 0x95, 0x5c, 0xfe, 0x43, 0x32, 0xba, 0x7b, 0x7a, 0x34, 0x8e,
|
||||
0xf8, 0xa0, 0xfa, 0x3c, 0xf7, 0x4d, 0x1a, 0x7a, 0xcc, 0x4a, 0xe2, 0x16, 0xf8, 0xb9, 0x16, 0x45,
|
||||
0xff, 0x02, 0x8e, 0x7f, 0x3d, 0x89, 0x31, 0xf8, 0x73, 0x5e, 0xb8, 0x75, 0x0f, 0x99, 0x9d, 0xfb,
|
||||
0x33, 0xe8, 0xfc, 0xd4, 0xe2, 0x0e, 0x34, 0xa6, 0x62, 0x6d, 0xb1, 0x36, 0x33, 0x23, 0xee, 0x42,
|
||||
0xb3, 0xe4, 0xb3, 0x95, 0xb0, 0x4b, 0xb6, 0x99, 0x0b, 0x38, 0x80, 0xfd, 0x52, 0x2c, 0x55, 0x2e,
|
||||
0xe7, 0x41, 0xa3, 0x87, 0xa2, 0x06, 0xdb, 0x45, 0x7c, 0x02, 0xad, 0x4c, 0xe4, 0x69, 0xa6, 0x03,
|
||||
0xbf, 0x87, 0xa2, 0x26, 0xab, 0x53, 0x1c, 0xbf, 0x57, 0x21, 0xda, 0x54, 0x21, 0xfa, 0xaa, 0x42,
|
||||
0xf4, 0xba, 0x0d, 0xbd, 0xcd, 0x36, 0xf4, 0x3e, 0xb6, 0xa1, 0xf7, 0x1c, 0xa5, 0xb9, 0xce, 0x56,
|
||||
0x09, 0x99, 0xc8, 0x82, 0xd6, 0x27, 0x74, 0x9f, 0x6b, 0xf5, 0x32, 0xad, 0x0f, 0xa9, 0xd7, 0x0b,
|
||||
0xa1, 0x92, 0x96, 0xbd, 0xc6, 0xed, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x75, 0x87, 0x24, 0x7b,
|
||||
0xea, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *SnapshotItem) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SnapshotItem) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *SnapshotItem) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.Item != nil {
|
||||
{
|
||||
size := m.Item.Size()
|
||||
i -= size
|
||||
if _, err := m.Item.MarshalTo(dAtA[i:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *SnapshotItem_Store) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *SnapshotItem_Store) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
if m.Store != nil {
|
||||
{
|
||||
size, err := m.Store.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintSnapshot(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
func (m *SnapshotItem_IAVL) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *SnapshotItem_IAVL) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
if m.IAVL != nil {
|
||||
{
|
||||
size, err := m.IAVL.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintSnapshot(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
func (m *SnapshotStoreItem) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SnapshotStoreItem) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *SnapshotStoreItem) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Name) > 0 {
|
||||
i -= len(m.Name)
|
||||
copy(dAtA[i:], m.Name)
|
||||
i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Name)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.Height != 0 {
|
||||
i = encodeVarintSnapshot(dAtA, i, uint64(m.Height))
|
||||
i--
|
||||
dAtA[i] = 0x20
|
||||
}
|
||||
if m.Version != 0 {
|
||||
i = encodeVarintSnapshot(dAtA, i, uint64(m.Version))
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
if len(m.Value) > 0 {
|
||||
i -= len(m.Value)
|
||||
copy(dAtA[i:], m.Value)
|
||||
i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Value)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.Key) > 0 {
|
||||
i -= len(m.Key)
|
||||
copy(dAtA[i:], m.Key)
|
||||
i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Key)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintSnapshot(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovSnapshot(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *SnapshotItem) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Item != nil {
|
||||
n += m.Item.Size()
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *SnapshotItem_Store) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Store != nil {
|
||||
l = m.Store.Size()
|
||||
n += 1 + l + sovSnapshot(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
func (m *SnapshotItem_IAVL) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.IAVL != nil {
|
||||
l = m.IAVL.Size()
|
||||
n += 1 + l + sovSnapshot(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
func (m *SnapshotStoreItem) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Name)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSnapshot(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *SnapshotIAVLItem) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Key)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSnapshot(uint64(l))
|
||||
}
|
||||
l = len(m.Value)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSnapshot(uint64(l))
|
||||
}
|
||||
if m.Version != 0 {
|
||||
n += 1 + sovSnapshot(uint64(m.Version))
|
||||
}
|
||||
if m.Height != 0 {
|
||||
n += 1 + sovSnapshot(uint64(m.Height))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovSnapshot(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozSnapshot(x uint64) (n int) {
|
||||
return sovSnapshot(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *SnapshotItem) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SnapshotItem: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SnapshotItem: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Store", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
v := &SnapshotStoreItem{}
|
||||
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Item = &SnapshotItem_Store{v}
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field IAVL", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
v := &SnapshotIAVLItem{}
|
||||
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Item = &SnapshotItem_IAVL{v}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSnapshot(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *SnapshotStoreItem) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SnapshotStoreItem: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SnapshotStoreItem: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Name = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSnapshot(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *SnapshotIAVLItem) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SnapshotIAVLItem: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SnapshotIAVLItem: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Key == nil {
|
||||
m.Key = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Value == nil {
|
||||
m.Value = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType)
|
||||
}
|
||||
m.Version = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Version |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType)
|
||||
}
|
||||
m.Height = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Height |= int32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSnapshot(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthSnapshot
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipSnapshot(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSnapshot
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthSnapshot
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupSnapshot
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthSnapshot
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthSnapshot = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowSnapshot = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupSnapshot = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
@@ -131,6 +132,7 @@ type CacheMultiStore interface {
|
||||
type CommitMultiStore interface {
|
||||
Committer
|
||||
MultiStore
|
||||
snapshottypes.Snapshotter
|
||||
|
||||
// Mount a store of type using the given db.
|
||||
// If db == nil, the new store will use the CommitMultiStore db.
|
||||
|
||||
Reference in New Issue
Block a user