Skip to content

Commit

Permalink
refactor(daemon): Add known-peers-store formula (merge #2179)
Browse files Browse the repository at this point in the history
Closes #2166 

Replace the known peers store adapter with a dedicated `known-peers-store` formula type, instantiated the same way as other "special" formulas such as `least-authority`. The adapter used a `pet-store` formula under the hood. Giving it a different formula entirely is probably less likely to confuse us in the future.
  • Loading branch information
rekmarks authored Mar 25, 2024
2 parents 39b8599 + a028690 commit 653dd0b
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 57 deletions.
71 changes: 27 additions & 44 deletions packages/daemon/src/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { makeGuestMaker } from './guest.js';
import { makeHostMaker } from './host.js';
import { assertPetName } from './pet-name.js';
import { makeContextMaker } from './context.js';
import { parseId, formatId } from './formula-identifier.js';
import { assertValidNumber, parseId, formatId } from './formula-identifier.js';
import { makeSerialJobs } from './serial-jobs.js';
import { makeWeakMultimap } from './weak-multimap.js';
import { makeLoopbackNetwork } from './networks/loopback.js';
Expand Down Expand Up @@ -127,15 +127,18 @@ const makeDaemonCore = async (
);
console.log('Node', ownNodeIdentifier);

const peersFormulaNumber = deriveId(
const knownPeersFormulaNumber = deriveId(
'peers',
rootEntropy,
cryptoPowers.makeSha512(),
);
const ownPeersId = formatId({
number: peersFormulaNumber,
const knownPeersId = formatId({
number: knownPeersFormulaNumber,
node: ownNodeIdentifier,
});
await persistencePowers.writeFormula(knownPeersFormulaNumber, {
type: 'known-peers-store',
});

// Prepare least authority formula
const leastAuthorityFormulaNumber = deriveId(
Expand Down Expand Up @@ -620,10 +623,11 @@ const makeDaemonCore = async (
);
},
addPeerInfo: async peerInfo => {
// eslint-disable-next-line no-use-before-define
const knownPeers = await provideKnownPeers(formula.peers);
const knownPeers = /** @type {import('./types.js').PetStore} */ (
// eslint-disable-next-line no-use-before-define
await provide(formula.peers)
);
const { node: nodeIdentifier, addresses } = peerInfo;
// eslint-disable-next-line no-use-before-define
if (knownPeers.has(nodeIdentifier)) {
// We already have this peer.
// TODO: merge connection info
Expand Down Expand Up @@ -687,9 +691,19 @@ const makeDaemonCore = async (
} else if (formula.type === 'pet-store') {
const external = petStorePowers.makeIdentifiedPetStore(
formulaNumber,
'pet-store',
assertPetName,
);
return { external, internal: undefined };
} else if (formula.type === 'known-peers-store') {
const external = petStorePowers.makeIdentifiedPetStore(
formulaNumber,
'known-peers-store',
// The known peers store is just a pet store that only accepts node identifiers
// (i.e. formula numbers) as "names".
assertValidNumber,
);
return { external, internal: undefined };
} else if (formula.type === 'pet-inspector') {
// Behold, unavoidable forward-reference:
// eslint-disable-next-line no-use-before-define
Expand Down Expand Up @@ -823,9 +837,11 @@ const makeDaemonCore = async (
if (nodeIdentifier === ownNodeIdentifier) {
throw new Error(`Cannot get peer formula identifier for self`);
}
// eslint-disable-next-line no-use-before-define
const knownPeers = await provideKnownPeers(ownPeersId);
const peerId = knownPeers.identify(nodeIdentifier);
const knownPeers = /** @type {import('./types.js').PetStore} */ (
// eslint-disable-next-line no-use-before-define
await provide(knownPeersId)
);
const peerId = knownPeers.identifyLocal(nodeIdentifier);
if (peerId === undefined) {
throw new Error(
`No peer found for node identifier ${q(nodeIdentifier)}.`,
Expand Down Expand Up @@ -1372,12 +1388,6 @@ const makeDaemonCore = async (
await randomHex512(),
);
const { id: networksDirectoryId } = await formulateNetworksDirectory();
const { id: newPeersId } = await formulateNumberedPetStore(
peersFormulaNumber,
);
if (newPeersId !== ownPeersId) {
assert.Fail`Peers PetStore formula identifier did not match expected value, expected ${ownPeersId}, got ${newPeersId}`;
}

// Ensure the default host is formulated and persisted.
const { id: defaultHostId } = await formulateNumberedHost(
Expand All @@ -1399,7 +1409,7 @@ const makeDaemonCore = async (
const formula = {
type: 'endo',
networks: identifiers.networksDirectoryId,
peers: ownPeersId,
peers: knownPeersId,
host: identifiers.defaultHostId,
leastAuthority: leastAuthorityId,
};
Expand Down Expand Up @@ -1481,33 +1491,6 @@ const makeDaemonCore = async (
throw new Error('Cannot connect to peer: no supported addresses');
};

/**
* The "known peers store" is like a pet store, but maps node identifiers to
* full peer ids.
*
* @type {import('./types.js').DaemonCore['provideKnownPeers']}
*/
const provideKnownPeers = async peersFormulaId => {
// "Known peers" is just a pet store with an adapter over it.
const petStore = /** @type {import('./types.js').PetStore} */ (
await provide(peersFormulaId)
);

// Pet stores do not accept full ids as names.
/** @param {string} nodeIdentifier */
const getNameFor = nodeIdentifier => {
return `p${nodeIdentifier.slice(0, 126)}`;
};

return harden({
has: nodeIdentifier => petStore.has(getNameFor(nodeIdentifier)),
identify: nodeIdentifier =>
petStore.identifyLocal(getNameFor(nodeIdentifier)),
write: (nodeIdentifier, peerId) =>
petStore.write(getNameFor(nodeIdentifier), peerId),
});
};

/**
* This is used to provide a value for a formula identifier that is known to
* originate from the specified peer.
Expand Down
9 changes: 9 additions & 0 deletions packages/daemon/src/formula-identifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ const idPattern = /^(?<number>[0-9a-f]{128}):(?<node>[0-9a-f]{128})$/;
export const isValidNumber = allegedNumber =>
typeof allegedNumber === 'string' && numberPattern.test(allegedNumber);

/**
* @param {string} allegedNumber - The formula number or node identifier to test.
*/
export const assertValidNumber = allegedNumber => {
if (!isValidNumber(allegedNumber)) {
throw assert.error(`Invalid number ${q(allegedNumber)}`);
}
};

/**
* @param {string} id
* @param {string} [petName]
Expand Down
1 change: 1 addition & 0 deletions packages/daemon/src/formula-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const formulaTypes = new Set([
'guest',
'handle',
'host',
'known-peers-store',
'least-authority',
'lookup',
'loopback-network',
Expand Down
12 changes: 7 additions & 5 deletions packages/daemon/src/pet-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,13 @@ export const makePetStoreMaker = (filePowers, locator) => {
};

/**
* @param {string} formulaNumber
* @param {(name: string) => void} assertValidName
* @returns {Promise<import('./types.js').PetStore>}
* @type {import('./types.js').PetStorePowers['makeIdentifiedPetStore']}
*/
const makeIdentifiedPetStore = (formulaNumber, assertValidName) => {
const makeIdentifiedPetStore = (
formulaNumber,
formulaType,
assertValidName,
) => {
if (!isValidNumber(formulaNumber)) {
throw new Error(
`Invalid formula number for pet store ${q(formulaNumber)}`,
Expand All @@ -236,7 +238,7 @@ export const makePetStoreMaker = (filePowers, locator) => {
const suffix = formulaNumber.slice(2);
const petNameDirectoryPath = filePowers.joinPath(
locator.statePath,
'pet-store',
formulaType,
prefix,
suffix,
);
Expand Down
14 changes: 6 additions & 8 deletions packages/daemon/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ type HandleFormula = {
target: string;
};

type KnownPeersStoreFormula = {
type: 'known-peers-store';
};

type PetStoreFormula = {
type: 'pet-store';
};
Expand Down Expand Up @@ -210,6 +214,7 @@ export type Formula =
| WebBundleFormula
| HandleFormula
| PetInspectorFormula
| KnownPeersStoreFormula
| PetStoreFormula
| DirectoryFormula
| PeerFormula;
Expand Down Expand Up @@ -488,12 +493,6 @@ export interface EndoPeer {
export type EndoPeerControllerPartial = ControllerPartial<EndoPeer, undefined>;
export type EndoPeerController = Controller<EndoPeer, undefined>;

export interface EndoKnownPeers {
has: (nodeIdentifier: string) => boolean;
identify: (nodeIdentifier: string) => string | undefined;
write: (nodeIdentifier: string, peerId: string) => Promise<void>;
}

export interface EndoGateway {
provide: (id: string) => Promise<unknown>;
}
Expand Down Expand Up @@ -626,6 +625,7 @@ export type AssertValidNameFn = (name: string) => void;
export type PetStorePowers = {
makeIdentifiedPetStore: (
id: string,
formulaType: 'pet-store' | 'known-peers-store',
assertValidName: AssertValidNameFn,
) => Promise<PetStore>;
};
Expand Down Expand Up @@ -858,8 +858,6 @@ export interface DaemonCore {
provideController: (id: string) => Controller;

provideControllerAndResolveHandle: (id: string) => Promise<Controller>;

provideKnownPeers: (peersFormulaId: string) => Promise<EndoKnownPeers>;
}

export interface DaemonCoreExternal {
Expand Down

0 comments on commit 653dd0b

Please sign in to comment.