Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: prepare for use of non-trapping integrity trait #10795

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion packages/SwingSet/src/kernel/deviceSlots.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ import {
} from '../lib/parseVatSlots.js';
import { insistCapData } from '../lib/capdata.js';

const { freeze } = Object;

/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* Although a frozen-only object will not be defensive, since it could still
* be made non-trapping, these are encapsulated only within proxies that
* will refuse to be made non-trapping, and so can safely be shared.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const target = freeze({});

// 'makeDeviceSlots' is a subset of makeLiveSlots, for device code

export function makeDeviceSlots(
Expand Down Expand Up @@ -142,7 +153,7 @@ export function makeDeviceSlots(
(slot && parseVatSlot(slot).type === 'object') ||
Fail`SO(x) must be called on a Presence, not ${x}`;
const handler = PresenceHandler(slot);
const p = harden(new Proxy({}, handler));
const p = new Proxy(target, handler);
outstandingProxies.add(p);
return p;
}
Expand Down
28 changes: 24 additions & 4 deletions packages/SwingSet/tools/run-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { makeQueue } from '@endo/stream';
* @import { RunPolicy } from '../src/types-external.js'
*/

const { freeze } = Object;

/** @typedef {{ provideRunPolicy: () => RunPolicy | undefined }} RunHarness */

/**
Expand Down Expand Up @@ -103,11 +105,29 @@ export const makeRunUtils = (controller, harness) => {
// promise that can remain pending indefinitely, possibly to be settled by a
// future message delivery.

/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* Although a frozen-only object will not be defensive, since it could still
* be made non-trapping, these are encapsulated only within proxies that
* will refuse to be made non-trapping, and so can safely be shared.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const objTarget = freeze({});

/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* Although a frozen-only object will not be defensive, since it could still
* be made non-trapping, these are encapsulated only within proxies that
* will refuse to be made non-trapping, and so can safely be shared.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const funcTarget = freeze(() => {});

/** @type {EVProxy} */
// @ts-expect-error cast, approximate
const EV = Object.assign(
presence =>
new Proxy(harden({}), {
new Proxy(funcTarget, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use funcTarget instead of objTarget here and below? EV does not support remotable functions at this time, and has various other deficiencies when compared with E. I'd rather fix those deficiencies in a separate PR instead of just making partial changes that aren't fully baked.

get: (_t, method, _rx) => {
const boundMethod = (...args) =>
queueAndRun(() =>
Expand All @@ -118,7 +138,7 @@ export const makeRunUtils = (controller, harness) => {
}),
{
vat: vatName =>
new Proxy(harden({}), {
new Proxy(funcTarget, {
get: (_t, method, _rx) => {
const boundMethod = (...args) =>
queueAndRun(() =>
Expand All @@ -128,7 +148,7 @@ export const makeRunUtils = (controller, harness) => {
},
}),
sendOnly: presence =>
new Proxy(harden({}), {
new Proxy(funcTarget, {
get: (_t, method, _rx) => {
const boundMethod = (...args) =>
queueAndRun(
Expand All @@ -139,7 +159,7 @@ export const makeRunUtils = (controller, harness) => {
},
}),
get: presence =>
new Proxy(harden({}), {
new Proxy(objTarget, {
get: (_t, pathElement, _rx) =>
queueAndRun(() =>
controller.queueToVatRoot('bootstrap', 'awaitVatObject', [
Expand Down
9 changes: 8 additions & 1 deletion packages/swingset-liveslots/src/liveslots.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { makeCollectionManager } from './collectionManager.js';
import { makeWatchedPromiseManager } from './watchedPromises.js';
import { makeBOYDKit } from './boyd-gc.js';

const { freeze } = Object;

const SYSCALL_CAPDATA_BODY_SIZE_LIMIT = 10_000_000;
const SYSCALL_CAPDATA_SLOTS_LENGTH_LIMIT = 10_000;

Expand Down Expand Up @@ -864,8 +866,13 @@ function build(
if (!slot || parseVatSlot(slot).type !== 'device') {
throw Error('D() must be given a device node');
}
/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const target = freeze({});
const handler = DeviceHandler(slot);
const pr = harden(new Proxy({}, handler));
const pr = new Proxy(target, handler);
outstandingProxies.add(pr);
return pr;
}
Expand Down
16 changes: 14 additions & 2 deletions packages/vats/src/core/promise-space.js
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change in this file points to a potential future upgrade hazard. It means we cannot simply use the currently deployed code and re-run its transcript on top of a lockdown + liveslots (or an XS engine) that introduces non-trapping behavior. Such a "replay" is one of the option we're still keeping under consideration, especially for the bootstrap vat which cannot be upgraded.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { assertKey } from '@agoric/store';
import { canBeDurable } from '@agoric/vat-data';
import { makePromiseKit } from '@endo/promise-kit';

const { freeze } = Object;

/**
* @typedef {{
* onAddKey: (key: string) => void;
Expand All @@ -14,6 +16,16 @@ import { makePromiseKit } from '@endo/promise-kit';

const noop = harden(() => {});

/**
* `freeze` but not `harden` the proxy target so it remains trapping. Although a
* frozen-only object will not be defensive, since it could still be made
* non-trapping, these are encapsulated only within proxies that will refuse to
* be made non-trapping, and so can safely be shared.
*
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const target = freeze({});

/**
* @param {typeof console.log} log
* @returns {PromiseSpaceHooks}
Expand Down Expand Up @@ -167,7 +179,7 @@ export const makePromiseSpace = (optsOrLog = {}) => {

/** @type {PromiseSpaceOf<T>['consume']} */
// @ts-expect-error cast
const consume = new Proxy(harden({}), {
const consume = new Proxy(target, {
get: (_target, name) => {
assert.typeof(name, 'string');
return provideState(name).pk.promise;
Expand All @@ -176,7 +188,7 @@ export const makePromiseSpace = (optsOrLog = {}) => {

/** @type {PromiseSpaceOf<T>['produce']} */
// @ts-expect-error cast
const produce = new Proxy(harden({}), {
const produce = new Proxy(target, {
get: (_target, name) => {
assert.typeof(name, 'string');
return makeProducer(name);
Expand Down
9 changes: 7 additions & 2 deletions packages/vats/src/core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { makeLogHooks, makePromiseSpace } from './promise-space.js';

import './types-ambient.js';

const { entries, fromEntries, keys } = Object;
const { entries, fromEntries, keys, freeze } = Object;

/**
* Used in bootstrap to reserve names in the agoricNames namespace before any
Expand Down Expand Up @@ -130,7 +130,12 @@ export const extract = (template, specimen, path = []) => {
specimen,
)}`;
}
const target = harden(
/**
* `freeze` but not `harden` the proxy target so it remains trapping.
*
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const target = freeze(
fromEntries(
entries(template).map(([propName, subTemplate]) => [
propName,
Expand Down
40 changes: 24 additions & 16 deletions packages/vow/src/E.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { X, q, Fail, makeError } from '@endo/errors';
import { trackTurns } from './track-turns.js';
import { makeMessageBreakpointTester } from './message-breakpoints.js';

const { assign, create } = Object;
const { assign, create, freeze } = Object;

const onSend = makeMessageBreakpointTester('ENDO_SEND_BREAKPOINTS');

Expand Down Expand Up @@ -200,6 +200,24 @@ const makeEGetProxyHandler = (x, HandledPromise, unwrap) =>
/** @param {any} x */
const resolve = x => HandledPromise.resolve(x);

/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* Although a frozen-only object will not be defensive, since it could still
* be made non-trapping, these are encapsulated only within proxies that
* will refuse to be made non-trapping, and so can safely be shared.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const objTarget = freeze(create(null));

/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* Although a frozen-only object will not be defensive, since it could still
* be made non-trapping, these are encapsulated only within proxies that
* will refuse to be made non-trapping, and so can safely be shared.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const funcTarget = freeze(() => {});

/**
* @template [A={}]
* @param {HandledPromiseConstructor} HandledPromise
Expand All @@ -224,10 +242,7 @@ const makeE = (HandledPromise, powers = {}) => {
* @param {T} x target for method/function call
* @returns {ECallableOrMethods<RemoteFunctions<T>>} method/function call proxy
*/
x =>
harden(
new Proxy(() => {}, makeEProxyHandler(x, HandledPromise, unwrap)),
),
x => new Proxy(funcTarget, makeEProxyHandler(x, HandledPromise, unwrap)),
{
/**
* E.get(x) returns a proxy on which you can get arbitrary properties.
Expand All @@ -241,12 +256,7 @@ const makeE = (HandledPromise, powers = {}) => {
* @readonly
*/
get: x =>
harden(
new Proxy(
create(null),
makeEGetProxyHandler(x, HandledPromise, unwrap),
),
),
new Proxy(objTarget, makeEGetProxyHandler(x, HandledPromise, unwrap)),

/**
* E.resolve(x) converts x to a handled promise. It is
Expand All @@ -269,11 +279,9 @@ const makeE = (HandledPromise, powers = {}) => {
* @readonly
*/
sendOnly: x =>
harden(
new Proxy(
() => {},
makeESendOnlyProxyHandler(x, HandledPromise, unwrap),
),
new Proxy(
funcTarget,
makeESendOnlyProxyHandler(x, HandledPromise, unwrap),
),

/**
Expand Down
Loading