Skip to content

Commit

Permalink
Fix all pruning, snapshot, and migration errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Manav-Aggarwal committed Jul 22, 2022
1 parent 52957f1 commit 9aa377e
Show file tree
Hide file tree
Showing 15 changed files with 1,601 additions and 614 deletions.
73 changes: 73 additions & 0 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,12 @@
- [StoreKVPair](#cosmos.base.store.v1beta1.StoreKVPair)

- [cosmos/base/store/v1beta1/snapshot.proto](#cosmos/base/store/v1beta1/snapshot.proto)
- [SnapshotExtensionMeta](#cosmos.base.store.v1beta1.SnapshotExtensionMeta)
- [SnapshotExtensionPayload](#cosmos.base.store.v1beta1.SnapshotExtensionPayload)
- [SnapshotIAVLItem](#cosmos.base.store.v1beta1.SnapshotIAVLItem)
- [SnapshotItem](#cosmos.base.store.v1beta1.SnapshotItem)
- [SnapshotKVItem](#cosmos.base.store.v1beta1.SnapshotKVItem)
- [SnapshotSchema](#cosmos.base.store.v1beta1.SnapshotSchema)
- [SnapshotStoreItem](#cosmos.base.store.v1beta1.SnapshotStoreItem)

- [cosmos/base/tendermint/v1beta1/query.proto](#cosmos/base/tendermint/v1beta1/query.proto)
Expand Down Expand Up @@ -1268,6 +1272,9 @@ tags are stringified and the log is JSON decoded.
| `gas_used` | [int64](#int64) | | Amount of gas consumed by transaction. |
| `tx` | [google.protobuf.Any](#google.protobuf.Any) | | The request transaction bytes. |
| `timestamp` | [string](#string) | | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time. |
| `events` | [tendermint.abci.Event](#tendermint.abci.Event) | repeated | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante handler. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages.

Since: cosmos-sdk 0.42.11, 0.44.5, 0.45 |



Expand Down Expand Up @@ -2747,6 +2754,37 @@ Since: cosmos-sdk 0.43



<a name="cosmos.base.store.v1beta1.SnapshotExtensionMeta"></a>

### SnapshotExtensionMeta



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `name` | [string](#string) | | |
| `format` | [uint32](#uint32) | | |






<a name="cosmos.base.store.v1beta1.SnapshotExtensionPayload"></a>

### SnapshotExtensionPayload



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `payload` | [bytes](#bytes) | | |






<a name="cosmos.base.store.v1beta1.SnapshotIAVLItem"></a>

### SnapshotIAVLItem
Expand Down Expand Up @@ -2775,6 +2813,41 @@ SnapshotItem is an item contained in a rootmulti.Store snapshot.
| ----- | ---- | ----- | ----------- |
| `store` | [SnapshotStoreItem](#cosmos.base.store.v1beta1.SnapshotStoreItem) | | |
| `iavl` | [SnapshotIAVLItem](#cosmos.base.store.v1beta1.SnapshotIAVLItem) | | |
| `extension` | [SnapshotExtensionMeta](#cosmos.base.store.v1beta1.SnapshotExtensionMeta) | | |
| `extension_payload` | [SnapshotExtensionPayload](#cosmos.base.store.v1beta1.SnapshotExtensionPayload) | | |
| `kv` | [SnapshotKVItem](#cosmos.base.store.v1beta1.SnapshotKVItem) | | |
| `schema` | [SnapshotSchema](#cosmos.base.store.v1beta1.SnapshotSchema) | | |






<a name="cosmos.base.store.v1beta1.SnapshotKVItem"></a>

### SnapshotKVItem



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `key` | [bytes](#bytes) | | |
| `value` | [bytes](#bytes) | | |






<a name="cosmos.base.store.v1beta1.SnapshotSchema"></a>

### SnapshotSchema



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `keys` | [bytes](#bytes) | repeated | |



Expand Down
28 changes: 26 additions & 2 deletions proto/cosmos/base/store/v1beta1/snapshot.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,44 @@ option go_package = "github.com/cosmos/cosmos-sdk/store/types";
message SnapshotItem {
// item is the specific type of snapshot item.
oneof item {
SnapshotStoreItem store = 1;
SnapshotIAVLItem iavl = 2 [(gogoproto.customname) = "IAVL"];
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;
}
}


// SnapshotStoreItem contains metadata about a snapshotted store.
message SnapshotStoreItem {
string name = 1;
}


// SnapshotIAVLItem is an exported IAVL node.
message SnapshotIAVLItem {
bytes key = 1;
bytes value = 2;
int64 version = 3;
int32 height = 4;
}

message SnapshotSchema{
repeated bytes keys = 1;
}

message SnapshotKVItem {
bytes key = 1;
bytes value = 2;
}

message SnapshotExtensionPayload {
bytes payload = 1;
}

message SnapshotExtensionMeta {
string name = 1;
uint32 format = 2;
}
3 changes: 3 additions & 0 deletions snapshots/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const (
opRestore operation = "restore"

chunkBufferSize = 4

snapshotMaxItemSize = int(64e6) // SDK has no key/value size limit, so we set an arbitrary limit

)

// operation represents a Manager operation. Only one operation can be in progress at a time.
Expand Down
117 changes: 117 additions & 0 deletions snapshots/stream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package snapshots

import (
"bufio"
"compress/zlib"
"io"

protoio "github.com/gogo/protobuf/io"
"github.com/gogo/protobuf/proto"

sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

const (
// Do not change chunk size without new snapshot format (must be uniform across nodes)
snapshotChunkSize = uint64(10e6)
snapshotBufferSize = int(snapshotChunkSize)
// Do not change compression level without new snapshot format (must be uniform across nodes)
snapshotCompressionLevel = 7
)

// StreamWriter set up a stream pipeline to serialize snapshot nodes:
// Exported Items -> delimited Protobuf -> zlib -> buffer -> chunkWriter -> chan io.ReadCloser
type StreamWriter struct {
chunkWriter *ChunkWriter
bufWriter *bufio.Writer
zWriter *zlib.Writer
protoWriter protoio.WriteCloser
}

// NewStreamWriter set up a stream pipeline to serialize snapshot DB records.
func NewStreamWriter(ch chan<- io.ReadCloser) *StreamWriter {
chunkWriter := NewChunkWriter(ch, snapshotChunkSize)
bufWriter := bufio.NewWriterSize(chunkWriter, snapshotBufferSize)
zWriter, err := zlib.NewWriterLevel(bufWriter, snapshotCompressionLevel)
if err != nil {
chunkWriter.CloseWithError(sdkerrors.Wrap(err, "zlib failure"))
return nil
}
protoWriter := protoio.NewDelimitedWriter(zWriter)
return &StreamWriter{
chunkWriter: chunkWriter,
bufWriter: bufWriter,
zWriter: zWriter,
protoWriter: protoWriter,
}
}

// WriteMsg implements protoio.Write interface
func (sw *StreamWriter) WriteMsg(msg proto.Message) error {
return sw.protoWriter.WriteMsg(msg)
}

// Close implements io.Closer interface
func (sw *StreamWriter) Close() error {
if err := sw.protoWriter.Close(); err != nil {
sw.chunkWriter.CloseWithError(err)
return err
}
if err := sw.zWriter.Close(); err != nil {
sw.chunkWriter.CloseWithError(err)
return err
}
if err := sw.bufWriter.Flush(); err != nil {
sw.chunkWriter.CloseWithError(err)
return err
}
return sw.chunkWriter.Close()
}

// CloseWithError pass error to chunkWriter
func (sw *StreamWriter) CloseWithError(err error) {
sw.chunkWriter.CloseWithError(err)
}

// StreamReader set up a restore stream pipeline
// chan io.ReadCloser -> chunkReader -> zlib -> delimited Protobuf -> ExportNode
type StreamReader struct {
chunkReader *ChunkReader
zReader io.ReadCloser
protoReader protoio.ReadCloser
}

// NewStreamReader set up a restore stream pipeline.
func NewStreamReader(chunks <-chan io.ReadCloser) (*StreamReader, error) {
chunkReader := NewChunkReader(chunks)
zReader, err := zlib.NewReader(chunkReader)
if err != nil {
return nil, sdkerrors.Wrap(err, "zlib failure")
}
protoReader := protoio.NewDelimitedReader(zReader, snapshotMaxItemSize)
return &StreamReader{
chunkReader: chunkReader,
zReader: zReader,
protoReader: protoReader,
}, nil
}

// ReadMsg implements protoio.Reader interface
func (sr *StreamReader) ReadMsg(msg proto.Message) error {
return sr.protoReader.ReadMsg(msg)
}

// Close implements io.Closer interface
func (sr *StreamReader) Close() error {
var err error
if err1 := sr.protoReader.Close(); err1 != nil {
err = err1
}
if err2 := sr.zReader.Close(); err2 != nil {
err = err2
}
if err3 := sr.chunkReader.Close(); err3 != nil {
err = err3
}
return err
}
19 changes: 19 additions & 0 deletions snapshots/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package snapshots

import (
"io"
"math"

snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

Expand Down Expand Up @@ -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
}
8 changes: 4 additions & 4 deletions store/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,11 @@ func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore {
return store
}

// getStoreByName performs a lookup of a StoreKey given a store name typically
// GetStoreByName performs a lookup of a StoreKey given a store name typically
// provided in a path. The StoreKey is then used to perform a lookup and return
// a Store. If the Store is wrapped in an inter-block cache, it will be unwrapped
// prior to being returned. If the StoreKey does not exist, nil is returned.
func (rs *Store) getStoreByName(name string) types.Store {
func (rs *Store) GetStoreByName(name string) types.Store {
key := rs.keysByName[name]
if key == nil {
return nil
Expand All @@ -560,7 +560,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery {
return sdkerrors.QueryResult(err)
}

store := rs.getStoreByName(storeName)
store := rs.GetStoreByName(storeName)
if store == nil {
return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no such store: %s", storeName))
}
Expand Down Expand Up @@ -816,7 +816,7 @@ func (rs *Store) Restore(
}
importer.Close()
}
store, ok := rs.getStoreByName(item.Store.Name).(*iavl.Store)
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)
}
Expand Down
Loading

0 comments on commit 9aa377e

Please sign in to comment.