@agoric/cosmos 0.34.2-dev-ecf2d8e.0 → 0.35.0-other-dev-70beeb7.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/app/app.go +103 -14
  3. package/app/const.go +6 -0
  4. package/cmd/agd/main.go +11 -133
  5. package/cmd/libdaemon/main.go +53 -67
  6. package/daemon/cmd/root.go +24 -55
  7. package/daemon/main.go +1 -3
  8. package/git-revision.txt +1 -1
  9. package/package.json +3 -3
  10. package/proto/agoric/vstorage/query.proto +1 -53
  11. package/vm/controller.go +18 -8
  12. package/x/lien/lien.go +4 -6
  13. package/x/lien/lien_test.go +15 -19
  14. package/x/swingset/abci.go +2 -3
  15. package/x/swingset/swingset.go +2 -4
  16. package/x/swingset/types/default-params.go +1 -1
  17. package/x/swingset/types/msgs.pb.go +16 -16
  18. package/x/vbank/vbank.go +10 -11
  19. package/x/vbank/vbank_test.go +5 -5
  20. package/x/vibc/ibc.go +11 -12
  21. package/x/vibc/keeper/keeper.go +15 -1
  22. package/x/vibc/types/expected_keepers.go +1 -2
  23. package/x/vstorage/keeper/grpc_query.go +0 -221
  24. package/x/vstorage/keeper/querier.go +11 -31
  25. package/x/vstorage/types/path_keys.go +10 -22
  26. package/x/vstorage/types/path_keys_test.go +18 -84
  27. package/x/vstorage/types/query.pb.go +36 -646
  28. package/x/vstorage/types/query.pb.gw.go +0 -119
  29. package/x/vstorage/vstorage.go +15 -16
  30. package/x/vstorage/vstorage_test.go +4 -4
  31. package/cmd/agd/agvm.go +0 -42
  32. package/vm/client.go +0 -113
  33. package/vm/client_test.go +0 -184
  34. package/vm/jsonrpcconn/jsonrpcconn.go +0 -160
  35. package/vm/jsonrpcconn/jsonrpcconn_test.go +0 -126
  36. package/vm/server.go +0 -23
  37. package/x/vstorage/README.md +0 -95
  38. package/x/vstorage/capdata/capdata.go +0 -298
  39. package/x/vstorage/capdata/capdata_test.go +0 -352
  40. package/x/vstorage/keeper/keeper_grpc_test.go +0 -300
