Skip to content

Commit

Permalink
feat(swingset): defaultManagerType option in makeSwingsetController
Browse files Browse the repository at this point in the history
... and to buildVatController

Usage: WORKER_TYPE=xs-worker yarn test
   or: XSNAP_DEBUG=1 WORKER_TYPE=xs-worker yarn test
   or: XSNAP_DEBUG=1 WORKER_TYPE=xs-worker yarn test --watch

ref #2260

  - fix: comms vat must be local to use setUp
  - chore(swingset): log fallback-to-local workerType
  - chore: refine xs-worker diagnostics
  - chore(xs-worker): include vatID in log messages
  - fix(xs-worker): catch exceptions from exception handler
  - chore(swingset): use ambient process.env unless caller overrides
  - fix(swingset): proplems in types.js shown by @ts-check
  • Loading branch information
dckc committed Feb 5, 2021
1 parent ffa0057 commit 5184f71
Show file tree
Hide file tree
Showing 13 changed files with 89 additions and 36 deletions.
16 changes: 13 additions & 3 deletions packages/SwingSet/src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,16 @@ export async function makeSwingsetController(
) {
insistStorageAPI(hostStorage);

// Use ambient process.env only if caller did not specify.
const { env = process.env } = runtimeOptions;

// build console early so we can add console.log to diagnose early problems
const {
verbose,
debugPrefix = '',
slogFile,
testTrackDecref,
defaultManagerType = env.WORKER_TYPE || 'local',
} = runtimeOptions;
if (typeof Compartment === 'undefined') {
throw Error('SES must be installed before calling makeSwingsetController');
Expand Down Expand Up @@ -166,7 +170,7 @@ export async function makeSwingsetController(
name,
stdout: 'inherit',
stderr: 'inherit',
// debug: true,
debug: !!env.XSNAP_DEBUG,
});

const bundles = {
Expand Down Expand Up @@ -205,7 +209,7 @@ export async function makeSwingsetController(
FinalizationRegistry,
};

const kernelOptions = { verbose, testTrackDecref };
const kernelOptions = { verbose, testTrackDecref, defaultManagerType };
const kernel = buildKernel(kernelEndowments, deviceEndowments, kernelOptions);

if (runtimeOptions.verbose) {
Expand Down Expand Up @@ -298,8 +302,14 @@ export async function buildVatController(
kernelBundles,
debugPrefix,
testTrackDecref,
defaultManagerType,
} = runtimeOptions;
const actualRuntimeOptions = { verbose, debugPrefix, testTrackDecref };
const actualRuntimeOptions = {
verbose,
debugPrefix,
testTrackDecref,
defaultManagerType,
};
const initializationOptions = { verbose, kernelBundles };
let bootstrapResult;
if (!swingsetIsInitialized(hostStorage)) {
Expand Down
1 change: 1 addition & 0 deletions packages/SwingSet/src/initializeSwingset.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ export async function initializeSwingset(
creationOptions: {
enablePipelining: true,
enableSetup: true,
managerType: 'local',
},
};

Expand Down
7 changes: 6 additions & 1 deletion packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ export default function buildKernel(
FinalizationRegistry,
} = kernelEndowments;
deviceEndowments = { ...deviceEndowments }; // copy so we can modify
const { verbose, testTrackDecref = false } = kernelOptions;
const {
verbose,
testTrackDecref = false,
defaultManagerType = 'local',
} = kernelOptions;
const logStartup = verbose ? console.debug : () => 0;

insistStorageAPI(hostStorage);
Expand Down Expand Up @@ -562,6 +566,7 @@ export default function buildKernel(
startSubprocessWorkerNode,
startXSnap,
gcTools,
defaultManagerType,
});

function buildVatSyscallHandler(vatID, translators) {
Expand Down
24 changes: 19 additions & 5 deletions packages/SwingSet/src/kernel/vatManager/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function makeVatManagerFactory({
startSubprocessWorkerNode,
startXSnap,
gcTools,
defaultManagerType,
}) {
const localFactory = makeLocalVatManagerFactory({
allVatPowers,
Expand Down Expand Up @@ -75,17 +76,30 @@ export function makeVatManagerFactory({
// returns promise for new vatManager
function vatManagerFactory(vatID, managerOptions) {
validateManagerOptions(managerOptions);
const { managerType = 'local', setup, bundle } = managerOptions;
const {
managerType = defaultManagerType,
setup,
bundle,
metered,
enableSetup,
} = managerOptions;

if (managerType === 'local') {
if (metered && managerType !== 'local') {
console.warn(
`TODO: support metered with ${managerType}; using local as work-around`,
);
}
if (setup && managerType !== 'local') {
console.warn(
`TODO: stop using setup() with ${managerType}; using local as work-around`,
);
}
if (managerType === 'local' || metered || enableSetup) {
if (setup) {
return localFactory.createFromSetup(vatID, setup, managerOptions);
}
return localFactory.createFromBundle(vatID, bundle, managerOptions);
}
// 'setup' based vats must be local. TODO: stop using 'setup' in vats,
// but tests and comms-vat still need it
assert(!setup, `setup()-based vats must use a local Manager`);

if (managerType === 'nodeWorker') {
return nodeWorkerFactory.createFromBundle(vatID, bundle, managerOptions);
Expand Down
25 changes: 14 additions & 11 deletions packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ export function makeXsSubprocessFactory({
* @param { ManagerOptions } managerOptions
*/
async function createFromBundle(vatID, bundle, managerOptions) {
parentLog('createFromBundle', { vatID });
parentLog(vatID, 'createFromBundle', { vatID });
const { vatParameters, virtualObjectCacheSize } = managerOptions;
assert(!managerOptions.metered, 'not supported yet');
assert(!managerOptions.enableSetup, 'not supported at all');
assert(!managerOptions.metered, 'xs-worker: metered not supported yet');
assert(
!managerOptions.enableSetup,
'xs-worker: enableSetup not supported at all',
);
if (managerOptions.enableInternalMetering) {
// TODO: warn+ignore, rather than throw, because the kernel enables it
// for all vats, because the Spawner still needs it. When the kernel
Expand Down Expand Up @@ -74,10 +77,10 @@ export function makeXsSubprocessFactory({

/** @type { (item: Tagged) => unknown } */
function handleUpstream([type, ...args]) {
parentLog(`handleUpstream`, type, args.length);
parentLog(vatID, `handleUpstream`, type, args.length);
switch (type) {
case 'syscall': {
parentLog(`syscall`, args);
parentLog(vatID, `syscall`, args[0], args.length);
const [scTag, ...vatSyscallArgs] = args;
return handleSyscall([scTag, ...vatSyscallArgs]);
}
Expand Down Expand Up @@ -116,15 +119,15 @@ export function makeXsSubprocessFactory({

/** @type { (msg: Uint8Array) => Uint8Array } */
function handleCommand(msg) {
parentLog('handleCommand', { length: msg.byteLength });
// parentLog('handleCommand', { length: msg.byteLength });
const tagged = handleUpstream(JSON.parse(decoder.decode(msg)));
return encoder.encode(JSON.stringify(tagged));
}

// start the worker and establish a connection
const { worker, bundles } = startXSnap(`${vatID}`, handleCommand);
for await (const [it, superCode] of Object.entries(bundles)) {
parentLog('bundle', it);
parentLog(vatID, 'eval bundle', it);
assert(
superCode.moduleFormat === 'getExport',
details`${it} unexpected: ${superCode.moduleFormat}`,
Expand All @@ -134,15 +137,15 @@ export function makeXsSubprocessFactory({

/** @type { (item: Tagged) => Promise<Tagged> } */
async function issueTagged(item) {
parentLog('issueTagged', item[0]);
parentLog(item[0], '...', item.length - 1);
const txt = await worker.issueStringCommand(JSON.stringify(item));
const reply = JSON.parse(txt);
assert(Array.isArray(reply));
const [tag, ...rest] = reply;
return [tag, ...rest];
}

parentLog(`instructing worker to load bundle..`);
parentLog(vatID, `instructing worker to load bundle..`);
const bundleReply = await issueTagged([
'setBundle',
vatID,
Expand All @@ -151,7 +154,7 @@ export function makeXsSubprocessFactory({
virtualObjectCacheSize,
]);
if (bundleReply[0] === 'dispatchReady') {
parentLog(`bundle loaded. dispatch ready.`);
parentLog(vatID, `bundle loaded. dispatch ready.`);
} else {
throw new Error(`failed to setBundle: ${bundleReply}`);
}
Expand Down Expand Up @@ -189,7 +192,7 @@ export function makeXsSubprocessFactory({
shutdown,
});

parentLog('manager', Object.keys(manager));
parentLog(vatID, 'manager', Object.keys(manager));
return manager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const decoder = new TextDecoder();
function workerLog(first, ...args) {
// @ts-ignore
// eslint-disable-next-line
// print(`---worker: ${first}`, ...args);
// console.log(`---worker: ${first}`, ...args);
}

workerLog(`supervisor started`);
Expand Down Expand Up @@ -59,6 +59,7 @@ function managerPort(issueCommand) {
* @template T
*/
handlerFrom(f) {
const lastResort = encoder.encode(`exception from ${f.name}`).buffer;
return msg => {
const report = {};
f(decode(msg))
Expand All @@ -67,7 +68,10 @@ function managerPort(issueCommand) {
report.result = encode(item);
})
.catch(err => {
report.result = encode(['err', err.message]);
report.result = encode(['err', f.name, err.message]);
})
.catch(_err => {
report.result = lastResort;
});
return report;
};
Expand All @@ -82,12 +86,14 @@ function managerPort(issueCommand) {
function runAndWait(f, errmsg) {
Promise.resolve()
.then(f)
.then(undefined, err => workerLog(`doProcess: ${errmsg}:`, err));
.then(undefined, err => {
workerLog(`doProcess: ${errmsg}:`, err.message);
});
return waitUntilQuiescent();
}

/**
* @param { ReturnType<managerPort> } port
* @param { ReturnType<typeof managerPort> } port
*/
function makeWorker(port) {
/** @type { Record<string, (...args: unknown[]) => void> | null } */
Expand Down
12 changes: 6 additions & 6 deletions packages/SwingSet/src/types.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// @ts-check

/**
* @typedef {Object} CapData
* @property {string} body
* @property {Array<string>} slots
* @typedef {CapData<string>} CapDataS
*/

/**
* @typedef {{
* bundle: Bundle,
* bundle: unknown,
* enableSetup: false,
* }} HasBundle
* @typedef {{
Expand All @@ -21,7 +21,7 @@
* managerType: 'local' | 'nodeWorker' | 'node-subprocess' | 'xs-worker',
* metered?: boolean,
* enableInternalMetering?: boolean,
* vatParameters: Serializable,
* vatParameters: Record<string, unknown>,
* virtualObjectCacheSize: number,
* } & (HasBundle | HasSetup)} ManagerOptions
*/
Expand All @@ -44,7 +44,7 @@
* }} MeteringVatPowers
*
* @typedef {{
* transformTildot: ReturnType<import('@agoric/transform-eventual-send').makeTransform>,
* transformTildot: ReturnType<typeof import('@agoric/transform-eventual-send').makeTransform>,
* }} EventualSyntaxVatPowers
*
* @typedef {{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ function capargs(args, slots = []) {
return capdata(JSON.stringify(args), slots);
}

const localOnlyForNow = { defaultManagerType: 'local' };

// Dynamic vats can be created without metering

test('unmetered dynamic vat', async t => {
Expand All @@ -23,7 +25,7 @@ test('unmetered dynamic vat', async t => {
},
},
};
const c = await buildVatController(config, []);
const c = await buildVatController(config, [], localOnlyForNow);
const nextLog = makeNextLog(c);

// let the vatAdminService get wired up before we create any new vats
Expand Down
4 changes: 3 additions & 1 deletion packages/SwingSet/test/metering/test-within-vat.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ function capargs(args, slots = []) {
return capdata(JSON.stringify(args), slots);
}

const localOnlyForNow = { defaultManagerType: 'local' };

test('metering within a vat', async t => {
// we'll give this bundle to the vat, which will import it under metering
const bundle = await bundleSource(require.resolve('./metered-code.js'));
Expand All @@ -22,7 +24,7 @@ test('metering within a vat', async t => {
},
},
};
const c = await buildVatController(config, []);
const c = await buildVatController(config, [], localOnlyForNow);
const nextLog = makeNextLog(c);

// 'start' will import the bundle
Expand Down
6 changes: 5 additions & 1 deletion packages/SwingSet/test/test-device-bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ test('bridge device', async t => {

await initializeSwingset(config, argv, storage.storage);
const c = await makeSwingsetController(storage.storage, deviceEndowments);
t.teardown(c.shutdown);
await c.run();

t.deepEqual(outboundLog, argv);
Expand Down Expand Up @@ -141,7 +142,10 @@ test('bridge device can return undefined', async t => {
argv[0] = { hello: 'from' };
argv[1] = ['swingset'];
await initializeSwingset(config, argv, storage.storage);
const c = await makeSwingsetController(storage.storage, deviceEndowments);
const c = await makeSwingsetController(storage.storage, deviceEndowments, {
defaultManagerType: 'local',
});
t.teardown(c.shutdown);
await c.run();

t.deepEqual(outboundLog, argv);
Expand Down
7 changes: 6 additions & 1 deletion packages/SwingSet/test/test-message-patterns.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ test.before(async t => {
creationOptions: {
enablePipelining: true,
enableSetup: true,
managerType: 'local',
},
};
const moreVatTP = { bundle: kernelBundles.vattp };
Expand All @@ -97,7 +98,10 @@ test.before(async t => {

export async function runVatsLocally(t, name) {
const { localConfig: config, kernelBundles } = t.context.data;
const c = await buildVatController(config, [name], { kernelBundles });
const c = await buildVatController(config, [name], {
kernelBundles,
});
t.teardown(c.shutdown);
// await runWithTrace(c);
await c.run();
return c.dump().log;
Expand Down Expand Up @@ -135,6 +139,7 @@ export async function runVatsInComms(t, name) {
const hostStorage = initSwingStore().storage;
await initializeSwingset(config, [name], hostStorage, { kernelBundles });
const c = await makeSwingsetController(hostStorage, deviceEndowments);
t.teardown(c.shutdown);

// await runWithTrace(c);
await c.run();
Expand Down
3 changes: 2 additions & 1 deletion packages/SwingSet/test/test-tildot.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ test('vat code can use tildot', async t => {
},
},
};
const c = await buildVatController(config, []);
const c = await buildVatController(config);
t.teardown(c.shutdown);
await c.step();
// this also checks that vats get transformTildot, e.g. for a REPL
t.deepEqual(c.dump().log, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ test('exit with presence', async t => {
]);
});

test('dispatches to the dead do not harm kernel', async t => {
test.failing('dispatches to the dead do not harm kernel', async t => {
const configPath = path.resolve(__dirname, 'swingset-speak-to-dead.json');
const config = loadSwingsetConfigFile(configPath);

Expand Down

0 comments on commit 5184f71

Please sign in to comment.