Skip to content

Commit

Permalink
Feat: Add private arguments to contract start functions, via E(zoe)…
Browse files Browse the repository at this point in the history
….startInstance (#3576)

* feat: add ability to pass arguments privately to contract `start` function through `zoe.startInstance`

* chore: add Swingset test

* chore: assert copyRecord

* chore: address PR comments

* chore: address PR comments
  • Loading branch information
katelynsills authored Aug 3, 2021
1 parent 38dfe2d commit f353e86
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 5 deletions.
6 changes: 4 additions & 2 deletions packages/zoe/src/contractFacet/internal-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
* @typedef ZCFZygote
* @property {(bundle: SourceBundle) => void} evaluateContract
* @property {(instanceAdminFromZoe: ERef<ZoeInstanceAdmin>,
instanceRecordFromZoe: InstanceRecord,
issuerStorageFromZoe: IssuerRecords) => Promise<ExecuteContractResult>} startContract
* instanceRecordFromZoe: InstanceRecord,
* issuerStorageFromZoe: IssuerRecords,
* privateArgs: Object=,
* ) => Promise<ExecuteContractResult>} startContract
*/
1 change: 1 addition & 0 deletions packages/zoe/src/contractFacet/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
/**
* @callback ContractStartFn
* @param {ContractFacet} zcf
* @param {Object=} privateArgs
* @returns {ContractStartFnResult}
*/

