-
Notifications
You must be signed in to change notification settings - Fork 413
/
snapshotter.go
145 lines (118 loc) · 3.58 KB
/
snapshotter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package keeper
import (
"encoding/hex"
"io"
"math"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/log"
snapshot "cosmossdk.io/store/snapshots/types"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/CosmWasm/wasmd/x/wasm/ioutils"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
var _ snapshot.ExtensionSnapshotter = &WasmSnapshotter{}
// SnapshotFormat format 1 is just gzipped wasm byte code for each item payload. No protobuf envelope, no metadata.
const SnapshotFormat = 1
type WasmSnapshotter struct {
wasm *Keeper
cms storetypes.MultiStore
}
func NewWasmSnapshotter(cms storetypes.MultiStore, wasm *Keeper) *WasmSnapshotter {
return &WasmSnapshotter{
wasm: wasm,
cms: cms,
}
}
func (ws *WasmSnapshotter) SnapshotName() string {
return types.ModuleName
}
func (ws *WasmSnapshotter) SnapshotFormat() uint32 {
return SnapshotFormat
}
func (ws *WasmSnapshotter) SupportedFormats() []uint32 {
// If we support older formats, add them here and handle them in Restore
return []uint32{SnapshotFormat}
}
func (ws *WasmSnapshotter) SnapshotExtension(height uint64, payloadWriter snapshot.ExtensionPayloadWriter) error {
cacheMS, err := ws.cms.CacheMultiStoreWithVersion(int64(height))
if err != nil {
return err
}
ctx := sdk.NewContext(cacheMS, tmproto.Header{}, false, log.NewNopLogger())
seenBefore := make(map[string]bool)
var rerr error
ws.wasm.IterateCodeInfos(ctx, func(id uint64, info types.CodeInfo) bool {
// Many code ids may point to the same code hash... only sync it once
hexHash := hex.EncodeToString(info.CodeHash)
// if seenBefore, just skip this one and move to the next
if seenBefore[hexHash] {
return false
}
seenBefore[hexHash] = true
// load code and abort on error
wasmBytes, err := ws.wasm.GetByteCode(ctx, id)
if err != nil {
rerr = err
return true
}
compressedWasm, err := ioutils.GzipIt(wasmBytes)
if err != nil {
rerr = err
return true
}
err = payloadWriter(compressedWasm)
if err != nil {
rerr = err
return true
}
return false
})
return rerr
}
func (ws *WasmSnapshotter) RestoreExtension(height uint64, format uint32, payloadReader snapshot.ExtensionPayloadReader) error {
if format == SnapshotFormat {
return ws.processAllItems(height, payloadReader, restoreV1, finalizeV1)
}
return snapshot.ErrUnknownFormat
}
func restoreV1(_ sdk.Context, k *Keeper, compressedCode []byte) error {
if !ioutils.IsGzip(compressedCode) {
return types.ErrInvalid.Wrap("not a gzip")
}
wasmCode, err := ioutils.Uncompress(compressedCode, math.MaxInt64)
if err != nil {
return errorsmod.Wrap(types.ErrCreateFailed, err.Error())
}
// FIXME: check which codeIDs the checksum matches??
_, err = k.wasmVM.StoreCodeUnchecked(wasmCode)
if err != nil {
return errorsmod.Wrap(types.ErrCreateFailed, err.Error())
}
return nil
}
func finalizeV1(ctx sdk.Context, k *Keeper) error {
// FIXME: ensure all codes have been uploaded?
return k.InitializePinnedCodes(ctx)
}
func (ws *WasmSnapshotter) processAllItems(
height uint64,
payloadReader snapshot.ExtensionPayloadReader,
cb func(sdk.Context, *Keeper, []byte) error,
finalize func(sdk.Context, *Keeper) error,
) error {
ctx := sdk.NewContext(ws.cms, tmproto.Header{Height: int64(height)}, false, log.NewNopLogger())
for {
payload, err := payloadReader()
if err == io.EOF {
break
} else if err != nil {
return err
}
if err := cb(ctx, ws.wasm, payload); err != nil {
return errorsmod.Wrap(err, "processing snapshot item")
}
}
return finalize(ctx, ws.wasm)
}