Skip to content

Commit

Permalink
Use (mostly numeric) vatID/deviceID everywhere within kernel
Browse files Browse the repository at this point in the history
.. as the index for kernel state data structures, instead of user-provided
vatName/deviceName strings. This will make it easier to use key/value state
storage (#144), since the keys will be more uniform (and shorter, and not
vulnerable to people using the separator string in their vat name).

Also it will make adding dynamic Vats easier (#19), as we'll just increment a
counter instead of asking the user to discover a unique name.

closes #146
  • Loading branch information
warner committed Sep 19, 2019
1 parent fdfe3eb commit 16fd904
Show file tree
Hide file tree
Showing 10 changed files with 587 additions and 394 deletions.
82 changes: 45 additions & 37 deletions src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import makeDefaultEvaluateOptions from '@agoric/default-evaluate-options';
import kernelSourceFunc from './bundles/kernel';
import buildKernelNonSES from './kernel/index';
import bundleSource from './build-source-bundle';
import { insist } from './insist';
import { insistCapData } from './capdata';
import { parseVatSlot } from './parseVatSlots';

const evaluateOptions = makeDefaultEvaluateOptions();

Expand Down Expand Up @@ -133,8 +135,8 @@ export async function buildVatController(config, withSES = true, argv = []) {
: buildNonSESKernel(initialState);
// console.log('kernel', kernel);

async function addGenesisVat(vatID, sourceIndex, options = {}) {
console.log(`= adding vat '${vatID}' from ${sourceIndex}`);
async function addGenesisVat(name, sourceIndex, options = {}) {
console.log(`= adding vat '${name}' from ${sourceIndex}`);
if (!(sourceIndex[0] === '.' || path.isAbsolute(sourceIndex))) {
throw Error(
'sourceIndex must be relative (./foo) or absolute (/foo) not bare (foo)',
Expand Down Expand Up @@ -163,7 +165,7 @@ export async function buildVatController(config, withSES = true, argv = []) {
// eslint-disable-next-line global-require,import/no-dynamic-require
setup = require(`${sourceIndex}`).default;
}
kernel.addGenesisVat(vatID, setup, options);
kernel.addGenesisVat(name, setup, options);
}

async function addGenesisDevice(name, sourceIndex, endowments) {
Expand All @@ -185,13 +187,35 @@ export async function buildVatController(config, withSES = true, argv = []) {
kernel.addGenesisDevice(name, setup, endowments);
}

if (config.devices) {
for (const [name, srcpath, endowments] of config.devices) {
// eslint-disable-next-line no-await-in-loop
await addGenesisDevice(name, srcpath, endowments);
}
}

if (config.vats) {
for (const name of config.vats.keys()) {
const v = config.vats.get(name);
// eslint-disable-next-line no-await-in-loop
await addGenesisVat(name, v.sourcepath, v.options || {});
}
}

let bootstrapVatName;
if (config.bootstrapIndexJS) {
bootstrapVatName = '_bootstrap';
await addGenesisVat(bootstrapVatName, config.bootstrapIndexJS, {});
}

// start() may queue bootstrap if state doesn't say we did it already. It
// also replays the transcripts from a previous run, if any, which will
// execute vat code (but all syscalls will be disabled)
await kernel.start(bootstrapVatName, JSON.stringify(argv));

// the kernel won't leak our objects into the Vats, we must do
// the same in this wrapper
const controller = harden({
addVat(vatID, sourceIndex, options = {}) {
return addGenesisVat(vatID, sourceIndex, options);
},

log(str) {
kernel.log(str);
},
Expand All @@ -212,40 +236,24 @@ export async function buildVatController(config, withSES = true, argv = []) {
await kernel.step();
},

queueToExport(vatID, facetID, method, args) {
insistCapData(args);
kernel.addExport(vatID, facetID);
kernel.queueToExport(vatID, facetID, method, args);
// these are for tests

vatNameToID(vatName) {
return kernel.vatNameToID(vatName);
},
deviceNameToID(deviceName) {
return kernel.deviceNameToID(deviceName);
},

callBootstrap(vatID, bootstrapArgv) {
kernel.callBootstrap(`${vatID}`, JSON.stringify(bootstrapArgv));
queueToVatExport(vatName, exportID, method, args) {
const vatID = kernel.vatNameToID(vatName);
parseVatSlot(exportID);
insist(method === `${method}`);
insistCapData(args);
kernel.addExport(vatID, exportID);
kernel.queueToExport(vatID, exportID, method, args);
},
});

if (config.devices) {
for (const [name, srcpath, endowments] of config.devices) {
// eslint-disable-next-line no-await-in-loop
await addGenesisDevice(name, srcpath, endowments);
}
}

if (config.vats) {
for (const vatID of config.vats.keys()) {
const v = config.vats.get(vatID);
// eslint-disable-next-line no-await-in-loop
await addGenesisVat(vatID, v.sourcepath, v.options || {});
}
}

if (config.bootstrapIndexJS) {
await addGenesisVat('_bootstrap', config.bootstrapIndexJS, {});
}

// start() may queue bootstrap if state doesn't say we did it already. It
// also replays the transcripts from a previous run, if any, which will
// execute vat code (but all syscalls will be disabled)
await kernel.start('_bootstrap', JSON.stringify(argv));

return controller;
}
67 changes: 67 additions & 0 deletions src/kernel/id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import harden from '@agoric/harden';
import Nat from '@agoric/nat';

// Vats are identified by an integer index, which (for typechecking purposes)
// is encoded as `vNN`. Devices are similarly identified as `dNN`. Both have
// human-readable names, which are provided to controller.addGenesisVat(),
// and usually come from the `vat-NAME.js` filenames processed in
// loadBasedir(). These names also appear in the `vats` and `devices`
// arguments to the bootstrap Vat's `bootstrap()` function, and in debug
// messages.

export function insistVatID(s) {
try {
if (s !== `${s}`) {
throw new Error(`not a string`);
}
s = `${s}`;
if (!s.startsWith(`v`)) {
throw new Error(`does not start with 'v'`);
}
Nat(Number(s.slice(1)));
} catch (e) {
throw new Error(`'${s} is not a 'vNN'-style VatID: ${e.message}`);
}
}

export function makeVatID(index) {
return `v${Nat(index)}`;
}

export function insistDeviceID(s) {
try {
if (s !== `${s}`) {
throw new Error(`not a string`);
}
s = `${s}`;
if (!s.startsWith(`d`)) {
throw new Error(`does not start with 'd'`);
}
Nat(Number(s.slice(1)));
} catch (e) {
throw new Error(`'${s} is not a 'dNN'-style DeviceID: ${e.message}`);
}
}

export function makeDeviceID(index) {
return `d${Nat(index)}`;
}

export function parseVatOrDeviceID(s) {
if (s !== `${s}`) {
throw new Error(`${s} is not a string, so cannot be a VatID/DevieID`);
}
s = `${s}`;
let type;
let idSuffix;
if (s.startsWith('v')) {
type = 'vat';
idSuffix = s.slice(1);
} else if (s.startsWith('v')) {
type = 'device';
idSuffix = s.slice(1);
} else {
throw new Error(`'${s}' is neither a VatID nor a DeviceID`);
}
return harden({ type, id: Nat(Number(idSuffix)) });
}
Loading

0 comments on commit 16fd904

Please sign in to comment.