Skip to content

Commit

Permalink
feat: Make extension snapshotter interface safer to use (cosmos#11825)
Browse files Browse the repository at this point in the history
* Make extension snapshotter interface safer to use

Closes: cosmos#11824
Solution:
- Use new methods `SnapshotExtension`/`RestoreExtension` to handle payload stream specifically.
- Improve unit tests.

* update changelog

* Update snapshots/types/util.go

* changelog

* go linter

* Update CHANGELOG.md

Co-authored-by: Aleksandr Bezobchuk <[email protected]>

(cherry picked from commit e397434)
  • Loading branch information
yihuang authored and JeancarloBarrios committed Sep 28, 2024
1 parent 82e83d5 commit e977735
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### API Breaking Changes

* [#13673](https://github.com/cosmos/cosmos-sdk/pull/13673) The `GetFromFields` function now takes `Context` as an argument and removes `genOnly`.
* (store) [#11825](https://github.com/cosmos/cosmos-sdk/pull/11825) Make extension snapshotter interface safer to use, renamed the util function `WriteExtensionItem` to `WriteExtensionPayload`.

## v0.45.10 - 2022-10-24

Expand Down
20 changes: 17 additions & 3 deletions docs/architecture/adr-049-state-sync-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
## Changelog

- Jan 19, 2022: Initial Draft
- Apr 29, 2022: Safer extension snapshotter interface

## Status

Draft, Under Implementation
Implemented

## Abstract

Expand Down Expand Up @@ -107,11 +108,16 @@ func (m *Manager) RegisterExtensions(extensions ...types.ExtensionSnapshotter) e
On top of the existing `Snapshotter` interface for the `multistore`, we add `ExtensionSnapshotter` interface for the extension snapshotters. Three more function signatures: `SnapshotFormat()`, `SupportedFormats()` and `SnapshotName()` are added to `ExtensionSnapshotter`.

```go
// ExtensionPayloadReader read extension payloads,
// it returns io.EOF when reached either end of stream or the extension boundaries.
type ExtensionPayloadReader = func() ([]byte, error)

// ExtensionPayloadWriter is a helper to write extension payloads to underlying stream.
type ExtensionPayloadWriter = func([]byte) error

// ExtensionSnapshotter is an extension Snapshotter that is appended to the snapshot stream.
// ExtensionSnapshotter has an unique name and manages it's own internal formats.
type ExtensionSnapshotter interface {
Snapshotter

// SnapshotName returns the name of snapshotter, it should be unique in the manager.
SnapshotName() string

Expand All @@ -120,6 +126,14 @@ type ExtensionSnapshotter interface {

// SupportedFormats returns a list of formats it can restore from.
SupportedFormats() []uint32

// SnapshotExtension writes extension payloads into the underlying protobuf stream.
SnapshotExtension(height uint64, payloadWriter ExtensionPayloadWriter) error

// RestoreExtension restores an extension state snapshot,
// the payload reader returns `io.EOF` when reached the extension boundaries.
RestoreExtension(height uint64, format uint32, payloadReader ExtensionPayloadReader) error

}
```

Expand Down
17 changes: 10 additions & 7 deletions store/snapshots/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,12 @@ func TestManager_Take(t *testing.T) {
snapshotter := &mockSnapshotter{
items: items,
}
expectChunks := snapshotItems(items)
extSnapshotter := newExtSnapshotter(10)

expectChunks := snapshotItems(items, extSnapshotter)
manager := snapshots.NewManager(store, snapshotter)
err := manager.RegisterExtensions(extSnapshotter)
require.NoError(t, err)

// nil manager should return error
_, err = (*snapshots.Manager)(nil).Create(1)
Expand All @@ -93,7 +97,7 @@ func TestManager_Take(t *testing.T) {
Height: 5,
Format: snapshotter.SnapshotFormat(),
Chunks: 1,
Hash: []uint8{0xcd, 0x17, 0x9e, 0x7f, 0x28, 0xb6, 0x82, 0x90, 0xc7, 0x25, 0xf3, 0x42, 0xac, 0x65, 0x73, 0x50, 0xaa, 0xa0, 0x10, 0x5c, 0x40, 0x8c, 0xd5, 0x1, 0xed, 0x82, 0xb5, 0xca, 0x8b, 0xe0, 0x83, 0xa2},
Hash: []uint8{0x89, 0xfa, 0x18, 0xbc, 0x5a, 0xe3, 0xdc, 0x36, 0xa6, 0x95, 0x5, 0x17, 0xf9, 0x2, 0x1a, 0x55, 0x36, 0x16, 0x5d, 0x4b, 0x8b, 0x2b, 0x3d, 0xfd, 0xe, 0x2f, 0xb6, 0x40, 0x6b, 0xc3, 0xbc, 0x23},
Metadata: types.Metadata{
ChunkHashes: checksums(expectChunks),
},
Expand Down Expand Up @@ -132,11 +136,9 @@ func TestManager_Prune(t *testing.T) {

func TestManager_Restore(t *testing.T) {
store := setupStore(t)
target := &mockSnapshotter{
prunedHeights: make(map[int64]struct{}),
}
target := &mockSnapshotter{}
extSnapshotter := newExtSnapshotter(0)
manager := snapshots.NewManager(store, opts, target, nil, log.NewNopLogger())
manager := snapshots.NewManager(store, target)
err := manager.RegisterExtensions(extSnapshotter)
require.NoError(t, err)

Expand All @@ -146,7 +148,7 @@ func TestManager_Restore(t *testing.T) {
{7, 8, 9},
}

chunks := snapshotItems(expectItems)
chunks := snapshotItems(expectItems, newExtSnapshotter(10))

// Restore errors on invalid format
err = manager.Restore(types.Snapshot{
Expand Down Expand Up @@ -209,6 +211,7 @@ func TestManager_Restore(t *testing.T) {
}

assert.Equal(t, expectItems, target.items)
assert.Equal(t, 10, len(extSnapshotter.state))

// Starting a new restore should fail now, because the target already has contents.
err = manager.Restore(types.Snapshot{
Expand Down

0 comments on commit e977735

Please sign in to comment.