|
1 | 1 | #! /usr/bin/env node
|
2 |
| -//console.log('Starting Node'); |
3 |
| -require = require('esm')(module); |
4 | 2 |
|
5 |
| -const bootAddress = process.env.BOOT_ADDRESS; |
6 |
| -const ROLE = process.env.ROLE || 'chain'; |
7 |
| -const BEGIN_BLOCK = 'BEGIN_BLOCK'; |
8 |
| -const DELIVER_INBOUND = 'DELIVER_INBOUND'; |
9 |
| -const AG_COSMOS_INIT = 'AG_COSMOS_INIT'; |
10 |
| - |
11 |
| -// TODO: use the 'basedir' pattern |
12 |
| - |
13 |
| -// Try to determine the cosmos chain home. |
14 |
| -function getFlagValue(flagName, deflt) { |
15 |
| - let flagValue = deflt; |
16 |
| - const envValue = process.env[`AG_CHAIN_COSMOS_${flagName.toUpperCase()}`]; |
17 |
| - if (envValue !== undefined) { |
18 |
| - flagValue = envValue; |
19 |
| - } |
20 |
| - const flag = `--${flagName}`; |
21 |
| - const flagEquals = `--${flagName}=`; |
22 |
| - for (let i = 0; i < process.argv.length; i += 1) { |
23 |
| - const arg = process.argv[i]; |
24 |
| - if (arg === flag) { |
25 |
| - i += 1; |
26 |
| - flagValue = process.argv[i]; |
27 |
| - } else if (arg.startsWith(flagEquals)) { |
28 |
| - flagValue = arg.substr(flagEquals.length); |
29 |
| - } |
30 |
| - } |
31 |
| - return flagValue; |
32 |
| -} |
33 |
| - |
34 |
| -// We try to find the actual cosmos state directory (default=~/.ag-chain-cosmos), which |
35 |
| -// is better than scribbling into the current directory. |
36 |
| -const cosmosHome = getFlagValue('home', `${process.env.HOME}/.ag-chain-cosmos`); |
37 |
| -const stateDBDir = `${cosmosHome}/data/ag-cosmos-chain-state`; |
38 |
| - |
39 |
| -const { launch } = require('./launch-chain'); |
40 | 3 | const path = require('path');
|
41 |
| -const stringify = require('@agoric/swingset-vat/src/kernel/json-stable-stringify').default; |
42 |
| - |
43 | 4 | const agcc = require('bindings')('agcosmosdaemon.node');
|
44 |
| -//console.log('Have AG_COSMOS', agcc); |
45 |
| - |
46 |
| -const portHandlers = {}; |
47 |
| -let lastPort = 0; |
48 |
| -function registerPortHandler(portHandler) { |
49 |
| - const port = ++lastPort; |
50 |
| - portHandlers[port] = portHandler; |
51 |
| - return port; |
52 |
| -} |
53 |
| -function fromGo(port, str, replier) { |
54 |
| - const handler = portHandlers[port]; |
55 |
| - if (!handler) { |
56 |
| - return replier.reject(`invalid requested port ${port}`); |
57 |
| - } |
58 |
| - const action = JSON.parse(str); |
59 |
| - const p = Promise.resolve(handler(action)); |
60 |
| - p.then(res => replier.resolve(`${res}`), |
61 |
| - rej => replier.reject(`rejection ${rej} ignored`)); |
62 |
| -} |
63 |
| - |
64 |
| -// Actually run the main ag-chain-cosmos program. Before we start the daemon, |
65 |
| -// there will be a call to nodePort/AG_COSMOS_INIT, otherwise exit. |
66 |
| -const nodePort = registerPortHandler(toSwingSet); |
67 |
| -// Need to keep the process alive until Go exits. |
68 |
| -setInterval(() => undefined, 30000); |
69 |
| -agcc.runAgCosmosDaemon(nodePort, fromGo, process.argv.slice(1)); |
70 |
| - |
71 |
| -let deliverInbound; |
72 |
| -let deliverStartBlock; |
73 |
| -let deliveryFunctionsInitialized = false; |
74 |
| - |
75 |
| -// this storagePort changes for every single message. We define it out here |
76 |
| -// so the 'externalStorage' object can close over the single mutable |
77 |
| -// instance, and we update the 'sPort' value each time toSwingSet is called |
78 |
| -let sPort; |
79 |
| - |
80 |
| -function toSwingSet(action, replier) { |
81 |
| - // console.log(`toSwingSet`, action, replier); |
82 |
| - return toSwingSet0(action, replier) |
83 |
| - .then(ret => { |
84 |
| - // console.log(`toSwingSet returning:`, ret); |
85 |
| - return ret; |
86 |
| - }, err => { |
87 |
| - console.log('toSwingSet threw error:', err); |
88 |
| - throw err; |
89 |
| - }); |
90 |
| -} |
91 |
| - |
92 |
| -async function launchAndInitializeDeliverInbound() { |
93 |
| - // this object is used to store the mailbox state. we only ever use |
94 |
| - // key='mailbox' |
95 |
| - const mailboxStorage = { |
96 |
| - has(key) { |
97 |
| - // x/swingset/storage.go returns "true" or "false" |
98 |
| - const retStr = agcc.send(sPort, stringify({ method: 'has', key })); |
99 |
| - const ret = JSON.parse(retStr); |
100 |
| - if (Boolean(ret) !== ret) { |
101 |
| - throw new Error(`agcc.send(has) returned ${ret} not Boolean`); |
102 |
| - } |
103 |
| - return ret; |
104 |
| - }, |
105 |
| - set(key, value) { |
106 |
| - if (value !== `${value}`) { |
107 |
| - throw new Error(`golang storage API only takes string values, not '${JSON.stringify(value)}'`); |
108 |
| - } |
109 |
| - const encodedValue = stringify(value); |
110 |
| - agcc.send(sPort, stringify({ method: 'set', key, value: encodedValue })); |
111 |
| - }, |
112 |
| - get(key) { |
113 |
| - const retStr = agcc.send(sPort, stringify({ method: 'get', key })); |
114 |
| - //console.log(`s.get(${key}) retstr=${retstr}`); |
115 |
| - const encodedValue = JSON.parse(retStr); |
116 |
| - //console.log(` encodedValue=${encodedValue}`); |
117 |
| - const value = JSON.parse(encodedValue); |
118 |
| - //console.log(` value=${value}`); |
119 |
| - return value; |
120 |
| - }, |
121 |
| - }; |
122 |
| - |
123 |
| - const vatsdir = path.resolve(__dirname, '../lib/ag-solo/vats'); |
124 |
| - const argv = [`--role=${ROLE}`]; |
125 |
| - if (bootAddress) { |
126 |
| - argv.push(...bootAddress.trim().split(/\s+/)); |
127 |
| - } |
128 |
| - const s = await launch(stateDBDir, mailboxStorage, vatsdir, argv); |
129 |
| - return s; |
130 |
| -} |
131 |
| - |
132 |
| -async function toSwingSet0(action, _replier) { |
133 |
| - if (action.type === AG_COSMOS_INIT) { |
134 |
| - return true; |
135 |
| - } |
136 |
| - |
137 |
| - // Only start running for DELIVER_INBOUND. |
138 |
| - if (action.type !== DELIVER_INBOUND && action.type !== BEGIN_BLOCK) { |
139 |
| - throw `Unknown action type ${action.type}`; |
140 |
| - } |
141 |
| - |
142 |
| - if (action.storagePort) { |
143 |
| - // Initialize the storage for this particular transaction. |
144 |
| - // console.log(` setting sPort to`, action.storagePort); |
145 |
| - sPort = action.storagePort; |
146 |
| - } |
147 |
| - |
148 |
| - // launch the swingset once |
149 |
| - if (!deliveryFunctionsInitialized) { |
150 |
| - const deliveryFunctions = await launchAndInitializeDeliverInbound(); |
151 |
| - deliverInbound = deliveryFunctions.deliverInbound; |
152 |
| - deliverStartBlock = deliveryFunctions.deliverStartBlock; |
153 |
| - deliveryFunctionsInitialized = true; |
154 |
| - } |
155 |
| - |
156 |
| - switch (action.type) { |
157 |
| - case DELIVER_INBOUND: |
158 |
| - return deliverInbound( |
159 |
| - action.peer, |
160 |
| - action.messages, |
161 |
| - action.ack, |
162 |
| - action.blockHeight, |
163 |
| - action.blockTime, |
164 |
| - action.committed, |
165 |
| - ); |
166 |
| - case BEGIN_BLOCK: |
167 |
| - return deliverStartBlock( |
168 |
| - action.blockHeight, |
169 |
| - action.blockTime, |
170 |
| - action.committed, |
171 |
| - ); |
172 |
| - default: |
173 |
| - throw new Error(`${action.type} not recognized. must be DELIVER_INBOUND or BEGIN_BLOCK`); |
174 |
| - } |
175 |
| -} |
| 5 | +const esmRequire = require('esm')(module); |
| 6 | + |
| 7 | +const main = esmRequire('./chain-main.js').default; |
| 8 | + |
| 9 | +main(process.argv[1], process.argv.splice(2), { |
| 10 | + path, |
| 11 | + env: process.env, |
| 12 | + agcc, |
| 13 | +}).then( |
| 14 | + _res => 0, |
| 15 | + rej => { |
| 16 | + console.log(`error running ag-chain-cosmos:`, rej); |
| 17 | + process.exit(1); |
| 18 | + }, |
| 19 | +); |
0 commit comments