Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into mfig-exo-attenuator
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed May 4, 2023
2 parents c210889 + 76a3231 commit eea8945
Show file tree
Hide file tree
Showing 44 changed files with 434 additions and 881 deletions.
13 changes: 3 additions & 10 deletions packages/SwingSet/src/kernel/vat-loader/manager-local.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ export function makeLocalVatManagerFactory({
vatEndowments,
gcTools,
}) {
const baseVP = {
makeMarshal: allVatPowers.makeMarshal,
};
// testLog is also a vatPower, only for unit tests
const { testLog } = allVatPowers; // used by unit tests

function prepare(managerOptions) {
const { retainSyscall = false } = managerOptions;
Expand All @@ -44,10 +41,9 @@ export function makeLocalVatManagerFactory({
assert.typeof(setup, 'function', 'setup is not an in-realm function');

const { syscall, finish } = prepare(managerOptions);
const { testLog } = allVatPowers;
const helpers = harden({}); // DEPRECATED, todo remove from setup()
const state = null; // TODO remove from setup()
const vatPowers = harden({ ...baseVP, testLog });
const vatPowers = harden({ testLog });

const dispatch = setup(syscall, state, helpers, vatPowers);
return finish(dispatch);
Expand All @@ -64,10 +60,7 @@ export function makeLocalVatManagerFactory({

const { syscall, finish } = prepare(managerOptions);

const vatPowers = harden({
...baseVP,
testLog: allVatPowers.testLog,
});
const vatPowers = harden({ testLog });

const makeLogMaker = source => {
const makeLog = level => {
Expand Down
1 change: 0 additions & 1 deletion packages/SwingSet/src/types-ambient.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
*
* @typedef { import('./types-external.js').VatPowers } VatPowers
* @typedef { import('./types-external.js').StaticVatPowers } StaticVatPowers
* @typedef { import('./types-external.js').MarshallingVatPowers } MarshallingVatPowers
* @typedef { import('./types-external.js').MeteringVatPowers } MeteringVatPowers
*
* @typedef { import('./types-external.js').TerminationVatPowers } TerminationVatPowers
Expand Down
7 changes: 1 addition & 6 deletions packages/SwingSet/src/types-external.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,11 @@ export {};
/**
* See ../docs/static-vats.md#vatpowers
*
* @typedef { MarshallingVatPowers & TerminationVatPowers } VatPowers
* @typedef { TerminationVatPowers } VatPowers
*
* @typedef { (VatPowers & MeteringVatPowers) } StaticVatPowers
*
* @typedef {{
* Remotable: unknown,
* getInterfaceOf: unknown,
* }} MarshallingVatPowers
*
* @typedef {{
* makeGetMeter: unknown,
* transformMetering: unknown,
* }} MeteringVatPowers
Expand Down
261 changes: 21 additions & 240 deletions packages/SwingSet/tools/bundleTool.js
Original file line number Diff line number Diff line change
@@ -1,261 +1,42 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import bundleSource from '@endo/bundle-source';
import { makeReadPowers } from '@endo/compartment-mapper/node-powers.js';
import { makePromiseKit } from '@endo/promise-kit';
import { makeNodeBundleCache as wrappedMaker } from '@endo/bundle-source/cache.js';
import styles from 'ansi-styles'; // less authority than 'chalk'

const { quote: q, Fail } = assert;

/**
* @typedef {object} BundleMeta
* @property {string} bundleFileName
* @property {string} bundleTime as ISO string
* @property {{relative: string, absolute: string}} moduleSource
* @property {Array<{relativePath: string, mtime: string}>} contents
*/

export const makeFileReader = (fileName, { fs, path }) => {
const make = there => makeFileReader(there, { fs, path });
return harden({
toString: () => fileName,
readText: () => fs.promises.readFile(fileName, 'utf-8'),
neighbor: ref => make(path.resolve(fileName, ref)),
stat: () => fs.promises.stat(fileName),
absolute: () => path.normalize(fileName),
relative: there => path.relative(fileName, there),
exists: () => fs.existsSync(fileName),
});
};

/**
* @param {string} fileName
* @param {{ fs: import('fs'), path: import('path') }} io
*/
export const makeFileWriter = (fileName, { fs, path }) => {
const make = there => makeFileWriter(there, { fs, path });
return harden({
toString: () => fileName,
writeText: txt => fs.promises.writeFile(fileName, txt),
readOnly: () => makeFileReader(fileName, { fs, path }),
neighbor: ref => make(path.resolve(fileName, ref)),
mkdir: opts => fs.promises.mkdir(fileName, opts),
});
};

/** @type {(n: string) => string} */
const toBundleName = n => `bundle-${n}.js`;
/** @type {(n: string) => string} */
const toBundleMeta = n => `bundle-${n}-meta.json`;

/** @type {Map<string, Promise<*>>} */
const providedCaches = new Map();

/**
* @param {ReturnType<typeof makeFileWriter>} wr
* @param {*} bundleOptions
* @param {ReturnType<typeof makeFileReader>} cwd
* @param {*} readPowers
*/
export const makeBundleCache = (wr, bundleOptions, cwd, readPowers) => {
const dimLog = (...args) =>
console.log(
`${styles.dim.open}[bundleTool] ${[...args].join(' ')}${
styles.dim.close
}`,
export const makeNodeBundleCache = async (dest, options, loadModule) => {
const log = (...args) => {
const flattened = args.map(arg =>
// Don't print stack traces.
arg instanceof Error ? arg.message : arg,
);

const add = async (rootPath, targetName) => {
const srcRd = cwd.neighbor(rootPath);

const modTimeByPath = new Map();

const loggedRead = async loc => {
if (!loc.match(/\bpackage.json$/)) {
try {
const itemRd = cwd.neighbor(new URL(loc).pathname);
const ref = srcRd.relative(itemRd.absolute());
const { mtime } = await itemRd.stat();
modTimeByPath.set(ref, mtime);
// console.log({ loc, mtime, ref });
} catch (oops) {
console.error(oops);
}
}
return readPowers.read(loc);
};
const bundle = await bundleSource(rootPath, bundleOptions, {
...readPowers,
read: loggedRead,
});

const { moduleFormat } = bundle;
assert.equal(moduleFormat, 'endoZipBase64');

const code = `export default ${JSON.stringify(bundle)};`;
await wr.mkdir({ recursive: true });
const bundleFileName = toBundleName(targetName);
const bundleWr = wr.neighbor(bundleFileName);
await bundleWr.writeText(code);
const { mtime: bundleTime } = await bundleWr.readOnly().stat();

/** @type {BundleMeta} */
const meta = {
bundleFileName,
bundleTime: bundleTime.toISOString(),
moduleSource: {
relative: bundleWr.readOnly().relative(srcRd.absolute()),
absolute: srcRd.absolute(),
},
contents: [...modTimeByPath.entries()].map(([relativePath, mtime]) => ({
relativePath,
mtime: mtime.toISOString(),
})),
};

await wr
.neighbor(toBundleMeta(targetName))
.writeText(JSON.stringify(meta, null, 2));
return meta;
};

const validate = async (targetName, rootOpt) => {
const metaRd = wr.readOnly().neighbor(toBundleMeta(targetName));
let txt;
try {
txt = await metaRd.readText();
} catch (ioErr) {
Fail`${q(targetName)}: cannot read bundle metadata: ${q(ioErr)}`;
}
const meta = JSON.parse(txt);
const {
bundleFileName,
bundleTime,
contents,
moduleSource: { absolute: moduleSource },
} = meta;
assert.equal(bundleFileName, toBundleName(targetName));
if (rootOpt) {
moduleSource === cwd.neighbor(rootOpt).absolute() ||
Fail`bundle ${targetName} was for ${moduleSource}, not ${rootOpt}`;
}
const { mtime: actualBundleTime } = await wr
.readOnly()
.neighbor(bundleFileName)
.stat();
assert.equal(actualBundleTime.toISOString(), bundleTime);
const moduleRd = wr.readOnly().neighbor(moduleSource);
const actualTimes = await Promise.all(
contents.map(async ({ relativePath }) => {
const itemRd = moduleRd.neighbor(relativePath);
const { mtime } = await itemRd.stat();
return { relativePath, mtime: mtime.toISOString() };
}),
console.log(
// Make all messages prefixed and dim.
`${styles.dim.open}[bundleTool]`,
...flattened,
styles.dim.close,
);
const outOfDate = actualTimes.filter(({ mtime }) => mtime > bundleTime);
outOfDate.length === 0 ||
Fail`out of date: ${q(outOfDate)}. ${q(targetName)} bundled at ${q(
bundleTime,
)}`;
return meta;
};

/**
*
* @param {string} rootPath
* @param {string} targetName
* @returns {Promise<BundleMeta>}
*/
const validateOrAdd = async (rootPath, targetName) => {
let meta;
if (wr.readOnly().neighbor(toBundleMeta(targetName)).exists()) {
try {
meta = await validate(targetName, rootPath);
} catch (invalid) {
dimLog(invalid.message);
}
}
if (!meta) {
dimLog(`${wr}`, 'add:', targetName, 'from', rootPath);
meta = await add(rootPath, targetName);
}
return meta;
};

const loaded = new Map();
/**
* @param {string} rootPath
* @param {string} [targetName]
*/
const load = async (
rootPath,
targetName = readPowers.basename(rootPath, '.js'),
) => {
const found = loaded.get(targetName);
// console.log('load', { targetName, found: !!found, rootPath });
if (found && found.rootPath === rootPath) {
return found.bundle;
}
const todo = makePromiseKit();
loaded.set(targetName, { rootPath, bundle: todo.promise });
const bundle = await validateOrAdd(rootPath, targetName)
.then(({ bundleFileName }) =>
import(`${wr.readOnly().neighbor(bundleFileName)}`),
)
.then(m => harden(m.default));
assert.equal(bundle.moduleFormat, 'endoZipBase64');
todo.resolve(bundle);
return bundle;
};

return harden({
add,
validate,
validateOrAdd,
load,
});
return wrappedMaker(dest, { log, ...options }, loadModule);
};

/**
* Make a new bundle cache for the destination. If there is already one for that destination, error.
*
* @param {string} dest
* @param {{ format?: string, dev?: boolean }} options
* @param {(id: string) => Promise<any>} loadModule
*/
export const makeNodeBundleCache = async (dest, options, loadModule) => {
const [fs, path, url, crypto] = await Promise.all([
await loadModule('fs'),
await loadModule('path'),
await loadModule('url'),
await loadModule('crypto'),
]);

const readPowers = {
...makeReadPowers({ fs, url, crypto }),
basename: path.basename,
};

const cwd = makeFileReader('', { fs, path });
const destWr = makeFileWriter(dest, { fs, path });
return makeBundleCache(destWr, options, cwd, readPowers);
};
/** @type {Map<string, ReturnType<typeof makeNodeBundleCache>>} */
const providedCaches = new Map();

/**
* Make a new bundle cache for the destination. If there is already one for that destination, error.
* Make a new bundle cache for the destination. If there is already one for that
* destination, return it.
*
* @param {string} dest
* @param {{ format?: string, dev?: boolean }} options
* @param {(id: string) => Promise<any>} loadModule
*/
export const provideBundleCache = (dest, options, loadModule) => {
const uniqueDest = [dest, options.format, options.dev].join('-');
if (!providedCaches.has(uniqueDest)) {
providedCaches.set(
uniqueDest,
makeNodeBundleCache(dest, options, loadModule),
);
let bundleCache = providedCaches.get(uniqueDest);
if (!bundleCache) {
bundleCache = makeNodeBundleCache(dest, options, loadModule);
providedCaches.set(uniqueDest, bundleCache);
}
return providedCaches.get(uniqueDest);
return bundleCache;
};
harden(provideBundleCache);

Expand Down
2 changes: 1 addition & 1 deletion packages/agoric-cli/src/lib/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const getLastUpdate = (addr, { readLatestHead }) => {
* @param {Pick<import('stream').Writable,'write'>} [stdout]
*/
export const outputAction = (bridgeAction, stdout = process.stdout) => {
const capData = marshaller.serialize(bridgeAction);
const capData = marshaller.serialize(harden(bridgeAction));
stdout.write(JSON.stringify(capData));
stdout.write('\n');
};
Expand Down
6 changes: 3 additions & 3 deletions packages/agoric-cli/test/test-inter-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const makeNet = published => {
const ctx = makeFromBoard();
const m = boardSlottingMarshaller(ctx.convertSlotToVal);
const fmt = obj => {
const capData = m.serialize(obj);
const capData = m.serialize(harden(obj));
const values = [JSON.stringify(capData)];
const specimen = { blockHeight: undefined, values };
const txt = JSON.stringify({
Expand Down Expand Up @@ -583,10 +583,10 @@ test('README ex1: inter bid place by-price: printed offer is correct', async t =

const txt = out.join('').trim();
const obj = net.marshaller.unserialize(JSON.parse(txt));
obj.offer.result = 'Your bid has been accepted'; // pretend we processed it
const offer = { ...obj.offer, result: 'Your bid has been accepted' }; // pretend we processed it

const assets = Object.values(agoricNames.vbankAsset);
const bidInfo = fmtBid(obj.offer, assets);
const bidInfo = fmtBid(offer, assets);
t.deepEqual(bidInfo, expected);
});

Expand Down
4 changes: 3 additions & 1 deletion packages/cache/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ const makeKeyToString = (sanitize = obj => obj) => {
return slot;
};

const { serialize: keyToJsonable } = makeMarshal(valToSlot);
const { serialize: keyToJsonable } = makeMarshal(valToSlot, undefined, {
serializeBodyFormat: 'smallcaps',
});
const keyToString = async keyP => {
const key = await sanitize(keyP);
const obj = keyToJsonable(key);
Expand Down
Loading

0 comments on commit eea8945

Please sign in to comment.