feat: ADR-040: add state sync for v2 store (#10794)

## Description

Closes: #10705 


State Sync for V2 Store (ADR-40) 
---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
Sai Kumar 2022-03-04 11:35:23 +05:30 committed by GitHub
parent 0a7ad0181b
commit 489b3997e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2537 additions and 134 deletions

View File

@ -69,6 +69,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#10015](https://github.com/cosmos/cosmos-sdk/pull/10015) ADR-040: ICS-23 proofs for SMT store
* [\#11240](https://github.com/cosmos/cosmos-sdk/pull/11240) Replace various modules `ModuleCdc` with the global `legacy.Cdc`
* [#11179](https://github.com/cosmos/cosmos-sdk/pull/11179) Add state rollback command.
* [\#10794](https://github.com/cosmos/cosmos-sdk/pull/10794) ADR-040: Add State Sync to V2 Store
### API Breaking Changes

File diff suppressed because it is too large Load Diff

View File

@ -1917,8 +1917,8 @@ func TestListSnapshots(t *testing.T) {
s.Metadata = nil
}
assert.Equal(t, abci.ResponseListSnapshots{Snapshots: []*abci.Snapshot{
{Height: 4, Format: 1, Chunks: 2},
{Height: 2, Format: 1, Chunks: 1},
{Height: 4, Format: snapshottypes.CurrentFormat, Chunks: 2},
{Height: 2, Format: snapshottypes.CurrentFormat, Chunks: 1},
}}, resp)
}
@ -1932,13 +1932,13 @@ func TestLoadSnapshotChunk(t *testing.T) {
chunk uint32
expectEmpty bool
}{
"Existing snapshot": {2, 1, 1, false},
"Missing height": {100, 1, 1, true},
"Missing format": {2, 2, 1, true},
"Missing chunk": {2, 1, 9, true},
"Zero height": {0, 1, 1, true},
"Existing snapshot": {2, snapshottypes.CurrentFormat, 1, false},
"Missing height": {100, snapshottypes.CurrentFormat, 1, true},
"Missing format": {2, 3, 1, true},
"Missing chunk": {2, snapshottypes.CurrentFormat, 9, true},
"Zero height": {0, snapshottypes.CurrentFormat, 1, true},
"Zero format": {2, 0, 1, true},
"Zero chunk": {2, 1, 0, false},
"Zero chunk": {2, snapshottypes.CurrentFormat, 0, false},
}
for name, tc := range testcases {
tc := tc
@ -1976,13 +1976,13 @@ func TestOfferSnapshot_Errors(t *testing.T) {
Height: 1, Format: 9, Chunks: 3, Hash: hash, Metadata: metadata,
}, abci.ResponseOfferSnapshot_REJECT_FORMAT},
"incorrect chunk count": {&abci.Snapshot{
Height: 1, Format: 1, Chunks: 2, Hash: hash, Metadata: metadata,
Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 2, Hash: hash, Metadata: metadata,
}, abci.ResponseOfferSnapshot_REJECT},
"no chunks": {&abci.Snapshot{
Height: 1, Format: 1, Chunks: 0, Hash: hash, Metadata: metadata,
Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 0, Hash: hash, Metadata: metadata,
}, abci.ResponseOfferSnapshot_REJECT},
"invalid metadata serialization": {&abci.Snapshot{
Height: 1, Format: 1, Chunks: 0, Hash: hash, Metadata: []byte{3, 1, 4},
Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 0, Hash: hash, Metadata: []byte{3, 1, 4},
}, abci.ResponseOfferSnapshot_REJECT},
}
for name, tc := range testcases {

File diff suppressed because one or more lines are too long

View File

@ -7,10 +7,10 @@ option go_package = "github.com/cosmos/cosmos-sdk/snapshots/types";
// Snapshot contains Tendermint state sync snapshot info.
message Snapshot {
uint64 height = 1;
uint32 format = 2;
uint32 chunks = 3;
bytes hash = 4;
uint64 height = 1;
uint32 format = 2;
uint32 chunks = 3;
bytes hash = 4;
Metadata metadata = 5 [(gogoproto.nullable) = false];
}
@ -23,10 +23,12 @@ message Metadata {
message SnapshotItem {
// item is the specific type of snapshot item.
oneof item {
SnapshotStoreItem store = 1;
SnapshotIAVLItem iavl = 2 [(gogoproto.customname) = "IAVL"];
SnapshotExtensionMeta extension = 3;
SnapshotExtensionPayload extension_payload = 4;
SnapshotStoreItem store = 1;
SnapshotIAVLItem iavl = 2 [(gogoproto.customname) = "IAVL"];
SnapshotExtensionMeta extension = 3;
SnapshotExtensionPayload extension_payload = 4;
SnapshotKVItem kv = 5 [(gogoproto.customname) = "KV"];
SnapshotSchema schema = 6;
}
}
@ -37,17 +39,17 @@ message SnapshotStoreItem {
// SnapshotIAVLItem is an exported IAVL node.
message SnapshotIAVLItem {
bytes key = 1;
bytes value = 2;
bytes key = 1;
bytes value = 2;
// version is block height
int64 version = 3;
// height is depth of the tree.
int32 height = 4;
int32 height = 4;
}
// SnapshotExtensionMeta contains metadata about an external snapshotter.
message SnapshotExtensionMeta {
string name = 1;
string name = 1;
uint32 format = 2;
}
@ -55,3 +57,14 @@ message SnapshotExtensionMeta {
message SnapshotExtensionPayload {
bytes payload = 1;
}
// SnapshotKVItem is an exported Key/Value Pair
message SnapshotKVItem {
bytes key = 1;
bytes value = 2;
}
// SnapshotSchema is an exported schema of smt store
message SnapshotSchema{
repeated bytes keys = 1;
}

View File

@ -287,7 +287,6 @@ func NewSimApp(
app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper)
// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
app.StakingKeeper = *stakingKeeper.SetHooks(

View File

@ -1,7 +1,9 @@
package snapshots
import (
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"io"
"math"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
@ -161,3 +163,20 @@ func DrainChunks(chunks <-chan io.ReadCloser) {
_ = chunk.Close()
}
}
// ValidRestoreHeight will check height is valid for snapshot restore or not
func ValidRestoreHeight(format uint32, height uint64) 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 > uint64(math.MaxInt64) {
return sdkerrors.Wrapf(snapshottypes.ErrInvalidMetadata,
"snapshot height %v cannot exceed %v", height, int64(math.MaxInt64))
}
return nil
}

View File

@ -136,10 +136,10 @@ func (m *mockSnapshotter) Snapshot(height uint64, protoWriter protoio.Writer) er
}
func (m *mockSnapshotter) SnapshotFormat() uint32 {
return 1
return snapshottypes.CurrentFormat
}
func (m *mockSnapshotter) SupportedFormats() []uint32 {
return []uint32{1}
return []uint32{snapshottypes.CurrentFormat}
}
// setupBusyManager creates a manager with an empty store that is busy creating a snapshot at height 1.

View File

@ -139,13 +139,13 @@ func TestManager_Restore(t *testing.T) {
require.ErrorIs(t, err, types.ErrUnknownFormat)
// Restore errors on no chunks
err = manager.Restore(types.Snapshot{Height: 3, Format: 1, Hash: []byte{1, 2, 3}})
err = manager.Restore(types.Snapshot{Height: 3, Format: types.CurrentFormat, Hash: []byte{1, 2, 3}})
require.Error(t, err)
// Restore errors on chunk and chunkhashes mismatch
err = manager.Restore(types.Snapshot{
Height: 3,
Format: 1,
Format: types.CurrentFormat,
Hash: []byte{1, 2, 3},
Chunks: 4,
Metadata: types.Metadata{ChunkHashes: checksums(chunks)},
@ -155,7 +155,7 @@ func TestManager_Restore(t *testing.T) {
// Starting a restore works
err = manager.Restore(types.Snapshot{
Height: 3,
Format: 1,
Format: types.CurrentFormat,
Hash: []byte{1, 2, 3},
Chunks: 1,
Metadata: types.Metadata{ChunkHashes: checksums(chunks)},
@ -190,7 +190,7 @@ func TestManager_Restore(t *testing.T) {
// Starting a new restore should fail now, because the target already has contents.
err = manager.Restore(types.Snapshot{
Height: 3,
Format: 1,
Format: types.CurrentFormat,
Hash: []byte{1, 2, 3},
Chunks: 3,
Metadata: types.Metadata{ChunkHashes: checksums(chunks)},
@ -203,7 +203,7 @@ func TestManager_Restore(t *testing.T) {
target.items = nil
err = manager.Restore(types.Snapshot{
Height: 3,
Format: 1,
Format: types.CurrentFormat,
Hash: []byte{1, 2, 3},
Chunks: 1,
Metadata: types.Metadata{ChunkHashes: checksums(chunks)},

View File

@ -13,4 +13,7 @@ var (
// ErrInvalidMetadata is returned when the snapshot metadata is invalid.
ErrInvalidMetadata = errors.New("invalid snapshot metadata")
// ErrInvalidSnapshotVersion is returned when the snapshot version is invalid
ErrInvalidSnapshotVersion = errors.New("invalid snapshot version")
)

View File

@ -3,4 +3,4 @@ package types
// CurrentFormat is the currently used format for snapshots. Snapshots using the same format
// must be identical across all nodes for a given height, so this must be bumped when the binary
// snapshot output changes.
const CurrentFormat uint32 = 1
const CurrentFormat uint32 = 2

View File

@ -154,6 +154,8 @@ type SnapshotItem struct {
// *SnapshotItem_IAVL
// *SnapshotItem_Extension
// *SnapshotItem_ExtensionPayload
// *SnapshotItem_KV
// *SnapshotItem_Schema
Item isSnapshotItem_Item `protobuf_oneof:"item"`
}
@ -208,11 +210,19 @@ type SnapshotItem_Extension struct {
type SnapshotItem_ExtensionPayload struct {
ExtensionPayload *SnapshotExtensionPayload `protobuf:"bytes,4,opt,name=extension_payload,json=extensionPayload,proto3,oneof" json:"extension_payload,omitempty"`
}
type SnapshotItem_KV struct {
KV *SnapshotKVItem `protobuf:"bytes,5,opt,name=kv,proto3,oneof" json:"kv,omitempty"`
}
type SnapshotItem_Schema struct {
Schema *SnapshotSchema `protobuf:"bytes,6,opt,name=schema,proto3,oneof" json:"schema,omitempty"`
}
func (*SnapshotItem_Store) isSnapshotItem_Item() {}
func (*SnapshotItem_IAVL) isSnapshotItem_Item() {}
func (*SnapshotItem_Extension) isSnapshotItem_Item() {}
func (*SnapshotItem_ExtensionPayload) isSnapshotItem_Item() {}
func (*SnapshotItem_KV) isSnapshotItem_Item() {}
func (*SnapshotItem_Schema) isSnapshotItem_Item() {}
func (m *SnapshotItem) GetItem() isSnapshotItem_Item {
if m != nil {
@ -249,6 +259,20 @@ func (m *SnapshotItem) GetExtensionPayload() *SnapshotExtensionPayload {
return nil
}
func (m *SnapshotItem) GetKV() *SnapshotKVItem {
if x, ok := m.GetItem().(*SnapshotItem_KV); ok {
return x.KV
}
return nil
}
func (m *SnapshotItem) GetSchema() *SnapshotSchema {
if x, ok := m.GetItem().(*SnapshotItem_Schema); ok {
return x.Schema
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*SnapshotItem) XXX_OneofWrappers() []interface{} {
return []interface{}{
@ -256,6 +280,8 @@ func (*SnapshotItem) XXX_OneofWrappers() []interface{} {
(*SnapshotItem_IAVL)(nil),
(*SnapshotItem_Extension)(nil),
(*SnapshotItem_ExtensionPayload)(nil),
(*SnapshotItem_KV)(nil),
(*SnapshotItem_Schema)(nil),
}
}
@ -473,6 +499,104 @@ func (m *SnapshotExtensionPayload) GetPayload() []byte {
return nil
}
// SnapshotKVItem is an exported Key/Value Pair
type SnapshotKVItem 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"`
}
func (m *SnapshotKVItem) Reset() { *m = SnapshotKVItem{} }
func (m *SnapshotKVItem) String() string { return proto.CompactTextString(m) }
func (*SnapshotKVItem) ProtoMessage() {}
func (*SnapshotKVItem) Descriptor() ([]byte, []int) {
return fileDescriptor_dd7a3c9b0a19e1ee, []int{7}
}
func (m *SnapshotKVItem) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *SnapshotKVItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_SnapshotKVItem.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 *SnapshotKVItem) XXX_Merge(src proto.Message) {
xxx_messageInfo_SnapshotKVItem.Merge(m, src)
}
func (m *SnapshotKVItem) XXX_Size() int {
return m.Size()
}
func (m *SnapshotKVItem) XXX_DiscardUnknown() {
xxx_messageInfo_SnapshotKVItem.DiscardUnknown(m)
}
var xxx_messageInfo_SnapshotKVItem proto.InternalMessageInfo
func (m *SnapshotKVItem) GetKey() []byte {
if m != nil {
return m.Key
}
return nil
}
func (m *SnapshotKVItem) GetValue() []byte {
if m != nil {
return m.Value
}
return nil
}
// SnapshotSchema is an exported schema of smt store
type SnapshotSchema struct {
Keys [][]byte `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"`
}
func (m *SnapshotSchema) Reset() { *m = SnapshotSchema{} }
func (m *SnapshotSchema) String() string { return proto.CompactTextString(m) }
func (*SnapshotSchema) ProtoMessage() {}
func (*SnapshotSchema) Descriptor() ([]byte, []int) {
return fileDescriptor_dd7a3c9b0a19e1ee, []int{8}
}
func (m *SnapshotSchema) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *SnapshotSchema) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_SnapshotSchema.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 *SnapshotSchema) XXX_Merge(src proto.Message) {
xxx_messageInfo_SnapshotSchema.Merge(m, src)
}
func (m *SnapshotSchema) XXX_Size() int {
return m.Size()
}
func (m *SnapshotSchema) XXX_DiscardUnknown() {
xxx_messageInfo_SnapshotSchema.DiscardUnknown(m)
}
var xxx_messageInfo_SnapshotSchema proto.InternalMessageInfo
func (m *SnapshotSchema) GetKeys() [][]byte {
if m != nil {
return m.Keys
}
return nil
}
func init() {
proto.RegisterType((*Snapshot)(nil), "cosmos.base.snapshots.v1beta1.Snapshot")
proto.RegisterType((*Metadata)(nil), "cosmos.base.snapshots.v1beta1.Metadata")
@ -481,6 +605,8 @@ func init() {
proto.RegisterType((*SnapshotIAVLItem)(nil), "cosmos.base.snapshots.v1beta1.SnapshotIAVLItem")
proto.RegisterType((*SnapshotExtensionMeta)(nil), "cosmos.base.snapshots.v1beta1.SnapshotExtensionMeta")
proto.RegisterType((*SnapshotExtensionPayload)(nil), "cosmos.base.snapshots.v1beta1.SnapshotExtensionPayload")
proto.RegisterType((*SnapshotKVItem)(nil), "cosmos.base.snapshots.v1beta1.SnapshotKVItem")
proto.RegisterType((*SnapshotSchema)(nil), "cosmos.base.snapshots.v1beta1.SnapshotSchema")
}
func init() {
@ -488,40 +614,44 @@ func init() {
}
var fileDescriptor_dd7a3c9b0a19e1ee = []byte{
// 513 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xd1, 0x6e, 0xd3, 0x30,
0x14, 0x8d, 0xd7, 0xb4, 0x74, 0x37, 0x41, 0xea, 0xac, 0x81, 0x22, 0x24, 0xb2, 0x92, 0x97, 0xf5,
0x61, 0x4b, 0x58, 0x99, 0xc4, 0x33, 0x45, 0xa0, 0x54, 0x02, 0x81, 0x3c, 0xc4, 0x03, 0x2f, 0x93,
0xdb, 0x7a, 0x4d, 0xd4, 0x26, 0xae, 0x6a, 0xb7, 0xa2, 0x7f, 0xc1, 0xaf, 0xf0, 0x17, 0x7b, 0xdc,
0x23, 0x4f, 0x13, 0x6a, 0x3f, 0x80, 0x5f, 0x40, 0xb6, 0x93, 0x30, 0x8d, 0x0d, 0xb6, 0xa7, 0xde,
0x73, 0x7a, 0xee, 0xf1, 0xf5, 0xc9, 0x35, 0x1c, 0x0c, 0xb9, 0xc8, 0xb8, 0x88, 0x06, 0x54, 0xb0,
0x48, 0xe4, 0x74, 0x26, 0x12, 0x2e, 0x45, 0xb4, 0x3c, 0x1a, 0x30, 0x49, 0x8f, 0x2a, 0x26, 0x9c,
0xcd, 0xb9, 0xe4, 0xf8, 0xa9, 0x51, 0x87, 0x4a, 0x1d, 0x56, 0xea, 0xb0, 0x50, 0x3f, 0xd9, 0x1d,
0xf3, 0x31, 0xd7, 0xca, 0x48, 0x55, 0xa6, 0x29, 0xf8, 0x8e, 0xa0, 0x79, 0x52, 0x68, 0xf1, 0x63,
0x68, 0x24, 0x2c, 0x1d, 0x27, 0xd2, 0x43, 0x6d, 0xd4, 0xb1, 0x49, 0x81, 0x14, 0x7f, 0xc6, 0xe7,
0x19, 0x95, 0xde, 0x56, 0x1b, 0x75, 0x1e, 0x92, 0x02, 0x29, 0x7e, 0x98, 0x2c, 0xf2, 0x89, 0xf0,
0x6a, 0x86, 0x37, 0x08, 0x63, 0xb0, 0x13, 0x2a, 0x12, 0xcf, 0x6e, 0xa3, 0x8e, 0x4b, 0x74, 0x8d,
0xfb, 0xd0, 0xcc, 0x98, 0xa4, 0x23, 0x2a, 0xa9, 0x57, 0x6f, 0xa3, 0x8e, 0xd3, 0xdd, 0x0f, 0xff,
0x39, 0x70, 0xf8, 0xbe, 0x90, 0xf7, 0xec, 0xf3, 0xcb, 0x3d, 0x8b, 0x54, 0xed, 0xc1, 0x21, 0x34,
0xcb, 0xff, 0xf0, 0x33, 0x70, 0xf5, 0xa1, 0xa7, 0xea, 0x10, 0x26, 0x3c, 0xd4, 0xae, 0x75, 0x5c,
0xe2, 0x68, 0x2e, 0xd6, 0x54, 0xf0, 0x6b, 0x0b, 0xdc, 0xf2, 0x8a, 0x7d, 0xc9, 0x32, 0x1c, 0x43,
0x5d, 0x48, 0x3e, 0x67, 0xfa, 0x96, 0x4e, 0xf7, 0xf9, 0x7f, 0xe6, 0x28, 0x7b, 0x4f, 0x54, 0x8f,
0x32, 0x88, 0x2d, 0x62, 0x0c, 0xf0, 0x07, 0xb0, 0x53, 0xba, 0x9c, 0xea, 0x58, 0x9c, 0x6e, 0x74,
0x47, 0xa3, 0xfe, 0xab, 0xcf, 0xef, 0x94, 0x4f, 0xaf, 0xb9, 0xbe, 0xdc, 0xb3, 0x15, 0x8a, 0x2d,
0xa2, 0x8d, 0xf0, 0x27, 0xd8, 0x66, 0x5f, 0x25, 0xcb, 0x45, 0xca, 0x73, 0x1d, 0xaa, 0xd3, 0x3d,
0xbe, 0xa3, 0xeb, 0x9b, 0xb2, 0x4f, 0x65, 0x13, 0x5b, 0xe4, 0x8f, 0x11, 0x3e, 0x83, 0x9d, 0x0a,
0x9c, 0xce, 0xe8, 0x6a, 0xca, 0xe9, 0x48, 0x7f, 0x1c, 0xa7, 0xfb, 0xf2, 0xbe, 0xee, 0x1f, 0x4d,
0x7b, 0x6c, 0x91, 0x16, 0xbb, 0xc6, 0xf5, 0x1a, 0x60, 0xa7, 0x92, 0x65, 0xc1, 0x3e, 0xec, 0xfc,
0x15, 0x9a, 0x5a, 0x8a, 0x9c, 0x66, 0x26, 0xf4, 0x6d, 0xa2, 0xeb, 0x60, 0x0a, 0xad, 0xeb, 0xa1,
0xe0, 0x16, 0xd4, 0x26, 0x6c, 0xa5, 0x65, 0x2e, 0x51, 0x25, 0xde, 0x85, 0xfa, 0x92, 0x4e, 0x17,
0x4c, 0xc7, 0xec, 0x12, 0x03, 0xb0, 0x07, 0x0f, 0x96, 0x6c, 0x5e, 0x05, 0x55, 0x23, 0x25, 0xbc,
0xb2, 0xc6, 0xea, 0x8e, 0xf5, 0x72, 0x8d, 0x83, 0xd7, 0xf0, 0xe8, 0xc6, 0xb0, 0x6e, 0x1a, 0xed,
0xb6, 0x9d, 0x0f, 0x8e, 0xc1, 0xbb, 0x2d, 0x13, 0x35, 0x52, 0x99, 0xae, 0x19, 0xbf, 0x84, 0xbd,
0xb7, 0xe7, 0x6b, 0x1f, 0x5d, 0xac, 0x7d, 0xf4, 0x73, 0xed, 0xa3, 0x6f, 0x1b, 0xdf, 0xba, 0xd8,
0xf8, 0xd6, 0x8f, 0x8d, 0x6f, 0x7d, 0x39, 0x18, 0xa7, 0x32, 0x59, 0x0c, 0xc2, 0x21, 0xcf, 0xa2,
0xe2, 0xb9, 0x9b, 0x9f, 0x43, 0x31, 0x9a, 0x5c, 0x79, 0xf4, 0x72, 0x35, 0x63, 0x62, 0xd0, 0xd0,
0xaf, 0xf6, 0xc5, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6c, 0x90, 0xf8, 0x1f, 0x1a, 0x04, 0x00,
0x00,
// 581 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xc1, 0x6e, 0xd3, 0x40,
0x10, 0xb5, 0x13, 0xc7, 0xa4, 0x63, 0x83, 0xda, 0x55, 0x41, 0x16, 0x12, 0x6e, 0xb0, 0x90, 0x9a,
0x43, 0x6b, 0xd3, 0x50, 0x09, 0xae, 0x04, 0x41, 0x5d, 0x15, 0x04, 0xda, 0xa0, 0x1c, 0xb8, 0x54,
0x9b, 0x64, 0x1b, 0x47, 0x8e, 0xb3, 0x51, 0x76, 0x63, 0x91, 0x23, 0x7f, 0xc0, 0xaf, 0xf0, 0x17,
0x3d, 0xf6, 0xc8, 0x29, 0x42, 0xc9, 0x8f, 0xa0, 0x5d, 0xdb, 0x69, 0x29, 0x2d, 0xa4, 0xa7, 0xcc,
0x4c, 0xde, 0x7b, 0x9e, 0x9d, 0xb7, 0xb3, 0xb0, 0xd7, 0x65, 0x3c, 0x61, 0x3c, 0xe8, 0x10, 0x4e,
0x03, 0x3e, 0x22, 0x63, 0x1e, 0x31, 0xc1, 0x83, 0xf4, 0xa0, 0x43, 0x05, 0x39, 0x58, 0x55, 0xfc,
0xf1, 0x84, 0x09, 0x86, 0x9e, 0x64, 0x68, 0x5f, 0xa2, 0xfd, 0x15, 0xda, 0xcf, 0xd1, 0x8f, 0xb7,
0xfb, 0xac, 0xcf, 0x14, 0x32, 0x90, 0x51, 0x46, 0xf2, 0x7e, 0xe8, 0x50, 0x6d, 0xe5, 0x58, 0xf4,
0x08, 0xcc, 0x88, 0x0e, 0xfa, 0x91, 0x70, 0xf4, 0x9a, 0x5e, 0x37, 0x70, 0x9e, 0xc9, 0xfa, 0x19,
0x9b, 0x24, 0x44, 0x38, 0xa5, 0x9a, 0x5e, 0xbf, 0x8f, 0xf3, 0x4c, 0xd6, 0xbb, 0xd1, 0x74, 0x14,
0x73, 0xa7, 0x9c, 0xd5, 0xb3, 0x0c, 0x21, 0x30, 0x22, 0xc2, 0x23, 0xc7, 0xa8, 0xe9, 0x75, 0x1b,
0xab, 0x18, 0x1d, 0x43, 0x35, 0xa1, 0x82, 0xf4, 0x88, 0x20, 0x4e, 0xa5, 0xa6, 0xd7, 0xad, 0xc6,
0xae, 0xff, 0xcf, 0x86, 0xfd, 0x0f, 0x39, 0xbc, 0x69, 0x9c, 0xcf, 0x77, 0x34, 0xbc, 0xa2, 0x7b,
0xfb, 0x50, 0x2d, 0xfe, 0x43, 0x4f, 0xc1, 0x56, 0x1f, 0x3d, 0x95, 0x1f, 0xa1, 0xdc, 0xd1, 0x6b,
0xe5, 0xba, 0x8d, 0x2d, 0x55, 0x0b, 0x55, 0xc9, 0xfb, 0x66, 0x80, 0x5d, 0x1c, 0xf1, 0x58, 0xd0,
0x04, 0x85, 0x50, 0xe1, 0x82, 0x4d, 0xa8, 0x3a, 0xa5, 0xd5, 0x78, 0xfe, 0x9f, 0x3e, 0x0a, 0x6e,
0x4b, 0x72, 0xa4, 0x40, 0xa8, 0xe1, 0x4c, 0x00, 0x7d, 0x04, 0x63, 0x40, 0xd2, 0xa1, 0x1a, 0x8b,
0xd5, 0x08, 0xd6, 0x14, 0x3a, 0x7e, 0xdd, 0x7e, 0x2f, 0x75, 0x9a, 0xd5, 0xc5, 0x7c, 0xc7, 0x90,
0x59, 0xa8, 0x61, 0x25, 0x84, 0x3e, 0xc3, 0x06, 0xfd, 0x2a, 0xe8, 0x88, 0x0f, 0xd8, 0x48, 0x0d,
0xd5, 0x6a, 0x1c, 0xae, 0xa9, 0xfa, 0xb6, 0xe0, 0xc9, 0xd9, 0x84, 0x1a, 0xbe, 0x14, 0x42, 0x67,
0xb0, 0xb5, 0x4a, 0x4e, 0xc7, 0x64, 0x36, 0x64, 0xa4, 0xa7, 0xcc, 0xb1, 0x1a, 0x2f, 0xef, 0xaa,
0xfe, 0x29, 0xa3, 0x87, 0x1a, 0xde, 0xa4, 0xd7, 0x6a, 0xe8, 0x08, 0x4a, 0x71, 0x9a, 0xbb, 0xbb,
0xbf, 0xa6, 0xf0, 0x49, 0x5b, 0x8d, 0xc2, 0x5c, 0xcc, 0x77, 0x4a, 0x27, 0xed, 0x50, 0xc3, 0xa5,
0x38, 0x45, 0x47, 0x60, 0xf2, 0x6e, 0x44, 0x13, 0xe2, 0x98, 0x77, 0x12, 0x6b, 0x29, 0x52, 0xa8,
0xe1, 0x9c, 0xde, 0x34, 0xc1, 0x18, 0x08, 0x9a, 0x78, 0xbb, 0xb0, 0xf5, 0x97, 0x8d, 0xf2, 0x9a,
0x8e, 0x48, 0x92, 0x5d, 0x83, 0x0d, 0xac, 0x62, 0x6f, 0x08, 0x9b, 0xd7, 0x6d, 0x42, 0x9b, 0x50,
0x8e, 0xe9, 0x4c, 0xc1, 0x6c, 0x2c, 0x43, 0xb4, 0x0d, 0x95, 0x94, 0x0c, 0xa7, 0x54, 0x19, 0x6f,
0xe3, 0x2c, 0x41, 0x0e, 0xdc, 0x4b, 0xe9, 0x64, 0x65, 0x5d, 0x19, 0x17, 0xe9, 0x95, 0xc5, 0x92,
0x53, 0xaf, 0x14, 0x8b, 0xe5, 0xbd, 0x81, 0x87, 0x37, 0xda, 0x77, 0x53, 0x6b, 0xb7, 0x6d, 0xa1,
0x77, 0x08, 0xce, 0x6d, 0x2e, 0xc9, 0x96, 0x0a, 0xbf, 0xb3, 0xf6, 0x8b, 0xd4, 0x7b, 0x05, 0x0f,
0xfe, 0xb4, 0x60, 0xdd, 0x63, 0x7a, 0xcf, 0x2e, 0x99, 0xd9, 0xbc, 0x65, 0xb7, 0x31, 0x9d, 0x15,
0xcb, 0xa7, 0xe2, 0xe6, 0xbb, 0xf3, 0x85, 0xab, 0x5f, 0x2c, 0x5c, 0xfd, 0xd7, 0xc2, 0xd5, 0xbf,
0x2f, 0x5d, 0xed, 0x62, 0xe9, 0x6a, 0x3f, 0x97, 0xae, 0xf6, 0x65, 0xaf, 0x3f, 0x10, 0xd1, 0xb4,
0xe3, 0x77, 0x59, 0x12, 0xe4, 0x0f, 0x5c, 0xf6, 0xb3, 0xcf, 0x7b, 0xf1, 0x95, 0x67, 0x4e, 0xcc,
0xc6, 0x94, 0x77, 0x4c, 0xf5, 0x4e, 0xbd, 0xf8, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x70, 0xb0, 0xd0,
0xad, 0x0c, 0x05, 0x00, 0x00,
}
func (m *Snapshot) Marshal() (dAtA []byte, err error) {
@ -727,6 +857,48 @@ func (m *SnapshotItem_ExtensionPayload) MarshalToSizedBuffer(dAtA []byte) (int,
}
return len(dAtA) - i, nil
}
func (m *SnapshotItem_KV) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *SnapshotItem_KV) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
if m.KV != nil {
{
size, err := m.KV.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintSnapshot(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x2a
}
return len(dAtA) - i, nil
}
func (m *SnapshotItem_Schema) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *SnapshotItem_Schema) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
if m.Schema != nil {
{
size, err := m.Schema.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintSnapshot(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x32
}
return len(dAtA) - i, nil
}
func (m *SnapshotStoreItem) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -869,6 +1041,75 @@ func (m *SnapshotExtensionPayload) MarshalToSizedBuffer(dAtA []byte) (int, error
return len(dAtA) - i, nil
}
func (m *SnapshotKVItem) 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 *SnapshotKVItem) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *SnapshotKVItem) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
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 (m *SnapshotSchema) 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 *SnapshotSchema) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *SnapshotSchema) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Keys) > 0 {
for iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.Keys[iNdEx])
copy(dAtA[i:], m.Keys[iNdEx])
i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Keys[iNdEx])))
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func encodeVarintSnapshot(dAtA []byte, offset int, v uint64) int {
offset -= sovSnapshot(v)
base := offset
@ -979,6 +1220,30 @@ func (m *SnapshotItem_ExtensionPayload) Size() (n int) {
}
return n
}
func (m *SnapshotItem_KV) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.KV != nil {
l = m.KV.Size()
n += 1 + l + sovSnapshot(uint64(l))
}
return n
}
func (m *SnapshotItem_Schema) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Schema != nil {
l = m.Schema.Size()
n += 1 + l + sovSnapshot(uint64(l))
}
return n
}
func (m *SnapshotStoreItem) Size() (n int) {
if m == nil {
return 0
@ -1044,6 +1309,38 @@ func (m *SnapshotExtensionPayload) Size() (n int) {
return n
}
func (m *SnapshotKVItem) 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))
}
return n
}
func (m *SnapshotSchema) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Keys) > 0 {
for _, b := range m.Keys {
l = len(b)
n += 1 + l + sovSnapshot(uint64(l))
}
}
return n
}
func sovSnapshot(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@ -1475,6 +1772,76 @@ func (m *SnapshotItem) Unmarshal(dAtA []byte) error {
}
m.Item = &SnapshotItem_ExtensionPayload{v}
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field KV", 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 := &SnapshotKVItem{}
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
m.Item = &SnapshotItem_KV{v}
iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Schema", 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 := &SnapshotSchema{}
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
m.Item = &SnapshotItem_Schema{v}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipSnapshot(dAtA[iNdEx:])
@ -1919,6 +2286,206 @@ func (m *SnapshotExtensionPayload) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *SnapshotKVItem) 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: SnapshotKVItem: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: SnapshotKVItem: 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
default:
iNdEx = preIndex
skippy, err := skipSnapshot(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthSnapshot
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *SnapshotSchema) 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: SnapshotSchema: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: SnapshotSchema: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Keys", 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.Keys = append(m.Keys, make([]byte, postIndex-iNdEx))
copy(m.Keys[len(m.Keys)-1], dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipSnapshot(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (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

172
store/v2/multi/snapshot.go Normal file
View File

@ -0,0 +1,172 @@
package multi
import (
"bytes"
"fmt"
"io"
"sort"
protoio "github.com/gogo/protobuf/io"
"github.com/cosmos/cosmos-sdk/snapshots"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
types "github.com/cosmos/cosmos-sdk/store/v2"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// Snapshot implements snapshottypes.Snapshotter.
func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error {
if height == 0 {
return snapshottypes.ErrInvalidSnapshotVersion
}
if height > uint64(rs.LastCommitID().Version) {
return sdkerrors.Wrapf(sdkerrors.ErrLogic, "cannot snapshot future height %v", height)
}
// get the saved snapshot at height
vs, err := rs.getView(int64(height))
if err != nil {
return sdkerrors.Wrap(err, fmt.Sprintf("error while get the version at height %d", height))
}
// sending the snapshot store schema
var storeByteKeys [][]byte
for sKey := range vs.schema {
if vs.schema[sKey] == storetypes.StoreTypePersistent {
storeByteKeys = append(storeByteKeys, []byte(sKey))
}
}
sort.Slice(storeByteKeys, func(i, j int) bool {
return bytes.Compare(storeByteKeys[i], storeByteKeys[j]) == -1
})
err = protoWriter.WriteMsg(&snapshottypes.SnapshotItem{
Item: &snapshottypes.SnapshotItem_Schema{
Schema: &snapshottypes.SnapshotSchema{
Keys: storeByteKeys,
},
},
})
if err != nil {
return err
}
for _, sKey := range storeByteKeys {
subStore, err := vs.getSubstore(string(sKey))
if err != nil {
return err
}
err = protoWriter.WriteMsg(&snapshottypes.SnapshotItem{
Item: &snapshottypes.SnapshotItem_Store{
Store: &snapshottypes.SnapshotStoreItem{
Name: string(sKey),
},
},
})
if err != nil {
return err
}
iter := subStore.Iterator(nil, nil)
for ; iter.Valid(); iter.Next() {
err = protoWriter.WriteMsg(&snapshottypes.SnapshotItem{
Item: &snapshottypes.SnapshotItem_KV{
KV: &snapshottypes.SnapshotKVItem{
Key: iter.Key(),
Value: iter.Value(),
},
},
})
if err != nil {
return err
}
}
err = iter.Close()
if err != nil {
return err
}
}
return nil
}
// Restore implements snapshottypes.Snapshotter.
func (rs *Store) Restore(
height uint64, format uint32, protoReader protoio.Reader,
) (snapshottypes.SnapshotItem, error) {
if err := snapshots.ValidRestoreHeight(format, height); err != nil {
return snapshottypes.SnapshotItem{}, err
}
if rs.LastCommitID().Version != 0 {
return snapshottypes.SnapshotItem{}, sdkerrors.Wrapf(sdkerrors.ErrLogic, "cannot restore snapshot for non empty store at height %v", height)
}
var subStore *substore
var storeSchemaReceived = false
var snapshotItem snapshottypes.SnapshotItem
loop:
for {
snapshotItem = snapshottypes.SnapshotItem{}
err := protoReader.ReadMsg(&snapshotItem)
if err == io.EOF {
break
} else if err != nil {
return snapshottypes.SnapshotItem{}, sdkerrors.Wrap(err, "invalid protobuf message")
}
switch item := snapshotItem.Item.(type) {
case *snapshottypes.SnapshotItem_Schema:
receivedStoreSchema := make(StoreSchema, len(item.Schema.GetKeys()))
storeSchemaReceived = true
for _, sKey := range item.Schema.GetKeys() {
receivedStoreSchema[string(sKey)] = types.StoreTypePersistent
}
if !rs.schema.equal(receivedStoreSchema) {
return snapshottypes.SnapshotItem{}, sdkerrors.Wrap(sdkerrors.ErrLogic, "received schema does not match app schema")
}
case *snapshottypes.SnapshotItem_Store:
storeName := item.Store.GetName()
// checking the store schema is received or not
if !storeSchemaReceived {
return snapshottypes.SnapshotItem{}, sdkerrors.Wrapf(sdkerrors.ErrLogic, "received store name before store schema %s", storeName)
}
// checking the store schema exists or not
if _, has := rs.schema[storeName]; !has {
return snapshottypes.SnapshotItem{}, sdkerrors.Wrapf(sdkerrors.ErrLogic, "store is missing from schema %s", storeName)
}
// get the substore
subStore, err = rs.getSubstore(storeName)
if err != nil {
return snapshottypes.SnapshotItem{}, sdkerrors.Wrap(err, fmt.Sprintf("error while getting the substore for key %s", storeName))
}
case *snapshottypes.SnapshotItem_KV:
if subStore == nil {
return snapshottypes.SnapshotItem{}, sdkerrors.Wrap(sdkerrors.ErrLogic, "received KV Item before store item")
}
// update the key/value SMT.Store
subStore.Set(item.KV.Key, item.KV.Value)
default:
break loop
}
}
// commit the all key/values to store
_, err := rs.commit(height)
if err != nil {
return snapshotItem, sdkerrors.Wrap(err, fmt.Sprintf("error during commit the store at height %d", height))
}
return snapshotItem, nil
}

View File

@ -0,0 +1,316 @@
package multi
import (
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"io"
"math/rand"
"sort"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
dbm "github.com/cosmos/cosmos-sdk/db"
"github.com/cosmos/cosmos-sdk/db/memdb"
"github.com/cosmos/cosmos-sdk/snapshots"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"github.com/cosmos/cosmos-sdk/store/types"
)
func multiStoreConfig(t *testing.T, stores int) StoreConfig {
opts := DefaultStoreConfig()
opts.Pruning = types.PruneNothing
for i := 0; i < stores; i++ {
sKey := types.NewKVStoreKey(fmt.Sprintf("store%d", i))
require.NoError(t, opts.RegisterSubstore(sKey.Name(), types.StoreTypePersistent))
}
return opts
}
func newMultiStoreWithGeneratedData(t *testing.T, db dbm.DBConnection, stores int, storeKeys uint64) *Store {
cfg := multiStoreConfig(t, stores)
store, err := NewStore(db, cfg)
require.NoError(t, err)
r := rand.New(rand.NewSource(49872768940)) // Fixed seed for deterministic tests
var sKeys []string
for sKey := range store.schema {
sKeys = append(sKeys, sKey)
}
sort.Slice(sKeys, func(i, j int) bool {
return strings.Compare(sKeys[i], sKeys[j]) == -1
})
for _, sKey := range sKeys {
sStore, err := store.getSubstore(sKey)
require.NoError(t, err)
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)
}
sStore.Set(k, v)
}
}
store.Commit()
return store
}
func newMultiStoreWithBasicData(t *testing.T, db dbm.DBConnection, stores int) *Store {
cfg := multiStoreConfig(t, stores)
store, err := NewStore(db, cfg)
require.NoError(t, err)
for sKey := range store.schema {
sStore, err := store.getSubstore(sKey)
require.NoError(t, err)
for k, v := range alohaData {
sStore.Set([]byte(k), []byte(v))
}
}
store.Commit()
return store
}
func newMultiStore(t *testing.T, db dbm.DBConnection, stores int) *Store {
cfg := multiStoreConfig(t, stores)
store, err := NewStore(db, cfg)
require.NoError(t, err)
return store
}
func TestMultistoreSnapshot_Errors(t *testing.T) {
store := newMultiStoreWithBasicData(t, memdb.NewDB(), 4)
testcases := map[string]struct {
height uint64
expectType error
}{
"0 height": {0, snapshottypes.ErrInvalidSnapshotVersion},
"1 height": {1, nil},
}
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
chunks := make(chan io.ReadCloser)
streamWriter := snapshots.NewStreamWriter(chunks)
err := store.Snapshot(tc.height, streamWriter)
if tc.expectType != nil {
assert.True(t, errors.Is(err, tc.expectType))
}
})
}
}
func TestMultistoreRestore_Errors(t *testing.T) {
store := newMultiStoreWithBasicData(t, memdb.NewDB(), 4)
testcases := map[string]struct {
height uint64
format uint32
expectErrorType 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)
require.Error(t, err)
if tc.expectErrorType != nil {
assert.True(t, errors.Is(err, tc.expectErrorType))
}
})
}
}
func TestMultistoreSnapshot_Checksum(t *testing.T) {
store := newMultiStoreWithGeneratedData(t, memdb.NewDB(), 5, 10000)
version := uint64(store.LastCommitID().Version)
testcases := []struct {
format uint32
chunkHashes []string
}{
{1, []string{
"b0635a30d94d56b6cd1073fbfa109fa90b194d0ff2397659b00934c844a1f6fb",
"8c32e05f312cf2dee6b7d2bdb41e1a2bb2372697f25504e676af1718245d8b63",
"05dfef0e32c34ef3900300f9de51f228d7fb204fa8f4e4d0d1529f083d122029",
"77d30aeeb427b0bdcedf3639adde1e822c15233d652782e171125280875aa492",
"c00c3801da889ea4370f0e647ffe1e291bd47f500e2a7269611eb4cc198b993f",
"6d565eb28776631f3e3e764decd53436c3be073a8a01fa5434afd539f9ae6eda",
}},
}
for _, tc := range testcases {
tc := tc
t.Run(fmt.Sprintf("Format %v", tc.format), func(t *testing.T) {
chunks := make(chan io.ReadCloser, 100)
hashes := []string{}
go func() {
streamWriter := snapshots.NewStreamWriter(chunks)
defer streamWriter.Close()
require.NotNil(t, streamWriter)
err := store.Snapshot(version, streamWriter)
require.NoError(t, err)
}()
hasher := sha256.New()
for chunk := range chunks {
hasher.Reset()
_, 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 TestMultistoreSnapshotRestore(t *testing.T) {
source := newMultiStoreWithGeneratedData(t, memdb.NewDB(), 3, 4)
target := newMultiStore(t, memdb.NewDB(), 3)
require.Equal(t, source.LastCommitID().Version, int64(1))
version := uint64(source.LastCommitID().Version)
// check for target store restore
require.Equal(t, target.LastCommitID().Version, int64(0))
dummyExtensionItem := snapshottypes.SnapshotItem{
Item: &snapshottypes.SnapshotItem_Extension{
Extension: &snapshottypes.SnapshotExtensionMeta{
Name: "test",
Format: 1,
},
},
}
chunks := make(chan io.ReadCloser, 100)
go func() {
streamWriter := snapshots.NewStreamWriter(chunks)
require.NotNil(t, streamWriter)
defer streamWriter.Close()
err := source.Snapshot(version, streamWriter)
require.NoError(t, err)
// write an extension metadata
err = streamWriter.WriteMsg(&dummyExtensionItem)
require.NoError(t, err)
}()
streamReader, err := snapshots.NewStreamReader(chunks)
require.NoError(t, err)
nextItem, err := target.Restore(version, snapshottypes.CurrentFormat, streamReader)
require.NoError(t, err)
require.Equal(t, *dummyExtensionItem.GetExtension(), *nextItem.GetExtension())
assert.Equal(t, source.LastCommitID(), target.LastCommitID())
for sKey := range source.schema {
sourceSubStore, err := source.getSubstore(sKey)
require.NoError(t, err)
targetSubStore, err := target.getSubstore(sKey)
require.NoError(t, err)
require.Equal(t, sourceSubStore, targetSubStore)
}
// checking snapshot restoring for store with existed schema and without existing versions
target3 := newMultiStore(t, memdb.NewDB(), 4)
chunks3 := make(chan io.ReadCloser, 100)
go func() {
streamWriter3 := snapshots.NewStreamWriter(chunks3)
require.NotNil(t, streamWriter3)
defer streamWriter3.Close()
err := source.Snapshot(version, streamWriter3)
require.NoError(t, err)
}()
streamReader3, err := snapshots.NewStreamReader(chunks3)
require.NoError(t, err)
_, err = target3.Restore(version, snapshottypes.CurrentFormat, streamReader3)
require.Error(t, err)
}
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 int, storeKeys uint64) {
b.Skip("Noisy with slow setup time, please see https://github.com/cosmos/cosmos-sdk/issues/8855.")
b.ReportAllocs()
b.StopTimer()
source := newMultiStoreWithGeneratedData(nil, memdb.NewDB(), stores, storeKeys)
version := source.LastCommitID().Version
require.EqualValues(b, 1, version)
b.StartTimer()
for i := 0; i < b.N; i++ {
target := newMultiStore(nil, memdb.NewDB(), stores)
require.EqualValues(b, 0, target.LastCommitID().Version)
chunks := make(chan io.ReadCloser)
go func() {
streamWriter := snapshots.NewStreamWriter(chunks)
require.NotNil(b, streamWriter)
err := source.Snapshot(uint64(version), streamWriter)
require.NoError(b, err)
}()
for reader := range chunks {
_, err := io.Copy(io.Discard, reader)
require.NoError(b, err)
err = reader.Close()
require.NoError(b, err)
}
}
}
func benchmarkMultistoreSnapshotRestore(b *testing.B, stores int, storeKeys uint64) {
b.Skip("Noisy with slow setup time, please see https://github.com/cosmos/cosmos-sdk/issues/8855.")
b.ReportAllocs()
b.StopTimer()
source := newMultiStoreWithGeneratedData(nil, memdb.NewDB(), stores, storeKeys)
version := uint64(source.LastCommitID().Version)
require.EqualValues(b, 1, version)
b.StartTimer()
for i := 0; i < b.N; i++ {
target := newMultiStore(nil, memdb.NewDB(), stores)
require.EqualValues(b, 0, target.LastCommitID().Version)
chunks := make(chan io.ReadCloser)
go func() {
writer := snapshots.NewStreamWriter(chunks)
require.NotNil(b, writer)
err := source.Snapshot(version, writer)
require.NoError(b, err)
}()
reader, err := snapshots.NewStreamReader(chunks)
require.NoError(b, err)
_, err = target.Restore(version, snapshottypes.CurrentFormat, reader)
require.NoError(b, err)
require.Equal(b, source.LastCommitID(), target.LastCommitID())
}
}

View File

@ -13,7 +13,6 @@ import (
dbm "github.com/cosmos/cosmos-sdk/db"
prefixdb "github.com/cosmos/cosmos-sdk/db/prefix"
util "github.com/cosmos/cosmos-sdk/internal"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps"
"github.com/cosmos/cosmos-sdk/store/listenkv"
"github.com/cosmos/cosmos-sdk/store/prefix"
@ -24,7 +23,6 @@ import (
"github.com/cosmos/cosmos-sdk/store/v2/transient"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/kv"
protoio "github.com/gogo/protobuf/io"
)
var (
@ -523,23 +521,19 @@ func (s *Store) Commit() types.CommitID {
// Substores read-lock this mutex; lock to prevent racey invalidation of underlying txns
s.mtx.Lock()
defer s.mtx.Unlock()
// Determine the target version
versions, err := s.stateDB.Versions()
if err != nil {
panic(err)
}
target := versions.Last() + 1
if target > math.MaxInt64 {
panic(ErrMaximumHeight)
}
// Fast forward to initial version if needed
if s.InitialVersion != 0 && target < s.InitialVersion {
target = s.InitialVersion
}
cid, err := s.commit(target)
if err != nil {
panic(err)
@ -902,12 +896,3 @@ func (tlm *traceListenMixin) wrapTraceListen(store types.KVStore, skey types.Sto
func (s *Store) GetPruning() types.PruningOptions { return s.Pruning }
func (s *Store) SetPruning(po types.PruningOptions) { s.Pruning = po }
func (rs *Store) Restore(
height uint64, format uint32, protoReader protoio.Reader,
) (snapshottypes.SnapshotItem, error) {
return snapshottypes.SnapshotItem{}, nil
}
func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error {
return nil
}

View File

@ -26,11 +26,11 @@ const (
FlagDescription = "description"
// Deprecated: only used for v1beta1 legacy proposals.
FlagProposalType = "type"
FlagDeposit = "deposit"
flagVoter = "voter"
flagDepositor = "depositor"
flagStatus = "status"
flagMetadata = "metadata"
FlagDeposit = "deposit"
flagVoter = "voter"
flagDepositor = "depositor"
flagStatus = "status"
flagMetadata = "metadata"
// Deprecated: only used for v1beta1 legacy proposals.
FlagProposal = "proposal"
)