@agoric/cosmos 0.34.2-dev-7cc5def.0 → 0.34.2-dev-3ce0599.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/app.go +10 -1
- package/cmd/agd/main.go +5 -2
- package/daemon/cmd/root.go +93 -3
- package/git-revision.txt +1 -1
- package/package.json +2 -2
- package/x/swingset/genesis.go +88 -15
- package/x/swingset/keeper/swing_store_exports_handler.go +64 -42
- package/x/swingset/module.go +22 -10
package/app/app.go
CHANGED
|
@@ -126,6 +126,14 @@ import (
|
|
|
126
126
|
|
|
127
127
|
const appName = "agoric"
|
|
128
128
|
|
|
129
|
+
// FlagSwingStoreExportDir defines the config flag used to specify where a
|
|
130
|
+
// genesis swing-store export is expected. For start from genesis, the default
|
|
131
|
+
// value is config/swing-store in the home directory. For genesis export, the
|
|
132
|
+
// value is always a "swing-store" directory sibling to the exported
|
|
133
|
+
// genesis.json file.
|
|
134
|
+
// TODO: document this flag in config, likely alongside the genesis path
|
|
135
|
+
const FlagSwingStoreExportDir = "swing-store-export-dir"
|
|
136
|
+
|
|
129
137
|
var (
|
|
130
138
|
// DefaultNodeHome default home directories for the application daemon
|
|
131
139
|
DefaultNodeHome string
|
|
@@ -588,6 +596,7 @@ func NewAgoricApp(
|
|
|
588
596
|
app.EvidenceKeeper = *evidenceKeeper
|
|
589
597
|
|
|
590
598
|
skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants))
|
|
599
|
+
swingStoreExportDir := cast.ToString(appOpts.Get(FlagSwingStoreExportDir))
|
|
591
600
|
|
|
592
601
|
// NOTE: Any module instantiated in the module manager that is later modified
|
|
593
602
|
// must be passed by reference here.
|
|
@@ -617,7 +626,7 @@ func NewAgoricApp(
|
|
|
617
626
|
transferModule,
|
|
618
627
|
icaModule,
|
|
619
628
|
vstorage.NewAppModule(app.VstorageKeeper),
|
|
620
|
-
swingset.NewAppModule(app.SwingSetKeeper, setBootstrapNeeded, app.ensureControllerInited),
|
|
629
|
+
swingset.NewAppModule(app.SwingSetKeeper, &app.SwingStoreExportsHandler, setBootstrapNeeded, app.ensureControllerInited, swingStoreExportDir),
|
|
621
630
|
vibcModule,
|
|
622
631
|
vbankModule,
|
|
623
632
|
lienModule,
|
package/cmd/agd/main.go
CHANGED
|
@@ -13,7 +13,7 @@ import (
|
|
|
13
13
|
|
|
14
14
|
func main() {
|
|
15
15
|
// We need to delegate to our default app for running the actual chain.
|
|
16
|
-
|
|
16
|
+
launchVM := func(logger log.Logger) {
|
|
17
17
|
args := []string{"ag-chain-cosmos", "--home", gaia.DefaultNodeHome}
|
|
18
18
|
args = append(args, os.Args[1:]...)
|
|
19
19
|
|
|
@@ -22,12 +22,15 @@ func main() {
|
|
|
22
22
|
panic(lookErr)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
logger.Info("
|
|
25
|
+
logger.Info("agd delegating to JS executable", "binary", binary, "args", args)
|
|
26
26
|
execErr := syscall.Exec(binary, args, os.Environ())
|
|
27
27
|
if execErr != nil {
|
|
28
28
|
panic(execErr)
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
daemoncmd.OnStartHook = launchVM
|
|
33
|
+
daemoncmd.OnExportHook = launchVM
|
|
34
|
+
|
|
32
35
|
daemon.RunWithController(nil)
|
|
33
36
|
}
|
package/daemon/cmd/root.go
CHANGED
|
@@ -28,6 +28,7 @@ import (
|
|
|
28
28
|
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
|
29
29
|
"github.com/spf13/cast"
|
|
30
30
|
"github.com/spf13/cobra"
|
|
31
|
+
"github.com/spf13/viper"
|
|
31
32
|
tmcli "github.com/tendermint/tendermint/libs/cli"
|
|
32
33
|
"github.com/tendermint/tendermint/libs/log"
|
|
33
34
|
dbm "github.com/tendermint/tm-db"
|
|
@@ -40,7 +41,8 @@ import (
|
|
|
40
41
|
type Sender func(needReply bool, str string) (string, error)
|
|
41
42
|
|
|
42
43
|
var AppName = "agd"
|
|
43
|
-
var OnStartHook func(log.Logger)
|
|
44
|
+
var OnStartHook func(logger log.Logger)
|
|
45
|
+
var OnExportHook func(logger log.Logger)
|
|
44
46
|
|
|
45
47
|
// NewRootCmd creates a new root command for simd. It is called once in the
|
|
46
48
|
// main function.
|
|
@@ -133,6 +135,14 @@ func initRootCmd(sender Sender, rootCmd *cobra.Command, encodingConfig params.En
|
|
|
133
135
|
}
|
|
134
136
|
server.AddCommands(rootCmd, gaia.DefaultNodeHome, ac.newApp, ac.appExport, addModuleInitFlags)
|
|
135
137
|
|
|
138
|
+
hasVMController := sender != nil
|
|
139
|
+
for _, command := range rootCmd.Commands() {
|
|
140
|
+
if command.Name() == "export" {
|
|
141
|
+
extendCosmosExportCommand(command, hasVMController)
|
|
142
|
+
break
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
136
146
|
// add keybase, auxiliary RPC, query, and tx child commands
|
|
137
147
|
rootCmd.AddCommand(
|
|
138
148
|
rpc.StatusCommand(),
|
|
@@ -232,7 +242,16 @@ func (ac appCreator) newApp(
|
|
|
232
242
|
panic(err)
|
|
233
243
|
}
|
|
234
244
|
|
|
235
|
-
|
|
245
|
+
homePath := cast.ToString(appOpts.Get(flags.FlagHome))
|
|
246
|
+
|
|
247
|
+
// Set a default value for FlagSwingStoreExportDir based on the homePath
|
|
248
|
+
// in case we need to InitGenesis with swing-store data
|
|
249
|
+
viper, ok := appOpts.(*viper.Viper)
|
|
250
|
+
if ok && cast.ToString(appOpts.Get(gaia.FlagSwingStoreExportDir)) == "" {
|
|
251
|
+
viper.Set(gaia.FlagSwingStoreExportDir, filepath.Join(homePath, "config", ExportedSwingStoreDirectoryName))
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
snapshotDir := filepath.Join(homePath, "data", "snapshots")
|
|
236
255
|
snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir)
|
|
237
256
|
if err != nil {
|
|
238
257
|
panic(err)
|
|
@@ -245,7 +264,7 @@ func (ac appCreator) newApp(
|
|
|
245
264
|
return gaia.NewAgoricApp(
|
|
246
265
|
ac.sender,
|
|
247
266
|
logger, db, traceStore, true, skipUpgradeHeights,
|
|
248
|
-
|
|
267
|
+
homePath,
|
|
249
268
|
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
|
|
250
269
|
ac.encCfg,
|
|
251
270
|
appOpts,
|
|
@@ -263,6 +282,74 @@ func (ac appCreator) newApp(
|
|
|
263
282
|
)
|
|
264
283
|
}
|
|
265
284
|
|
|
285
|
+
const (
|
|
286
|
+
// FlagExportDir is the command-line flag for the "export" command specifying
|
|
287
|
+
// where the output of the export should be placed. It contains both the
|
|
288
|
+
// items names below: the genesis file, and a directory containing the
|
|
289
|
+
// exported swing-store artifacts
|
|
290
|
+
FlagExportDir = "export-dir"
|
|
291
|
+
// ExportedGenesisFileName is the file name used to save the genesis in the export-dir
|
|
292
|
+
ExportedGenesisFileName = "genesis.json"
|
|
293
|
+
// ExportedSwingStoreDirectoryName is the directory name used to save the swing-store
|
|
294
|
+
// export (artifacts only) in the export-dir
|
|
295
|
+
ExportedSwingStoreDirectoryName = "swing-store"
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
// extendCosmosExportCommand monkey-patches the "export" command added by
|
|
299
|
+
// cosmos-sdk to add a required "export-dir" command-line flag, and create the
|
|
300
|
+
// genesis export in the specified directory.
|
|
301
|
+
func extendCosmosExportCommand(cmd *cobra.Command, hasVMController bool) {
|
|
302
|
+
cmd.Flags().String(FlagExportDir, "", "The directory where to create the genesis export")
|
|
303
|
+
err := cmd.MarkFlagRequired(FlagExportDir)
|
|
304
|
+
if err != nil {
|
|
305
|
+
panic(err)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
originalRunE := cmd.RunE
|
|
309
|
+
|
|
310
|
+
extendedRunE := func(cmd *cobra.Command, args []string) error {
|
|
311
|
+
serverCtx := server.GetServerContextFromCmd(cmd)
|
|
312
|
+
|
|
313
|
+
exportDir, _ := cmd.Flags().GetString(FlagExportDir)
|
|
314
|
+
err := os.MkdirAll(exportDir, os.ModePerm)
|
|
315
|
+
if err != nil {
|
|
316
|
+
return err
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
genesisPath := filepath.Join(exportDir, ExportedGenesisFileName)
|
|
320
|
+
swingStoreExportPath := filepath.Join(exportDir, ExportedSwingStoreDirectoryName)
|
|
321
|
+
|
|
322
|
+
err = os.MkdirAll(swingStoreExportPath, os.ModePerm)
|
|
323
|
+
if err != nil {
|
|
324
|
+
return err
|
|
325
|
+
}
|
|
326
|
+
// We unconditionally set FlagSwingStoreExportDir as for export, it makes
|
|
327
|
+
// little sense for users to control this location separately, and we don't
|
|
328
|
+
// want to override any swing-store artifacts that may be associated to the
|
|
329
|
+
// current genesis.
|
|
330
|
+
serverCtx.Viper.Set(gaia.FlagSwingStoreExportDir, swingStoreExportPath)
|
|
331
|
+
|
|
332
|
+
// This will fail is a genesis.json already exists in the export-dir
|
|
333
|
+
genesisFile, err := os.OpenFile(genesisPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, os.ModePerm)
|
|
334
|
+
if err != nil {
|
|
335
|
+
return err
|
|
336
|
+
}
|
|
337
|
+
defer genesisFile.Close()
|
|
338
|
+
|
|
339
|
+
cmd.SetOut(genesisFile)
|
|
340
|
+
|
|
341
|
+
return originalRunE(cmd, args)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Only modify the command handler when we have a VM controller to handle
|
|
345
|
+
// the full export logic. Otherwise, appExport will just exec the VM program
|
|
346
|
+
// (OnExportHook), which will result in re-entering this flow with the VM
|
|
347
|
+
// controller set.
|
|
348
|
+
if hasVMController {
|
|
349
|
+
cmd.RunE = extendedRunE
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
266
353
|
func (ac appCreator) appExport(
|
|
267
354
|
logger log.Logger,
|
|
268
355
|
db dbm.DB,
|
|
@@ -272,6 +359,9 @@ func (ac appCreator) appExport(
|
|
|
272
359
|
jailAllowedAddrs []string,
|
|
273
360
|
appOpts servertypes.AppOptions,
|
|
274
361
|
) (servertypes.ExportedApp, error) {
|
|
362
|
+
if OnExportHook != nil {
|
|
363
|
+
OnExportHook(logger)
|
|
364
|
+
}
|
|
275
365
|
|
|
276
366
|
homePath, ok := appOpts.Get(flags.FlagHome).(string)
|
|
277
367
|
if !ok || homePath == "" {
|
package/git-revision.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3ce0599
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/cosmos",
|
|
3
|
-
"version": "0.34.2-dev-
|
|
3
|
+
"version": "0.34.2-dev-3ce0599.0+3ce0599",
|
|
4
4
|
"description": "Connect JS to the Cosmos blockchain SDK",
|
|
5
5
|
"parsers": {
|
|
6
6
|
"js": "mjs"
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "3ce0599d5173b802598b5bedf57d3c30f016f789"
|
|
39
39
|
}
|
package/x/swingset/genesis.go
CHANGED
|
@@ -4,6 +4,8 @@ import (
|
|
|
4
4
|
// "os"
|
|
5
5
|
"fmt"
|
|
6
6
|
|
|
7
|
+
agoric "github.com/Agoric/agoric-sdk/golang/cosmos/types"
|
|
8
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/keeper"
|
|
7
9
|
"github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/types"
|
|
8
10
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
9
11
|
)
|
|
@@ -28,33 +30,58 @@ func DefaultGenesisState() *types.GenesisState {
|
|
|
28
30
|
|
|
29
31
|
// InitGenesis initializes the (Cosmos-side) SwingSet state from the GenesisState.
|
|
30
32
|
// Returns whether the app should send a bootstrap action to the controller.
|
|
31
|
-
func InitGenesis(ctx sdk.Context,
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
func InitGenesis(ctx sdk.Context, k Keeper, swingStoreExportsHandler *SwingStoreExportsHandler, swingStoreExportDir string, data *types.GenesisState) bool {
|
|
34
|
+
k.SetParams(ctx, data.GetParams())
|
|
35
|
+
k.SetState(ctx, data.GetState())
|
|
34
36
|
|
|
35
37
|
swingStoreExportData := data.GetSwingStoreExportData()
|
|
36
|
-
if len(swingStoreExportData)
|
|
37
|
-
|
|
38
|
-
panic("genesis with swing-store state not implemented")
|
|
38
|
+
if len(swingStoreExportData) == 0 {
|
|
39
|
+
return true
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
artifactProvider, err := keeper.OpenSwingStoreExportDirectory(swingStoreExportDir)
|
|
43
|
+
if err != nil {
|
|
44
|
+
panic(err)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
swingStore := k.GetSwingStore(ctx)
|
|
48
|
+
|
|
49
|
+
for _, entry := range swingStoreExportData {
|
|
50
|
+
swingStore.Set([]byte(entry.Key), []byte(entry.Value))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
snapshotHeight := uint64(ctx.BlockHeight())
|
|
54
|
+
|
|
55
|
+
getExportDataReader := func() (agoric.KVEntryReader, error) {
|
|
56
|
+
exportDataIterator := swingStore.Iterator(nil, nil)
|
|
57
|
+
return agoric.NewKVIteratorReader(exportDataIterator), nil
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
err = swingStoreExportsHandler.RestoreExport(
|
|
61
|
+
keeper.SwingStoreExportProvider{
|
|
62
|
+
BlockHeight: snapshotHeight,
|
|
63
|
+
GetExportDataReader: getExportDataReader,
|
|
64
|
+
ReadNextArtifact: artifactProvider.ReadNextArtifact,
|
|
65
|
+
},
|
|
66
|
+
keeper.SwingStoreRestoreOptions{
|
|
67
|
+
ArtifactMode: keeper.SwingStoreArtifactModeReplay,
|
|
68
|
+
ExportDataMode: keeper.SwingStoreExportDataModeAll,
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
if err != nil {
|
|
72
|
+
panic(err)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return false
|
|
43
76
|
}
|
|
44
77
|
|
|
45
|
-
func ExportGenesis(ctx sdk.Context, k Keeper) *types.GenesisState {
|
|
78
|
+
func ExportGenesis(ctx sdk.Context, k Keeper, swingStoreExportsHandler *SwingStoreExportsHandler, swingStoreExportDir string) *types.GenesisState {
|
|
46
79
|
gs := &types.GenesisState{
|
|
47
80
|
Params: k.GetParams(ctx),
|
|
48
81
|
State: k.GetState(ctx),
|
|
49
82
|
SwingStoreExportData: []*types.SwingStoreExportDataEntry{},
|
|
50
83
|
}
|
|
51
84
|
|
|
52
|
-
// Only export the swing-store shadow copy for now
|
|
53
|
-
// TODO:
|
|
54
|
-
// - perform state-sync export with check blockHeight (figure out how to
|
|
55
|
-
// handle export of historical height),
|
|
56
|
-
// - include swing-store artifacts in genesis state
|
|
57
|
-
// See https://github.com/Agoric/agoric-sdk/issues/6527
|
|
58
85
|
exportDataIterator := k.GetSwingStore(ctx).Iterator(nil, nil)
|
|
59
86
|
defer exportDataIterator.Close()
|
|
60
87
|
for ; exportDataIterator.Valid(); exportDataIterator.Next() {
|
|
@@ -64,5 +91,51 @@ func ExportGenesis(ctx sdk.Context, k Keeper) *types.GenesisState {
|
|
|
64
91
|
}
|
|
65
92
|
gs.SwingStoreExportData = append(gs.SwingStoreExportData, &entry)
|
|
66
93
|
}
|
|
94
|
+
|
|
95
|
+
snapshotHeight := uint64(ctx.BlockHeight())
|
|
96
|
+
|
|
97
|
+
err := swingStoreExportsHandler.InitiateExport(
|
|
98
|
+
// The export will fail if the export of a historical height was requested
|
|
99
|
+
snapshotHeight,
|
|
100
|
+
swingStoreGenesisEventHandler{exportDir: swingStoreExportDir, snapshotHeight: snapshotHeight},
|
|
101
|
+
// The export will fail if the swing-store does not contain all replay artifacts
|
|
102
|
+
keeper.SwingStoreExportOptions{
|
|
103
|
+
ArtifactMode: keeper.SwingStoreArtifactModeReplay,
|
|
104
|
+
ExportDataMode: keeper.SwingStoreExportDataModeSkip,
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
if err != nil {
|
|
108
|
+
panic(err)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
err = keeper.WaitUntilSwingStoreExportDone()
|
|
112
|
+
if err != nil {
|
|
113
|
+
panic(err)
|
|
114
|
+
}
|
|
115
|
+
|
|
67
116
|
return gs
|
|
68
117
|
}
|
|
118
|
+
|
|
119
|
+
type swingStoreGenesisEventHandler struct {
|
|
120
|
+
exportDir string
|
|
121
|
+
snapshotHeight uint64
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
func (eventHandler swingStoreGenesisEventHandler) OnExportStarted(height uint64, retrieveSwingStoreExport func() error) error {
|
|
125
|
+
return retrieveSwingStoreExport()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func (eventHandler swingStoreGenesisEventHandler) OnExportRetrieved(provider keeper.SwingStoreExportProvider) error {
|
|
129
|
+
if eventHandler.snapshotHeight != provider.BlockHeight {
|
|
130
|
+
return fmt.Errorf("snapshot block height (%d) doesn't match requested height (%d)", provider.BlockHeight, eventHandler.snapshotHeight)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
artifactsProvider := keeper.SwingStoreExportProvider{
|
|
134
|
+
GetExportDataReader: func() (agoric.KVEntryReader, error) {
|
|
135
|
+
return nil, nil
|
|
136
|
+
},
|
|
137
|
+
ReadNextArtifact: provider.ReadNextArtifact,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return keeper.WriteSwingStoreExportToDirectory(artifactsProvider, eventHandler.exportDir)
|
|
141
|
+
}
|
|
@@ -638,19 +638,42 @@ func (exportsHandler SwingStoreExportsHandler) retrieveExport(onExportRetrieved
|
|
|
638
638
|
|
|
639
639
|
defer os.RemoveAll(exportDir)
|
|
640
640
|
|
|
641
|
-
|
|
641
|
+
provider, err := OpenSwingStoreExportDirectory(exportDir)
|
|
642
642
|
if err != nil {
|
|
643
643
|
return err
|
|
644
644
|
}
|
|
645
645
|
|
|
646
|
-
|
|
647
|
-
|
|
646
|
+
if blockHeight != 0 && provider.BlockHeight != blockHeight {
|
|
647
|
+
return fmt.Errorf("export manifest blockHeight (%d) doesn't match (%d)", provider.BlockHeight, blockHeight)
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
err = onExportRetrieved(provider)
|
|
648
651
|
if err != nil {
|
|
649
652
|
return err
|
|
650
653
|
}
|
|
651
654
|
|
|
652
|
-
|
|
653
|
-
|
|
655
|
+
operationDetails.logger.Info("retrieved swing-store export", "exportDir", exportDir)
|
|
656
|
+
|
|
657
|
+
return nil
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// OpenSwingStoreExportDirectory creates an export provider from a swing-store
|
|
661
|
+
// export saved on disk in the provided directory. It expects the export manifest
|
|
662
|
+
// to be present in that directory. The provider's function will read the
|
|
663
|
+
// export's data and artifacts from disk on demand. Each artifact is using a
|
|
664
|
+
// dedicated file, and the export data is read from a jsonl-like file, if any.
|
|
665
|
+
// The export manifest filename and overall export format is common with the JS
|
|
666
|
+
// swing-store import/export logic.
|
|
667
|
+
func OpenSwingStoreExportDirectory(exportDir string) (SwingStoreExportProvider, error) {
|
|
668
|
+
rawManifest, err := os.ReadFile(filepath.Join(exportDir, ExportManifestFilename))
|
|
669
|
+
if err != nil {
|
|
670
|
+
return SwingStoreExportProvider{}, err
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
var manifest exportManifest
|
|
674
|
+
err = json.Unmarshal(rawManifest, &manifest)
|
|
675
|
+
if err != nil {
|
|
676
|
+
return SwingStoreExportProvider{}, err
|
|
654
677
|
}
|
|
655
678
|
|
|
656
679
|
getExportDataReader := func() (agoric.KVEntryReader, error) {
|
|
@@ -689,18 +712,7 @@ func (exportsHandler SwingStoreExportsHandler) retrieveExport(onExportRetrieved
|
|
|
689
712
|
return artifact, err
|
|
690
713
|
}
|
|
691
714
|
|
|
692
|
-
|
|
693
|
-
if err != nil {
|
|
694
|
-
return err
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// if nextArtifact != len(manifest.Artifacts) {
|
|
698
|
-
// return errors.New("not all export artifacts were retrieved")
|
|
699
|
-
// }
|
|
700
|
-
|
|
701
|
-
operationDetails.logger.Info("retrieved swing-store export", "exportDir", exportDir)
|
|
702
|
-
|
|
703
|
-
return nil
|
|
715
|
+
return SwingStoreExportProvider{BlockHeight: manifest.BlockHeight, GetExportDataReader: getExportDataReader, ReadNextArtifact: readNextArtifact}, nil
|
|
704
716
|
}
|
|
705
717
|
|
|
706
718
|
// RestoreExport restores the JS swing-store using previously exported data and artifacts.
|
|
@@ -739,8 +751,41 @@ func (exportsHandler SwingStoreExportsHandler) RestoreExport(provider SwingStore
|
|
|
739
751
|
}
|
|
740
752
|
defer os.RemoveAll(exportDir)
|
|
741
753
|
|
|
742
|
-
|
|
754
|
+
err = WriteSwingStoreExportToDirectory(provider, exportDir)
|
|
755
|
+
if err != nil {
|
|
756
|
+
return err
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
action := &swingStoreRestoreExportAction{
|
|
760
|
+
Type: swingStoreExportActionType,
|
|
743
761
|
BlockHeight: blockHeight,
|
|
762
|
+
Request: restoreRequest,
|
|
763
|
+
Args: [1]swingStoreImportOptions{{
|
|
764
|
+
ExportDir: exportDir,
|
|
765
|
+
ArtifactMode: restoreOptions.ArtifactMode,
|
|
766
|
+
ExportDataMode: restoreOptions.ExportDataMode,
|
|
767
|
+
}},
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
_, err = exportsHandler.blockingSend(action, true)
|
|
771
|
+
if err != nil {
|
|
772
|
+
return err
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
exportsHandler.logger.Info("restored swing-store export", "exportDir", exportDir, "height", blockHeight)
|
|
776
|
+
|
|
777
|
+
return nil
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// WriteSwingStoreExportToDirectory consumes a provider and saves a swing-store
|
|
781
|
+
// export to disk in the provided directory. It creates files for each artifact
|
|
782
|
+
// deriving a filename from the artifact name, and stores any "export data" in
|
|
783
|
+
// a jsonl-like file, before saving the export manifest linking these together.
|
|
784
|
+
// The export manifest filename and overall export format is common with the JS
|
|
785
|
+
// swing-store import/export logic.
|
|
786
|
+
func WriteSwingStoreExportToDirectory(provider SwingStoreExportProvider, exportDir string) error {
|
|
787
|
+
manifest := exportManifest{
|
|
788
|
+
BlockHeight: provider.BlockHeight,
|
|
744
789
|
}
|
|
745
790
|
|
|
746
791
|
exportDataReader, err := provider.GetExportDataReader()
|
|
@@ -808,28 +853,5 @@ func (exportsHandler SwingStoreExportsHandler) RestoreExport(provider SwingStore
|
|
|
808
853
|
if err != nil {
|
|
809
854
|
return err
|
|
810
855
|
}
|
|
811
|
-
|
|
812
|
-
if err != nil {
|
|
813
|
-
return err
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
action := &swingStoreRestoreExportAction{
|
|
817
|
-
Type: swingStoreExportActionType,
|
|
818
|
-
BlockHeight: blockHeight,
|
|
819
|
-
Request: restoreRequest,
|
|
820
|
-
Args: [1]swingStoreImportOptions{{
|
|
821
|
-
ExportDir: exportDir,
|
|
822
|
-
ArtifactMode: restoreOptions.ArtifactMode,
|
|
823
|
-
ExportDataMode: restoreOptions.ExportDataMode,
|
|
824
|
-
}},
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
_, err = exportsHandler.blockingSend(action, true)
|
|
828
|
-
if err != nil {
|
|
829
|
-
return err
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
exportsHandler.logger.Info("restored swing-store export", "exportDir", exportDir, "height", blockHeight)
|
|
833
|
-
|
|
834
|
-
return nil
|
|
856
|
+
return writeExportFile(ExportManifestFilename, manifestBytes)
|
|
835
857
|
}
|
package/x/swingset/module.go
CHANGED
|
@@ -80,18 +80,22 @@ func (AppModuleBasic) GetTxCmd() *cobra.Command {
|
|
|
80
80
|
|
|
81
81
|
type AppModule struct {
|
|
82
82
|
AppModuleBasic
|
|
83
|
-
keeper
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
keeper Keeper
|
|
84
|
+
swingStoreExportsHandler *SwingStoreExportsHandler
|
|
85
|
+
setBootstrapNeeded func()
|
|
86
|
+
ensureControllerInited func(sdk.Context)
|
|
87
|
+
swingStoreExportDir string
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
// NewAppModule creates a new AppModule Object
|
|
89
|
-
func NewAppModule(k Keeper, setBootstrapNeeded func(), ensureControllerInited func(sdk.Context)) AppModule {
|
|
91
|
+
func NewAppModule(k Keeper, swingStoreExportsHandler *SwingStoreExportsHandler, setBootstrapNeeded func(), ensureControllerInited func(sdk.Context), swingStoreExportDir string) AppModule {
|
|
90
92
|
am := AppModule{
|
|
91
|
-
AppModuleBasic:
|
|
92
|
-
keeper:
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
AppModuleBasic: AppModuleBasic{},
|
|
94
|
+
keeper: k,
|
|
95
|
+
swingStoreExportsHandler: swingStoreExportsHandler,
|
|
96
|
+
setBootstrapNeeded: setBootstrapNeeded,
|
|
97
|
+
ensureControllerInited: ensureControllerInited,
|
|
98
|
+
swingStoreExportDir: swingStoreExportDir,
|
|
95
99
|
}
|
|
96
100
|
return am
|
|
97
101
|
}
|
|
@@ -150,10 +154,17 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V
|
|
|
150
154
|
return []abci.ValidatorUpdate{}
|
|
151
155
|
}
|
|
152
156
|
|
|
157
|
+
func (am AppModule) checkSwingStoreExportSetup() {
|
|
158
|
+
if am.swingStoreExportDir == "" {
|
|
159
|
+
panic(fmt.Errorf("SwingStore export dir not set"))
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
153
163
|
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {
|
|
154
164
|
var genesisState types.GenesisState
|
|
155
165
|
cdc.MustUnmarshalJSON(data, &genesisState)
|
|
156
|
-
|
|
166
|
+
am.checkSwingStoreExportSetup()
|
|
167
|
+
bootstrapNeeded := InitGenesis(ctx, am.keeper, am.swingStoreExportsHandler, am.swingStoreExportDir, &genesisState)
|
|
157
168
|
if bootstrapNeeded {
|
|
158
169
|
am.setBootstrapNeeded()
|
|
159
170
|
}
|
|
@@ -161,6 +172,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.
|
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
|
|
164
|
-
|
|
175
|
+
am.checkSwingStoreExportSetup()
|
|
176
|
+
gs := ExportGenesis(ctx, am.keeper, am.swingStoreExportsHandler, am.swingStoreExportDir)
|
|
165
177
|
return cdc.MustMarshalJSON(gs)
|
|
166
178
|
}
|