Skip to content

Commit

Permalink
feat(zone): first cut at @agoric/zone
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Mar 17, 2023
1 parent e656f14 commit 74a7865
Show file tree
Hide file tree
Showing 10 changed files with 295 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test-all-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ jobs:
run: cd packages/time && yarn ${{ steps.vars.outputs.test }} | $TEST_COLLECT
- name: yarn test (swingset-liveslots)
run: cd packages/swingset-liveslots && yarn ${{ steps.vars.outputs.test }} | $TEST_COLLECT
- name: yarn test (zone)
run: cd packages/zone && yarn ${{ steps.vars.outputs.test }} | $TEST_COLLECT

# The meta-test!
- name: Check for untested packages
Expand Down
1 change: 1 addition & 0 deletions packages/zone/durable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/durable.js';
1 change: 1 addition & 0 deletions packages/zone/heap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/heap.js';
19 changes: 19 additions & 0 deletions packages/zone/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// This file can contain .js-specific Typescript compiler config.
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"checkJs": true,
"noEmit": true,
"downlevelIteration": true,
"strictNullChecks": true,
"noImplicitThis": true,
"moduleResolution": "node",
},
"include": [
"*.js",
"scripts",
"src",
"test",
],
}
46 changes: 46 additions & 0 deletions packages/zone/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@agoric/zone",
"version": "0.1.0",
"description": "Allocation zone abstraction for objects on the heap, persistent stores, etc.",
"type": "module",
"repository": "https://github.com/Agoric/agoric-sdk",
"main": "./src/index.js",
"scripts": {
"build": "exit 0",
"test": "true || ava",
"test:c8": "true || c8 $C8_OPTIONS ava --config=ava-nesm.config.js",
"test:xs": "exit 0",
"lint-fix": "yarn lint:eslint --fix",
"lint": "run-s --continue-on-error lint:*",
"lint:types": "tsc -p jsconfig.json",
"lint:eslint": "eslint ."
},
"exports": {
".": "./src/index.js",
"./durable.js": "./durable.js",
"./heap.js": "./heap.js",
"./virtual.js": "./virtual.js"
},
"keywords": [],
"author": "Agoric",
"license": "Apache-2.0",
"dependencies": {
"@agoric/store": "^0.8.3",
"@agoric/vat-data": "^0.4.3",
"@endo/far": "^0.2.14"
},
"devDependencies": {},
"publishConfig": {
"access": "public"
},
"engines": {
"node": ">=14.15.0"
},
"ava": {
"files": [
"test/**/test-*.js"
],
"timeout": "20m",
"workerThreads": false
}
}
82 changes: 82 additions & 0 deletions packages/zone/src/durable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {
canBeDurable,
makeScalarMapStore,
prepareExo,
prepareExoClass,
prepareExoClassKit,
provideDurableMapStore,
provideDurableSetStore,
provideDurableWeakMapStore,
provideDurableWeakSetStore,
M,
} from '@agoric/vat-data';

import { Far } from '@endo/far';

/**
* @param {() => import('@agoric/vat-data').Baggage} getBaggage
*/
const attachDurableStores = getBaggage => {
/** @type {import('.').Zone['mapStore']} */
const mapStore = (label, options) =>
provideDurableMapStore(getBaggage(), label, options);
/** @type {import('.').Zone['setStore']} */
const setStore = (label, options) =>
provideDurableSetStore(getBaggage(), label, options);
/** @type {import('.').Zone['weakSetStore']} */
const weakSetStore = (label, options) =>
provideDurableWeakSetStore(getBaggage(), label, options);
/** @type {import('.').Zone['weakMapStore']} */
const weakMapStore = (label, options) =>
provideDurableWeakMapStore(getBaggage(), label, options);

/** @type {import('.').Stores} */
return Far('durableStores', {
// eslint-disable-next-line no-use-before-define
detached: () => detachedDurableStores,
isStorable: canBeDurable,
mapStore,
setStore,
weakMapStore,
weakSetStore,
});
};

/** @type {import('.').Stores} */
export const detachedDurableStores = attachDurableStores(() =>
makeScalarMapStore('detached'),
);

/**
* Create a zone whose objects persist between Agoric vat upgrades.
*
* @param {import('@agoric/vat-data').Baggage} baggage
* @returns {import('.').Zone}
*/
export const makeDurableZone = baggage => {
/** @type {import('.').Zone['exoClass']} */
const exoClass = (...args) => prepareExoClass(baggage, ...args);
/** @type {import('.').Zone['exoClassKit']} */
const exoClassKit = (...args) => prepareExoClassKit(baggage, ...args);
/** @type {import('.').Zone['exo']} */
const exo = (...args) => prepareExo(baggage, ...args);

const attachedStores = attachDurableStores(() => baggage);

/** @type {import('.').Zone['subZone']} */
const subZone = (label, options = {}) => {
const subBaggage = provideDurableMapStore(baggage, label, options);
return makeDurableZone(subBaggage);
};

return Far('durableZone', {
exo,
exoClass,
exoClassKit,
subZone,
...attachedStores,
});
};
harden(makeDurableZone);

