Skip to content

Commit

Permalink
fix(zoe): get ZCF bundlecap from vatAdminService
Browse files Browse the repository at this point in the history
Zoe needs access to the vatAdminSvc, to create a new ZCF vat to host each
contract. `makeZoeKit()` provides an optional argument to control which
bundle is used for this purpose. This 4th argument was a string, defaulting
to 'zcf', and relied upon `E(vatAdminSvc).createVatByName` (which is going
away).

To move everything closer to bundlecaps, the `makeZoeKit()` optional argument
now takes `{ name }` or `{ id }` or `{ bundleCap }`, instead of only a name.
Zoe uses the new `E(vatAdminSvc).getNamedBundleCap()` to convert a name into
a bundlecap, but in the future I expect our chain-side bootstrap() to call
`makeZoeKit()` with a specific bundlecap. In the long run, I'm trying to make
room for Zoe to accomodate multiple versions of ZCF, each indexed by its
bundlecap.

Non-swingset-based zoe-using unit tests generally use `fakeVatAdmin.js` to
build a mock `vatAdminSvc`. This commit changes `fakeVatAdmin.js` to include
an additional `zcfBundleCap` export, which is an empty marker object that
serves as a stand-in for the bundlecap. The fake `vatAdminSvc` can accept
this fake `zcfBundleCap`, and will evaluate the ZCF code appropriately.
However the fake `vatAdminSvc` also knows how to convert the default `'zcf'`
name into that bundlecap, so downstream code should not need to change.
`fakeVatAdmin` no longer has a `createVatByName` method, as Zoe no longer
needs it.

Code that uses `makeZoeKit()` and provides the optional fourth argument needs
to be updated to the new signature. This commit changes all such instances in
the current codebase.

refs #4487
  • Loading branch information
