diff --git a/packages/cli/src/pet-name.js b/packages/cli/src/pet-name.js index fdea2a8214..2e18833364 100644 --- a/packages/cli/src/pet-name.js +++ b/packages/cli/src/pet-name.js @@ -1,3 +1,5 @@ +const { quote: q } = assert; + /** * Splits a dot-delimited pet name path into an array of pet names. * Throws if any of the path segments are empty. @@ -10,7 +12,7 @@ export const parsePetNamePath = petNamePath => { for (const petName of petNames) { if (petName === '') { throw new Error( - `Pet name path "${petNamePath}" contains an empty segment.`, + `Pet name path ${q(petNamePath)} contains an empty segment.`, ); } } diff --git a/packages/daemon/src/daemon.js b/packages/daemon/src/daemon.js index f5c08b3497..205bc5559b 100644 --- a/packages/daemon/src/daemon.js +++ b/packages/daemon/src/daemon.js @@ -895,6 +895,19 @@ const makeDaemonCore = async ( ); }; + /** @type {import('./types.js').DaemonCore['incarnateReadableBlob']} */ + const incarnateReadableBlob = async contentSha512 => { + const formulaNumber = await randomHex512(); + /** @type {import('./types.js').ReadableBlobFormula} */ + const formula = { + type: 'readable-blob', + content: contentSha512, + }; + return /** @type {import('./types.js').IncarnateResult} */ ( + provideValueForNumberedFormula(formula.type, formulaNumber, formula) + ); + }; + /** * Incarnates a `handle` formula and synchronously adds it to the formula graph. * The returned promise is resolved after the formula is persisted. @@ -1201,6 +1214,41 @@ const makeDaemonCore = async ( return guestIncarnation.formulaIdentifier; }; + /** + * Helper for `incarnateUnconfined` and `incarnateBundle`. + * @param {'make-bundle' | 'make-unconfined'} formulaType + * @param {string} hostFormulaIdentifier + * @param {import('./types.js').DeferredTasks} deferredTasks + * @param {string} [specifiedWorkerFormulaIdentifier] + * @param {string} [specifiedPowersFormulaIdentifier] + */ + const incarnateCapletDependencies = async ( + formulaType, + hostFormulaIdentifier, + deferredTasks, + specifiedWorkerFormulaIdentifier, + specifiedPowersFormulaIdentifier, + ) => { + const ownFormulaNumber = await randomHex512(); + const identifiers = harden({ + powersFormulaIdentifier: await providePowersFormulaIdentifier( + hostFormulaIdentifier, + specifiedPowersFormulaIdentifier, + ), + capletFormulaIdentifier: serializeFormulaIdentifier({ + type: formulaType, + number: ownFormulaNumber, + node: ownNodeIdentifier, + }), + capletFormulaNumber: ownFormulaNumber, + workerFormulaIdentifier: await provideWorkerFormulaIdentifier( + specifiedWorkerFormulaIdentifier, + ), + }); + await deferredTasks.execute(identifiers); + return identifiers; + }; + /** @type {import('./types.js').DaemonCore['incarnateUnconfined']} */ const incarnateUnconfined = async ( hostFormulaIdentifier, @@ -1211,28 +1259,17 @@ const makeDaemonCore = async ( ) => { const { powersFormulaIdentifier, - unconfinedFormulaNumber: formulaNumber, + capletFormulaNumber, workerFormulaIdentifier, - } = await formulaGraphMutex.enqueue(async () => { - const ownFormulaNumber = await randomHex512(); - const identifiers = harden({ - powersFormulaIdentifier: await providePowersFormulaIdentifier( - hostFormulaIdentifier, - specifiedPowersFormulaIdentifier, - ), - unconfinedFormulaIdentifier: serializeFormulaIdentifier({ - type: 'make-unconfined', - number: ownFormulaNumber, - node: ownNodeIdentifier, - }), - unconfinedFormulaNumber: ownFormulaNumber, - workerFormulaIdentifier: await provideWorkerFormulaIdentifier( - specifiedWorkerFormulaIdentifier, - ), - }); - await deferredTasks.execute(identifiers); - return identifiers; - }); + } = await formulaGraphMutex.enqueue(() => + incarnateCapletDependencies( + 'make-unconfined', + hostFormulaIdentifier, + deferredTasks, + specifiedWorkerFormulaIdentifier, + specifiedPowersFormulaIdentifier, + ), + ); /** @type {import('./types.js').MakeUnconfinedFormula} */ const formula = { @@ -1241,21 +1278,46 @@ const makeDaemonCore = async ( powers: powersFormulaIdentifier, specifier, }; - return /** @type {import('./types.js').IncarnateResult} */ ( - provideValueForNumberedFormula(formula.type, formulaNumber, formula) + return provideValueForNumberedFormula( + formula.type, + capletFormulaNumber, + formula, ); }; - /** @type {import('./types.js').DaemonCore['incarnateReadableBlob']} */ - const incarnateReadableBlob = async contentSha512 => { - const formulaNumber = await randomHex512(); - /** @type {import('./types.js').ReadableBlobFormula} */ + /** @type {import('./types.js').DaemonCore['incarnateBundle']} */ + const incarnateBundle = async ( + hostFormulaIdentifier, + bundleFormulaIdentifier, + deferredTasks, + specifiedWorkerFormulaIdentifier, + specifiedPowersFormulaIdentifier, + ) => { + const { + powersFormulaIdentifier, + capletFormulaNumber, + workerFormulaIdentifier, + } = await formulaGraphMutex.enqueue(() => + incarnateCapletDependencies( + 'make-bundle', + hostFormulaIdentifier, + deferredTasks, + specifiedWorkerFormulaIdentifier, + specifiedPowersFormulaIdentifier, + ), + ); + + /** @type {import('./types.js').MakeBundleFormula} */ const formula = { - type: 'readable-blob', - content: contentSha512, + type: 'make-bundle', + worker: workerFormulaIdentifier, + powers: powersFormulaIdentifier, + bundle: bundleFormulaIdentifier, }; - return /** @type {import('./types.js').IncarnateResult} */ ( - provideValueForNumberedFormula(formula.type, formulaNumber, formula) + return provideValueForNumberedFormula( + formula.type, + capletFormulaNumber, + formula, ); }; @@ -1275,23 +1337,6 @@ const makeDaemonCore = async ( return provideValueForNumberedFormula(formula.type, formulaNumber, formula); }; - /** @type {import('./types.js').DaemonCore['incarnateBundle']} */ - const incarnateBundle = async ( - powersFormulaIdentifier, - workerFormulaIdentifier, - bundleFormulaIdentifier, - ) => { - const formulaNumber = await randomHex512(); - /** @type {import('./types.js').MakeBundleFormula} */ - const formula = { - type: 'make-bundle', - worker: workerFormulaIdentifier, - powers: powersFormulaIdentifier, - bundle: bundleFormulaIdentifier, - }; - return provideValueForNumberedFormula(formula.type, formulaNumber, formula); - }; - /** @type {import('./types.js').DaemonCore['incarnateWebBundle']} */ const incarnateWebBundle = async ( powersFormulaIdentifier, diff --git a/packages/daemon/src/host.js b/packages/daemon/src/host.js index 931a551c5b..638d05a56a 100644 --- a/packages/daemon/src/host.js +++ b/packages/daemon/src/host.js @@ -223,35 +223,12 @@ export const makeHostMaker = ({ ); }; - /** - * @param {string | 'MAIN' | 'NEW'} workerName - */ - const provideWorkerFormulaIdentifier = async workerName => { - if (workerName === 'MAIN') { - return mainWorkerFormulaIdentifier; - } else if (workerName === 'NEW') { - const { formulaIdentifier: workerFormulaIdentifier } = - await incarnateWorker(); - return workerFormulaIdentifier; - } - - assertPetName(workerName); - let workerFormulaIdentifier = petStore.identifyLocal(workerName); - if (workerFormulaIdentifier === undefined) { - ({ formulaIdentifier: workerFormulaIdentifier } = - await incarnateWorker()); - assertPetName(workerName); - await petStore.write(workerName, workerFormulaIdentifier); - } - return workerFormulaIdentifier; - }; - /** * @param {string | 'MAIN' | 'NEW'} workerName * @param {import('./types.js').DeferredTasks<{ workerFormulaIdentifier: string }>['push']} deferTask * @returns {string | undefined} */ - const provideWorkerFormulaIdentifierSync = (workerName, deferTask) => { + const prepareWorkerFormulaIdentifier = (workerName, deferTask) => { if (workerName === 'MAIN') { return mainWorkerFormulaIdentifier; } else if (workerName === 'NEW') { @@ -292,7 +269,7 @@ export const makeHostMaker = ({ * @param {import('./types.js').DeferredTasks<{ powersFormulaIdentifier: string }>['push']} deferTask * @returns {string | undefined} */ - const providePowersFormulaIdentifierSync = (partyName, deferTask) => { + const preparePowersFormulaIdentifier = (partyName, deferTask) => { const powersFormulaIdentifier = petStore.identifyLocal(partyName); if (powersFormulaIdentifier === undefined) { deferTask(identifiers => @@ -326,7 +303,7 @@ export const makeHostMaker = ({ /** @type {import('./types.js').DeferredTasks} */ const tasks = makeDeferredTasks(); - const workerFormulaIdentifier = provideWorkerFormulaIdentifierSync( + const workerFormulaIdentifier = prepareWorkerFormulaIdentifier( workerName, tasks.push, ); @@ -368,34 +345,47 @@ export const makeHostMaker = ({ return value; }; - /** @type {import('./types.js').EndoHost['makeUnconfined']} */ - const makeUnconfined = async ( - workerName, - specifier, - powersName, - resultName, - ) => { + /** + * Helper function for makeUnconfined and makeBundle. + * @param {string} powersName + * @param {string} workerName + * @param {string} [resultName] + */ + const prepareMakeCaplet = (powersName, workerName, resultName) => { assertPowersName(powersName); - /** @type {import('./types.js').DeferredTasks} */ + /** @type {import('./types.js').DeferredTasks} */ const tasks = makeDeferredTasks(); - const workerFormulaIdentifier = provideWorkerFormulaIdentifierSync( + const workerFormulaIdentifier = prepareWorkerFormulaIdentifier( workerName, tasks.push, ); - const powersFormulaIdentifier = providePowersFormulaIdentifierSync( + const powersFormulaIdentifier = preparePowersFormulaIdentifier( powersName, tasks.push, ); if (resultName !== undefined) { tasks.push(identifiers => - petStore.write(resultName, identifiers.unconfinedFormulaIdentifier), + petStore.write(resultName, identifiers.capletFormulaIdentifier), ); } + return { tasks, workerFormulaIdentifier, powersFormulaIdentifier }; + }; + + /** @type {import('./types.js').EndoHost['makeUnconfined']} */ + const makeUnconfined = async ( + workerName, + specifier, + powersName, + resultName, + ) => { + const { tasks, workerFormulaIdentifier, powersFormulaIdentifier } = + prepareMakeCaplet(powersName, workerName, resultName); + // Behold, recursion: // eslint-disable-next-line no-use-before-define const { value } = await incarnateUnconfined( @@ -420,31 +410,23 @@ export const makeHostMaker = ({ powersName, resultName, ) => { - const workerFormulaIdentifier = await provideWorkerFormulaIdentifier( - workerName, - ); - const bundleFormulaIdentifier = petStore.identifyLocal(bundleName); if (bundleFormulaIdentifier === undefined) { - throw new TypeError(`Unknown pet name for bundle: ${bundleName}`); + throw new TypeError(`Unknown pet name for bundle: ${q(bundleName)}`); } - const powersFormulaIdentifier = await providePowersFormulaIdentifier( - powersName, - ); + const { tasks, workerFormulaIdentifier, powersFormulaIdentifier } = + prepareMakeCaplet(powersName, workerName, resultName); // Behold, recursion: // eslint-disable-next-line no-use-before-define - const { value, formulaIdentifier } = await incarnateBundle( - powersFormulaIdentifier, - workerFormulaIdentifier, + const { value } = await incarnateBundle( + hostFormulaIdentifier, bundleFormulaIdentifier, + tasks, + workerFormulaIdentifier, + powersFormulaIdentifier, ); - - if (resultName !== undefined) { - await petStore.write(resultName, formulaIdentifier); - } - return value; }; diff --git a/packages/daemon/src/types.d.ts b/packages/daemon/src/types.d.ts index 111311e8fd..99b238b3f0 100644 --- a/packages/daemon/src/types.d.ts +++ b/packages/daemon/src/types.d.ts @@ -143,12 +143,6 @@ type MakeUnconfinedFormula = { // TODO formula slots }; -export type MakeUnconfinedDeferredTaskParams = { - powersFormulaIdentifier: string; - unconfinedFormulaIdentifier: string; - workerFormulaIdentifier: string; -}; - type MakeBundleFormula = { type: 'make-bundle'; worker: string; @@ -157,6 +151,12 @@ type MakeBundleFormula = { // TODO formula slots }; +export type MakeCapletDeferredTaskParams = { + capletFormulaIdentifier: string; + powersFormulaIdentifier: string; + workerFormulaIdentifier: string; +}; + type PeerFormula = { type: 'peer'; networks: string; @@ -779,18 +779,20 @@ export interface DaemonCore { incarnateUnconfined: ( hostFormulaIdentifier: string, specifier: string, - deferredTasks: DeferredTasks, + deferredTasks: DeferredTasks, specifiedWorkerFormulaIdentifier?: string, specifiedPowersFormulaIdentifier?: string, ) => IncarnateResult; - incarnateBundler: ( - powersFormulaIdentifier: string, - workerFormulaIdentifier: string, - ) => IncarnateResult; incarnateBundle: ( + hostFormulaIdentifier: string, + bundleFormulaIdentifier: string, + deferredTasks: DeferredTasks, + specifiedWorkerFormulaIdentifier?: string, + specifiedPowersFormulaIdentifier?: string, + ) => IncarnateResult; + incarnateBundler: ( powersFormulaIdentifier: string, workerFormulaIdentifier: string, - bundleFormulaIdentifier: string, ) => IncarnateResult; incarnateWebBundle: ( powersFormulaIdentifier: string,