@agoric/cosmos 0.34.2-dev-5fcf452.0 → 0.34.2-dev-d355030.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 +5 -4
- package/cmd/agd/agvm.go +42 -0
- package/cmd/agd/main.go +133 -11
- package/cmd/libdaemon/main.go +67 -53
- package/daemon/cmd/root.go +55 -24
- package/daemon/main.go +3 -1
- package/git-revision.txt +1 -1
- package/package.json +2 -2
- package/vm/client.go +113 -0
- package/vm/client_test.go +184 -0
- package/vm/controller.go +8 -18
- package/vm/jsonrpcconn/jsonrpcconn.go +160 -0
- package/vm/jsonrpcconn/jsonrpcconn_test.go +126 -0
- package/vm/server.go +23 -0
- package/x/lien/lien.go +6 -4
- package/x/lien/lien_test.go +19 -15
- package/x/swingset/abci.go +3 -2
- package/x/swingset/swingset.go +4 -2
- package/x/vbank/vbank.go +11 -10
- package/x/vbank/vbank_test.go +5 -5
- package/x/vibc/ibc.go +11 -9
- package/x/vstorage/vstorage.go +16 -15
- package/x/vstorage/vstorage_test.go +4 -4
package/app/app.go
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package gaia
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"context"
|
|
4
5
|
"encoding/json"
|
|
5
6
|
"fmt"
|
|
6
7
|
"io"
|
|
@@ -287,7 +288,7 @@ func NewGaiaApp(
|
|
|
287
288
|
appOpts servertypes.AppOptions,
|
|
288
289
|
baseAppOptions ...func(*baseapp.BaseApp),
|
|
289
290
|
) *GaiaApp {
|
|
290
|
-
defaultController := func(needReply bool, str string) (string, error) {
|
|
291
|
+
defaultController := func(ctx context.Context, needReply bool, str string) (string, error) {
|
|
291
292
|
fmt.Fprintln(os.Stderr, "FIXME: Would upcall to controller with", str)
|
|
292
293
|
return "", nil
|
|
293
294
|
}
|
|
@@ -299,7 +300,7 @@ func NewGaiaApp(
|
|
|
299
300
|
}
|
|
300
301
|
|
|
301
302
|
func NewAgoricApp(
|
|
302
|
-
sendToController func(bool, string) (string, error),
|
|
303
|
+
sendToController func(context.Context, bool, string) (string, error),
|
|
303
304
|
logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool,
|
|
304
305
|
homePath string, invCheckPeriod uint, encodingConfig gaiaappparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp),
|
|
305
306
|
) *GaiaApp {
|
|
@@ -449,7 +450,7 @@ func NewAgoricApp(
|
|
|
449
450
|
app.CheckControllerInited(true)
|
|
450
451
|
// We use SwingSet-level metering to charge the user for the call.
|
|
451
452
|
defer vm.SetControllerContext(ctx)()
|
|
452
|
-
return sendToController(true, str)
|
|
453
|
+
return sendToController(sdk.WrapSDKContext(ctx), true, str)
|
|
453
454
|
}
|
|
454
455
|
|
|
455
456
|
setBootstrapNeeded := func() {
|
|
@@ -481,7 +482,7 @@ func NewAgoricApp(
|
|
|
481
482
|
if err != nil {
|
|
482
483
|
return "", err
|
|
483
484
|
}
|
|
484
|
-
return sendToController(true, string(bz))
|
|
485
|
+
return sendToController(context.Background(), true, string(bz))
|
|
485
486
|
},
|
|
486
487
|
)
|
|
487
488
|
|
package/cmd/agd/agvm.go
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"os"
|
|
6
|
+
"os/exec"
|
|
7
|
+
|
|
8
|
+
"github.com/tendermint/tendermint/libs/log"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// NewVMCommand creates a new OS command to run the Agoric VM. It sets up the
|
|
12
|
+
// file descriptors for the VM to communicate with agd, and passes their numbers
|
|
13
|
+
// via AGVM_FROM_AGD and AGVM_TO_AGD environment variables.
|
|
14
|
+
func NewVMCommand(logger log.Logger, binary string, args []string, vmFromAgd, vmToAgd *os.File) *exec.Cmd {
|
|
15
|
+
logger.Info("agd connecting to VM", "binary", binary, "args", args)
|
|
16
|
+
cmd := exec.Command(binary, args[1:]...)
|
|
17
|
+
|
|
18
|
+
// Manage the file descriptors.
|
|
19
|
+
cmd.Stdout = os.Stdout
|
|
20
|
+
cmd.Stderr = os.Stderr
|
|
21
|
+
cmd.Stdin = os.Stdin
|
|
22
|
+
numStdFiles := 3 // stdin, stdout, stderr
|
|
23
|
+
|
|
24
|
+
// We start our file descriptor allocations after the standard ones, including
|
|
25
|
+
// Node.js IPC (fd=3).
|
|
26
|
+
fdFromAgd := 4
|
|
27
|
+
fdToAgd := fdFromAgd + 1
|
|
28
|
+
|
|
29
|
+
// ExtraFiles begins at fd numStdFiles, so we need to compute the array.
|
|
30
|
+
cmd.ExtraFiles = make([]*os.File, fdToAgd - numStdFiles + 1)
|
|
31
|
+
cmd.ExtraFiles[fdFromAgd - numStdFiles] = vmFromAgd
|
|
32
|
+
cmd.ExtraFiles[fdToAgd - numStdFiles] = vmToAgd
|
|
33
|
+
|
|
34
|
+
// Pass the file descriptor numbers in the environment.
|
|
35
|
+
cmd.Env = append(
|
|
36
|
+
os.Environ(),
|
|
37
|
+
fmt.Sprintf("AGVM_FROM_AGD=%d", fdFromAgd),
|
|
38
|
+
fmt.Sprintf("AGVM_TO_AGD=%d", fdToAgd),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return cmd
|
|
42
|
+
}
|
package/cmd/agd/main.go
CHANGED
|
@@ -1,36 +1,158 @@
|
|
|
1
1
|
package main
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"context"
|
|
5
|
+
"errors"
|
|
6
|
+
"net/rpc"
|
|
7
|
+
"net/rpc/jsonrpc"
|
|
4
8
|
"os"
|
|
9
|
+
"os/exec"
|
|
5
10
|
"syscall"
|
|
11
|
+
"time"
|
|
6
12
|
|
|
13
|
+
"github.com/spf13/cast"
|
|
7
14
|
"github.com/tendermint/tendermint/libs/log"
|
|
8
15
|
|
|
9
16
|
gaia "github.com/Agoric/agoric-sdk/golang/cosmos/app"
|
|
10
17
|
"github.com/Agoric/agoric-sdk/golang/cosmos/daemon"
|
|
11
18
|
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"
|
|
12
22
|
)
|
|
13
23
|
|
|
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.
|
|
14
56
|
func main() {
|
|
15
|
-
|
|
16
|
-
|
|
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 {
|
|
17
86
|
args := []string{"ag-chain-cosmos", "--home", gaia.DefaultNodeHome}
|
|
18
87
|
args = append(args, os.Args[1:]...)
|
|
19
88
|
|
|
20
|
-
binary
|
|
21
|
-
if
|
|
22
|
-
|
|
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
|
|
23
124
|
}
|
|
24
125
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
29
134
|
}
|
|
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
|
|
30
147
|
}
|
|
31
148
|
|
|
32
|
-
daemoncmd.OnStartHook = launchVM
|
|
33
149
|
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
|
+
}
|
|
34
156
|
|
|
35
|
-
daemon.RunWithController(
|
|
157
|
+
daemon.RunWithController(sendToNode)
|
|
36
158
|
}
|
package/cmd/libdaemon/main.go
CHANGED
|
@@ -10,8 +10,9 @@ package main
|
|
|
10
10
|
import "C"
|
|
11
11
|
|
|
12
12
|
import (
|
|
13
|
+
"context"
|
|
13
14
|
"encoding/json"
|
|
14
|
-
"
|
|
15
|
+
"net/rpc"
|
|
15
16
|
"os"
|
|
16
17
|
"path/filepath"
|
|
17
18
|
|
|
@@ -21,6 +22,7 @@ import (
|
|
|
21
22
|
"github.com/Agoric/agoric-sdk/golang/cosmos/daemon"
|
|
22
23
|
daemoncmd "github.com/Agoric/agoric-sdk/golang/cosmos/daemon/cmd"
|
|
23
24
|
"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
|
|
25
|
+
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
|
24
26
|
)
|
|
25
27
|
|
|
26
28
|
type goReturn = struct {
|
|
@@ -30,8 +32,32 @@ type goReturn = struct {
|
|
|
30
32
|
|
|
31
33
|
const SwingSetPort = 123
|
|
32
34
|
|
|
33
|
-
var
|
|
34
|
-
var
|
|
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
|
+
}
|
|
35
61
|
|
|
36
62
|
//export RunAgCosmosDaemon
|
|
37
63
|
func RunAgCosmosDaemon(nodePort C.int, toNode C.sendFunc, cosmosArgs []*C.char) C.int {
|
|
@@ -42,46 +68,39 @@ func RunAgCosmosDaemon(nodePort C.int, toNode C.sendFunc, cosmosArgs []*C.char)
|
|
|
42
68
|
|
|
43
69
|
gaia.DefaultNodeHome = filepath.Join(userHomeDir, ".ag-chain-cosmos")
|
|
44
70
|
daemoncmd.AppName = "ag-chain-cosmos"
|
|
71
|
+
if err := os.Setenv(daemoncmd.EmbeddedVmEnvVar, "libdaemon"); err != nil {
|
|
72
|
+
panic(err)
|
|
73
|
+
}
|
|
45
74
|
|
|
46
|
-
|
|
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
|
-
}
|
|
75
|
+
var sendToNode daemoncmd.Sender
|
|
54
76
|
|
|
55
|
-
|
|
56
|
-
C.invokeSendFunc(toNode,
|
|
57
|
-
if !needReply {
|
|
58
|
-
// Return immediately
|
|
59
|
-
// fmt.Fprintln(os.Stderr, "Don't wait")
|
|
60
|
-
return "<no-reply-requested>", nil
|
|
61
|
-
}
|
|
62
|
-
|
|
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
|
|
77
|
+
sendFunc := func(port int, reply int, str string) {
|
|
78
|
+
C.invokeSendFunc(toNode, C.int(port), C.int(reply), C.CString(str))
|
|
69
79
|
}
|
|
70
80
|
|
|
81
|
+
vmClientCodec, sendToNode = ConnectVMClientCodec(
|
|
82
|
+
context.Background(),
|
|
83
|
+
int(nodePort),
|
|
84
|
+
sendFunc,
|
|
85
|
+
)
|
|
86
|
+
agdServer = vm.NewAgdServer()
|
|
87
|
+
|
|
71
88
|
args := make([]string, len(cosmosArgs))
|
|
72
89
|
for i, s := range cosmosArgs {
|
|
73
90
|
args[i] = C.GoString(s)
|
|
74
91
|
}
|
|
92
|
+
|
|
75
93
|
// fmt.Fprintln(os.Stderr, "Starting Cosmos", args)
|
|
76
94
|
os.Args = args
|
|
77
95
|
go func() {
|
|
78
96
|
// We run in the background, but exit when the job is over.
|
|
79
97
|
// swingset.SendToNode("hello from Initial Go!")
|
|
80
98
|
exitCode := 0
|
|
81
|
-
daemoncmd.OnStartHook = func(logger log.Logger) {
|
|
99
|
+
daemoncmd.OnStartHook = func(logger log.Logger, appOpts servertypes.AppOptions) error {
|
|
82
100
|
// We tried running start, which should never exit, so exit with non-zero
|
|
83
101
|
// code if we ever stop.
|
|
84
102
|
exitCode = 99
|
|
103
|
+
return nil
|
|
85
104
|
}
|
|
86
105
|
daemon.RunWithController(sendToNode)
|
|
87
106
|
// fmt.Fprintln(os.Stderr, "Shutting down Cosmos")
|
|
@@ -94,22 +113,10 @@ func RunAgCosmosDaemon(nodePort C.int, toNode C.sendFunc, cosmosArgs []*C.char)
|
|
|
94
113
|
//export ReplyToGo
|
|
95
114
|
func ReplyToGo(replyPort C.int, isError C.int, resp C.Body) C.int {
|
|
96
115
|
respStr := C.GoString(resp)
|
|
97
|
-
// fmt.
|
|
98
|
-
|
|
99
|
-
|
|
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)
|
|
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)
|
|
104
119
|
}
|
|
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
|
|
113
120
|
return C.int(0)
|
|
114
121
|
}
|
|
115
122
|
|
|
@@ -121,20 +128,27 @@ type errorWrapper struct {
|
|
|
121
128
|
func SendToGo(port C.int, msg C.Body) C.Body {
|
|
122
129
|
msgStr := C.GoString(msg)
|
|
123
130
|
// fmt.Fprintln(os.Stderr, "Send to Go", msgStr)
|
|
124
|
-
respStr
|
|
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)
|
|
125
148
|
if err != nil {
|
|
126
|
-
|
|
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)
|
|
149
|
+
panic(err)
|
|
136
150
|
}
|
|
137
|
-
return C.CString(
|
|
151
|
+
return C.CString(string(respBytes))
|
|
138
152
|
}
|
|
139
153
|
|
|
140
154
|
// Do nothing in main.
|
package/daemon/cmd/root.go
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package cmd
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"context"
|
|
4
5
|
"errors"
|
|
5
6
|
"io"
|
|
6
7
|
"os"
|
|
@@ -38,11 +39,11 @@ import (
|
|
|
38
39
|
)
|
|
39
40
|
|
|
40
41
|
// Sender is a function that sends a request to the controller.
|
|
41
|
-
type Sender func(needReply bool, str string) (string, error)
|
|
42
|
+
type Sender func(ctx context.Context, needReply bool, str string) (string, error)
|
|
42
43
|
|
|
43
44
|
var AppName = "agd"
|
|
44
|
-
var OnStartHook func(
|
|
45
|
-
var OnExportHook func(
|
|
45
|
+
var OnStartHook func(log.Logger, servertypes.AppOptions) error
|
|
46
|
+
var OnExportHook func(log.Logger, servertypes.AppOptions) error
|
|
46
47
|
|
|
47
48
|
// NewRootCmd creates a new root command for simd. It is called once in the
|
|
48
49
|
// main function.
|
|
@@ -60,7 +61,7 @@ func NewRootCmd(sender Sender) (*cobra.Command, params.EncodingConfig) {
|
|
|
60
61
|
|
|
61
62
|
rootCmd := &cobra.Command{
|
|
62
63
|
Use: AppName,
|
|
63
|
-
Short: "
|
|
64
|
+
Short: "Agoric Cosmos App",
|
|
64
65
|
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
|
|
65
66
|
// set the default command outputs
|
|
66
67
|
cmd.SetOut(cmd.OutOrStdout())
|
|
@@ -135,10 +136,9 @@ func initRootCmd(sender Sender, rootCmd *cobra.Command, encodingConfig params.En
|
|
|
135
136
|
}
|
|
136
137
|
server.AddCommands(rootCmd, gaia.DefaultNodeHome, ac.newApp, ac.appExport, addModuleInitFlags)
|
|
137
138
|
|
|
138
|
-
hasVMController := sender != nil
|
|
139
139
|
for _, command := range rootCmd.Commands() {
|
|
140
140
|
if command.Name() == "export" {
|
|
141
|
-
extendCosmosExportCommand(command
|
|
141
|
+
extendCosmosExportCommand(command)
|
|
142
142
|
break
|
|
143
143
|
}
|
|
144
144
|
}
|
|
@@ -154,8 +154,31 @@ func initRootCmd(sender Sender, rootCmd *cobra.Command, encodingConfig params.En
|
|
|
154
154
|
rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler))
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
const (
|
|
158
|
+
// FlagSplitVm is the command-line flag for subcommands that can use a
|
|
159
|
+
// split-process Agoric VM. The default is to use an embedded VM.
|
|
160
|
+
FlagSplitVm = "split-vm"
|
|
161
|
+
EmbeddedVmEnvVar = "AGD_EMBEDDED_VM"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
// hasVMController returns true if we have a VM (are running in split-vm mode,
|
|
165
|
+
// or with an embedded VM).
|
|
166
|
+
func hasVMController(serverCtx *server.Context) bool {
|
|
167
|
+
return serverCtx.Viper.GetString(FlagSplitVm) != "" ||
|
|
168
|
+
os.Getenv(EmbeddedVmEnvVar) != ""
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func addAgoricVMFlags(cmd *cobra.Command) {
|
|
172
|
+
cmd.PersistentFlags().String(
|
|
173
|
+
FlagSplitVm,
|
|
174
|
+
"",
|
|
175
|
+
"Specify the external Agoric VM program",
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
157
179
|
func addModuleInitFlags(startCmd *cobra.Command) {
|
|
158
180
|
crisis.AddModuleInitFlags(startCmd)
|
|
181
|
+
addAgoricVMFlags(startCmd)
|
|
159
182
|
}
|
|
160
183
|
|
|
161
184
|
func queryCommand() *cobra.Command {
|
|
@@ -223,7 +246,9 @@ func (ac appCreator) newApp(
|
|
|
223
246
|
appOpts servertypes.AppOptions,
|
|
224
247
|
) servertypes.Application {
|
|
225
248
|
if OnStartHook != nil {
|
|
226
|
-
OnStartHook(logger)
|
|
249
|
+
if err := OnStartHook(logger, appOpts); err != nil {
|
|
250
|
+
panic(err)
|
|
251
|
+
}
|
|
227
252
|
}
|
|
228
253
|
|
|
229
254
|
var cache sdk.MultiStorePersistentCache
|
|
@@ -297,8 +322,9 @@ const (
|
|
|
297
322
|
|
|
298
323
|
// extendCosmosExportCommand monkey-patches the "export" command added by
|
|
299
324
|
// 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
|
|
325
|
+
// genesis export in the specified directory if the VM is running.
|
|
326
|
+
func extendCosmosExportCommand(cmd *cobra.Command) {
|
|
327
|
+
addAgoricVMFlags(cmd)
|
|
302
328
|
cmd.Flags().String(FlagExportDir, "", "The directory where to create the genesis export")
|
|
303
329
|
err := cmd.MarkFlagRequired(FlagExportDir)
|
|
304
330
|
if err != nil {
|
|
@@ -329,25 +355,28 @@ func extendCosmosExportCommand(cmd *cobra.Command, hasVMController bool) {
|
|
|
329
355
|
// current genesis.
|
|
330
356
|
serverCtx.Viper.Set(gaia.FlagSwingStoreExportDir, swingStoreExportPath)
|
|
331
357
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
358
|
+
if hasVMController(serverCtx) {
|
|
359
|
+
// Capture the export in the genesisPath.
|
|
360
|
+
// This will fail if a genesis.json already exists in the export-dir
|
|
361
|
+
genesisFile, err := os.OpenFile(
|
|
362
|
+
genesisPath,
|
|
363
|
+
os.O_CREATE|os.O_EXCL|os.O_WRONLY,
|
|
364
|
+
os.ModePerm,
|
|
365
|
+
)
|
|
366
|
+
if err != nil {
|
|
367
|
+
return err
|
|
368
|
+
}
|
|
369
|
+
defer genesisFile.Close()
|
|
370
|
+
cmd.SetOut(genesisFile)
|
|
336
371
|
}
|
|
337
|
-
defer genesisFile.Close()
|
|
338
|
-
|
|
339
|
-
cmd.SetOut(genesisFile)
|
|
340
372
|
|
|
373
|
+
// If we don't have a VM, appExport will just use the OnExportHook to exec
|
|
374
|
+
// the VM program, which will result in reentering this function with the VM
|
|
375
|
+
// controller set, and activate the above condition.
|
|
341
376
|
return originalRunE(cmd, args)
|
|
342
377
|
}
|
|
343
378
|
|
|
344
|
-
|
|
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
|
-
}
|
|
379
|
+
cmd.RunE = extendedRunE
|
|
351
380
|
}
|
|
352
381
|
|
|
353
382
|
func (ac appCreator) appExport(
|
|
@@ -360,7 +389,9 @@ func (ac appCreator) appExport(
|
|
|
360
389
|
appOpts servertypes.AppOptions,
|
|
361
390
|
) (servertypes.ExportedApp, error) {
|
|
362
391
|
if OnExportHook != nil {
|
|
363
|
-
OnExportHook(logger)
|
|
392
|
+
if err := OnExportHook(logger, appOpts); err != nil {
|
|
393
|
+
return servertypes.ExportedApp{}, err
|
|
394
|
+
}
|
|
364
395
|
}
|
|
365
396
|
|
|
366
397
|
homePath, ok := appOpts.Get(flags.FlagHome).(string)
|
package/daemon/main.go
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package daemon
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"context"
|
|
4
5
|
"fmt"
|
|
5
6
|
"os"
|
|
6
7
|
"os/signal"
|
|
@@ -17,7 +18,7 @@ import (
|
|
|
17
18
|
)
|
|
18
19
|
|
|
19
20
|
// DefaultController is a stub controller.
|
|
20
|
-
var DefaultController = func(needReply bool, str string) (string, error) {
|
|
21
|
+
var DefaultController = func(ctx context.Context, needReply bool, str string) (string, error) {
|
|
21
22
|
return "", fmt.Errorf("Controller not configured; did you mean to use `ag-chain-cosmos` instead?")
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -34,6 +35,7 @@ func RunWithController(sendToController cmd.Sender) {
|
|
|
34
35
|
signal.Notify(sigs, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
|
35
36
|
go func() {
|
|
36
37
|
<-sigs
|
|
38
|
+
_, _ = sendToController(context.Background(), false, "shutdown")
|
|
37
39
|
os.Exit(98)
|
|
38
40
|
}()
|
|
39
41
|
|
package/git-revision.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
d355030
|
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-d355030.0+d355030",
|
|
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": "d35503027f8de03dfedf7bc3a5adce00d0985435"
|
|
39
39
|
}
|