Expand Down
2 changes: 2 additions & 0 deletions packages/zoe/src/contractFacet/vatRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function buildRootObject(powers, _params, testJigSetter = undefined) {
zoeInstanceAdmin,
instanceRecordFromZoe,
issuerStorageFromZoe,
privateArgs = undefined,
) => {
/** @type {ZCFZygote} */
const zcfZygote = makeZCFZygote(
Expand All @@ -48,6 +49,7 @@ export function buildRootObject(powers, _params, testJigSetter = undefined) {
zoeInstanceAdmin,
instanceRecordFromZoe,
issuerStorageFromZoe,
privateArgs,
);
};

Expand Down
3 changes: 2 additions & 1 deletion packages/zoe/src/contractFacet/zcfZygote.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ export const makeZCFZygote = (
instanceAdminFromZoe,
instanceRecordFromZoe,
issuerStorageFromZoe,
privateArgs = undefined,
) => {
zoeInstanceAdminPromiseKit.resolve(instanceAdminFromZoe);
instantiateInstanceRecordStorage(instanceRecordFromZoe);
Expand All @@ -299,7 +300,7 @@ export const makeZCFZygote = (
// Next, execute the contract code, passing in zcf
/** @type {Promise<ExecuteContractResult>} */
const result = E(contractCode)
.start(zcf)
.start(zcf, privateArgs)
.then(
({
creatorFacet = Far('emptyCreatorFacet', {}),
Expand Down
1 change: 1 addition & 0 deletions packages/zoe/src/internal-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
* @param {ZoeInstanceAdmin} zoeInstanceAdmin
* @param {InstanceRecord} instanceRecord
* @param {IssuerRecords} issuerStorageFromZoe
* @param {Object=} privateArgs
* @returns {Promise<ExecuteContractResult>}
*
*/
Expand Down
16 changes: 14 additions & 2 deletions packages/zoe/src/zoeService/startInstance.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// @ts-check

import { assert, details as X } from '@agoric/assert';
import { assert, details as X, quote as q } from '@agoric/assert';
import { E } from '@agoric/eventual-send';
import { makePromiseKit } from '@agoric/promise-kit';
import { makeWeakStore as makeNonVOWeakStore } from '@agoric/store';
import { Far } from '@agoric/marshal';
import { Far, passStyleOf } from '@agoric/marshal';

import { makeZoeSeatAdminKit } from './zoeSeat';
import { makeHandle } from '../makeHandle';
Expand All @@ -26,13 +26,24 @@ export const makeStartInstance = (
installationP,
uncleanIssuerKeywordRecord = harden({}),
customTerms = harden({}),
privateArgs = undefined,
) => {
/** @type {WeakStore<SeatHandle, ZoeSeatAdmin>} */
const seatHandleToZoeSeatAdmin = makeNonVOWeakStore('seatHandle');

const { installation, bundle } = await unwrapInstallation(installationP);
// AWAIT ///

if (privateArgs !== undefined) {
const passStyle = passStyleOf(privateArgs);
assert(
passStyle === 'copyRecord',
X`privateArgs must be a pass-by-copy record, but instead was a ${q(
passStyle,
)}: ${privateArgs}`,
);
}

const instance = makeHandle('Instance');

const zoeInstanceStorageManager = await makeZoeInstanceStorageManager(
Expand Down Expand Up @@ -190,6 +201,7 @@ export const makeStartInstance = (
zoeInstanceAdminForZcf,
zoeInstanceStorageManager.getInstanceRecord(),
zoeInstanceStorageManager.getIssuerRecords(),
privateArgs,
);

handleOfferObjPromiseKit.resolve(handleOfferObj);
Expand Down
3 changes: 3 additions & 0 deletions packages/zoe/src/zoeService/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
* @param {ERef<Installation>} installation
* @param {IssuerKeywordRecord=} issuerKeywordRecord
* @param {Object=} terms
* @param {Object=} privateArgs - an optional configuration object
* that can be used to pass in arguments that should not be in the
* public terms
* @returns {Promise<StartInstanceResult>}
*/

Expand Down
14 changes: 14 additions & 0 deletions packages/zoe/test/privateArgsUsageContract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// @ts-check

import { E } from '@agoric/eventual-send';
import { Far } from '@agoric/marshal';

/** @type {ContractStartFn} */
const start = (_zcf, privateArgs) => {
const creatorFacet = Far('creatorFacet', {
usePrivateArgs: () => E(privateArgs.myArg).doTest(),
});
return harden({ creatorFacet });
};
harden(start);
export { start };
22 changes: 22 additions & 0 deletions packages/zoe/test/swingsetTests/privateArgs/bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { E } from '@agoric/eventual-send';
import { Far } from '@agoric/marshal';

export function buildRootObject(vatPowers, vatParameters) {
const { contractBundles: cb } = vatParameters;
return Far('root', {
async bootstrap(vats, devices) {
const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService(
devices.vatAdmin,
);
const zoe = await E(vats.zoe).buildZoe(vatAdminSvc);
const installations = {
privateArgsUsageContract: await E(zoe).install(
cb.privateArgsUsageContract,
),
};

const aliceP = E(vats.alice).build(zoe, installations);
await E(aliceP).privateArgsUsageTest();
},
});
}
76 changes: 76 additions & 0 deletions packages/zoe/test/swingsetTests/privateArgs/test-privateArgs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* global __dirname */

// TODO Remove babel-standalone preinitialization
// https://github.com/endojs/endo/issues/768
import '@agoric/babel-standalone';
// eslint-disable-next-line import/no-extraneous-dependencies
import '@agoric/install-ses';
// eslint-disable-next-line import/no-extraneous-dependencies
import test from 'ava';
// eslint-disable-next-line import/no-extraneous-dependencies
import { buildVatController, buildKernelBundles } from '@agoric/swingset-vat';
import bundleSource from '@agoric/bundle-source';

const CONTRACT_FILES = ['privateArgsUsageContract'];

test.before(async t => {
const start = Date.now();
const kernelBundles = await buildKernelBundles();
const step2 = Date.now();
const contractBundles = {};
await Promise.all(
CONTRACT_FILES.map(async settings => {
let bundleName;
let contractPath;
if (typeof settings === 'string') {
bundleName = settings;
contractPath = settings;
} else {
({ bundleName, contractPath } = settings);
}
const source = `${__dirname}/../../${contractPath}`;
const bundle = await bundleSource(source);
contractBundles[bundleName] = bundle;
}),
);
const step3 = Date.now();

const vats = {};
await Promise.all(
['alice', 'zoe'].map(async name => {
const source = `${__dirname}/vat-${name}.js`;
const bundle = await bundleSource(source);
vats[name] = { bundle };
}),
);
const bootstrapSource = `${__dirname}/bootstrap.js`;
vats.bootstrap = {
bundle: await bundleSource(bootstrapSource),
parameters: { contractBundles }, // argv will be added to this
};
const config = { bootstrap: 'bootstrap', vats };
config.defaultManagerType = 'xs-worker';

const step4 = Date.now();
const ktime = `${(step2 - start) / 1000}s kernel`;
const ctime = `${(step3 - step2) / 1000}s contracts`;
const vtime = `${(step4 - step3) / 1000}s vats`;
const ttime = `${(step4 - start) / 1000}s total`;
console.log(`bundling: ${ktime}, ${ctime}, ${vtime}, ${ttime}`);

t.context.data = { kernelBundles, config };
});

async function main(t, argv) {
const { kernelBundles, config } = t.context.data;
const controller = await buildVatController(config, argv, { kernelBundles });
await controller.run();
return controller.dump();
}

const expected = ['privateArgs.myArg was accessed in the contract'];

test.serial('private args usage', async t => {
const dump = await main(t);
t.deepEqual(dump.log, expected);
});
29 changes: 29 additions & 0 deletions packages/zoe/test/swingsetTests/privateArgs/vat-alice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { E } from '@agoric/eventual-send';
import { Far } from '@agoric/marshal';

const build = async (log, zoe, installations) => {
return Far('build', {
privateArgsUsageTest: async () => {
const privateArgs = harden({
myArg: Far('arg', {
doTest: () => 'privateArgs.myArg was accessed in the contract',
}),
});
const { creatorFacet } = await E(zoe).startInstance(
installations.privateArgsUsageContract,
undefined,
undefined,
privateArgs,
);

const testResult = await E(creatorFacet).usePrivateArgs();
log(testResult);
},
});
};

export function buildRootObject(vatPowers) {
return Far('root', {
build: (...args) => build(vatPowers.testLog, ...args),
});
}
10 changes: 10 additions & 0 deletions packages/zoe/test/swingsetTests/privateArgs/vat-zoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Far } from '@agoric/marshal';

// noinspection ES6PreferShortImport
import { makeZoe } from '../../../src/zoeService/zoe';

export function buildRootObject(_vatPowers) {
return Far('root', {
buildZoe: vatAdminSvc => makeZoe(vatAdminSvc),
});
}

0 comments on commit f353e86

Please sign in to comment.