Skip to content

Commit

Permalink
Merge pull request #7891 from Agoric/mfig-zone-make-once
Browse files Browse the repository at this point in the history
feat(zone)!: implement `zone.makeOnce(key, maker)`
  • Loading branch information
michaelfig authored Jul 25, 2023
2 parents 8358d20 + dc8eb4a commit 8baf0aa
Show file tree
Hide file tree
Showing 29 changed files with 732 additions and 164 deletions.
7 changes: 4 additions & 3 deletions packages/SwingSet/docs/vat-upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ The [zone API](https://github.com/Agoric/agoric-sdk/tree/master/packages/zone#re

You can obtain individual zones implementing this API as follows:
* Heap objects in vat RAM
- `import { heapZone } from '@agoric/zone';`
- `import { makeHeapZone } from '@agoric/zone';`
* Virtual objects in disk-based storage
- `import { virtualZone } from '@agoric/zone/virtual.js';`
- `import { makeVirtualZone } from '@agoric/zone/virtual.js';`
* Durable objects in disk-based storage
- zone API maker found at `import { makeDurableZone } from '@agoric/zone/durable.js';` and
- zone API backed by a durable map and created by `makeDurableZone(durableMap)`
Expand Down Expand Up @@ -136,7 +136,8 @@ const makeFoo = prepareExoClass(someDurableMap, 'foo', fooI, initFoo, fooMethods
or with the zone API:

```js
import { M, makeDurableZone } from '@agoric/zone';
import { M } from '@endo/patterns';
import { makeDurableZone } from '@agoric/zone';
const FooI = M.interface('foo', fooMethodGuards);
// someDurableMap should generally be reachable from baggage.
const zone = makeDurableZone(someDurableMap);
Expand Down
43 changes: 4 additions & 39 deletions packages/SwingSet/tools/prepare-test-env.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,14 @@
/* global globalThis */
/**
* Prepare Agoric SwingSet vat global environment for testing.
*
* Installs Hardened JS (and does lockdown), plus adds mocks for virtual objects
* and stores.
*/

import '@endo/init/pre-bundle-source.js';
import '@endo/init/pre.js';

import './install-ses-debug.js';
import { makeFakeVirtualStuff } from '@agoric/swingset-liveslots/tools/fakeVirtualSupport.js';
import { reincarnate } from './setup-vat-data.js';

const { vom, cm, wpm } = makeFakeVirtualStuff();

const {
defineKind,
defineKindMulti,
defineDurableKind,
defineDurableKindMulti,
makeKindHandle,
canBeDurable,
} = vom;

const {
makeScalarBigMapStore,
makeScalarBigWeakMapStore,
makeScalarBigSetStore,
makeScalarBigWeakSetStore,
} = cm;

const { watchPromise, providePromiseWatcher } = wpm;

const VatData = harden({
defineKind,
defineKindMulti,
defineDurableKind,
defineDurableKindMulti,
makeKindHandle,
providePromiseWatcher,
watchPromise,
makeScalarBigMapStore,
makeScalarBigWeakMapStore,
makeScalarBigSetStore,
makeScalarBigWeakSetStore,
canBeDurable,
});

globalThis.VatData = VatData;
// Install the VatData globals.
reincarnate();
54 changes: 54 additions & 0 deletions packages/SwingSet/tools/setup-vat-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// @ts-check
/* global globalThis */
// This file produces the globalThis.VatData property outside of a running
// SwingSet so that it can be used by '@agoric/vat-data' (which only *consumes*
// `globalThis.VatData`) in code under test.
import { makeFakeVirtualStuff } from '@agoric/swingset-liveslots/tools/fakeVirtualSupport.js';

const { WeakMap, WeakSet } = globalThis;

/** @type {ReturnType<makeFakeVirtualStuff>} */
let fakeVomKit;

globalThis.VatData = harden({
defineKind: (...args) => fakeVomKit.vom.defineKind(...args),
defineKindMulti: (...args) => fakeVomKit.vom.defineKindMulti(...args),
defineDurableKind: (...args) => fakeVomKit.vom.defineDurableKind(...args),
defineDurableKindMulti: (...args) =>
fakeVomKit.vom.defineDurableKindMulti(...args),
makeKindHandle: (...args) => fakeVomKit.vom.makeKindHandle(...args),
canBeDurable: (...args) => fakeVomKit.vom.canBeDurable(...args),
providePromiseWatcher: (...args) =>
fakeVomKit.wpm.providePromiseWatcher(...args),
watchPromise: (...args) => fakeVomKit.wpm.watchPromise(...args),
makeScalarBigMapStore: (...args) =>
fakeVomKit.cm.makeScalarBigMapStore(...args),
makeScalarBigWeakMapStore: (...args) =>
fakeVomKit.cm.makeScalarBigWeakMapStore(...args),
makeScalarBigSetStore: (...args) =>
fakeVomKit.cm.makeScalarBigSetStore(...args),
makeScalarBigWeakSetStore: (...args) =>
fakeVomKit.cm.makeScalarBigWeakSetStore(...args),
});

export const reincarnate = (options = {}) => {
const { fakeStore = new Map(), fakeVomKit: fvk } = options;

if (options.fakeVomKit) {
fvk.vom.flushStateCache();
fvk.cm.flushSchemaCache();
fvk.vrm.flushIDCounters();
}

fakeVomKit = makeFakeVirtualStuff({
...options,
fakeStore,
WeakMap,
WeakSet,
});

globalThis.WeakMap = fakeVomKit.vom.VirtualObjectAwareWeakMap;
globalThis.WeakSet = fakeVomKit.vom.VirtualObjectAwareWeakSet;

return { ...options, fakeStore, fakeVomKit };
};
5 changes: 3 additions & 2 deletions packages/inter-protocol/test/psm/test-psm.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from '@agoric/vats/src/core/basic-behaviors.js';
import { E, Far } from '@endo/far';
import path from 'path';
import { heapZone } from '@agoric/zone';
import { makeHeapZone } from '@agoric/zone';
import { Stable } from '../../src/tokens.js';
import { makeAnchorAsset, startPSM } from '../../src/proposals/startPSM.js';
import {
Expand Down Expand Up @@ -759,9 +759,10 @@ test('restore PSM: startPSM with previous metrics, params', async t => {

// Prep bootstrap space
{
const zone = makeHeapZone();
await produceDiagnostics({ produce });
// @ts-expect-error Doesnt actually require all bootstrap powers
await produceStartUpgradable({ zone: heapZone, consume, produce });
await produceStartUpgradable({ zone, consume, produce });

const {
installs,
Expand Down
4 changes: 2 additions & 2 deletions packages/inter-protocol/test/smartWallet/boot-psm.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
WALLET_FACTORY_MANIFEST,
} from '@agoric/vats/src/core/startWalletFactory.js';
import * as utils from '@agoric/vats/src/core/utils.js';
import { heapZone } from '@agoric/zone';
import { makeHeapZone } from '@agoric/zone';
import { Stable, Stake } from '../../src/tokens.js';
import {
ECON_COMMITTEE_MANIFEST,
Expand Down Expand Up @@ -212,7 +212,7 @@ export const buildRootObject = async (vatPowers, vatParameters) => {
devices,
produce,
consume,
zone: heapZone,
zone: makeHeapZone(),
...spaces,
// ISSUE: needed? runBehaviors,
// These module namespaces might be useful for core eval governance.
Expand Down
7 changes: 4 additions & 3 deletions packages/inter-protocol/test/smartWallet/contexts.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
produceStartGovernedUpgradable,
produceDiagnostics,
} from '@agoric/vats/src/core/basic-behaviors.js';
import { heapZone } from '@agoric/zone';
import { makeHeapZone } from '@agoric/zone';
import { E } from '@endo/far';
import path from 'path';
import {
Expand Down Expand Up @@ -43,6 +43,7 @@ export const makeDefaultTestContext = async (t, makeSpace) => {
const log = () => null;

const bundleCache = await unsafeMakeBundleCache('bundles/');
const zone = makeHeapZone();

// @ts-expect-error xxx
const { consume, produce, instance } = await makeSpace(log, bundleCache);
Expand All @@ -52,7 +53,7 @@ export const makeDefaultTestContext = async (t, makeSpace) => {
// @ts-expect-error Doesnt actually require all bootstrap powers
await produceDiagnostics({ consume, produce });
// @ts-expect-error Doesnt actually require all bootstrap powers
await produceStartUpgradable({ zone: heapZone, consume, produce });
await produceStartUpgradable({ zone, consume, produce });

//#region Installs
const pathname = new URL(import.meta.url).pathname;
Expand Down Expand Up @@ -82,7 +83,7 @@ export const makeDefaultTestContext = async (t, makeSpace) => {
consume,
// @ts-expect-error Doesnt actually require all bootstrap powers
produce,
zone: heapZone,
zone,
installation: {
// @ts-expect-error Doesnt actually require all bootstrap powers
consume: { contractGovernor },
Expand Down
5 changes: 3 additions & 2 deletions packages/internal/src/lib-chainStorage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// @ts-check

import { E } from '@endo/far';
import { M, heapZone } from '@agoric/zone';
import { M } from '@endo/patterns';
import { makeHeapZone } from '@agoric/zone';
import * as cb from './callback.js';

const { Fail } = assert;
Expand Down Expand Up @@ -207,7 +208,7 @@ export const prepareChainStorageNode = zone => {
return makeChainStorageNode;
};

const makeHeapChainStorageNode = prepareChainStorageNode(heapZone);
const makeHeapChainStorageNode = prepareChainStorageNode(makeHeapZone());

/**
* Create a heap-based root storage node for a given backing function and root path.
Expand Down
10 changes: 3 additions & 7 deletions packages/internal/test/test-callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import '@endo/init';
import test from 'ava';

import { Far } from '@endo/far';
import { heapZone } from '@agoric/zone';
import { makeHeapZone } from '@agoric/zone';
import * as cb from '../src/callback.js';

test('near function callbacks', t => {
Expand Down Expand Up @@ -266,12 +266,8 @@ test('isCallback', t => {
});

test('makeAttenuator', async t => {
const makeAttenuator = cb.prepareAttenuator(heapZone, [
'm0',
'm1',
'm2',
'm4',
]);
const zone = makeHeapZone();
const makeAttenuator = cb.prepareAttenuator(zone, ['m0', 'm1', 'm2', 'm4']);
const target = Far('original', {
m0() {
return 'return original.m0';
Expand Down
33 changes: 28 additions & 5 deletions packages/swingset-liveslots/tools/fakeVirtualSupport.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global WeakRef */
/* global globalThis */
/* eslint-disable max-classes-per-file */
import { makeMarshal } from '@endo/marshal';
import { assert } from '@agoric/assert';
Expand All @@ -9,6 +9,14 @@ import { makeWatchedPromiseManager } from '../src/watchedPromises.js';
import { makeFakeVirtualObjectManager } from './fakeVirtualObjectManager.js';
import { makeFakeCollectionManager } from './fakeCollectionManager.js';

const { Fail } = assert;

const {
WeakRef: RealWeakRef,
WeakMap: RealWeakMap,
WeakSet: RealWeakSet,
} = globalThis;

class FakeFinalizationRegistry {
// eslint-disable-next-line no-useless-constructor, no-empty-function
constructor() {}
Expand All @@ -30,8 +38,6 @@ class FakeWeakRef {
}
}

const RealWeakRef = WeakRef;

export function makeFakeLiveSlotsStuff(options = {}) {
let vrm;
function setVrm(vrmToUse) {
Expand All @@ -45,6 +51,8 @@ export function makeFakeLiveSlotsStuff(options = {}) {
log,
FinalizationRegistry = FakeFinalizationRegistry,
WeakRef = FakeWeakRef, // VRM uses this
WeakMap = RealWeakMap,
WeakSet = RealWeakSet,
addToPossiblyDeadSet = () => {},
addToPossiblyRetiredSet = () => {},
} = options;
Expand Down Expand Up @@ -206,24 +214,33 @@ export function makeFakeLiveSlotsStuff(options = {}) {
}
return val;
}
let result;
if (virtual || durable) {
if (vrm) {
val = vrm.reanimate(slot);
if (facet !== undefined) {
return vrm.getFacet(id, val, facet);
result = vrm.getFacet(id, val, facet);
}
} else {
assert.fail('fake liveSlots stuff configured without vrm');
}
}
return val;
// eslint-disable-next-line no-use-before-define
registerEntry(baseRef, val, facet !== undefined);
if (!result) {
result = val;
}
return result;
}

const marshal = makeMarshal(convertValToSlot, convertSlotToVal, {
serializeBodyFormat: 'smallcaps',
});

function registerEntry(baseRef, val, valIsCohort) {
const { facet } = parseVatSlot(baseRef);
!facet ||
Fail`registerEntry(${baseRef} should not receive individual facets`;
setValForSlot(baseRef, val);
if (valIsCohort) {
const { id } = parseVatSlot(baseRef);
Expand Down Expand Up @@ -264,6 +281,8 @@ export function makeFakeLiveSlotsStuff(options = {}) {
deleteEntry,
FinalizationRegistry,
WeakRef,
WeakMap,
WeakSet,
addToPossiblyDeadSet,
addToPossiblyRetiredSet,
dumpStore,
Expand Down Expand Up @@ -311,6 +330,10 @@ export function makeFakeWatchedPromiseManager(
* @param {object} [options]
* @param {number} [options.cacheSize]
* @param {boolean} [options.relaxDurabilityRules]
* @param {Map<any, any>} [options.fakeStore]
* @param {WeakMapConstructor} [options.WeakMap]
* @param {WeakSetConstructor} [options.WeakSet]
* @param {boolean} [options.weak]
*/
export function makeFakeVirtualStuff(options = {}) {
const actualOptions = {
Expand Down
4 changes: 2 additions & 2 deletions packages/vats/src/core/lib-boot.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check
import { E, Far } from '@endo/far';
import { makePassableEncoding } from '@agoric/swingset-vat/tools/passableEncoding.js';
import { heapZone } from '@agoric/zone';
import { makeHeapZone } from '@agoric/zone';
import {
makeVatSpace,
makeWellKnownSpaces,
Expand Down Expand Up @@ -64,7 +64,7 @@ export const makeBootstrap = (
bootManifest,
behaviors,
modules,
zone = heapZone,
zone = makeHeapZone(),
) => {
const { keys } = Object;
const extra = setDiff(keys(bootManifest), keys(behaviors));
Expand Down
4 changes: 2 additions & 2 deletions packages/vats/src/nameHub.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
makeSyncMethodCallback,
prepareGuardedAttenuator,
} from '@agoric/internal/src/callback.js';
import { heapZone } from '@agoric/zone';
import { makeHeapZone } from '@agoric/zone';
import { deeplyFulfilled } from '@endo/marshal';

const { Fail, quote: q } = assert;
Expand Down Expand Up @@ -369,4 +369,4 @@ export const prepareNameHubKit = zone => {
*
* @returns {import('./types.js').NameHubKit}
*/
export const makeNameHubKit = prepareNameHubKit(heapZone);
export const makeNameHubKit = prepareNameHubKit(makeHeapZone());
Loading

0 comments on commit 8baf0aa

Please sign in to comment.