warner committed Feb 25, 2022
1 parent 4cbac37 commit 872a11a
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 23 deletions.
22 changes: 18 additions & 4 deletions packages/zoe/src/zoeService/createZCFVat.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,28 @@ import { E } from '@agoric/eventual-send';
* ZCF Vats can be created.
*
* @param {VatAdminSvc} vatAdminSvc
* @param {string=} zcfBundleName
* @param {ZCFSpec} zcfSpec
* @returns {CreateZCFVat}
*/
export const setupCreateZCFVat = (vatAdminSvc, zcfBundleName = 'zcf') => {
export const setupCreateZCFVat = (vatAdminSvc, zcfSpec) => {
/** @type {CreateZCFVat} */
const createZCFVat = async () => {
assert.typeof(zcfBundleName, 'string');
const rootAndAdminNodeP = E(vatAdminSvc).createVatByName(zcfBundleName);
/** @type {ERef<BundleCap>} */
let bundleCapP;
if (zcfSpec.bundleCap) {
bundleCapP = zcfSpec.bundleCap;
} else if (zcfSpec.name) {
bundleCapP = E(vatAdminSvc).getNamedBundleCap(zcfSpec.name);
} else if (zcfSpec.id) {
bundleCapP = E(vatAdminSvc).getBundleCap(zcfSpec.id);
} else {
const keys = Object.keys(zcfSpec).join(',');
assert.fail(`setupCreateZCFVat: bad zcfSpec, has keys '${keys}'`);
}
/** @type {BundleCap} */
const bundleCap = await bundleCapP;
assert(bundleCap, `setupCreateZCFVat did not get bundleCap`);
const rootAndAdminNodeP = E(vatAdminSvc).createVat(bundleCap);
const rootAndAdminNode = await rootAndAdminNodeP;
return rootAndAdminNode;
};
Expand Down
9 changes: 7 additions & 2 deletions packages/zoe/src/zoeService/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,13 @@

/**
* @typedef {Object} VatAdminSvc
* @property {(bundle: SourceBundle) => RootAndAdminNode} createVat
* @property {(BundleName: string) => RootAndAdminNode} createVatByName
* @property {(BundleID: id) => BundleCap} getBundleCap
* @property {(name: string) => BundleCap} getNamedBundleCap
* @property {(bundleCap: BundleCap) => RootAndAdminNode} createVat
*/

/**
* @typedef {{bundleCap: BundleCap } | {name: string} | {id: BundleID}} ZCFSpec
*/

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/zoe/src/zoeService/zoe.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { createFeeMint } from './feeMint.js';
* shutdown the Zoe Vat. This function needs to use the vatPowers
* available to a vat.
* @param {FeeIssuerConfig} feeIssuerConfig
* @param {string} [zcfBundleName] - The name of the contract facet bundle.
* @param {ZCFSpec} [zcfSpec] - Pointer to the contract facet bundle.
* @returns {{
* zoeService: ZoeService,
* feeMintAccess: FeeMintAccess,
Expand All @@ -49,7 +49,7 @@ const makeZoeKit = (
assetKind: AssetKind.NAT,
displayInfo: harden({ decimalPlaces: 6, assetKind: AssetKind.NAT }),
},
zcfBundleName = undefined,
zcfSpec = { name: 'zcf' },
) => {
// We must pass the ZoeService to `makeStartInstance` before it is
// defined. See below where the promise is resolved.
Expand All @@ -64,7 +64,7 @@ const makeZoeKit = (
// This method contains the power to create a new ZCF Vat, and must
// be closely held. vatAdminSvc is even more powerful - any vat can
// be created. We severely restrict access to vatAdminSvc for this reason.
const createZCFVat = setupCreateZCFVat(vatAdminSvc, zcfBundleName);
const createZCFVat = setupCreateZCFVat(vatAdminSvc, zcfSpec);

// The ZoeStorageManager composes and consolidates capabilities
// needed by Zoe according to POLA.
Expand Down
17 changes: 8 additions & 9 deletions packages/zoe/test/unitTests/zoe/test-createZCFVat.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,21 @@ test('setupCreateZCFVat', async t => {
// This is difficult to unit test, since the real functionality
// creates a new vat

const zcfBundleCap = Far('zcfBundleCap', {});
const fakeVatAdminSvc = Far('fakeVatAdminSvc', {
createVatByName: _name => {
return harden({ adminNode: undefined, root: undefined });
getNamedBundleCap: name => {
assert.equal(name, 'zcf');
return zcfBundleCap;
},
createVat: _bundle => {
createVat: bundleCap => {
assert.equal(bundleCap, zcfBundleCap);
return harden({ adminNode: undefined, root: undefined });
},
});

// @ts-ignore fakeVatAdminSvc is mocked
t.deepEqual(await setupCreateZCFVat(fakeVatAdminSvc, undefined)(), {
adminNode: undefined,
root: undefined,
});
// @ts-ignore fakeVatAdminSvc is mocked
t.deepEqual(await setupCreateZCFVat(fakeVatAdminSvc, 'myVat')(), {
t.deepEqual(await setupCreateZCFVat(fakeVatAdminSvc, { name: 'zcf' })(), {
// @ts-ignore fakeVatAdminSvc is mocked
adminNode: undefined,
root: undefined,
});
Expand Down
21 changes: 16 additions & 5 deletions packages/zoe/tools/fakeVatAdmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ import { Far } from '@endo/marshal';
import { assert } from '@agoric/assert';
import { evalContractBundle } from '../src/contractFacet/evalContractCode.js';
import { handlePKitWarning } from '../src/handleWarning.js';
import { makeHandle } from '../src/makeHandle.js';
import zcfContractBundle from '../bundles/bundle-contractFacet.js';

// this simulates a bundlecap, which is normally a swingset "device node"
/** @typedef { import('@agoric/swingset-vat').BundleCap } BundleCap */
/** @type {BundleCap} */
export const zcfBundleCap = makeHandle('BundleCap');

/**
* @param { (...args) => unknown } [testContextSetter]
* @param { (x: unknown) => unknown } [makeRemote]
Expand Down Expand Up @@ -36,7 +42,16 @@ function makeFakeVatAdmin(testContextSetter = undefined, makeRemote = x => x) {
// test-only state can be provided from contracts
// to their tests.
const admin = Far('vatAdmin', {
createVat: bundle => {
getBundleCap: _bundleID => {
assert.fail(`fakeVatAdmin.getBundleCap() not yet implemented`);
},
getNamedBundleCap: name => {
assert.equal(name, 'zcf', 'fakeVatAdmin only knows ZCF');
return zcfBundleCap;
},
createVat: bundleCap => {
assert.equal(bundleCap, zcfBundleCap, 'fakeVatAdmin only knows ZCF');
const bundle = zcfContractBundle;
return harden({
root: makeRemote(
E(evalContractBundle(bundle)).buildRootObject(
Expand All @@ -55,10 +70,6 @@ function makeFakeVatAdmin(testContextSetter = undefined, makeRemote = x => x) {
}),
});
},
createVatByName: name => {
assert.equal(name, 'zcf', `only name='zcf' accepted, not ${name}`);
return admin.createVat(zcfContractBundle);
},
});
const vatAdminState = {
getExitMessage: () => exitMessage,
Expand Down

0 comments on commit 872a11a

Please sign in to comment.