@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 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
- daemoncmd.OnStartHook = func(logger log.Logger) {
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("Start chain delegating to JS executable", "binary", binary, "args", args)
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
  }
@@ -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
- snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots")
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
- cast.ToString(appOpts.Get(flags.FlagHome)),
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
- 7cc5def
1
+ 3ce0599
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/cosmos",
3
- "version": "0.34.2-dev-7cc5def.0+7cc5def",
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": "7cc5defcf5c6d126fe39c94be4953afd11105a5c"
38
+ "gitHead": "3ce0599d5173b802598b5bedf57d3c30f016f789"
39
39
  }
@@ -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, keeper Keeper, data *types.GenesisState) bool {
32
- keeper.SetParams(ctx, data.GetParams())
33
- keeper.SetState(ctx, data.GetState())
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) > 0 {
37
- // See https://github.com/Agoric/agoric-sdk/issues/6527
38
- panic("genesis with swing-store state not implemented")
38
+ if len(swingStoreExportData) == 0 {
39
+ return true
39
40
  }
40
41
 
41
- // TODO: bootstrap only if not restoring swing-store from genesis state
42
- return true
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
- rawManifest, err := os.ReadFile(filepath.Join(exportDir, ExportManifestFilename))
641
+ provider, err := OpenSwingStoreExportDirectory(exportDir)
642
642
  if err != nil {
643
643
  return err
644
644
  }
645
645
 
646
- var manifest exportManifest
647
- err = json.Unmarshal(rawManifest, &manifest)
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
- if blockHeight != 0 && manifest.BlockHeight != blockHeight {
653
- return fmt.Errorf("export manifest blockHeight (%d) doesn't match (%d)", manifest.BlockHeight, blockHeight)
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
- err = onExportRetrieved(SwingStoreExportProvider{BlockHeight: manifest.BlockHeight, GetExportDataReader: getExportDataReader, ReadNextArtifact: readNextArtifact})
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
- manifest := exportManifest{
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
- err = writeExportFile(ExportManifestFilename, manifestBytes)
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
  }
@@ -80,18 +80,22 @@ func (AppModuleBasic) GetTxCmd() *cobra.Command {
80
80
 
81
81
  type AppModule struct {
82
82
  AppModuleBasic
83
- keeper Keeper
84
- setBootstrapNeeded func()
85
- ensureControllerInited func(sdk.Context)
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: AppModuleBasic{},
92
- keeper: k,
93
- setBootstrapNeeded: setBootstrapNeeded,
94
- ensureControllerInited: ensureControllerInited,
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
- bootstrapNeeded := InitGenesis(ctx, am.keeper, &genesisState)
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
- gs := ExportGenesis(ctx, am.keeper)
175
+ am.checkSwingStoreExportSetup()
176
+ gs := ExportGenesis(ctx, am.keeper, am.swingStoreExportsHandler, am.swingStoreExportDir)
165
177
  return cdc.MustMarshalJSON(gs)
166
178
  }