From e0ec2fdc2b86419833ef642b8ea00727dfa00cfd Mon Sep 17 00:00:00 2001 From: Chip Morningstar Date: Wed, 16 Feb 2022 23:32:33 -0800 Subject: [PATCH] feat: run vat creation and initialization in a crank to access to syscall and transcript logging Closes #2910 --- .../SwingSet/src/kernel/initializeKernel.js | 6 + packages/SwingSet/src/kernel/kernel.js | 103 ++++++++++++++---- packages/SwingSet/src/kernel/liveSlots.js | 63 ++++++----- .../src/kernel/vatAdmin/vatAdminWrapper.js | 3 + .../SwingSet/src/kernel/vatManager/factory.js | 10 +- .../src/kernel/vatManager/manager-local.js | 61 ++++++----- .../kernel/vatManager/manager-nodeworker.js | 3 +- .../vatManager/manager-subprocess-node.js | 3 +- .../vatManager/manager-subprocess-xsnap.js | 3 +- .../vatManager/supervisor-nodeworker.js | 41 ++++--- .../vatManager/supervisor-subprocess-node.js | 43 ++++---- .../vatManager/supervisor-subprocess-xsnap.js | 42 +++---- packages/SwingSet/src/kernel/vatTranslator.js | 12 ++ packages/SwingSet/src/message.js | 1 + packages/SwingSet/src/types.js | 8 +- packages/SwingSet/src/vats/comms/dispatch.js | 4 + packages/SwingSet/test/devices/bootstrap-0.js | 8 +- packages/SwingSet/test/devices/bootstrap-1.js | 24 ++-- packages/SwingSet/test/devices/bootstrap-4.js | 42 +++---- .../SwingSet/test/devices/test-devices.js | 32 +++++- packages/SwingSet/test/liveslots-helpers.js | 10 +- .../test/run-policy/test-run-policy.js | 4 + packages/SwingSet/test/stores/test-storeGC.js | 53 +++++---- packages/SwingSet/test/test-controller.js | 26 ++++- packages/SwingSet/test/test-liveslots.js | 46 ++++---- packages/SwingSet/test/test-promises.js | 6 + packages/SwingSet/test/test-vat-env.js | 6 + packages/SwingSet/test/test-vpid-liveslots.js | 10 +- packages/SwingSet/test/test-xsnap-errors.js | 3 + .../test/vat-admin/broken-module-vat.js | 6 + .../{broken-vat.js => broken-root-vat.js} | 0 .../test/vat-admin/test-create-vat.js | 39 +++++-- packages/SwingSet/test/vat-util.js | 2 +- .../vat-warehouse/test-reload-snapshot.js | 8 +- .../virtualObjects/test-virtualObjectGC.js | 53 +++++---- 35 files changed, 523 insertions(+), 261 deletions(-) create mode 100644 packages/SwingSet/test/vat-admin/broken-module-vat.js rename packages/SwingSet/test/vat-admin/{broken-vat.js => broken-root-vat.js} (100%) diff --git a/packages/SwingSet/src/kernel/initializeKernel.js b/packages/SwingSet/src/kernel/initializeKernel.js index 04faa959a168..6a10ef019189 100644 --- a/packages/SwingSet/src/kernel/initializeKernel.js +++ b/packages/SwingSet/src/kernel/initializeKernel.js @@ -72,6 +72,9 @@ export function initializeKernel(config, hostStorage, verbose = false) { creationOptions.vatParameters = vatParameters; creationOptions.description = `static name=${name}`; creationOptions.name = name; + if (creationOptions.useTranscript === undefined) { + creationOptions.useTranscript = true; + } if (!creationOptions.managerType) { creationOptions.managerType = kernelKeeper.getDefaultManagerType(); } @@ -84,6 +87,9 @@ export function initializeKernel(config, hostStorage, verbose = false) { const vatKeeper = kernelKeeper.provideVatKeeper(vatID); vatKeeper.setSourceAndOptions({ bundleID }, creationOptions); vatKeeper.initializeReapCountdown(creationOptions.reapInterval); + if (!creationOptions.enableSetup) { + kernelKeeper.addToRunQueue(harden({ type: 'startVat', vatID })); + } if (name === 'vatAdmin') { // Create a kref for the vatAdmin root, so the kernel can tell it // about creation/termination of dynamic vats. diff --git a/packages/SwingSet/src/kernel/kernel.js b/packages/SwingSet/src/kernel/kernel.js index cf0a6393bbf6..9e515b0fc261 100644 --- a/packages/SwingSet/src/kernel/kernel.js +++ b/packages/SwingSet/src/kernel/kernel.js @@ -336,31 +336,32 @@ export default function buildKernel( */ function terminateVat(vatID, shouldReject, info) { insistCapData(info); + // guard against somebody telling vatAdmin to kill a vat twice if (kernelKeeper.vatIsAlive(vatID)) { - const isDynamic = kernelKeeper.getDynamicVats().includes(vatID); const promisesToReject = kernelKeeper.cleanupAfterTerminatedVat(vatID); for (const kpid of promisesToReject) { resolveToError(kpid, VAT_TERMINATION_ERROR, vatID); } - if (isDynamic) { - assert( - vatAdminRootKref, - `initializeKernel did not set vatAdminRootKref`, - ); - notifyTermination( - vatID, - vatAdminRootKref, - shouldReject, - info, - queueToKref, - ); - } // else... static... maybe panic??? // ISSUE: terminate stuff in its own crank like creation? // eslint-disable-next-line no-use-before-define vatWarehouse.vatWasTerminated(vatID); } + if (vatAdminRootKref) { + // static vat termination can happen before vat admin vat exists + notifyTermination( + vatID, + vatAdminRootKref, + shouldReject, + info, + queueToKref, + ); + } else { + console.log( + `warning: vat ${vatID} terminated without a vatAdmin to report to`, + ); + } } let terminationTrigger; @@ -370,6 +371,7 @@ export default function buildKernel( terminationTrigger = undefined; postAbortActions = { meterDeductions: [], // list of { meterID, compute } + discardFailedDelivery: false, }; } resetDeliveryTriggers(); @@ -684,12 +686,40 @@ export default function buildKernel( return harden(policyInput); } + async function processStartVat(message) { + postAbortActions.discardFailedDelivery = true; + const { type, vatID } = message; + // console.log(`-- processStartVat(${vatID})`); + insistVatID(vatID); + // eslint-disable-next-line no-use-before-define + if (!vatWarehouse.lookup(vatID)) { + // Note a bit of weirdness here: if a vat's module initialization or + // buildRootObject function throws an error, the crank in which it was + // executed will be aborted, which will leave the 'startVat' delivery on + // the run queue (since the removal of the request from the run queue will + // have been rolled back by the abort). This means it will be delivered + // *again* on the next crank; that, however, will lead us here: the vat + // won't exist (because it was terminated) and the nugatory redundant + // 'startVat' will safely render as a no-op and go away. + /** @type { PolicyInput } */ + const policyInput = harden(['create-vat', {}]); + return harden(policyInput); + } + const kd = harden([type]); // TODO(4381) add vatParameters here + // eslint-disable-next-line no-use-before-define + const vd = vatWarehouse.kernelDeliveryToVatDelivery(vatID, kd); + // TODO: can we provide a computron count to the run policy? + const policyInput = await deliverAndLogToVat(vatID, kd, vd, false); + return harden(policyInput); + } + /** * * @param { * } message * @returns { Promise } */ async function processCreateVat(message) { + postAbortActions.discardFailedDelivery = true; assert(vatAdminRootKref, `initializeKernel did not set vatAdminRootKref`); const { vatID, source, dynamicOptions } = message; kernelKeeper.addDynamicVatID(vatID); @@ -703,6 +733,7 @@ export default function buildKernel( } vatKeeper.setSourceAndOptions(source, options); vatKeeper.initializeReapCountdown(options.reapInterval); + const { enableSetup } = options; function makeSuccessResponse() { // build success message, giving admin vat access to the new vat's root @@ -733,14 +764,22 @@ export default function buildKernel( /** @type { PolicyInput } */ const policyInput = harden(['create-vat', {}]); + // TODO: combine this with the return value from processStartVat - // eslint-disable-next-line no-use-before-define - return vatWarehouse - .createDynamicVat(vatID) - .then(makeSuccessResponse, makeErrorResponse) - .then(sendResponse) - .catch(err => console.error(`error in vat creation`, err)) - .then(() => policyInput); + return ( + // eslint-disable-next-line no-use-before-define + vatWarehouse + .createDynamicVat(vatID) + // if createDynamicVat fails, go directly to makeErrorResponse + .then(_ => + enableSetup ? null : processStartVat({ type: 'startVat', vatID }), + ) // TODO(4381) add vatParameters here + // if processStartVat fails, do we need to clean up the vat first?? + .then(makeSuccessResponse, makeErrorResponse) + .then(sendResponse) + .catch(err => console.error(`error in vat creation`, err)) + .then(() => policyInput) + ); } function legibilizeMessage(message) { @@ -751,11 +790,17 @@ export default function buildKernel( return `@${message.target} <- ${msg.method}(${argList}) : @${result}`; } else if (message.type === 'notify') { return `notify(vatID: ${message.vatID}, kpid: @${message.kpid})`; + } else if (message.type === 'create-vat') { + // prettier-ignore + return `create-vat ${message.vatID} opts: ${JSON.stringify(message.dynamicOptions)}`; // eslint-disable-next-line no-use-before-define } else if (gcMessages.includes(message.type)) { // prettier-ignore return `${message.type} ${message.vatID} ${message.krefs.map(e=>`@${e}`).join(' ')}`; - } else if (message.type === 'bringOutYourDead') { + } else if ( + message.type === 'bringOutYourDead' || + message.type === 'startVat' + ) { return `${message.type} ${message.vatID}`; } else { return `unknown message type ${message.type}`; @@ -797,7 +842,10 @@ export default function buildKernel( kernelKeeper.decrementRefCount(message.kpid, `deq|notify`); policyInput = await processNotify(message); } else if (message.type === 'create-vat') { + // creating a new dynamic vat will immediately do start-vat policyInput = await processCreateVat(message); + } else if (message.type === 'startVat') { + policyInput = await processStartVat(message); } else if (message.type === 'bringOutYourDead') { policyInput = await processBringOutYourDead(message); } else if (gcMessages.includes(message.type)) { @@ -814,11 +862,20 @@ export default function buildKernel( kernelKeeper.abortCrank(); didAbort = true; // but metering deductions and underflow notifications must survive - const { meterDeductions } = postAbortActions; + const { meterDeductions, discardFailedDelivery } = postAbortActions; for (const { meterID, compute } of meterDeductions) { deductMeter(meterID, compute, false); // that will re-push any notifications } + if (discardFailedDelivery) { + // kernelKeeper.abortCrank removed all evidence that the crank ever + // happened, including, notably, the removal of the delivery itself + // from the head of the run queue, which will result in it being + // delivered again on the next crank. If we don't want that, then + // we need to remove it again. + // eslint-disable-next-line no-use-before-define + getNextMessage(); + } } // state changes reflecting the termination must also survive, so // these happen after a possible abortCrank() diff --git a/packages/SwingSet/src/kernel/liveSlots.js b/packages/SwingSet/src/kernel/liveSlots.js index ed596b0d8a84..76aff74f0a60 100644 --- a/packages/SwingSet/src/kernel/liveSlots.js +++ b/packages/SwingSet/src/kernel/liveSlots.js @@ -36,13 +36,9 @@ const DEFAULT_VIRTUAL_OBJECT_CACHE_SIZE = 3; // XXX ridiculously small value to * @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent, gcAndFinalize, * meterControl } * @param {Console} console - * @returns {*} { vatGlobals, inescapableGlobalProperties, dispatch, setBuildRootObject } + * @param {*} buildVatNamespace * - * setBuildRootObject should be called, once, with a function that will - * create a root object for the new vat The caller provided buildRootObject - * function produces and returns the new vat's root object: - * - * buildRootObject(vatPowers, vatParameters) + * @returns {*} { dispatch } */ function build( syscall, @@ -54,6 +50,7 @@ function build( vatParameters, gcTools, console, + buildVatNamespace, ) { const { WeakRef, FinalizationRegistry, meterControl } = gcTools; const enableLSDebug = false; @@ -63,7 +60,7 @@ function build( } } - let didRoot = false; + let didStartVat = false; const outstandingProxies = new WeakSet(); @@ -825,7 +822,7 @@ function build( } function deliver(target, method, argsdata, result) { - assert(didRoot); + assert(didStartVat); insistCapData(argsdata); lsdebug( `ls[${forVatID}].dispatch.deliver ${target}.${method} -> ${result}`, @@ -951,7 +948,7 @@ function build( } function notify(resolutions) { - assert(didRoot); + assert(didStartVat); beginCollectingPromiseImports(); for (const resolution of resolutions) { const [vpid, rejected, data] = resolution; @@ -1103,9 +1100,22 @@ function build( assert(key.match(/^[-\w.+/]+$/), X`invalid vatstore key`); } - function setBuildRootObject(buildRootObject) { - assert(!didRoot); - didRoot = true; + async function startVat() { + assert(!didStartVat); + didStartVat = true; + // consume the first (unmetered) turn to ensure vat module code runs with metering + await Promise.resolve(); + // syscalls/VatData/makeKind must be enabled before invoking buildVatNamespace + const vatNS = await buildVatNamespace( + vatGlobals, + inescapableGlobalProperties, + ); + const buildRootObject = vatNS.buildRootObject; + assert.typeof( + buildRootObject, + 'function', + X`vat source bundle lacks buildRootObject() function`, + ); // Build the `vatPowers` provided to `buildRootObject`. We include // vatGlobals and inescapableGlobalProperties to make it easier to write @@ -1192,6 +1202,7 @@ function build( * @returns { void } */ function dispatchToUserspace(delivery) { + let result; const [type, ...args] = delivery; switch (type) { case 'message': { @@ -1220,9 +1231,14 @@ function build( retireImports(vrefs); break; } + case 'startVat': { + result = startVat(); + break; + } default: assert.fail(X`unknown delivery type ${type}`); } + return result; } // the first turn of each dispatch is spent in liveslots, and is not @@ -1299,10 +1315,10 @@ function build( // we return 'possiblyDeadSet' for unit tests return harden({ + dispatch, + startVat, vatGlobals, inescapableGlobalProperties, - setBuildRootObject, - dispatch, m, possiblyDeadSet, testHooks, @@ -1322,7 +1338,9 @@ function build( * @param {boolean} enableVatstore * @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent } * @param {Pick} [liveSlotsConsole] - * @returns {*} { vatGlobals, inescapableGlobalProperties, dispatch, setBuildRootObject } + * @param {*} buildVatNamespace + * + * @returns {*} { vatGlobals, inescapableGlobalProperties, dispatch } * * setBuildRootObject should be called, once, with a function that will * create a root object for the new vat The caller provided buildRootObject @@ -1356,6 +1374,7 @@ export function makeLiveSlots( enableVatstore = false, gcTools, liveSlotsConsole = console, + buildVatNamespace, ) { const allVatPowers = { ...vatPowers, @@ -1371,20 +1390,12 @@ export function makeLiveSlots( vatParameters, gcTools, liveSlotsConsole, + buildVatNamespace, ); - const { - vatGlobals, - inescapableGlobalProperties, - dispatch, - setBuildRootObject, - possiblyDeadSet, - testHooks, - } = r; // omit 'm' + const { dispatch, startVat, possiblyDeadSet, testHooks } = r; // omit 'm' return harden({ - vatGlobals, - inescapableGlobalProperties, dispatch, - setBuildRootObject, + startVat, possiblyDeadSet, testHooks, }); diff --git a/packages/SwingSet/src/kernel/vatAdmin/vatAdminWrapper.js b/packages/SwingSet/src/kernel/vatAdmin/vatAdminWrapper.js index 21d649187211..214c983e2c59 100644 --- a/packages/SwingSet/src/kernel/vatAdmin/vatAdminWrapper.js +++ b/packages/SwingSet/src/kernel/vatAdmin/vatAdminWrapper.js @@ -154,6 +154,9 @@ export function buildRootObject(vatPowers) { // the kernel sends this when the vat halts function vatTerminated(vatID, shouldReject, info) { + if (pending.has(vatID)) { + newVatCallback(vatID, { error: info }); + } if (!running.has(vatID)) { // a static vat terminated, so we have nobody to notify console.log(`DANGER: static vat ${vatID} terminated`); diff --git a/packages/SwingSet/src/kernel/vatManager/factory.js b/packages/SwingSet/src/kernel/vatManager/factory.js index 169e1f933910..92fd916bdd7c 100644 --- a/packages/SwingSet/src/kernel/vatManager/factory.js +++ b/packages/SwingSet/src/kernel/vatManager/factory.js @@ -99,7 +99,7 @@ export function makeVatManagerFactory({ if (setup && managerType !== 'local') { console.warn(`TODO: stop using setup() with ${managerType}`); } - if (managerType === 'local' || enableSetup) { + if (enableSetup) { if (setup) { return localFactory.createFromSetup( vatID, @@ -107,7 +107,15 @@ export function makeVatManagerFactory({ managerOptions, vatSyscallHandler, ); + } else { + return localFactory.createFromBundle( + vatID, + bundle, + managerOptions, + vatSyscallHandler, + ); } + } else if (managerType === 'local') { return localFactory.createFromBundle( vatID, bundle, diff --git a/packages/SwingSet/src/kernel/vatManager/manager-local.js b/packages/SwingSet/src/kernel/vatManager/manager-local.js index bb7135493586..a69ffbb992cd 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-local.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-local.js @@ -117,6 +117,28 @@ export function makeLocalVatManagerFactory(tools) { return makeLog; }; + const workerEndowments = harden({ + ...vatEndowments, + console: makeVatConsole(makeLogMaker(vatConsole)), + assert, + TextEncoder, + TextDecoder, + Base64: globalThis.Base64, // Available only on XSnap + URL: globalThis.URL, // Unavailable only on XSnap + }); + + async function buildVatNamespace( + lsEndowments, + inescapableGlobalProperties, + ) { + const vatNS = await importBundle(bundle, { + filePrefix: `vat-${vatID}/...`, + endowments: { ...workerEndowments, ...lsEndowments }, + inescapableGlobalProperties, + }); + return vatNS; + } + // we might or might not use this, depending upon whether the vat exports // 'buildRootObject' or a default 'setup' function const ls = makeLiveSlots( @@ -129,43 +151,26 @@ export function makeLocalVatManagerFactory(tools) { enableVatstore, gcTools, makeVatConsole(makeLogMaker(liveSlotsConsole)), + buildVatNamespace, ); - const endowments = harden({ - ...vatEndowments, - ...ls.vatGlobals, - console: makeVatConsole(makeLogMaker(vatConsole)), - assert, - TextEncoder, - TextDecoder, - Base64: globalThis.Base64, // Available only on XSnap - URL: globalThis.URL, // Unavailable only on XSnap - }); - const inescapableGlobalProperties = { ...ls.inescapableGlobalProperties }; - - const vatNS = await importBundle(bundle, { - filePrefix: `vat-${vatID}/...`, - endowments, - inescapableGlobalProperties, - }); - - let dispatch; - if (typeof vatNS.buildRootObject === 'function') { - const { buildRootObject } = vatNS; - ls.setBuildRootObject(buildRootObject); - dispatch = ls.dispatch; - } else if (enableSetup) { + if (enableSetup) { + const vatNS = await buildVatNamespace( + ls.vatGlobals, + ls.inescapableGlobalProperties, + ); const setup = vatNS.default; assert(setup, X`vat source bundle lacks (default) setup() function`); assert.typeof(setup, 'function'); const helpers = harden({}); // DEPRECATED, todo remove from setup() const state = null; // TODO remove from setup() - dispatch = setup(syscall, state, helpers, vatPowers, vatParameters); + const dispatch = setup(syscall, state, helpers, vatPowers, vatParameters); + return finish(dispatch); } else { - assert.fail(X`vat source bundle lacks buildRootObject() function`); + assert(ls.dispatch); + const result = finish(ls.dispatch); + return result; } - - return finish(dispatch); } const localVatManagerFactory = harden({ diff --git a/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js b/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js index 275a8f44897a..5ce151820dd4 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-nodeworker.js @@ -43,7 +43,6 @@ export function makeNodeWorkerVatManagerFactory(tools) { enableDisavow, enableVatstore, compareSyscalls, - useTranscript, } = managerOptions; assert(!managerOptions.enableSetup, 'not supported at all'); @@ -57,7 +56,7 @@ export function makeNodeWorkerVatManagerFactory(tools) { vatSyscallHandler, false, compareSyscalls, - useTranscript, + true, ); // start the worker and establish a connection diff --git a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js index beb82719cd86..89a23ecb7f3d 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-node.js @@ -23,7 +23,6 @@ export function makeNodeSubprocessFactory(tools) { enableDisavow, enableVatstore, compareSyscalls, - useTranscript, } = managerOptions; assert(!managerOptions.enableSetup, 'not supported at all'); @@ -34,7 +33,7 @@ export function makeNodeSubprocessFactory(tools) { vatSyscallHandler, false, compareSyscalls, - useTranscript, + true, ); // start the worker and establish a connection diff --git a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js index 481c86f3e517..342997f384f3 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js @@ -60,7 +60,6 @@ export function makeXsSubprocessFactory({ name, metered, compareSyscalls, - useTranscript, liveSlotsConsole, vatConsole, } = managerOptions; @@ -75,7 +74,7 @@ export function makeXsSubprocessFactory({ vatSyscallHandler, true, compareSyscalls, - useTranscript, + true, ); /** @type { (item: Tagged) => unknown } */ diff --git a/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js b/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js index f8bbe527c96b..d677257d11d7 100644 --- a/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js +++ b/packages/SwingSet/src/kernel/vatManager/supervisor-nodeworker.js @@ -100,6 +100,23 @@ parentPort.on('message', ([type, ...margs]) => { return makeLog; }; + const workerEndowments = { + console: makeVatConsole(makeLogMaker(`SwingSet:vat:${vatID}`)), + assert, + }; + + async function buildVatNamespace( + lsEndowments, + inescapableGlobalProperties, + ) { + const vatNS = await importBundle(bundle, { + endowments: { ...workerEndowments, ...lsEndowments }, + inescapableGlobalProperties, + }); + workerLog(`got vatNS:`, Object.keys(vatNS).join(',')); + return vatNS; + } + const ls = makeLiveSlots( syscall, vatID, @@ -110,26 +127,14 @@ parentPort.on('message', ([type, ...margs]) => { enableVatstore, gcTools, makeVatConsole(makeLogMaker(`SwingSet:ls:${vatID}`)), + buildVatNamespace, ); - const endowments = { - ...ls.vatGlobals, - console: makeVatConsole(makeLogMaker(`SwingSet:vat:${vatID}`)), - assert, - }; - - const inescapableGlobalProperties = { ...ls.inescapableGlobalProperties }; - - importBundle(bundle, { endowments, inescapableGlobalProperties }).then( - vatNS => { - workerLog(`got vatNS:`, Object.keys(vatNS).join(',')); - sendUplink(['gotBundle']); - ls.setBuildRootObject(vatNS.buildRootObject); - dispatch = makeSupervisorDispatch(ls.dispatch); - workerLog(`got dispatch:`, Object.keys(dispatch).join(',')); - sendUplink(['dispatchReady']); - }, - ); + sendUplink(['gotBundle']); + assert(ls.dispatch); + dispatch = makeSupervisorDispatch(ls.dispatch); + workerLog(`got dispatch:`, Object.keys(dispatch).join(',')); + sendUplink(['dispatchReady']); } else if (type === 'deliver') { if (!dispatch) { workerLog(`error: deliver before dispatchReady`); diff --git a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js index 34b94fb8cd0b..4405166cd74c 100644 --- a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js +++ b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-node.js @@ -119,6 +119,24 @@ fromParent.on('data', ([type, ...margs]) => { return makeLog; }; + // Enable or disable the console accordingly. + const workerEndowments = { + console: makeVatConsole(makeLogMaker(`SwingSet:vat:${vatID}`)), + assert, + }; + + async function buildVatNamespace( + lsEndowments, + inescapableGlobalProperties, + ) { + const vatNS = await importBundle(bundle, { + endowments: { ...workerEndowments, ...lsEndowments }, + inescapableGlobalProperties, + }); + workerLog(`got vatNS:`, Object.keys(vatNS).join(',')); + return vatNS; + } + const ls = makeLiveSlots( syscall, vatID, @@ -129,27 +147,14 @@ fromParent.on('data', ([type, ...margs]) => { enableVatstore, gcTools, makeVatConsole(makeLogMaker(`SwingSet:ls:${vatID}`)), + buildVatNamespace, ); - // Enable or disable the console accordingly. - const endowments = { - ...ls.vatGlobals, - console: makeVatConsole(makeLogMaker(`SwingSet:vat:${vatID}`)), - assert, - }; - - const inescapableGlobalProperties = { ...ls.inescapableGlobalProperties }; - - importBundle(bundle, { endowments, inescapableGlobalProperties }).then( - vatNS => { - workerLog(`got vatNS:`, Object.keys(vatNS).join(',')); - sendUplink(['gotBundle']); - ls.setBuildRootObject(vatNS.buildRootObject); - dispatch = makeSupervisorDispatch(ls.dispatch); - workerLog(`got dispatch:`, Object.keys(dispatch).join(',')); - sendUplink(['dispatchReady']); - }, - ); + sendUplink(['gotBundle']); + assert(ls.dispatch); + dispatch = makeSupervisorDispatch(ls.dispatch); + workerLog(`got dispatch:`, Object.keys(dispatch).join(',')); + sendUplink(['dispatchReady']); } else if (type === 'deliver') { if (!dispatch) { workerLog(`error: deliver before dispatchReady`); diff --git a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js index 41b34f437791..cfedbd29ce01 100644 --- a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js +++ b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js @@ -282,6 +282,28 @@ function makeWorker(port) { return makeLog; }; + const workerEndowments = { + console: makeVatConsole(makeLogMaker('console')), + assert, + // bootstrap provides HandledPromise + HandledPromise: globalThis.HandledPromise, + TextEncoder, + TextDecoder, + Base64: globalThis.Base64, // Present only in XSnap + }; + + async function buildVatNamespace( + lsEndowments, + inescapableGlobalProperties, + ) { + const vatNS = await importBundle(bundle, { + endowments: { ...workerEndowments, ...lsEndowments }, + inescapableGlobalProperties, + }); + workerLog(`got vatNS:`, Object.keys(vatNS).join(',')); + return vatNS; + } + const ls = makeLiveSlots( syscall, vatID, @@ -292,27 +314,9 @@ function makeWorker(port) { enableVatstore, gcTools, makeVatConsole(makeLogMaker('liveSlotsConsole')), + buildVatNamespace, ); - const endowments = { - ...ls.vatGlobals, - console: makeVatConsole(makeLogMaker('console')), - assert, - // bootstrap provides HandledPromise - HandledPromise: globalThis.HandledPromise, - TextEncoder, - TextDecoder, - Base64: globalThis.Base64, // Present only in XSnap - }; - - const inescapableGlobalProperties = { ...ls.inescapableGlobalProperties }; - - const vatNS = await importBundle(bundle, { - endowments, - inescapableGlobalProperties, - }); - workerLog(`got vatNS:`, Object.keys(vatNS).join(',')); - ls.setBuildRootObject(vatNS.buildRootObject); assert(ls.dispatch); dispatch = makeSupervisorDispatch(ls.dispatch); workerLog(`got dispatch`); diff --git a/packages/SwingSet/src/kernel/vatTranslator.js b/packages/SwingSet/src/kernel/vatTranslator.js index d0d1693d1c73..4df8013c8fc6 100644 --- a/packages/SwingSet/src/kernel/vatTranslator.js +++ b/packages/SwingSet/src/kernel/vatTranslator.js @@ -9,6 +9,9 @@ import { kdebug, legibilizeMessageArgs, legibilizeValue } from './kdebug.js'; /** @type { VatDeliveryBringOutYourDead } */ const reapMessageVatDelivery = harden(['bringOutYourDead']); +/** @type { VatDeliveryStartVat } */ +const startVatMessageVatDelivery = harden(['startVat']); + export function assertValidVatstoreKey(key) { assert.typeof(key, 'string'); } @@ -144,6 +147,10 @@ function makeTranslateKernelDeliveryToVatDelivery(vatID, kernelKeeper) { return vatDelivery; } + function translateStartVat() { + return startVatMessageVatDelivery; + } + function translateBringOutYourDead() { return reapMessageVatDelivery; } @@ -175,6 +182,10 @@ function makeTranslateKernelDeliveryToVatDelivery(vatID, kernelKeeper) { const [_, ...args] = kd; return translateRetireImports(...args); } + case 'startVat': { + const [_, ...args] = kd; + return translateStartVat(...args); + } case 'bringOutYourDead': { const [_, ...args] = kd; return translateBringOutYourDead(...args); @@ -188,6 +199,7 @@ function makeTranslateKernelDeliveryToVatDelivery(vatID, kernelKeeper) { // ['dropExports', vrefs] // ['retireExports', vrefs] // ['retireImports', vrefs] + // ['startVat'] // ['bringOutYourDead'] } diff --git a/packages/SwingSet/src/message.js b/packages/SwingSet/src/message.js index 7e787ef4661c..b885d187f618 100644 --- a/packages/SwingSet/src/message.js +++ b/packages/SwingSet/src/message.js @@ -65,6 +65,7 @@ export function insistVatDeliveryObject(vdo) { } break; } + case 'startVat': case 'bringOutYourDead': { assert(rest.length === 0); break; diff --git a/packages/SwingSet/src/types.js b/packages/SwingSet/src/types.js index fb2705dd2a58..0e21b3c2c7f5 100644 --- a/packages/SwingSet/src/types.js +++ b/packages/SwingSet/src/types.js @@ -95,9 +95,11 @@ * @typedef { [tag: 'dropExports', vrefs: string[] ]} VatDeliveryDropExports * @typedef { [tag: 'retireExports', vrefs: string[] ]} VatDeliveryRetireExports * @typedef { [tag: 'retireImports', vrefs: string[] ]} VatDeliveryRetireImports + * @typedef { [tag: 'startVat' ]} VatDeliveryStartVat * @typedef { [tag: 'bringOutYourDead' ]} VatDeliveryBringOutYourDead * @typedef { VatDeliveryMessage | VatDeliveryNotify | VatDeliveryDropExports - * | VatDeliveryRetireExports | VatDeliveryRetireImports | VatDeliveryBringOutYourDead + * | VatDeliveryRetireExports | VatDeliveryRetireImports + * | VatDeliveryStartVat | VatDeliveryBringOutYourDead * } VatDeliveryObject * @typedef { [tag: 'ok', message: null, usage: { compute: number } | null] | * [tag: 'error', message: string, usage: unknown | null] } VatDeliveryResult @@ -132,9 +134,11 @@ * @typedef { [tag: 'dropExports', krefs: string[] ]} KernelDeliveryDropExports * @typedef { [tag: 'retireExports', krefs: string[] ]} KernelDeliveryRetireExports * @typedef { [tag: 'retireImports', krefs: string[] ]} KernelDeliveryRetireImports + * @typedef { [tag: 'startVat']} KernelDeliveryStartVat * @typedef { [tag: 'bringOutYourDead']} KernelDeliveryBringOutYourDead * @typedef { KernelDeliveryMessage | KernelDeliveryNotify | KernelDeliveryDropExports - * | KernelDeliveryRetireExports | KernelDeliveryRetireImports | KernelDeliveryBringOutYourDead + * | KernelDeliveryRetireExports | KernelDeliveryRetireImports + * | KernelDeliveryStartVat | KernelDeliveryBringOutYourDead * } KernelDeliveryObject * @typedef { [tag: 'send', target: string, msg: Message] } KernelSyscallSend * @typedef { [tag: 'invoke', target: string, method: string, args: SwingSetCapData]} KernelSyscallInvoke diff --git a/packages/SwingSet/src/vats/comms/dispatch.js b/packages/SwingSet/src/vats/comms/dispatch.js index b365cbff85e3..b3737a5f88ff 100644 --- a/packages/SwingSet/src/vats/comms/dispatch.js +++ b/packages/SwingSet/src/vats/comms/dispatch.js @@ -184,6 +184,10 @@ export function buildCommsDispatch( gcFromKernel({ retireImports: filterMetaObjects(vrefs) }); break; } + case 'bringOutYourDead': { + // nothing to see here, move along + break; + } default: assert.fail(X`unknown delivery type ${type}`); } diff --git a/packages/SwingSet/test/devices/bootstrap-0.js b/packages/SwingSet/test/devices/bootstrap-0.js index 6de581475b44..46262ec4a62c 100644 --- a/packages/SwingSet/test/devices/bootstrap-0.js +++ b/packages/SwingSet/test/devices/bootstrap-0.js @@ -2,9 +2,11 @@ import { extractMessage } from '../vat-util.js'; export default function setup(syscall, state, _helpers, vatPowers) { function dispatch(vatDeliverObject) { - const { args } = extractMessage(vatDeliverObject); - vatPowers.testLog(args.body); - vatPowers.testLog(JSON.stringify(args.slots)); + if (vatDeliverObject[0] === 'message') { + const { args } = extractMessage(vatDeliverObject); + vatPowers.testLog(args.body); + vatPowers.testLog(JSON.stringify(args.slots)); + } } return dispatch; } diff --git a/packages/SwingSet/test/devices/bootstrap-1.js b/packages/SwingSet/test/devices/bootstrap-1.js index 78d58a281f1b..7d7ca2af37f0 100644 --- a/packages/SwingSet/test/devices/bootstrap-1.js +++ b/packages/SwingSet/test/devices/bootstrap-1.js @@ -5,17 +5,19 @@ export default function setup(syscall, state, _helpers, vatPowers) { const { testLog } = vatPowers; let deviceRef; function dispatch(vatDeliverObject) { - const { method, args } = extractMessage(vatDeliverObject); - if (method === 'bootstrap') { - const argb = JSON.parse(args.body); - const deviceIndex = argb[1].d1.index; - deviceRef = args.slots[deviceIndex]; - assert(deviceRef === 'd-71', X`bad deviceRef ${deviceRef}`); - } else if (method === 'step1') { - testLog(`callNow`); - const setArgs = harden({ body: JSON.stringify([1, 2]), slots: [] }); - const ret = syscall.callNow(deviceRef, 'set', setArgs); - testLog(JSON.stringify(ret)); + if (vatDeliverObject[0] === 'message') { + const { method, args } = extractMessage(vatDeliverObject); + if (method === 'bootstrap') { + const argb = JSON.parse(args.body); + const deviceIndex = argb[1].d1.index; + deviceRef = args.slots[deviceIndex]; + assert(deviceRef === 'd-71', X`bad deviceRef ${deviceRef}`); + } else if (method === 'step1') { + testLog(`callNow`); + const setArgs = harden({ body: JSON.stringify([1, 2]), slots: [] }); + const ret = syscall.callNow(deviceRef, 'set', setArgs); + testLog(JSON.stringify(ret)); + } } } return dispatch; diff --git a/packages/SwingSet/test/devices/bootstrap-4.js b/packages/SwingSet/test/devices/bootstrap-4.js index 2c6a5e1053e5..eeaf7dfba818 100644 --- a/packages/SwingSet/test/devices/bootstrap-4.js +++ b/packages/SwingSet/test/devices/bootstrap-4.js @@ -19,29 +19,31 @@ export default function setup(syscall, state, _helpers, vatPowers) { const { callNow } = syscall; const { testLog } = vatPowers; function dispatch(vatDeliverObject) { - const { method, args } = extractMessage(vatDeliverObject); - if (method === 'bootstrap') { - // find the device slot - const [_vats, devices] = JSON.parse(args.body); - const qnode = devices.d0; - assert.equal(qnode[QCLASS], 'slot'); - const slot = args.slots[qnode.index]; - insistVatType('device', slot); + if (vatDeliverObject[0] === 'message') { + const { method, args } = extractMessage(vatDeliverObject); + if (method === 'bootstrap') { + // find the device slot + const [_vats, devices] = JSON.parse(args.body); + const qnode = devices.d0; + assert.equal(qnode[QCLASS], 'slot'); + const slot = args.slots[qnode.index]; + insistVatType('device', slot); - const vpid = 'p+1'; // pretend we're exporting a promise - const pnode = { [QCLASS]: 'slot', index: 0 }; - const callNowArgs = capargs([pnode], [vpid]); + const vpid = 'p+1'; // pretend we're exporting a promise + const pnode = { [QCLASS]: 'slot', index: 0 }; + const callNowArgs = capargs([pnode], [vpid]); - testLog('sending Promise'); - try { - // this will throw an exception, but is also (eventually) vat-fatal - callNow(slot, 'send', callNowArgs); - testLog('oops: survived sending Promise'); - } catch (e) { - testLog('good: callNow failed'); + testLog('sending Promise'); + try { + // this will throw an exception, but is also (eventually) vat-fatal + callNow(slot, 'send', callNowArgs); + testLog('oops: survived sending Promise'); + } catch (e) { + testLog('good: callNow failed'); + } + } else if (method === 'ping') { + testLog('oops: still alive'); } - } else if (method === 'ping') { - testLog('oops: still alive'); } } return dispatch; diff --git a/packages/SwingSet/test/devices/test-devices.js b/packages/SwingSet/test/devices/test-devices.js index e3918dae3008..3c15ae9a328e 100644 --- a/packages/SwingSet/test/devices/test-devices.js +++ b/packages/SwingSet/test/devices/test-devices.js @@ -64,7 +64,16 @@ test.serial('d0', async t => { const hostStorage = provideHostStorage(); await initializeSwingset(config, [], hostStorage); const c = await makeSwingsetController(hostStorage, {}); + for (let i = 0; i < 5; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat start + } + for (let i = 0; i < 4; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // bring out your dead + } await c.step(); + // console.log(util.inspect(c.dump(), { depth: null })); t.deepEqual(JSON.parse(c.dump().log[0]), [ { @@ -118,6 +127,10 @@ test.serial('d1', async t => { const hostStorage = provideHostStorage(); await initializeSwingset(config, [], hostStorage, t.context.data); const c = await makeSwingsetController(hostStorage, deviceEndowments); + for (let i = 0; i < 5; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat start + } await c.step(); c.queueToVatRoot('bootstrap', 'step1', capargs([])); await c.step(); @@ -151,6 +164,10 @@ async function test2(t, mode) { const hostStorage = provideHostStorage(); await initializeSwingset(config, [mode], hostStorage, t.context.data); const c = await makeSwingsetController(hostStorage, {}); + for (let i = 0; i < 5; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat start + } c.pinVatRoot('bootstrap'); await c.step(); if (mode === '1') { @@ -325,7 +342,6 @@ test.serial('liveslots throws when D() gets promise', async t => { vats: { bootstrap: { bundle: t.context.data.bootstrap2, - creationOptions: { enableSetup: true }, }, }, devices: { @@ -338,6 +354,12 @@ test.serial('liveslots throws when D() gets promise', async t => { const hostStorage = provideHostStorage(); await initializeSwingset(config, ['promise1'], hostStorage, t.context.data); const c = await makeSwingsetController(hostStorage, {}); + for (let i = 0; i < 4; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat start + // eslint-disable-next-line no-await-in-loop + await c.step(); // bring out your dead + } await c.step(); // When liveslots catches an attempt to send a promise into D(), it throws // a regular error, which the vat can catch. @@ -374,7 +396,13 @@ test.serial('syscall.callNow(promise) is vat-fatal', async t => { const hostStorage = provideHostStorage(); await initializeSwingset(config, [], hostStorage, t.context.data); const c = await makeSwingsetController(hostStorage, {}); - await c.step(); + for (let i = 0; i < 3; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat start + // eslint-disable-next-line no-await-in-loop + await c.step(); // bring out your dead + } + await c.step(); // bootstrap, which will fail // if the kernel paniced, that c.step() will reject, and the await will throw t.deepEqual(c.dump().log, ['sending Promise', 'good: callNow failed']); // now check that the vat was terminated: this should throw an exception diff --git a/packages/SwingSet/test/liveslots-helpers.js b/packages/SwingSet/test/liveslots-helpers.js index 230f1e284b4d..5478b38272e8 100644 --- a/packages/SwingSet/test/liveslots-helpers.js +++ b/packages/SwingSet/test/liveslots-helpers.js @@ -103,7 +103,7 @@ export function buildSyscall() { return { log, syscall }; } -export function makeDispatch( +export async function makeDispatch( syscall, build, vatID = 'vatA', @@ -118,7 +118,7 @@ export function makeDispatch( gcAndFinalize: makeGcAndFinalize(engineGC), meterControl: makeDummyMeterControl(), }); - const { setBuildRootObject, dispatch, testHooks } = makeLiveSlots( + const { dispatch, startVat, testHooks } = makeLiveSlots( syscall, vatID, {}, @@ -127,10 +127,14 @@ export function makeDispatch( enableDisavow, false, gcTools, + undefined, + () => { + return { buildRootObject: build }; + }, ); + await startVat(); if (returnTestHooks) { returnTestHooks[0] = testHooks; } - setBuildRootObject(build); return dispatch; } diff --git a/packages/SwingSet/test/run-policy/test-run-policy.js b/packages/SwingSet/test/run-policy/test-run-policy.js index ce1c0c42f784..fb8ba3f9f460 100644 --- a/packages/SwingSet/test/run-policy/test-run-policy.js +++ b/packages/SwingSet/test/run-policy/test-run-policy.js @@ -33,6 +33,10 @@ async function testCranks(t, mode) { const rightKref = c.pinVatRoot('right'); const rightID = c.vatNameToID('right'); t.teardown(c.shutdown); + for (let i = 0; i < 5; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // start vat + } if (mode === 'messages' || mode === 'wallclock') { // The 'message' mode sends doMessage() to left, which makes left send diff --git a/packages/SwingSet/test/stores/test-storeGC.js b/packages/SwingSet/test/stores/test-storeGC.js index ab16dd0c6318..b7eb99a06605 100644 --- a/packages/SwingSet/test/stores/test-storeGC.js +++ b/packages/SwingSet/test/stores/test-storeGC.js @@ -248,11 +248,18 @@ function matchRetireImports(...slots) { const root = 'o+0'; -function setupLifecycleTest(t) { +async function setupLifecycleTest(t) { const { log, syscall } = buildSyscall(); const nextRP = makeRPMaker(); const th = []; - const dispatch = makeDispatch(syscall, buildRootObject, 'bob', false, 0, th); + const dispatch = await makeDispatch( + syscall, + buildRootObject, + 'bob', + false, + 0, + th, + ); const [testHooks] = th; async function dispatchMessage(message, args = capargs([])) { @@ -594,7 +601,7 @@ function validateRetireExports(v, idx) { // test 1: lerv -> Lerv -> LerV -> Lerv -> lerv test.serial('store lifecycle 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -618,7 +625,7 @@ test.serial('store lifecycle 1', async t => { // lERV -> LERV -> lERV -> leRV -> LeRV -> leRV -> LeRV -> LerV test.serial('store lifecycle 2', async t => { const { v, dispatchMessage, dispatchDropExports, dispatchRetireExports } = - setupLifecycleTest(t); + await setupLifecycleTest(t); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -685,7 +692,7 @@ test.serial('store lifecycle 2', async t => { // test 3: lerv -> Lerv -> LerV -> LERV -> LeRV -> leRV -> lerV -> lerv test.serial('store lifecycle 3', async t => { const { v, dispatchMessage, dispatchDropExports, dispatchRetireExports } = - setupLifecycleTest(t); + await setupLifecycleTest(t); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -719,7 +726,9 @@ test.serial('store lifecycle 3', async t => { // test 4: lerv -> Lerv -> LERv -> LeRv -> lerv test.serial('store lifecycle 4', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -742,7 +751,7 @@ test.serial('store lifecycle 4', async t => { // test 5: lerv -> Lerv -> LERv -> LeRv -> Lerv -> lerv test.serial('store lifecycle 5', async t => { const { v, dispatchMessage, dispatchDropExports, dispatchRetireExports } = - setupLifecycleTest(t); + await setupLifecycleTest(t); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -768,7 +777,9 @@ test.serial('store lifecycle 5', async t => { // test 6: lerv -> Lerv -> LERv -> LeRv -> LeRV -> LeRv -> LeRV -> leRV -> lerv test.serial('store lifecycle 6', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -806,7 +817,9 @@ test.serial('store lifecycle 6', async t => { // test 7: lerv -> Lerv -> LERv -> lERv -> LERv -> lERv -> lerv test.serial('store lifecycle 7', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -836,7 +849,9 @@ test.serial('store lifecycle 7', async t => { // test 8: lerv -> Lerv -> LERv -> LERV -> LERv -> LERV -> lERV -> lERv -> lerv test.serial('store lifecycle 8', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create store let rp = await dispatchMessage('makeAndHold'); @@ -919,7 +934,7 @@ function validatePrepareStore3( } test.serial('store refcount management 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHold'); validateInit(v); @@ -948,7 +963,7 @@ test.serial('store refcount management 1', async t => { }); test.serial('store refcount management 2', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHold'); validateInit(v); @@ -975,7 +990,7 @@ test.serial('store refcount management 2', async t => { }); test.serial('store refcount management 3', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHold'); validateInit(v); @@ -1020,7 +1035,7 @@ test.serial('store refcount management 3', async t => { }); test.serial('presence refcount management 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('importAndHold', thingArg('o-5')); validateInit(v); @@ -1051,7 +1066,7 @@ test.serial('presence refcount management 1', async t => { }); test.serial('presence refcount management 2', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('importAndHold', thingArg('o-5')); validateInit(v); @@ -1076,7 +1091,7 @@ test.serial('presence refcount management 2', async t => { }); test.serial('remotable refcount management 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHoldRemotable'); validateInit(v); @@ -1098,7 +1113,7 @@ test.serial('remotable refcount management 1', async t => { }); test.serial('remotable refcount management 2', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHoldRemotable'); validateInit(v); @@ -1120,7 +1135,7 @@ test.serial('remotable refcount management 2', async t => { }); test.serial('verify store weak key GC', async t => { - const { v, dispatchMessage, testHooks } = setupLifecycleTest(t); + const { v, dispatchMessage, testHooks } = await setupLifecycleTest(t); // Create a store to use as a key and hold onto it weakly let rp = await dispatchMessage('makeAndHoldAndKey'); @@ -1199,7 +1214,7 @@ test.serial('verify store weak key GC', async t => { test.serial('verify presence weak key GC', async t => { const { v, dispatchMessage, dispatchRetireImports, testHooks } = - setupLifecycleTest(t); + await setupLifecycleTest(t); // Import a presence to use as a key and hold onto it weakly let rp = await dispatchMessage('importAndHoldAndKey', thingArg('o-5')); diff --git a/packages/SwingSet/test/test-controller.js b/packages/SwingSet/test/test-controller.js index cbc69afdfa7b..97152bca9a74 100644 --- a/packages/SwingSet/test/test-controller.js +++ b/packages/SwingSet/test/test-controller.js @@ -68,6 +68,9 @@ async function simpleCall(t) { // vat1:o+0 will map to ko21 controller.queueToVatRoot('vat1', 'foo', capdata('args')); t.deepEqual(controller.dump().runQueue, [ + { type: 'startVat', vatID: 'v2' }, + { type: 'startVat', vatID: 'v4' }, + { type: 'startVat', vatID: 'v5' }, { msg: { method: 'foo', @@ -113,6 +116,10 @@ test('bootstrap', async t => { // basedir-controller-2/bootstrap.js logs "bootstrap called" and queues a call to // left[0].bootstrap const c = await buildVatController(config); + for (let i = 0; i < 5; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat starts + } t.deepEqual(c.dump().log, ['bootstrap called']); }); @@ -123,6 +130,10 @@ test('XS bootstrap', async t => { config.defaultManagerType = 'xs-worker'; const hostStorage = provideHostStorage(); const c = await buildVatController(config, [], { hostStorage }); + for (let i = 0; i < 5; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat starts + } t.deepEqual(c.dump().log, ['bootstrap called']); t.is( hostStorage.kvStore.get('kernel.defaultManagerType'), @@ -156,6 +167,10 @@ test('static vats are unmetered on XS', async t => { }, }, ); + for (let i = 0; i < 5; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat starts + } t.deepEqual(c.dump().log, ['bootstrap called']); t.deepEqual(limited, [false, false, false, false]); }); @@ -218,6 +233,12 @@ test.serial('bootstrap export', async t => { checkKT(t, c, kt); t.deepEqual(c.dump().runQueue, [ + { type: 'startVat', vatID: 'v1' }, + { type: 'startVat', vatID: 'v2' }, + { type: 'startVat', vatID: 'v3' }, + { type: 'startVat', vatID: 'v4' }, + { type: 'startVat', vatID: 'v6' }, + { type: 'startVat', vatID: 'v7' }, { msg: { result: 'kp40', @@ -258,6 +279,10 @@ test.serial('bootstrap export', async t => { } t.deepEqual(c.dump().log, []); + for (let i = 0; i < 7; i += 1) { + // eslint-disable-next-line no-await-in-loop + await stepGC(); // vat starts + } // console.log('--- c.step() running bootstrap.obj0.bootstrap'); await stepGC(); // message bootstrap // kernel promise for result of the foo() that bootstrap sends to vat-left @@ -289,7 +314,6 @@ test.serial('bootstrap export', async t => { }, ]); - await stepGC(); // dropExports await stepGC(); // message foo const barP = 'kp42'; t.deepEqual(c.dump().log, ['bootstrap.obj0.bootstrap()', 'left.foo 1']); diff --git a/packages/SwingSet/test/test-liveslots.js b/packages/SwingSet/test/test-liveslots.js index dd22f732d765..b38a40e1bae8 100644 --- a/packages/SwingSet/test/test-liveslots.js +++ b/packages/SwingSet/test/test-liveslots.js @@ -42,7 +42,7 @@ test('calls', async t => { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); const rootA = 'o+0'; @@ -99,7 +99,7 @@ test('liveslots pipelines to syscall.send', async t => { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); const rootA = 'o+0'; const x = 'o-5'; @@ -159,7 +159,7 @@ test('liveslots pipeline/non-pipeline calls', async t => { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); @@ -236,7 +236,7 @@ async function doOutboundPromise(t, mode) { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); @@ -349,7 +349,7 @@ test('liveslots retains pending exported promise', async t => { return root; } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); const rootA = 'o+0'; const resultP = 'p-1'; await dispatch(makeMessage(rootA, 'make', capargs([]), resultP)); @@ -392,7 +392,7 @@ async function doResultPromise(t, mode) { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); const slot0arg = { '@qclass': 'slot', index: 0 }; @@ -501,7 +501,7 @@ test('liveslots vs symbols', async t => { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); const rootA = 'o+0'; const target = 'o-1'; @@ -568,7 +568,7 @@ test('disable disavow', async t => { }, }); } - const dispatch = makeDispatch(syscall, build, 'vatA', false); + const dispatch = await makeDispatch(syscall, build, 'vatA', false); t.deepEqual(log, []); const rootA = 'o+0'; @@ -625,7 +625,7 @@ test('disavow', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; const import1 = 'o-1'; @@ -683,7 +683,7 @@ test('liveslots retains device nodes', async t => { return root; } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); const rootA = 'o+0'; const device = 'd-1'; await dispatch(makeMessage(rootA, 'first', capargsOneSlot(device))); @@ -711,7 +711,7 @@ test('GC syscall.dropImports', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; const arg = 'o-1'; @@ -772,7 +772,7 @@ test('GC dispatch.retireImports', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; const arg = 'o-1'; @@ -801,7 +801,7 @@ test('GC dispatch.retireExports', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; @@ -952,9 +952,13 @@ test('dropImports', async t => { false, false, gcTools, + undefined, + () => { + return { buildRootObject: build }; + }, ); - const { setBuildRootObject, dispatch, possiblyDeadSet } = ls; - setBuildRootObject(build); + const { dispatch, startVat, possiblyDeadSet } = ls; + await startVat(); const allFRs = gcTools.getAllFRs(); t.is(allFRs.length, 2); const FR = allFRs[0]; @@ -1085,7 +1089,7 @@ test('GC dispatch.dropExports', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; @@ -1147,7 +1151,7 @@ test('GC dispatch.retireExports inhibits syscall.retireExports', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; @@ -1218,7 +1222,7 @@ test('simple promise resolution', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; @@ -1259,7 +1263,7 @@ test('promise cycle', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; @@ -1319,7 +1323,7 @@ test('unserializable promise resolution', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; @@ -1379,7 +1383,7 @@ test('unserializable promise rejection', async t => { }); return root; } - const dispatch = makeDispatch(syscall, build, 'vatA', true); + const dispatch = await makeDispatch(syscall, build, 'vatA', true); t.deepEqual(log, []); const rootA = 'o+0'; diff --git a/packages/SwingSet/test/test-promises.js b/packages/SwingSet/test/test-promises.js index b0c0a377fb67..7a082161c783 100644 --- a/packages/SwingSet/test/test-promises.js +++ b/packages/SwingSet/test/test-promises.js @@ -19,6 +19,12 @@ test('flush', async t => { ); const c = await buildVatController(config, ['flush'], t.context.data); // all promises should settle before c.step() fires + for (let i = 0; i < 6; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat start + // eslint-disable-next-line no-await-in-loop + await c.step(); // bring out your dead + } await c.step(); t.deepEqual(c.dump().log, ['then1', 'then2']); }); diff --git a/packages/SwingSet/test/test-vat-env.js b/packages/SwingSet/test/test-vat-env.js index 6883a727f9c2..74b91051ead6 100644 --- a/packages/SwingSet/test/test-vat-env.js +++ b/packages/SwingSet/test/test-vat-env.js @@ -69,6 +69,12 @@ async function testForExpectedGlobals(t, workerType) { const c = await buildVatController(config, [], { hostStorage, }); + for (let i = 0; i < 4; i += 1) { + // eslint-disable-next-line no-await-in-loop + await c.step(); // vat start + // eslint-disable-next-line no-await-in-loop + await c.step(); // bring out your dead + } await c.step(); t.deepEqual(c.dump().log, [ 'control sample: undefined', diff --git a/packages/SwingSet/test/test-vpid-liveslots.js b/packages/SwingSet/test/test-vpid-liveslots.js index 0682daf58e73..c55ffd389d82 100644 --- a/packages/SwingSet/test/test-vpid-liveslots.js +++ b/packages/SwingSet/test/test-vpid-liveslots.js @@ -169,7 +169,7 @@ async function doVatResolveCase1(t, mode) { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); const rootA = 'o+0'; @@ -323,7 +323,7 @@ async function doVatResolveCase23(t, which, mode, stalls) { }, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); const rootA = 'o+0'; @@ -541,7 +541,7 @@ async function doVatResolveCase4(t, mode) { four() {}, }); } - const dispatch = makeDispatch(syscall, build); + const dispatch = await makeDispatch(syscall, build); t.deepEqual(log, []); const rootA = 'o+0'; @@ -669,8 +669,8 @@ test('inter-vat circular promise references', async t => { }, }); } - const dispatchA = makeDispatch(syscall, build, 'vatA'); - // const dispatchB = makeDispatch(syscall, build, 'vatB'); + const dispatchA = await makeDispatch(syscall, build, 'vatA'); + // const dispatchB = await makeDispatch(syscall, build, 'vatB'); t.deepEqual(log, []); const rootA = 'o+0'; diff --git a/packages/SwingSet/test/test-xsnap-errors.js b/packages/SwingSet/test/test-xsnap-errors.js index 084574b87c55..1087388237e0 100644 --- a/packages/SwingSet/test/test-xsnap-errors.js +++ b/packages/SwingSet/test/test-xsnap-errors.js @@ -39,6 +39,7 @@ test('child termination distinguished from meter exhaustion', async t => { const kernelKeeper = { provideVatKeeper: () => ({ getLastSnapshot: () => undefined, + addToTranscript: () => undefined, }), }; @@ -65,6 +66,8 @@ test('child termination distinguished from meter exhaustion', async t => { schandler, ); + await m.deliver(['startVat']); + const msg = { method: 'hang', args: capargs([]) }; /** @type { VatDeliveryObject } */ const delivery = ['message', 'o+0', msg]; diff --git a/packages/SwingSet/test/vat-admin/broken-module-vat.js b/packages/SwingSet/test/vat-admin/broken-module-vat.js new file mode 100644 index 000000000000..ec590682d16f --- /dev/null +++ b/packages/SwingSet/test/vat-admin/broken-module-vat.js @@ -0,0 +1,6 @@ +// eslint-disable-next-line no-undef +missing({}); + +export function buildRootObject(_vatPowers) { + return {}; +} diff --git a/packages/SwingSet/test/vat-admin/broken-vat.js b/packages/SwingSet/test/vat-admin/broken-root-vat.js similarity index 100% rename from packages/SwingSet/test/vat-admin/broken-vat.js rename to packages/SwingSet/test/vat-admin/broken-root-vat.js diff --git a/packages/SwingSet/test/vat-admin/test-create-vat.js b/packages/SwingSet/test/vat-admin/test-create-vat.js index bc8d1f939ee6..35d790efdbea 100644 --- a/packages/SwingSet/test/vat-admin/test-create-vat.js +++ b/packages/SwingSet/test/vat-admin/test-create-vat.js @@ -22,11 +22,20 @@ test.before(async t => { const vat44Bundle = await bundleSource( new URL('new-vat-44.js', import.meta.url).pathname, ); - const brokenVatBundle = await bundleSource( - new URL('broken-vat.js', import.meta.url).pathname, + const brokenModuleVatBundle = await bundleSource( + new URL('broken-module-vat.js', import.meta.url).pathname, + ); + const brokenRootVatBundle = await bundleSource( + new URL('broken-root-vat.js', import.meta.url).pathname, ); const nonBundle = `${nonBundleFunction}`; - const bundles = { vat13Bundle, vat44Bundle, brokenVatBundle, nonBundle }; + const bundles = { + vat13Bundle, + vat44Bundle, + brokenModuleVatBundle, + brokenRootVatBundle, + nonBundle, + }; t.context.data = { kernelBundles, bundles }; }); @@ -35,7 +44,8 @@ async function doTestSetup(t) { const config = await loadBasedir(new URL('./', import.meta.url).pathname); config.bundles = { new13: { bundle: bundles.vat13Bundle }, - broken: { bundle: bundles.brokenVatBundle }, + brokenModule: { bundle: bundles.brokenModuleVatBundle }, + brokenRoot: { bundle: bundles.brokenRootVatBundle }, }; const c = await buildVatController(config, [], { kernelBundles }); const id44 = await c.validateAndInstallBundle(bundles.vat44Bundle); @@ -87,19 +97,28 @@ test('counter test', async t => { t.deepEqual(JSON.parse(c.kpResolution(kpid).body), [4, 9, 2]); }); -test('broken vat creation fails', async t => { +async function brokenVatTest(t, bundleName) { const { c } = await doTestSetup(t); - const kpid = c.queueToVatRoot('bootstrap', 'brokenVat', capargs(['broken'])); + const kpid = c.queueToVatRoot( + 'bootstrap', + 'brokenVat', + capargs([bundleName]), + ); await c.run(); t.is(c.kpStatus(kpid), 'rejected'); const res = parse(c.kpResolution(kpid).body); t.truthy(res instanceof Error); - // 'Vat Creation Error: ReferenceError: missing is not defined' on node - // 'Vat Creation Error: Error: setBundle failed: "ReferenceError": - // "buildRootObject: get missing: undefined variable"' on XS + // 'Vat Creation Error: Error: missing is not defined' t.regex(res.message, /Vat Creation Error/); - t.regex(res.message, /ReferenceError/); t.regex(res.message, /missing/); +} + +test('broken vat creation fails (bad module)', async t => { + await brokenVatTest(t, 'brokenModule'); +}); + +test('broken vat creation fails (bad buildRootObject)', async t => { + await brokenVatTest(t, 'brokenRoot'); }); test('error creating vat from non-bundle', async t => { diff --git a/packages/SwingSet/test/vat-util.js b/packages/SwingSet/test/vat-util.js index 146ad9e62171..f571d33a7b08 100644 --- a/packages/SwingSet/test/vat-util.js +++ b/packages/SwingSet/test/vat-util.js @@ -6,7 +6,7 @@ import { QCLASS } from '@endo/marshal'; export function extractMessage(vatDeliverObject) { const [type, ...vdoargs] = vatDeliverObject; - assert.equal(type, 'message', `util.js .extractMessage`); + assert.equal(type, 'message', `util.js .extractMessage got type ${type}`); const [facetID, msg] = vdoargs; const { method, args, result } = msg; return { facetID, method, args, result }; diff --git a/packages/SwingSet/test/vat-warehouse/test-reload-snapshot.js b/packages/SwingSet/test/vat-warehouse/test-reload-snapshot.js index d6aa12eb25da..50d38f17371d 100644 --- a/packages/SwingSet/test/vat-warehouse/test-reload-snapshot.js +++ b/packages/SwingSet/test/vat-warehouse/test-reload-snapshot.js @@ -28,7 +28,7 @@ test('vat reload from snapshot', async t => { await initializeSwingset(config, argv, hostStorage); const c1 = await makeSwingsetController(hostStorage, null, { - warehousePolicy: { initialSnapshot: 2, snapshotInterval: 5 }, + warehousePolicy: { snapshotInitial: 3, snapshotInterval: 5 }, }); c1.pinVatRoot('target'); const vatID = c1.vatNameToID('target'); @@ -48,7 +48,7 @@ test('vat reload from snapshot', async t => { expected1.push(`count = 0`); await c1.run(); t.deepEqual(c1.dump().log, expected1); - t.deepEqual(getPositions(), [0, 1]); + t.deepEqual(getPositions(), [0, 2]); for (let i = 1; i < 11; i += 1) { c1.queueToVatRoot('target', 'count', capargs([])); @@ -56,7 +56,7 @@ test('vat reload from snapshot', async t => { } await c1.run(); t.deepEqual(c1.dump().log, expected1); - t.deepEqual(getPositions(), [7, 11]); + t.deepEqual(getPositions(), [8, 12]); await c1.shutdown(); const c2 = await makeSwingsetController(hostStorage); @@ -66,5 +66,5 @@ test('vat reload from snapshot', async t => { expected2.push(`count = 11`); await c2.run(); t.deepEqual(c2.dump().log, expected2); // note: *not* 0-11 - t.deepEqual(getPositions(), [7, 12]); + t.deepEqual(getPositions(), [8, 13]); }); diff --git a/packages/SwingSet/test/virtualObjects/test-virtualObjectGC.js b/packages/SwingSet/test/virtualObjects/test-virtualObjectGC.js index 6616b801eacc..454fa806584c 100644 --- a/packages/SwingSet/test/virtualObjects/test-virtualObjectGC.js +++ b/packages/SwingSet/test/virtualObjects/test-virtualObjectGC.js @@ -356,11 +356,18 @@ const cacheObjValue = thingValue('cacheDisplacer'); const NONE = undefined; // mostly just shorter, to maintain legibility while making prettier shut up -function setupLifecycleTest(t) { +async function setupLifecycleTest(t) { const { log, syscall } = buildSyscall(); const nextRP = makeRPMaker(); const th = []; - const dispatch = makeDispatch(syscall, buildRootObject, 'bob', false, 0, th); + const dispatch = await makeDispatch( + syscall, + buildRootObject, + 'bob', + false, + 0, + th, + ); const [testHooks] = th; async function dispatchMessage(message, args = capargs([])) { @@ -543,7 +550,7 @@ function validateRetireExport(v) { // test 1: lerv -> Lerv -> LerV -> Lerv -> lerv test.serial('VO lifecycle 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -566,7 +573,7 @@ test.serial('VO lifecycle 1', async t => { // lERV -> LERV -> lERV -> leRV -> LeRV -> leRV -> LeRV -> LerV test.serial('VO lifecycle 2', async t => { const { v, dispatchMessage, dispatchDropExports, dispatchRetireExports } = - setupLifecycleTest(t); + await setupLifecycleTest(t); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -632,7 +639,7 @@ test.serial('VO lifecycle 2', async t => { // test 3: lerv -> Lerv -> LerV -> LERV -> LeRV -> leRV -> lerV -> lerv test.serial('VO lifecycle 3', async t => { const { v, dispatchMessage, dispatchDropExports, dispatchRetireExports } = - setupLifecycleTest(t); + await setupLifecycleTest(t); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -665,7 +672,9 @@ test.serial('VO lifecycle 3', async t => { // test 4: lerv -> Lerv -> LERv -> LeRv -> lerv test.serial('VO lifecycle 4', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -687,7 +696,7 @@ test.serial('VO lifecycle 4', async t => { // test 5: lerv -> Lerv -> LERv -> LeRv -> Lerv -> lerv test.serial('VO lifecycle 5', async t => { const { v, dispatchMessage, dispatchDropExports, dispatchRetireExports } = - setupLifecycleTest(t); + await setupLifecycleTest(t); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -712,7 +721,9 @@ test.serial('VO lifecycle 5', async t => { // test 6: lerv -> Lerv -> LERv -> LeRv -> LeRV -> LeRv -> LeRV -> leRV -> lerv test.serial('VO lifecycle 6', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -749,7 +760,9 @@ test.serial('VO lifecycle 6', async t => { // test 7: lerv -> Lerv -> LERv -> lERv -> LERv -> lERv -> lerv test.serial('VO lifecycle 7', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -778,7 +791,9 @@ test.serial('VO lifecycle 7', async t => { // test 8: lerv -> Lerv -> LERv -> LERV -> LERv -> LERV -> lERV -> lERv -> lerv test.serial('VO lifecycle 8', async t => { - const { v, dispatchMessage, dispatchDropExports } = setupLifecycleTest(t); + const { v, dispatchMessage, dispatchDropExports } = await setupLifecycleTest( + t, + ); // lerv -> Lerv Create VO let rp = await dispatchMessage('makeAndHold'); @@ -831,7 +846,7 @@ function validatePrepareStore3(v, rp) { } test.serial('VO refcount management 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHold'); validateCreate(v, rp); @@ -860,7 +875,7 @@ test.serial('VO refcount management 1', async t => { }); test.serial('VO refcount management 2', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHold'); validateCreate(v, rp); @@ -894,7 +909,7 @@ test.serial('VO refcount management 2', async t => { }); test.serial('VO refcount management 3', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHold'); validateCreate(v, rp); @@ -944,7 +959,7 @@ test.serial('VO refcount management 3', async t => { }); test.serial('presence refcount management 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('importAndHold', thingArg('o-5')); validate(v, matchVatstoreSet('vom.o+1/1', cacheObjValue)); @@ -991,7 +1006,7 @@ test.serial('presence refcount management 1', async t => { }); test.serial('presence refcount management 2', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('importAndHold', thingArg('o-5')); validate(v, matchVatstoreSet('vom.o+1/1', cacheObjValue)); @@ -1037,7 +1052,7 @@ test.serial('presence refcount management 2', async t => { }); test.serial('remotable refcount management 1', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHoldRemotable'); validate(v, matchVatstoreSet('vom.o+1/1', cacheObjValue)); @@ -1067,7 +1082,7 @@ test.serial('remotable refcount management 1', async t => { }); test.serial('remotable refcount management 2', async t => { - const { v, dispatchMessage } = setupLifecycleTest(t); + const { v, dispatchMessage } = await setupLifecycleTest(t); let rp = await dispatchMessage('makeAndHoldRemotable'); validate(v, matchVatstoreSet('vom.o+1/1', cacheObjValue)); @@ -1096,7 +1111,7 @@ test.serial('remotable refcount management 2', async t => { }); test.serial('verify VO weak key GC', async t => { - const { v, dispatchMessage, testHooks } = setupLifecycleTest(t); + const { v, dispatchMessage, testHooks } = await setupLifecycleTest(t); // Create VO and hold onto it weakly let rp = await dispatchMessage('makeAndHoldAndKey'); @@ -1115,7 +1130,7 @@ test.serial('verify VO weak key GC', async t => { test.serial('verify presence weak key GC', async t => { const { v, dispatchMessage, dispatchRetireImports, testHooks } = - setupLifecycleTest(t); + await setupLifecycleTest(t); validate(v, matchVatstoreSet('vom.o+1/1', cacheObjValue)); validateDone(v);