-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Daemon: identify based lookup #2051
base: master
Are you sure you want to change the base?
Changes from all commits
6ca0a19
eb9b3aa
f19e5e6
5b3dc78
80cf019
3cdb9c5
06d96c8
7f0acf8
dd6f2f8
34b2cfa
d0c160f
f300808
9f5a079
482a657
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* global process */ | ||
import os from 'os'; | ||
import { E } from '@endo/far'; | ||
import { withEndoBootstrap } from '../context.js'; | ||
|
||
export const identify = async ({ cancel, cancelled, sockPath, namePath }) => | ||
withEndoBootstrap({ os, process }, async ({ bootstrap }) => { | ||
const defaultHostFormulaIdentifier = 'host'; | ||
const formulaId = await E(bootstrap).identifyFrom( | ||
defaultHostFormulaIdentifier, | ||
namePath, | ||
); | ||
console.log(formulaId); | ||
}); | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,14 @@ | ||
/* global process */ | ||
import os from 'os'; | ||
import { E } from '@endo/far'; | ||
import { withEndoParty } from '../context.js'; | ||
import { withEndoBootstrap } from '../context.js'; | ||
|
||
export const show = async ({ cancel, cancelled, sockPath, name, partyNames }) => | ||
withEndoParty(partyNames, { os, process }, async ({ party }) => { | ||
const pet = await E(party).lookup(name); | ||
export const show = async ({ cancel, cancelled, sockPath, namePath }) => | ||
withEndoBootstrap({ os, process }, async ({ bootstrap }) => { | ||
const defaultHostFormulaIdentifier = 'host'; | ||
const pet = await E(bootstrap).lookupFrom( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I see. In my head, I think we should move the method to Host in order to stay one step away from folding the Endo Bootstrap object into Host objects. They are equally powerful since you can’t get one without the other and there’s little reason to keep them separate. I’m not attached to the |
||
defaultHostFormulaIdentifier, | ||
namePath, | ||
); | ||
console.log(pet); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,6 +107,51 @@ const makeEndoBootstrap = ( | |
return `readable-blob-sha512:${sha512Hex}`; | ||
}; | ||
|
||
/** @type {import('./types.js').IdentifyFromFn} */ | ||
const identifyFrom = async (originFormulaIdentifier, namePath) => { | ||
await null; | ||
if (namePath.length === 0) { | ||
return originFormulaIdentifier; | ||
} | ||
// Attempt to shortcut the identify by reading directly from the petStore. | ||
const { type: formulaType, number: formulaNumber } = parseFormulaIdentifier( | ||
originFormulaIdentifier, | ||
); | ||
if (formulaType === 'host' || formulaType === 'host-id512') { | ||
let storeFormulaIdentifier = `pet-store`; | ||
if (formulaType === 'host-id512') { | ||
storeFormulaIdentifier = `pet-store-id512:${formulaNumber}`; | ||
} | ||
// eslint-disable-next-line no-use-before-define | ||
const petStore = await provideValueForFormulaIdentifier( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose we can’t make this synchronous! |
||
storeFormulaIdentifier, | ||
); | ||
const result = await E(petStore).identify(namePath); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should definitely rename |
||
// Use result if present, otherwise fallback to identifying from the host. | ||
if (result !== undefined) { | ||
return result; | ||
} | ||
} | ||
// eslint-disable-next-line no-use-before-define | ||
const origin = await provideValueForFormulaIdentifier( | ||
originFormulaIdentifier, | ||
); | ||
return E(origin).identify(namePath); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given this is async tail recursive and has to at least reïfy pet stores (an unavoidably async operation), I withdraw my hope that Given that it can’t be synchronous, there’s no reason to bundle up |
||
}; | ||
|
||
/** @type {import('./types.js').LookupFromFn} */ | ||
const lookupFrom = async (originFormulaIdentifier, namePath) => { | ||
const formulaIdentifier = await identifyFrom( | ||
originFormulaIdentifier, | ||
namePath, | ||
); | ||
if (formulaIdentifier === undefined) { | ||
throw new Error(`Failed to lookup ${namePath.join('.')}`); | ||
} | ||
// eslint-disable-next-line no-use-before-define | ||
return provideValueForFormulaIdentifier(formulaIdentifier); | ||
}; | ||
|
||
/** | ||
* @param {string} workerId512 | ||
*/ | ||
|
@@ -413,6 +458,7 @@ const makeEndoBootstrap = ( | |
const external = petStorePowers.makeOwnPetStore( | ||
'pet-store', | ||
assertPetName, | ||
identifyFrom, | ||
); | ||
return { external, internal: undefined }; | ||
} else if (formulaIdentifier === 'pet-inspector') { | ||
|
@@ -469,6 +515,7 @@ const makeEndoBootstrap = ( | |
const external = petStorePowers.makeIdentifiedPetStore( | ||
formulaNumber, | ||
assertPetName, | ||
identifyFrom, | ||
); | ||
return { external, internal: undefined }; | ||
} else if (formulaType === 'host-id512') { | ||
|
@@ -627,6 +674,7 @@ const makeEndoBootstrap = ( | |
}); | ||
|
||
const makeMailbox = makeMailboxMaker({ | ||
identifyFrom, | ||
formulaIdentifierForRef, | ||
provideValueForFormulaIdentifier, | ||
provideControllerForFormulaIdentifier, | ||
|
@@ -651,6 +699,24 @@ const makeEndoBootstrap = ( | |
makeMailbox, | ||
}); | ||
|
||
const allowedInspectorFormulaTypes = [ | ||
'eval-id512', | ||
'lookup-id512', | ||
'make-unconfined-id512', | ||
'make-bundle-id512', | ||
'guest-id512', | ||
'web-bundle', | ||
]; | ||
|
||
const allowedInspectorFormulaIdentificationsByType = { | ||
eval: ['endowments', 'worker'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m not sure that inspectors generalize this well. In short, I think we should have a boring identify function for each formula type rather than a generalization because it will be more legible and easier to debug. |
||
lookup: ['hub'], | ||
guest: ['host'], | ||
'make-bundle': ['bundle', 'powers', 'worker'], | ||
'make-unconfined': ['powers', 'worker'], | ||
'web-bundle': ['bundle', 'powers'], | ||
}; | ||
|
||
/** | ||
* Creates an inspector for the current party's pet store, used to create | ||
* inspectors for values therein. Notably, can provide references to otherwise | ||
|
@@ -665,28 +731,81 @@ const makeEndoBootstrap = ( | |
petStoreFormulaIdentifier, | ||
); | ||
|
||
const identifyOnFormula = (formula, propertyName, namePath) => { | ||
if ( | ||
allowedInspectorFormulaIdentificationsByType[formula.type] === undefined | ||
) { | ||
// Cannot provide a reference under the requested formula type. | ||
return { formulaIdentifier: undefined, remainderPath: namePath }; | ||
} | ||
const allowedInspectorFormulaIdentifications = | ||
allowedInspectorFormulaIdentificationsByType[formula.type]; | ||
if (!allowedInspectorFormulaIdentifications.includes(propertyName)) { | ||
// Cannot provide a reference for the requested property. | ||
return { formulaIdentifier: undefined, remainderPath: namePath }; | ||
} | ||
if (formula.type === 'eval' && propertyName === 'endowments') { | ||
// We consume an additional part of the path for the endowment name. | ||
const [endowmentName, ...namePathRest] = namePath; | ||
assertPetName(endowmentName); | ||
const endowmentIndex = formula.names.indexOf(endowmentName); | ||
if (endowmentIndex === -1) { | ||
// Cannot provide a reference to the missing endowment. | ||
return { formulaIdentifier: undefined, remainderPath: namePath }; | ||
} | ||
const formulaIdentifier = formula.values[endowmentIndex]; | ||
return { formulaIdentifier, remainderPath: namePathRest }; | ||
} | ||
const formulaIdentifier = formula[propertyName]; | ||
return { formulaIdentifier, remainderPath: namePath }; | ||
}; | ||
|
||
/** @type {import('./types.js').IdentifyFn} */ | ||
const identify = async maybeNamePath => { | ||
const namePath = Array.isArray(maybeNamePath) | ||
? maybeNamePath | ||
: [maybeNamePath]; | ||
const [petName, propertyName, ...namePathRest] = namePath; | ||
assertPetName(petName); | ||
assertPetName(propertyName); | ||
const entryFormulaIdentifier = petStore.identifyLocal(petName); | ||
if (entryFormulaIdentifier === undefined) { | ||
return undefined; | ||
} | ||
const { type: formulaType, number: formulaNumber } = | ||
parseFormulaIdentifier(entryFormulaIdentifier); | ||
Comment on lines
+775
to
+776
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By the time we get here, we may have removed the type from the formula identifier, but it can be trivially recovered from the controller object for the number. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we have a formula for every formula identifier (just the number), it might make sense to just generally store that on the controller too, so we benefit from the memo and avoid redundant reads from the formula store. |
||
// Identify is only supported on these types of formulas. | ||
if (!allowedInspectorFormulaTypes.includes(formulaType)) { | ||
return undefined; | ||
} | ||
const formula = await persistencePowers.readFormula( | ||
formulaType, | ||
formulaNumber, | ||
); | ||
const { formulaIdentifier, remainderPath } = identifyOnFormula( | ||
formula, | ||
propertyName, | ||
namePathRest, | ||
); | ||
if (formulaIdentifier === undefined) { | ||
return undefined; | ||
} | ||
return identifyFrom(formulaIdentifier, remainderPath); | ||
}; | ||
|
||
/** | ||
* @param {string} petName - The pet name to inspect. | ||
* @returns {Promise<import('./types').KnownEndoInspectors[string]>} An | ||
* inspector for the value of the given pet name. | ||
*/ | ||
const lookup = async petName => { | ||
const formulaIdentifier = petStore.lookup(petName); | ||
const formulaIdentifier = petStore.identifyLocal(petName); | ||
if (formulaIdentifier === undefined) { | ||
throw new Error(`Unknown pet name ${petName}`); | ||
} | ||
const { type: formulaType, number: formulaNumber } = | ||
parseFormulaIdentifier(formulaIdentifier); | ||
if ( | ||
![ | ||
'eval-id512', | ||
'lookup-id512', | ||
'make-unconfined-id512', | ||
'make-bundle-id512', | ||
'guest-id512', | ||
'web-bundle', | ||
].includes(formulaType) | ||
) { | ||
if (!allowedInspectorFormulaTypes.includes(formulaType)) { | ||
return makeInspector(formulaType, formulaNumber, harden({})); | ||
} | ||
const formula = await persistencePowers.readFormula( | ||
|
@@ -765,6 +884,7 @@ const makeEndoBootstrap = ( | |
const list = () => petStore.list(); | ||
|
||
const info = Far('Endo inspector facet', { | ||
identify, | ||
lookup, | ||
list, | ||
}); | ||
|
@@ -783,6 +903,9 @@ const makeEndoBootstrap = ( | |
|
||
host: () => provideValueForFormulaIdentifier('host'), | ||
|
||
identifyFrom, | ||
lookupFrom, | ||
|
||
leastAuthority: () => leastAuthority, | ||
|
||
webPageJs: () => provideValueForFormulaIdentifier('web-page-js'), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,9 +39,10 @@ export const makeHostMaker = ({ | |
); | ||
|
||
const { | ||
identifyLocal, | ||
identify, | ||
lookup, | ||
reverseLookup, | ||
lookupFormulaIdentifierForName, | ||
listMessages, | ||
provideLookupFormula, | ||
followMessages, | ||
|
@@ -75,7 +76,7 @@ export const makeHostMaker = ({ | |
/** @type {string | undefined} */ | ||
let formulaIdentifier; | ||
if (petName !== undefined) { | ||
formulaIdentifier = lookupFormulaIdentifierForName(petName); | ||
formulaIdentifier = identifyLocal(petName); | ||
} | ||
if (formulaIdentifier === undefined) { | ||
/** @type {import('./types.js').GuestFormula} */ | ||
|
@@ -129,7 +130,7 @@ export const makeHostMaker = ({ | |
if (typeof workerName !== 'string') { | ||
throw new Error('worker name must be string'); | ||
} | ||
let workerFormulaIdentifier = lookupFormulaIdentifierForName(workerName); | ||
let workerFormulaIdentifier = identifyLocal(workerName); | ||
if (workerFormulaIdentifier === undefined) { | ||
const workerId512 = await randomHex512(); | ||
workerFormulaIdentifier = `worker-id512:${workerId512}`; | ||
|
@@ -156,7 +157,7 @@ export const makeHostMaker = ({ | |
return `worker-id512:${workerId512}`; | ||
} | ||
assertPetName(workerName); | ||
let workerFormulaIdentifier = lookupFormulaIdentifierForName(workerName); | ||
let workerFormulaIdentifier = identifyLocal(workerName); | ||
if (workerFormulaIdentifier === undefined) { | ||
const workerId512 = await randomHex512(); | ||
workerFormulaIdentifier = `worker-id512:${workerId512}`; | ||
|
@@ -170,7 +171,7 @@ export const makeHostMaker = ({ | |
* @param {string | 'NONE' | 'SELF' | 'ENDO'} partyName | ||
*/ | ||
const providePowersFormulaIdentifier = async partyName => { | ||
let guestFormulaIdentifier = lookupFormulaIdentifierForName(partyName); | ||
let guestFormulaIdentifier = identifyLocal(partyName); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like abbreviating Since the difference between |
||
if (guestFormulaIdentifier === undefined) { | ||
const guest = await provideGuest(partyName); | ||
guestFormulaIdentifier = formulaIdentifierForRef.get(guest); | ||
|
@@ -216,9 +217,7 @@ export const makeHostMaker = ({ | |
|
||
const petNamePath = petNamePathFrom(petNameOrPath); | ||
if (petNamePath.length === 1) { | ||
const formulaIdentifier = lookupFormulaIdentifierForName( | ||
petNamePath[0], | ||
); | ||
const formulaIdentifier = identifyLocal(petNamePath[0]); | ||
if (formulaIdentifier === undefined) { | ||
throw new Error(`Unknown pet name ${q(petNamePath[0])}`); | ||
} | ||
|
@@ -308,8 +307,7 @@ export const makeHostMaker = ({ | |
workerName, | ||
); | ||
|
||
const bundleFormulaIdentifier = | ||
lookupFormulaIdentifierForName(bundleName); | ||
const bundleFormulaIdentifier = identifyLocal(bundleName); | ||
if (bundleFormulaIdentifier === undefined) { | ||
throw new TypeError(`Unknown pet name for bundle: ${bundleName}`); | ||
} | ||
|
@@ -364,7 +362,7 @@ export const makeHostMaker = ({ | |
/** @type {string | undefined} */ | ||
let formulaIdentifier; | ||
if (petName !== undefined) { | ||
formulaIdentifier = lookupFormulaIdentifierForName(petName); | ||
formulaIdentifier = identifyLocal(petName); | ||
} | ||
if (formulaIdentifier === undefined) { | ||
const id512 = await randomHex512(); | ||
|
@@ -393,8 +391,7 @@ export const makeHostMaker = ({ | |
* @param {string | 'NONE' | 'SELF' | 'ENDO'} powersName | ||
*/ | ||
const provideWebPage = async (webPageName, bundleName, powersName) => { | ||
const bundleFormulaIdentifier = | ||
lookupFormulaIdentifierForName(bundleName); | ||
const bundleFormulaIdentifier = identifyLocal(bundleName); | ||
if (bundleFormulaIdentifier === undefined) { | ||
throw new Error(`Unknown pet name: ${q(bundleName)}`); | ||
} | ||
|
@@ -442,6 +439,7 @@ export const makeHostMaker = ({ | |
/** @type {import('./types.js').EndoHost} */ | ||
const host = Far('EndoHost', { | ||
has, | ||
identify, | ||
lookup, | ||
reverseLookup, | ||
listMessages, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very close to what I imagined and a step in the right direction.
High level:
endo identify
would do that, but perhaps that should have a name likedescribe
. I thinkendo describe
should also be able to print the nonce/swissnum/identifier likeendo describe --id <name>
endo locate <pet-name-path>
and produce the URL by default, including the connection hints for the listening networks. Maybeendo locate --json <path>
gives you the JSON representation. Maybeendo locate --id <path>
trims that back to just the nonce.locate
anddescribe
are the same command or two commands with the same behavior but different defaults.Nits:
cancel
,cancelled
, andsockPath
here and where this refactor-cruft was copied from.host
is not a formula identifier anymore. We should always start looking stuff up atE(bootstrap).host()
.process.stdout.write(`${id}\n`)
instead ofconsole.log
just to break the bad habit of confusing the debugger for an output printer. ymmv.