From e40a8b9a4b8fb0651d915b21876bc7f7f963131a Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Fri, 30 Aug 2024 14:10:28 -0700 Subject: [PATCH] fix(liveslots): move passStyleOf from vatGlobals to inescapableGlobalProperties Previously, liveslots added the special `PassStyleOfEndowmentSymbol` on `vatGlobals`. This enabled the first-level vat bundle (the one that defines buildRootObject, e.g. ZCF) to use the same passStyleOf as liveslots is using, with a real WeakMap for its memoization cache. However, child Compartments of that vat, such as the ones contract bundles are loaded into, do not automatically get the same global, and ZCF does not pass any special options to `importBundle()`, which would enable that. This commit attaches the symbol to `inescapableGlobalProperties`, rather than `vatGlobals`. Those properties are automatically (indeed unavoidably) copied onto the `globalThis` of each child Compartment, recursively. This is stronger than we need: we're ok with a Compartment choosing to omit or change this property. This allows contract code which does `import { passStyleOf } from '@endo/pass-style'` to get the correct/fast/cheap version too. Tests were added to liveslots to assert that it gives the expected `inescapableGlobalProperties` option when asking the supervisor to build the vat's namespace, and to SwingSet to assert that both child and grandchild Compartments get the expected version of passStyleOf (which was not the case for mere `vatGlobals`). fixes #9981 --- packages/SwingSet/test/vat-env.test.js | 10 +++-- packages/SwingSet/test/vat-envtest.js | 39 ++++++++++++++++--- packages/swingset-liveslots/src/liveslots.js | 2 +- .../test/vat-environment.test.js | 9 +++-- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/packages/SwingSet/test/vat-env.test.js b/packages/SwingSet/test/vat-env.test.js index 1424e1641d8..aed60fadfdd 100644 --- a/packages/SwingSet/test/vat-env.test.js +++ b/packages/SwingSet/test/vat-env.test.js @@ -1,7 +1,8 @@ // @ts-nocheck +// eslint-disable-next-line import/order import { test, VatData } from '../tools/prepare-test-env-ava.js'; -// eslint-disable-next-line import/order +import bundleSource from '@endo/bundle-source'; import { initSwingStore } from '@agoric/swing-store'; import { buildVatController } from '../src/index.js'; @@ -75,8 +76,9 @@ async function testForExpectedGlobals(t, workerType) { }, defaultManagerType: workerType, }; + const bundle = await bundleSource(config.vats.bootstrap.sourceSpec); const kernelStorage = initSwingStore().kernelStorage; - const c = await buildVatController(config, [], { + const c = await buildVatController(config, [bundle], { kernelStorage, }); t.teardown(c.shutdown); @@ -98,7 +100,9 @@ async function testForExpectedGlobals(t, workerType) { 'VatData.makeScalarBigSetStore: function', 'VatData.makeScalarBigWeakSetStore: function', 'global has passStyleOf: true', - 'global passStyleOf is special: false', + 'passStyleOf delegates to global: true', + 'child compartment has matching passStyleOf: true', + 'grandchild compartment has matching passStyleOf: true', ]); } diff --git a/packages/SwingSet/test/vat-envtest.js b/packages/SwingSet/test/vat-envtest.js index f19c7ba2a21..0e750cde6f6 100644 --- a/packages/SwingSet/test/vat-envtest.js +++ b/packages/SwingSet/test/vat-envtest.js @@ -3,12 +3,30 @@ import { Far } from '@endo/far'; import { passStyleOf } from '@endo/pass-style'; import { PassStyleOfEndowmentSymbol } from '@endo/pass-style/endow.js'; +import { importBundle } from '@endo/import-bundle'; -export function buildRootObject(vatPowers) { +export function meta() { + return { globalThis, passStyleOf }; +} + +const endowments = { + console, + // See https://github.com/Agoric/agoric-sdk/issues/9515 + assert: globalThis.assert, + VatData: globalThis.VatData, +}; + +export async function recurse(bundle) { + return importBundle(bundle, { endowments }); +} + +export function buildRootObject(vatPowers, vatParameters) { const log = vatPowers.testLog; + const { argv } = vatParameters; + const [bundle] = argv; return Far('root', { - bootstrap(_vats) { + async bootstrap(_vats) { log(`control sample: ${typeof notThere}`); log(`harden: ${typeof harden}`); log(`VatData: ${typeof VatData}`); @@ -18,9 +36,20 @@ export function buildRootObject(vatPowers) { const globalPassStyleOf = globalThis && globalThis[PassStyleOfEndowmentSymbol]; log(`global has passStyleOf: ${!!globalPassStyleOf}`); - log( - `global passStyleOf is special: ${globalPassStyleOf !== passStyleOf}`, - ); + // we expect globalPassStyleOf and passStyleOf to be the same + // thing, because @endo/pass-style delegates to the version it + // finds on globalThis + const d1 = globalPassStyleOf === passStyleOf; + log(`passStyleOf delegates to global: ${d1}`); + + // make sure sub-compartments automatically get passStyleOf too + const c1 = await importBundle(bundle, { endowments }); + const m1 = c1.meta().passStyleOf === passStyleOf; + log(`child compartment has matching passStyleOf: ${m1}`); + + const c2 = await c1.recurse(bundle); + const m2 = c2.meta().passStyleOf === passStyleOf; + log(`grandchild compartment has matching passStyleOf: ${m2}`); }, }); } diff --git a/packages/swingset-liveslots/src/liveslots.js b/packages/swingset-liveslots/src/liveslots.js index 10747156c2d..9363b15e027 100644 --- a/packages/swingset-liveslots/src/liveslots.js +++ b/packages/swingset-liveslots/src/liveslots.js @@ -1208,12 +1208,12 @@ function build( makeScalarBigSetStore: collectionManager.makeScalarBigSetStore, makeScalarBigWeakSetStore: collectionManager.makeScalarBigWeakSetStore, }, - [PassStyleOfEndowmentSymbol]: passStyleOf, }); const inescapableGlobalProperties = harden({ WeakMap: vom.VirtualObjectAwareWeakMap, WeakSet: vom.VirtualObjectAwareWeakSet, + [PassStyleOfEndowmentSymbol]: passStyleOf, }); function getRetentionStats() { diff --git a/packages/swingset-liveslots/test/vat-environment.test.js b/packages/swingset-liveslots/test/vat-environment.test.js index 1c1d8e2e48d..96b7f111089 100644 --- a/packages/swingset-liveslots/test/vat-environment.test.js +++ b/packages/swingset-liveslots/test/vat-environment.test.js @@ -51,12 +51,15 @@ test('vat globals', async t => { t.is(typeof vatGlobals.VatData.makeScalarBigWeakMapStore, 'function'); t.is(typeof vatGlobals.VatData.makeScalarBigSetStore, 'function'); t.is(typeof vatGlobals.VatData.makeScalarBigWeakSetStore, 'function'); - t.is(typeof vatGlobals[PassStyleOfEndowmentSymbol], 'function'); - // this is the passStyleOf created by liveslots, with a real WeakMap - t.is(vatGlobals[PassStyleOfEndowmentSymbol], passStyleOf); t.is(typeof inescapableGlobalProperties.WeakMap, 'function'); t.not(inescapableGlobalProperties.WeakMap, WeakMap); t.is(typeof inescapableGlobalProperties.WeakSet, 'function'); t.not(inescapableGlobalProperties.WeakSet, WeakSet); + t.is( + typeof inescapableGlobalProperties[PassStyleOfEndowmentSymbol], + 'function', + ); + // this is the passStyleOf created by liveslots, with a real WeakMap + t.is(inescapableGlobalProperties[PassStyleOfEndowmentSymbol], passStyleOf); });