Skip to content

Commit 2e8d22d

Browse files
committed
refactor: move bulk of ag-chain-cosmos into chain-main.js
Also, tolerate the new END_BLOCK message.
1 parent b115b55 commit 2e8d22d

File tree

3 files changed

+202
-173
lines changed

3 files changed

+202
-173
lines changed
+15-171
Original file line numberDiff line numberDiff line change
@@ -1,175 +1,19 @@
11
#! /usr/bin/env node
2-
//console.log('Starting Node');
3-
require = require('esm')(module);
42

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

packages/cosmic-swingset/lib/launch-chain.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export async function launch(kernelStateDBDir, mailboxStorage, vatsDir, argv) {
116116
saveState(runTime);
117117
}
118118

119-
async function deliverInbound(sender, messages, ack, _committed) {
119+
async function deliverInbound(sender, messages, ack) {
120120
if (!(messages instanceof Array)) {
121121
throw new Error(`inbound given non-Array: ${messages}`);
122122
}
@@ -126,7 +126,7 @@ export async function launch(kernelStateDBDir, mailboxStorage, vatsDir, argv) {
126126
await turnCrank();
127127
}
128128

129-
async function deliverStartBlock(blockHeight, blockTime, _committed) {
129+
async function deliverStartBlock(blockHeight, blockTime) {
130130
const addedToQueue = timer.poll(blockTime);
131131
console.log(
132132
`polled; blockTime:${blockTime}, h:${blockHeight} ADDED: ${addedToQueue}`,

0 commit comments

Comments
 (0)