Skip to content

Commit

Permalink
chore: Improve liveslots-related types
Browse files Browse the repository at this point in the history
  • Loading branch information
gibson042 committed Mar 29, 2023
1 parent 33ce554 commit eaa8d2f
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 33 deletions.
2 changes: 1 addition & 1 deletion packages/SwingSet/misc-tools/replay-transcript.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ async function replay(transcriptFile) {
},
}
: makeSnapStore(process.cwd(), () => {}, makeSnapStoreIO());
const testLog = undefined;
const testLog = (..._args) => {};
const meterControl = makeDummyMeterControl();
const gcTools = harden({
WeakRef,
Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/src/kernel/vat-loader/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/**
* @callback BuildRootObjectForTestVat
* @param {VatPowers & {testLog: (msg: any)=> void}} vatPowers
* @param {VatPowers & {testLog: (...args: unknown[]) => void}} vatPowers
* @param {Record<string, unknown> & {argv: string[]}} vatParameters
* @returns {unknown}
*/
76 changes: 57 additions & 19 deletions packages/swingset-liveslots/src/liveslots.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,46 @@ const DEFAULT_VIRTUAL_OBJECT_CACHE_SIZE = 3; // XXX ridiculously small value to
const SYSCALL_CAPDATA_BODY_SIZE_LIMIT = 10_000_000;
const SYSCALL_CAPDATA_SLOTS_LENGTH_LIMIT = 10_000;

// 'makeLiveSlots' is a dispatcher which uses javascript Maps to keep track
// 'makeLiveSlots' returns a dispatcher which uses javascript Maps to keep track
// of local objects which have been exported. These cannot be persisted
// beyond the runtime of the javascript environment, so this mechanism is not
// going to work for our in-chain hosts.

/**
* @typedef {string} Vref
*
* @typedef {{WeakMap: typeof WeakMap, WeakSet: typeof WeakSet}} WeakConstructors
*
* @callback BuildRootObject
* @param {*} [vatPowers]
* @param {*} [vatParameters]
* @param {import('@agoric/vat-data').Baggage} [baggage]
* @returns {object | Promise<object>}
*
* @callback BuildVatNamespace
* @param {{VatData: import('@agoric/vat-data').VatData}} [vatGlobals]
* @param {WeakConstructors} [inescapableGlobalProperties]
* @returns {{buildRootObject: BuildRootObject}}
*/

/**
* Instantiate the liveslots layer for a new vat and then populate the vat with
* a new root object and its initial associated object graph, if any.
*
* @param {*} syscall Kernel syscall interface that the vat will have access to
* @param {*} forVatID Vat ID label, for use in debug diagnostics
* @param {string} forVatID Vat ID label, for use in debug diagnostics
* @param {*} vatPowers
* @param {import('./types').LiveSlotsOptions} liveSlotsOptions
* @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent, gcAndFinalize,
* meterControl }
* @param {import('./types').GcTools} gcTools
* @param {Pick<Console, 'debug' | 'log' | 'info' | 'warn' | 'error'>} console
* @param {*} buildVatNamespace
* @param {BuildVatNamespace} buildVatNamespace
*
* @returns {*} { dispatch }
* @returns {{
* dispatch: (delivery: import('./types').VatDeliveryObject) => Promise<void>,
* m: ReturnType<typeof import('@endo/marshal').makeMarshal>,
* possiblyDeadSet: Set<Vref>,
* testHooks: object,
* }}
*/
function build(
syscall,
Expand Down Expand Up @@ -1627,11 +1648,11 @@ function build(
// only after userspace is idle).
return gcTools.waitUntilQuiescent().then(() => {
afterDispatchActions();
// eslint-disable-next-line prefer-promise-reject-errors
return complete ? p : Promise.reject('buildRootObject unresolved');
// the only delivery that pays attention to a user-provided
// Promise is startVat, so the error message is specialized to
// the only user problem that could cause complete===false
// eslint-disable-next-line prefer-promise-reject-errors
return complete ? p : Promise.reject('buildRootObject unresolved');
});
}
}
Expand All @@ -1654,17 +1675,24 @@ function build(
* @param {*} forVatID Vat ID label, for use in debug diagostics
* @param {*} vatPowers
* @param {import('./types').LiveSlotsOptions} liveSlotsOptions
* @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent }
* @param {import('./types').GcTools} gcTools
* @param {Pick<Console, 'debug' | 'log' | 'info' | 'warn' | 'error'>} [liveSlotsConsole]
* @param {*} [buildVatNamespace]
* @param {*} [buildVatNamespace] TODO: make required and move before console
*
* @returns {*} { dispatch }
* @returns {{
* dispatch: (delivery: import('./types').VatDeliveryObject) => Promise<void>,
* possiblyDeadSet: Set<Vref>,
* testHooks: object,
* }}
*
* 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)
* When the returned `dispatch` function receives a 'startVat' delivery (which
* must only happen once and must precede any 'message' or 'notify' delivery),
* it will invoke the provided `buildVatNamespace` function to get an object
* from which it can extract a `buildRootObject` function and use that to
* create a root object for the new vat with an invocation like
* ```js
* const rootObject = await buildRootObject(vatPowers, vatParameters, baggage);
* ```
*
* Within the vat, `import { E } from '@endo/eventual-send'` will
* provide the E wrapper. For any object x, E(x) returns a proxy object
Expand Down Expand Up @@ -1698,7 +1726,7 @@ export function makeLiveSlots(
liveSlotsOptions,
gcTools,
liveSlotsConsole,
buildVatNamespace,
/** @type {BuildVatNamespace} */ (buildVatNamespace),
);
const { dispatch, possiblyDeadSet, testHooks } = r; // omit 'm'
return harden({
Expand All @@ -1710,7 +1738,17 @@ export function makeLiveSlots(

// for tests
export function makeMarshaller(syscall, gcTools, vatID = 'forVatID') {
// @ts-expect-error missing buildVatNamespace param
const { m } = build(syscall, vatID, {}, {}, gcTools, console);
const vatPowers = {};
const options = {};
const buildRootObject = () => Fail`Unexpected attempt to build vat`;
const { m } = build(
syscall,
vatID,
vatPowers,
options,
gcTools,
console,
() => ({ buildRootObject }),
);
return { m };
}
26 changes: 19 additions & 7 deletions packages/swingset-liveslots/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@
*
* @typedef {object} MeterControl
* @property {() => boolean} isMeteringDisabled Ask whether metering is currently disabled.
* @property {*} assertIsMetered
* @property {*} assertNotMetered
* @property {*} runWithoutMetering Run a callback outside metering
* @property {*} runWithoutMeteringAsync Run an async callback outside metering
* @property {*} unmetered Wrap a callback with runWithoutMetering
* @property {() => void} assertIsMetered
* @property {() => void} assertNotMetered
* @property {(fn: () => any) => ReturnType<fn>} runWithoutMetering Run a callback outside metering
* @property {(fn: () => any) => Promise<ReturnType<fn>>} runWithoutMeteringAsync Run an async callback outside metering
* @property {(fn: (...args: unknown[]) => any) => typeof fn} unmetered Wrap a callback with runWithoutMetering
*/

/**
* GcTools is the interface through which liveslots interacts with
* host environment garbage collection.
*
* @typedef {object} GcTools
* @property {typeof WeakRef} WeakRef
* @property {typeof FinalizationRegistry} FinalizationRegistry
* @property {() => Promise<void>} waitUntilQuiescent
* @property {() => Promise<void>} gcAndFinalize
* @property {MeterControl} meterControl
*/

/**
Expand Down Expand Up @@ -47,8 +59,8 @@
* } VatDeliveryObject
*
* @typedef { { compute: number } } MeterConsumption
* @typedef { [tag: 'ok', message: null, usage: MeterConsumption | null] |
* [tag: 'error', message: string, usage: MeterConsumption | null] } VatDeliveryResult
* @typedef { [tag: 'ok', problem: null, usage: MeterConsumption | null] |
* [tag: 'error', problem: string, usage: MeterConsumption | null] } VatDeliveryResult
*
*
* @typedef { [tag: 'send', target: string, msg: Message] } VatSyscallSend
Expand Down
40 changes: 35 additions & 5 deletions packages/swingset-liveslots/test/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,54 +47,84 @@ export function buildDispatch(onDispatchCallback) {
}

/**
*
* @param {unknown} target
* @param {string} target
* @param {string} method
* @param {any[]} args
* @param {unknown} result
* @param {string | null | undefined} result
* @returns {import('../src/types.js').VatDeliveryMessage}
*/
export function makeMessage(target, method, args = [], result = null) {
const methargs = kser([method, args]);
const msg = { methargs, result };
/** @type {import('../src/types.js').VatDeliveryMessage} */
const vatDeliverObject = harden(['message', target, msg]);
return vatDeliverObject;
}

/**
* @param {import('../src/types.js').SwingSetCapData} vatParameters
* @returns {import('../src/types.js').VatDeliveryStartVat}
*/
export function makeStartVat(vatParameters) {
/** @type {import('../src/types.js').VatDeliveryStartVat} */
return harden(['startVat', vatParameters]);
}

/**
* @returns {import('../src/types.js').VatDeliveryBringOutYourDead}
*/
export function makeBringOutYourDead() {
return harden(['bringOutYourDead']);
}

/**
* @param {import('../src/types.js').VatOneResolution[]} resolutions
* @returns {import('../src/types.js').VatDeliveryNotify}
*/
export function makeResolutions(resolutions) {
/** @type {import('../src/types.js').VatDeliveryNotify} */
const vatDeliverObject = harden(['notify', resolutions]);
return vatDeliverObject;
}

export function makeResolve(target, result) {
/** @type {[import('../src/types.js').VatOneResolution]} */
const resolutions = [[target, false, result]];
return makeResolutions(resolutions);
}

export function makeReject(target, result) {
/** @type {[import('../src/types.js').VatOneResolution]} */
const resolutions = [[target, true, result]];
const vatDeliverObject = harden(['notify', resolutions]);
return vatDeliverObject;
return makeResolutions(resolutions);
}

/**
* @param {string[]} vrefs
* @returns {import('../src/types.js').VatDeliveryDropExports}
*/
export function makeDropExports(...vrefs) {
/** @type {import('../src/types.js').VatDeliveryDropExports} */
const vatDeliverObject = harden(['dropExports', vrefs]);
return vatDeliverObject;
}

/**
* @param {string[]} vrefs
* @returns {import('../src/types.js').VatDeliveryRetireExports}
*/
export function makeRetireExports(...vrefs) {
/** @type {import('../src/types.js').VatDeliveryRetireExports} */
const vatDeliverObject = harden(['retireExports', vrefs]);
return vatDeliverObject;
}

/**
* @param {string[]} vrefs
* @returns {import('../src/types.js').VatDeliveryRetireImports}
*/
export function makeRetireImports(...vrefs) {
/** @type {import('../src/types.js').VatDeliveryRetireImports} */
const vatDeliverObject = harden(['retireImports', vrefs]);
return vatDeliverObject;
}
1 change: 1 addition & 0 deletions packages/vat-data/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export {
prepareSingleton,
} from './exo-utils.js';

/** @typedef {import('./types.js').VatData} VatData */
/** @typedef {import('./types.js').Baggage} Baggage */
/** @typedef {import('./types.js').DurableKindHandle} DurableKindHandle */
/** @template T @typedef {import('./types.js').DefineKindOptions<T>} DefineKindOptions */
Expand Down

0 comments on commit eaa8d2f

Please sign in to comment.