export { M };
40 changes: 40 additions & 0 deletions packages/zone/src/heap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
makeExo,
defineExoClass,
defineExoClassKit,
makeScalarMapStore,
makeScalarSetStore,
makeScalarWeakMapStore,
makeScalarWeakSetStore,
M,
} from '@agoric/store';

import { Far } from '@endo/far';

/**
* @type {import('.').Stores}
*/
const heapStores = Far('heapStores', {
detached: () => heapStores,
isStorable: _specimen => true,

setStore: makeScalarSetStore,
mapStore: makeScalarMapStore,
weakMapStore: makeScalarWeakMapStore,
weakSetStore: makeScalarWeakSetStore,
});

/**
* A heap (in-memory) zone that uses the default exo and store implementations.
*
* @type {import('.').Zone}
*/
export const heapZone = Far('heapZone', {
exoClass: defineExoClass,
exoClassKit: defineExoClassKit,
exo: makeExo,
subZone: (_label, _options) => heapZone,
...heapStores,
});

export { M };
35 changes: 35 additions & 0 deletions packages/zone/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { makeExo, defineExoClass, defineExoClassKit } from '@agoric/store';

export * from './heap.js';

// References to allow the below typeofs to succeed.
makeExo;
defineExoClass;
defineExoClassKit;

/**
* @typedef {ExoZone & Stores} Zone A bag of methods for creating defensible objects and
* collections with the same allocation semantics (ephemeral, persistent, etc)
*/

/**
* @typedef {object} ExoZone
* @property {typeof makeExo} exo create a singleton exo-object instance bound to this zone
* @property {typeof defineExoClass} exoClass create a maker function that can be used to create exo-objects bound to this zone
* @property {typeof defineExoClassKit} exoClassKit create a "kit" maker function that can be used to create a record of exo-objects sharing the same state
* @property {(label: string, options?: StoreOptions) => Zone} subZone create a new Zone that can be passed to untrusted consumers without exposing the storage of the parent zone
*/

/**
* @typedef {object} Stores
* @property {() => Stores} detached obtain store providers which are detached (the stores are anonymous rather than bound to `label` in the zone)
* @property {(specimen: unknown) => boolean} isStorable return true if the specimen can be stored in the zone, whether as exo-object state or in a store
* @property {<K,V>(label: string, options?: StoreOptions) => MapStore<K, V>} mapStore provide a Map-like store named `label` in the zone
* @property {<K>(label: string, options?: StoreOptions) => SetStore<K>} setStore provide a Set-like store named `label` in the zone
* @property {<K,V>(
* label: string, options?: StoreOptions) => WeakMapStore<K, V>
* } weakMapStore provide a WeakMap-like store named `label` in the zone
* @property {<K>(
* label: string, options?: StoreOptions) => WeakSetStore<K>
* } weakSetStore provide a WeakSet-like store named `label` in the zone
*/
68 changes: 68 additions & 0 deletions packages/zone/src/virtual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
canBeDurable,
defineVirtualExoClass,
defineVirtualExoClassKit,
makeScalarBigMapStore,
makeScalarBigSetStore,
makeScalarBigWeakMapStore,
makeScalarBigWeakSetStore,
M,
} from '@agoric/vat-data';

import { Far } from '@endo/far';

const emptyRecord = harden({});
const initEmpty = harden(() => emptyRecord);

/**
* This implementation of `defineVirtualExo` only exists to ensure there are no
* gaps in the virtualZone API.
*
* @type {import('.').Zone['exo']}
*/
const defineVirtualExo = (
label,
interfaceGuard,
methods,
options = undefined,
) => {
const defineKindOptions =
/** @type {import('@agoric/vat-data').DefineKindOptions<{ self: typeof methods }>} */ (
options
);
const makeInstance = defineVirtualExoClass(
label,
interfaceGuard,
initEmpty,
methods,
defineKindOptions,
);
return makeInstance();
};

/** @type {import('.').Stores} */
export const detachedVirtualStores = Far('virtualStores', {
detached: () => detachedVirtualStores,
isStorable: canBeDurable,
mapStore: makeScalarBigMapStore,
setStore: makeScalarBigSetStore,
weakMapStore: makeScalarBigWeakMapStore,
weakSetStore: makeScalarBigWeakSetStore,
});

/**
* A zone that utilizes external storage to reduce the memory footprint of the
* current vat.
*
* @type {import('.').Zone}
*/
export const virtualZone = Far('virtualZone', {
exo: defineVirtualExo,
exoClass: defineVirtualExoClass,
exoClassKit: defineVirtualExoClassKit,
subZone: (_label, _options = {}) => virtualZone,

...detachedVirtualStores,
});

export { M };
1 change: 1 addition & 0 deletions packages/zone/virtual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/virtual.js';

0 comments on commit 74a7865

Please sign in to comment.