package/CHANGELOG.md CHANGED
@@ -3,6 +3,51 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.35.0-u11.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/cosmos@0.34.1...@agoric/cosmos@0.35.0-u11.0) (2023-08-24)
7
+
8
+
9
+ ### ⚠ BREAKING CHANGES
10
+
11
+ * **cosmos:** add required export-dir export cmd option
12
+ * remove deprecated `ag-cosmos-helper`
13
+
14
+ ### Features
15
+
16
+ * **agd:** try harder to find cosmic-swingset ([a1d1666](https://github.com/Agoric/agoric-sdk/commit/a1d1666997c2f5b9c7bf14748f6d9603c0b3c5f9))
17
+ * **cosmic-swingset:** add repair-metadata snapshot restore option ([ebbb982](https://github.com/Agoric/agoric-sdk/commit/ebbb9829f1f845c0932ae92b23d0d43be9a0e196))
18
+ * **cosmic-swingset:** replace import/export options ([393b91b](https://github.com/Agoric/agoric-sdk/commit/393b91baaa25c61364955102e8cfcdcaec90870d))
19
+ * **cosmic-swingset:** use x/swingset for swing-store export data ([3336b62](https://github.com/Agoric/agoric-sdk/commit/3336b62fbb10bd2293a832f8c30e590530d14213))
20
+ * **cosmos:** add required export-dir export cmd option ([8d2571c](https://github.com/Agoric/agoric-sdk/commit/8d2571c51c2fe08d630dd2897d7e5e1b45ab45c9))
21
+ * **cosmos:** fix and migrate swing-store ([6ba1957](https://github.com/Agoric/agoric-sdk/commit/6ba19571688518dcfdc4553a0c822695a61908b1))
22
+ * **cosmos:** KVEntry implements json Marshaler and Unmarshaller ([6d2fe11](https://github.com/Agoric/agoric-sdk/commit/6d2fe11d144c5bbdc1611b59c84b6842e8084cb9))
23
+ * **cosmos:** spawn JS on export command ([fe4eb56](https://github.com/Agoric/agoric-sdk/commit/fe4eb56facf83569aa343f098e97c6229556afa9))
24
+ * **cosmos:** wire new swingset port handler ([3361b25](https://github.com/Agoric/agoric-sdk/commit/3361b25ddaa00116476d3de1107e800499ab5c21))
25
+ * **x/swingset:** add store data to genesis ([df72903](https://github.com/Agoric/agoric-sdk/commit/df729030643a097262ad1393503d380e243107eb))
26
+ * **x/swingset:** add WaitUntilSwingStoreExportDone ([f8acd22](https://github.com/Agoric/agoric-sdk/commit/f8acd22381ff3da4682bcb0cdcf71665095506a4))
27
+ * **x/swingset:** allow taking snapshot latest height ([0c0e742](https://github.com/Agoric/agoric-sdk/commit/0c0e74227d34d49ac7ce76ce8e92715816d5ea6a))
28
+ * **x/swingset:** export swing store in genesis ([e5f9425](https://github.com/Agoric/agoric-sdk/commit/e5f9425e74c7235323cd6b1b88540b73b57a69a6))
29
+ * **x/swingset:** import swing store from genesis state ([2446cf4](https://github.com/Agoric/agoric-sdk/commit/2446cf43bb13aad7de0805cd7e33c966d2e31016))
30
+ * Cosmos upgrade handler calls swingset ([66f7bcc](https://github.com/Agoric/agoric-sdk/commit/66f7bccce7ce30cf5b9e1e5321710567c05723cb))
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * **cosmos:** don't init controller before upgrade ([e567c21](https://github.com/Agoric/agoric-sdk/commit/e567c21a224d239c467f740bb937f84b18db9dd7))
36
+ * **cosmos:** module order independent init and bootstrap ([3ce4012](https://github.com/Agoric/agoric-sdk/commit/3ce4012ea99b39b2d6bfd422b1d7ea7a7e904568))
37
+ * **cosmos:** prevent Golang error wrapping stack frame divergence ([1d8acf6](https://github.com/Agoric/agoric-sdk/commit/1d8acf6270cadfbcdafb1081360155260d031ac1))
38
+ * **cosmos:** Support building on Linux aarch64 ([475708e](https://github.com/Agoric/agoric-sdk/commit/475708e63bb95d75184072547ca92586a978c5a0))
39
+ * **x/swingset:** enforce snapshot restore before init ([c946d58](https://github.com/Agoric/agoric-sdk/commit/c946d5866ef956c198d7ea14936eb9904aa272ae))
40
+ * **x/swingset:** guard snapshot restore for concurrency ([5320a30](https://github.com/Agoric/agoric-sdk/commit/5320a30a873455764104e13d89131e30a93a238c))
41
+ * **x/swingset:** switch export/import to replay artifact level ([c037ea3](https://github.com/Agoric/agoric-sdk/commit/c037ea3931877fe4d56df5b82cc7c3eb77a84a53))
42
+ * **x/vstorage:** value can be empty in genesis data ([9a51df5](https://github.com/Agoric/agoric-sdk/commit/9a51df515b87638b869564ab08445a0ce0d55707))
43
+
44
+
45
+ ### Build System
46
+
47
+ * remove deprecated `ag-cosmos-helper` ([ee43112](https://github.com/Agoric/agoric-sdk/commit/ee431121e3f93406896f8a9e7d949fbf1427c44e))
48
+
49
+
50
+
6
51
  ### [0.34.1](https://github.com/Agoric/agoric-sdk/compare/@agoric/cosmos@0.34.0...@agoric/cosmos@0.34.1) (2023-06-09)
7
52
 
8
53
  **Note:** Version bump only for package @agoric/cosmos
package/app/app.go CHANGED
@@ -1,7 +1,6 @@
1
1
  package gaia
2
2
 
3
3
  import (
4
- "context"
5
4
  "encoding/json"
6
5
  "fmt"
7
6
  "io"
@@ -288,7 +287,7 @@ func NewGaiaApp(
288
287
  appOpts servertypes.AppOptions,
289
288
  baseAppOptions ...func(*baseapp.BaseApp),
290
289
  ) *GaiaApp {
291
- defaultController := func(ctx context.Context, needReply bool, str string) (string, error) {
290
+ defaultController := func(needReply bool, str string) (string, error) {
292
291
  fmt.Fprintln(os.Stderr, "FIXME: Would upcall to controller with", str)
293
292
  return "", nil
294
293
  }
@@ -300,7 +299,7 @@ func NewGaiaApp(
300
299
  }
301
300
 
302
301
  func NewAgoricApp(
303
- sendToController func(context.Context, bool, string) (string, error),
302
+ sendToController func(bool, string) (string, error),
304
303
  logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool,
305
304
  homePath string, invCheckPeriod uint, encodingConfig gaiaappparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp),
306
305
  ) *GaiaApp {
@@ -450,7 +449,7 @@ func NewAgoricApp(
450
449
  app.CheckControllerInited(true)
451
450
  // We use SwingSet-level metering to charge the user for the call.
452
451
  defer vm.SetControllerContext(ctx)()
453
- return sendToController(sdk.WrapSDKContext(ctx), true, str)
452
+ return sendToController(true, str)
454
453
  }
455
454
 
456
455
  setBootstrapNeeded := func() {
@@ -482,7 +481,7 @@ func NewAgoricApp(
482
481
  if err != nil {
483
482
  return "", err
484
483
  }
485
- return sendToController(context.Background(), true, string(bz))
484
+ return sendToController(true, string(bz))
486
485
  },
487
486
  )
488
487
 
@@ -791,18 +790,13 @@ func NewAgoricApp(
791
790
  app.SetBeginBlocker(app.BeginBlocker)
792
791
  app.SetEndBlocker(app.EndBlocker)
793
792
 
794
- const (
795
- upgradeName = "agoric-upgrade-12"
796
- upgradeNameTest = "agorictest-upgrade-12"
797
- )
798
-
799
793
  app.UpgradeKeeper.SetUpgradeHandler(
800
794
  upgradeName,
801
- upgrade12Handler(app, upgradeName),
795
+ upgrade11Handler(app, upgradeName),
802
796
  )
803
797
  app.UpgradeKeeper.SetUpgradeHandler(
804
798
  upgradeNameTest,
805
- upgrade12Handler(app, upgradeNameTest),
799
+ upgrade11Handler(app, upgradeNameTest),
806
800
  )
807
801
 
808
802
  if loadLatest {
@@ -825,13 +819,108 @@ func NewAgoricApp(
825
819
  return app
826
820
  }
827
821
 
828
- // upgrade12Handler performs standard upgrade actions plus custom actions for upgrade-12.
829
- func upgrade12Handler(app *GaiaApp, targetUpgrade string) func(sdk.Context, upgradetypes.Plan, module.VersionMap) (module.VersionMap, error) {
822
+ type swingStoreMigrationEventHandler struct {
823
+ swingStore sdk.KVStore
824
+ }
825
+
826
+ func (eventHandler swingStoreMigrationEventHandler) OnExportStarted(height uint64, retrieveSwingStoreExport func() error) error {
827
+ return retrieveSwingStoreExport()
828
+ }
829
+
830
+ func (eventHandler swingStoreMigrationEventHandler) OnExportRetrieved(provider swingsetkeeper.SwingStoreExportProvider) (err error) {
831
+ exportDataReader, err := provider.GetExportDataReader()
832
+ if err != nil {
833
+ return err
834
+ }
835
+ defer exportDataReader.Close()
836
+
837
+ var hasExportData bool
838
+
839
+ for {
840
+ entry, err := exportDataReader.Read()
841
+ if err == io.EOF {
842
+ break
843
+ } else if err != nil {
844
+ return err
845
+ }
846
+ hasExportData = true
847
+ if !entry.HasValue() {
848
+ return fmt.Errorf("no value for export data key %s", entry.Key())
849
+ }
850
+ eventHandler.swingStore.Set([]byte(entry.Key()), []byte(entry.StringValue()))
851
+ }
852
+ if !hasExportData {
853
+ return fmt.Errorf("export data had no entries")
854
+ }
855
+ return nil
856
+ }
857
+
858
+ // upgrade11Handler performs standard upgrade actions plus custom actions for upgrade-11.
859
+ func upgrade11Handler(app *GaiaApp, targetUpgrade string) func(sdk.Context, upgradetypes.Plan, module.VersionMap) (module.VersionMap, error) {
830
860
  return func(ctx sdk.Context, plan upgradetypes.Plan, fromVm module.VersionMap) (module.VersionMap, error) {
831
861
  app.CheckControllerInited(false)
832
862
  // Record the plan to send to SwingSet
833
863
  app.upgradePlan = &plan
834
864
 
865
+ // Perform swing-store migrations. We do this in the app upgrade handler
866
+ // since it involves multiple modules (x/vstorage and x/swingset) which
867
+ // don't strictly have a version change on their own.
868
+
869
+ // We are at the begining of the upgrade block, so all stores are commited
870
+ // as of the end of the previous block
871
+ savedBlockHeight := uint64(ctx.BlockHeight() - 1)
872
+
873
+ // First, repair swing-store metadata in case this node was previously
874
+ // initialized from a state-sync snapshot. This is done with a check on the
875
+ // block height to catch early any hangover related mismatch.
876
+ // Only entries related to missing historical metadata are imported, but we
877
+ // don't know what these look like here, so we provide it all.
878
+ getSwingStoreExportDataFromVstorage := func() (reader agorictypes.KVEntryReader, err error) {
879
+ return agorictypes.NewVstorageDataEntriesReader(
880
+ app.VstorageKeeper.ExportStorageFromPrefix(ctx, swingsetkeeper.StoragePathSwingStore),
881
+ ), nil
882
+ }
883
+
884
+ // We're not restoring any artifact to swing-store, nor have any to provide
885
+ readNoArtifact := func() (artifact swingsettypes.SwingStoreArtifact, err error) {
886
+ return artifact, io.EOF
887
+ }
888
+
889
+ err := app.SwingStoreExportsHandler.RestoreExport(
890
+ swingsetkeeper.SwingStoreExportProvider{
891
+ BlockHeight: savedBlockHeight,
892
+ GetExportDataReader: getSwingStoreExportDataFromVstorage,
893
+ ReadNextArtifact: readNoArtifact,
894
+ },
895
+ swingsetkeeper.SwingStoreRestoreOptions{
896
+ ArtifactMode: swingsetkeeper.SwingStoreArtifactModeNone,
897
+ ExportDataMode: swingsetkeeper.SwingStoreExportDataModeRepairMetadata,
898
+ },
899
+ )
900
+ if err != nil {
901
+ return nil, err
902
+ }
903
+
904
+ // Then migrate the swing-store shadow copy:
905
+ // 1. Remove the swing-store "export data" shadow-copy entries from vstorage.
906
+ // 2. Export swing-store "export-data" (as of the previous block) through a
907
+ // handler that writes every entry into the swingset module's new Store.
908
+ app.VstorageKeeper.RemoveEntriesWithPrefix(ctx, swingsetkeeper.StoragePathSwingStore)
909
+ err = app.SwingStoreExportsHandler.InitiateExport(
910
+ savedBlockHeight,
911
+ swingStoreMigrationEventHandler{swingStore: app.SwingSetKeeper.GetSwingStore(ctx)},
912
+ swingsetkeeper.SwingStoreExportOptions{
913
+ ArtifactMode: swingsetkeeper.SwingStoreArtifactModeNone,
914
+ ExportDataMode: swingsetkeeper.SwingStoreExportDataModeAll,
915
+ },
916
+ )
917
+ if err == nil {
918
+ err = swingsetkeeper.WaitUntilSwingStoreExportDone()
919
+ }
920
+ if err != nil {
921
+ return nil, err
922
+ }
923
+
835
924
  // Always run module migrations
836
925
  mvm, err := app.mm.RunMigrations(ctx, app.configurator, fromVm)
837
926
  if err != nil {
package/app/const.go ADDED
@@ -0,0 +1,6 @@
1
+ package gaia
2
+
3
+ const (
4
+ upgradeName = "agoric-upgrade-11"
5
+ upgradeNameTest = "agorictest-upgrade-11"
6
+ )
package/cmd/agd/main.go CHANGED
@@ -1,158 +1,36 @@
1
1
  package main
2
2
 
3
3
  import (
4
- "context"
5
- "errors"
6
- "net/rpc"
7
- "net/rpc/jsonrpc"
8
4
  "os"
9
- "os/exec"
10
5
  "syscall"
11
- "time"
12
6
 
13
- "github.com/spf13/cast"
14
7
  "github.com/tendermint/tendermint/libs/log"
15
8
 
16
9
  gaia "github.com/Agoric/agoric-sdk/golang/cosmos/app"
17
10
  "github.com/Agoric/agoric-sdk/golang/cosmos/daemon"
18
11
  daemoncmd "github.com/Agoric/agoric-sdk/golang/cosmos/daemon/cmd"
19
- "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
20
- "github.com/Agoric/agoric-sdk/golang/cosmos/vm/jsonrpcconn"
21
- servertypes "github.com/cosmos/cosmos-sdk/server/types"
22
12
  )
23
13
 
24
- // TerminateSubprocessGracePeriod is how long we wait between closing the pipe
25
- // waiting for it to exit, then sending a termination signal.
26
- const TerminateSubprocessGracePeriod = 3 * time.Second
27
-
28
- // KillSubprocessGracePeriod is how long we wait between sending a subprocess a
29
- // termination signal, waiting for it to exit, then killing it.
30
- const KillSubprocessGracePeriod = 5 * time.Second
31
-
32
- // makeShutdown returns a function that terminates the vm.
33
- func makeShutdown(cmd *exec.Cmd, writer *os.File) func() error {
34
- return func() error {
35
- // Stop talking to the subprocess.
36
- _ = writer.Close()
37
- go func() {
38
- // Wait a bit.
39
- time.Sleep(TerminateSubprocessGracePeriod)
40
- // Then punch it in the shoulder.
41
- _ = cmd.Process.Signal(os.Interrupt)
42
- // Wait a bit.
43
- time.Sleep(KillSubprocessGracePeriod)
44
- // Then blow it away.
45
- _ = cmd.Process.Kill()
46
- }()
47
- // Wait for it to keel over.
48
- return cmd.Wait()
49
- }
50
- }
51
-
52
-
53
- // main is the entry point of the agd daemon. It determines whether to
54
- // initialize JSON-RPC communications with the separate `--split-vm` VM process,
55
- // or just to give up control entirely to another binary.
56
14
  func main() {
57
- var vmClient *rpc.Client
58
- var shutdown func() error
59
-
60
- nodePort := 1
61
- sendToNode := func(ctx context.Context, needReply bool, str string) (string, error) {
62
- if vmClient == nil {
63
- return "", errors.New("sendToVM called without VM client set up")
64
- }
65
-
66
- if str == "shutdown" {
67
- // We could ask nicely, but don't bother.
68
- if shutdown != nil {
69
- return "", shutdown()
70
- }
71
- return "", nil
72
- }
73
-
74
- msg := vm.Message{
75
- Port: nodePort,
76
- NeedsReply: needReply,
77
- Data: str,
78
- }
79
- var reply string
80
- err := vmClient.Call(vm.ReceiveMessageMethod, msg, &reply)
81
- return reply, err
82
- }
83
-
84
- exitCode := 0
85
- launchVM := func(logger log.Logger, appOpts servertypes.AppOptions) error {
15
+ // We need to delegate to our default app for running the actual chain.
16
+ launchVM := func(logger log.Logger) {
86
17
  args := []string{"ag-chain-cosmos", "--home", gaia.DefaultNodeHome}
87
18
  args = append(args, os.Args[1:]...)
88
19
 
89
- binary := cast.ToString(appOpts.Get(daemoncmd.FlagSplitVm))
90
- if binary == "" {
91
- binary, lookErr := FindCosmicSwingsetBinary()
92
- if lookErr != nil {
93
- return lookErr
94
- }
95
-
96
- // We completely delegate to our default app for running the actual chain.
97
- logger.Info("agd delegating to JS executable", "binary", binary, "args", args)
98
- return syscall.Exec(binary, args, os.Environ())
99
- }
100
-
101
- // Split the execution between us and the VM.
102
- agdFromVm, vmToAgd, err := os.Pipe()
103
- if err != nil {
104
- return err
105
- }
106
- vmFromAgd, agdToVm, err := os.Pipe()
107
- if err != nil {
108
- return err
109
- }
110
-
111
- // Start the command running, then continue.
112
- args[0] = binary
113
- cmd := NewVMCommand(logger, binary, args, vmFromAgd, vmToAgd)
114
- shutdown = makeShutdown(cmd, agdToVm)
115
-
116
- if err := cmd.Start(); err != nil {
117
- return err
118
- }
119
- if vmFromAgd.Close() != nil {
120
- return err
121
- }
122
- if vmToAgd.Close() != nil {
123
- return err
20
+ binary, lookErr := FindCosmicSwingsetBinary()
21
+ if lookErr != nil {
22
+ panic(lookErr)
124
23
  }
125
24
 
126
- // Multiplex bidirectional JSON-RPC over the pipes.
127
- agvmConn := jsonrpcconn.NewConn(agdFromVm, agdToVm)
128
- clientConn, serverConn := jsonrpcconn.ClientServerConn(agvmConn)
129
-
130
- // Set up the VM server.
131
- vmServer := rpc.NewServer()
132
- if err := vmServer.RegisterName("agd", vm.NewAgdServer()); err != nil {
133
- return err
25
+ logger.Info("agd delegating to JS executable", "binary", binary, "args", args)
26
+ execErr := syscall.Exec(binary, args, os.Environ())
27
+ if execErr != nil {
28
+ panic(execErr)
134
29
  }
135
- go vmServer.ServeCodec(jsonrpc.NewServerCodec(serverConn))
136
-
137
- // Set up the VM client.
138
- vmClient = jsonrpc.NewClient(clientConn)
139
-
140
- go func() {
141
- // Premature exit from `agd start` should exit the process.
142
- _ = cmd.Wait()
143
- os.Exit(exitCode)
144
- }()
145
-
146
- return nil
147
30
  }
148
31
 
32
+ daemoncmd.OnStartHook = launchVM
149
33
  daemoncmd.OnExportHook = launchVM
150
- daemoncmd.OnStartHook = func (logger log.Logger, appOpts servertypes.AppOptions) error {
151
- // We tried running start, which should never exit, so exit with non-zero
152
- // code if we do.
153
- exitCode = 99
154
- return launchVM(logger, appOpts)
155
- }
156
34
 
157
- daemon.RunWithController(sendToNode)
35
+ daemon.RunWithController(nil)
158
36
  }
@@ -10,9 +10,8 @@ package main
10
10
  import "C"
11
11
 
12
12
  import (
13
- "context"
14
13
  "encoding/json"
15
- "net/rpc"
14
+ "errors"
16
15
  "os"
17
16
  "path/filepath"
18
17
 
@@ -22,7 +21,6 @@ import (
22
21
  "github.com/Agoric/agoric-sdk/golang/cosmos/daemon"
23
22
  daemoncmd "github.com/Agoric/agoric-sdk/golang/cosmos/daemon/cmd"
24
23
  "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
25
- servertypes "github.com/cosmos/cosmos-sdk/server/types"
26
24
  )
27
25
 
28
26
  type goReturn = struct {
@@ -32,32 +30,8 @@ type goReturn = struct {
32
30
 
33
31
  const SwingSetPort = 123
34
32
 
35
- var vmClientCodec *vm.ClientCodec
36
- var agdServer *vm.AgdServer
37
-
38
- // ConnectVMClientCodec creates an RPC client codec and a sender to the
39
- // in-process implementation of the VM.
40
- func ConnectVMClientCodec(ctx context.Context, nodePort int, sendFunc func(int, int, string)) (*vm.ClientCodec, daemoncmd.Sender) {
41
- vmClientCodec = vm.NewClientCodec(context.Background(), sendFunc)
42
- vmClient := rpc.NewClientWithCodec(vmClientCodec)
43
-
44
- sendToNode := func(ctx context.Context, needReply bool, str string) (string, error) {
45
- if str == "shutdown" {
46
- return "", vmClientCodec.Close()
47
- }
48
-
49
- msg := vm.Message{
50
- Port: nodePort,
51
- NeedsReply: needReply,
52
- Data: str,
53
- }
54
- var reply string
55
- err := vmClient.Call(vm.ReceiveMessageMethod, msg, &reply)
56
- return reply, err
57
- }
58
-
59
- return vmClientCodec, sendToNode
60
- }
33
+ var replies = map[int]chan goReturn{}
34
+ var lastReply = 0
61
35
 
62
36
  //export RunAgCosmosDaemon
63
37
  func RunAgCosmosDaemon(nodePort C.int, toNode C.sendFunc, cosmosArgs []*C.char) C.int {
@@ -68,39 +42,46 @@ func RunAgCosmosDaemon(nodePort C.int, toNode C.sendFunc, cosmosArgs []*C.char)
68
42
 
69
43
  gaia.DefaultNodeHome = filepath.Join(userHomeDir, ".ag-chain-cosmos")
70
44
  daemoncmd.AppName = "ag-chain-cosmos"
71
- if err := os.Setenv(daemoncmd.EmbeddedVmEnvVar, "libdaemon"); err != nil {
72
- panic(err)
73
- }
74
45
 
75
- var sendToNode daemoncmd.Sender
46
+ // FIXME: Decouple the sending logic from the Cosmos app.
47
+ sendToNode := func(needReply bool, str string) (string, error) {
48
+ var rPort int
49
+ if needReply {
50
+ lastReply++
51
+ rPort = lastReply
52
+ replies[rPort] = make(chan goReturn)
53
+ }
76
54
 
77
- sendFunc := func(port int, reply int, str string) {
78
- C.invokeSendFunc(toNode, C.int(port), C.int(reply), C.CString(str))
79
- }
55
+ // Send the message
56
+ C.invokeSendFunc(toNode, nodePort, C.int(rPort), C.CString(str))
57
+ if !needReply {
58
+ // Return immediately
59
+ // fmt.Fprintln(os.Stderr, "Don't wait")
60
+ return "<no-reply-requested>", nil
61
+ }
80
62
 
81
- vmClientCodec, sendToNode = ConnectVMClientCodec(
82
- context.Background(),
83
- int(nodePort),
84
- sendFunc,
85
- )
86
- agdServer = vm.NewAgdServer()
63
+ // Block the sending goroutine while we wait for the reply
64
+ // fmt.Fprintln(os.Stderr, "Waiting for", rPort)
65
+ ret := <-replies[rPort]
66
+ delete(replies, rPort)
67
+ // fmt.Fprintln(os.Stderr, "Woken, got", ret)
68
+ return ret.str, ret.err
69
+ }
87
70
 
88
71
  args := make([]string, len(cosmosArgs))
89
72
  for i, s := range cosmosArgs {
90
73
  args[i] = C.GoString(s)
91
74
  }
92
-
93
75
  // fmt.Fprintln(os.Stderr, "Starting Cosmos", args)
94
76
  os.Args = args
95
77
  go func() {
96
78
  // We run in the background, but exit when the job is over.
97
79
  // swingset.SendToNode("hello from Initial Go!")
98
80
  exitCode := 0
99
- daemoncmd.OnStartHook = func(logger log.Logger, appOpts servertypes.AppOptions) error {
81
+ daemoncmd.OnStartHook = func(logger log.Logger) {
100
82
  // We tried running start, which should never exit, so exit with non-zero
101
83
  // code if we ever stop.
102
84
  exitCode = 99
103
- return nil
104
85
  }
105
86
  daemon.RunWithController(sendToNode)
106
87
  // fmt.Fprintln(os.Stderr, "Shutting down Cosmos")
@@ -113,10 +94,22 @@ func RunAgCosmosDaemon(nodePort C.int, toNode C.sendFunc, cosmosArgs []*C.char)
113
94
  //export ReplyToGo
114
95
  func ReplyToGo(replyPort C.int, isError C.int, resp C.Body) C.int {
115
96
  respStr := C.GoString(resp)
116
- // fmt.Printf("Reply to Go %d %s\n", replyPort, respStr)
117
- if err := vmClientCodec.Receive(int(replyPort), int(isError) != 0, respStr); err != nil {
118
- return C.int(1)
97
+ // fmt.Fprintln(os.Stderr, "Reply to Go", respStr)
98
+ returnCh := replies[int(replyPort)]
99
+ if returnCh == nil {
100
+ // Unexpected reply.
101
+ // This is okay, since the caller decides whether or
102
+ // not she wants to listen for replies.
103
+ return C.int(0)
119
104
  }
105
+ // Wake up the waiting goroutine
106
+ ret := goReturn{}
107
+ if int(isError) == 0 {
108
+ ret.str = respStr
109
+ } else {
110
+ ret.err = errors.New(respStr)
111
+ }
112
+ returnCh <- ret
120
113
  return C.int(0)
121
114
  }
122
115
 
@@ -128,27 +121,20 @@ type errorWrapper struct {
128
121
  func SendToGo(port C.int, msg C.Body) C.Body {
129
122
  msgStr := C.GoString(msg)
130
123
  // fmt.Fprintln(os.Stderr, "Send to Go", msgStr)
131
- var respStr string
132
- message := &vm.Message{
133
- Port: int(port),
134
- NeedsReply: true,
135
- Data: msgStr,
136
- }
137
-
138
- err := agdServer.ReceiveMessage(message, &respStr)
139
- if err == nil {
140
- return C.CString(respStr)
141
- }
142
-
143
- // fmt.Fprintln(os.Stderr, "Cannot receive from controller", err)
144
- errResp := errorWrapper{
145
- Error: err.Error(),
146
- }
147
- respBytes, err := json.Marshal(&errResp)
124
+ respStr, err := vm.ReceiveFromController(int(port), msgStr)
148
125
  if err != nil {
149
- panic(err)
126
+ // fmt.Fprintln(os.Stderr, "Cannot receive from controller", err)
127
+ errResp := errorWrapper{
128
+ Error: err.Error(),
129
+ }
130
+ respBytes, err := json.Marshal(&errResp)
131
+ if err != nil {
132
+ panic(err)
133
+ }
134
+ // fmt.Fprintln(os.Stderr, "Marshaled", errResp, respBytes)
135
+ respStr = string(respBytes)
150
136
  }
151
- return C.CString(string(respBytes))
137
+ return C.CString(respStr)
152
138
  }
153
139
 
154
140
  // Do nothing in main.