Skip to content

Commit

Permalink
Merge branch '3-evaluate'
Browse files Browse the repository at this point in the history
  • Loading branch information
warner committed Mar 27, 2019
2 parents f98d7e0 + 7b63490 commit d4cf5e4
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 11 deletions.
24 changes: 24 additions & 0 deletions agoric-evaluate/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@agoric/evaluate",
"version": "0.0.1",
"description": "(unsafe) two-argument evaluator funcion",
"main": "src/index.js",
"module": "src/main.js",
"engines": {
"node": ">=10.15.1"
},
"scripts": {
"test": "tape -r esm test/**/test*.js"
},
"devDependencies": {
"esm": "^3.2.5",
"tape": "^4.10.0"
},
"dependencies": {},
"author": "Agoric",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/Agoric/DomainVat/issues"
},
"homepage": "https://github.com/Agoric/DomainVat#readme"
}
11 changes: 11 additions & 0 deletions agoric-evaluate/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function evaluate(source, endowments = {}) {
const names = Object.getOwnPropertyNames(endowments);
const s = `(function(endowments) {
const { ${names.join(',')} } = endowments;
return ${source};
})`;
// eslint-disable-next-line no-eval
return eval(s)(endowments);
}

module.exports = evaluate;
3 changes: 3 additions & 0 deletions agoric-evaluate/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import evaluate from './index';

export default evaluate;
21 changes: 21 additions & 0 deletions agoric-evaluate/test/test-evaluate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// eslint doesn't realize that this file
// (agoric-evaluate/test/test-evaluate.js) is a test, since it lives in a
// non-"test" subdirectory.
// eslint-disable-next-line import/no-extraneous-dependencies
import { test } from 'tape';
import evaluate from '../src/main';

test('basic', t => {
t.deepEqual(evaluate('1+2'), 3);
t.deepEqual(evaluate('(a,b) => a+b')(1, 2), 3);
t.deepEqual(evaluate('(function(a,b) { return a+b; })')(1, 2), 3);
t.end();
});

test('endowments', t => {
t.deepEqual(evaluate('1+a', { a: 2 }), 3);
t.deepEqual(evaluate('(a,b) => a+b+c', { c: 3 })(1, 2), 6);
t.deepEqual(evaluate('(function(a,b) { return a+b+c; })', { c: 3 })(1, 2), 6);
t.deepEqual(evaluate('1+a+b', { a: 2, b: 3 }), 6);
t.end();
});
4 changes: 2 additions & 2 deletions demo/contractHost/vat-host.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* global SES Vow Flow */
// Copyright (C) 2012 Google Inc.
// Copyright (C) 2018 Agoric
//
Expand Down Expand Up @@ -84,6 +83,7 @@
/* eslint-disable-next-line global-require, import/no-extraneous-dependencies */
import harden from '@agoric/harden';
import makePromise from '../../src/kernel/makePromise';
import evaluate from '@agoric/evaluate';

function makeHost(E) {
const m = new WeakMap();
Expand All @@ -97,7 +97,7 @@ function makeHost(E) {
//let resolve;
//const f = new Flow();
//const resultP = f.makeVow(r => (resolve = r));
const contract = SES.confineExpr(contractSrc, {
const contract = evaluate(contractSrc, {
//Flow,
//Vow,
console,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"tape-promise": "^4.0.0"
},
"dependencies": {
"@agoric/evaluate": "./agoric-evaluate",
"@agoric/harden": "^0.0.4",
"@agoric/nat": "^2.0.0",
"rollup": "^1.1.2",
Expand Down
2 changes: 1 addition & 1 deletion src/build-source-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default async function bundleSource(startFilename) {
const bundle = await rollup({
input: require.resolve(startFilename),
treeshake: false,
external: ['@agoric/nat', '@agoric/harden'],
external: ['@agoric/evaluate', '@agoric/nat', '@agoric/harden'],
});
const { output } = await bundle.generate({
format: 'cjs',
Expand Down
17 changes: 16 additions & 1 deletion src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,27 @@ function getKernelSource() {
return `(${kernelSourceFunc})`;
}

// this feeds the SES realm's (real/safe) confineExpr() back into the Realm
// when it does require('@agoric/evaluate'), so we can get the same
// functionality both with and without SES
function makeEvaluate(e) {
const { confineExpr } = e;
return (source, endowments = {}) => confineExpr(source, endowments);
}

function buildSESKernel() {
const s = SES.makeSESRootRealm({
consoleMode: 'allow',
errorStackMode: 'allow',
});
const r = s.makeRequire({ '@agoric/harden': true, '@agoric/nat': Nat });
const r = s.makeRequire({
'@agoric/evaluate': {
attenuatorSource: `${makeEvaluate}`,
confineExpr: s.global.SES.confineExpr,
},
'@agoric/harden': true,
'@agoric/nat': Nat,
});
const kernelSource = getKernelSource();
// console.log('building kernel');
const buildKernel = s.evaluate(kernelSource, { require: r })();
Expand Down
14 changes: 8 additions & 6 deletions src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -781,12 +781,14 @@ export default function buildKernel(kernelEndowments) {
const vatObj0s = {};
Array.from(vats.entries()).forEach(e => {
const targetVatID = e[0];
if (targetVatID !== vatID) {
// don't give _bootstrap to itself
const vref = harden({}); // marker
vatObj0s[targetVatID] = vref;
vrefs.set(vref, { type: 'export', vatID: targetVatID, id: 0 });
}
// we happen to give _bootstrap to itself, because unit tests that
// don't have any other vats (bootstrap-only configs) then get a
// non-empty object as vatObj0s, since an empty object would be
// serialized as pass-by-presence. It wouldn't make much sense for the
// bootstrap object to call itself, though.
const vref = harden({}); // marker
vatObj0s[targetVatID] = vref;
vrefs.set(vref, { type: 'export', vatID: targetVatID, id: 0 });
});

function serializeSlot(vref, slots, slotMap) {
Expand Down
3 changes: 2 additions & 1 deletion test/test-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,11 @@ async function bootstrapExport(t, withSES) {
msg: {
method: 'bootstrap',
argsString:
'{"args":[[],{"left":{"@qclass":"slot","index":0},"right":{"@qclass":"slot","index":1}}]}',
'{"args":[[],{"left":{"@qclass":"slot","index":0},"right":{"@qclass":"slot","index":1},"_bootstrap":{"@qclass":"slot","index":2}}]}',
slots: [
{ type: 'export', vatID: 'left', id: 0 },
{ type: 'export', vatID: 'right', id: 0 },
{ type: 'export', vatID: '_bootstrap', id: 0 },
],
},
},
Expand Down
17 changes: 17 additions & 0 deletions test/test-evaluate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { test } from 'tape';
import evaluate from '@agoric/evaluate';

test('basic', t => {
t.deepEqual(evaluate('1+2'), 3);
t.deepEqual(evaluate('(a,b) => a+b')(1, 2), 3);
t.deepEqual(evaluate('(function(a,b) { return a+b; })')(1, 2), 3);
t.end();
});

test('endowments', t => {
t.deepEqual(evaluate('1+a', { a: 2 }), 3);
t.deepEqual(evaluate('(a,b) => a+b+c', { c: 3 })(1, 2), 6);
t.deepEqual(evaluate('(function(a,b) { return a+b+c; })', { c: 3 })(1, 2), 6);
t.deepEqual(evaluate('1+a+b', { a: 2, b: 3 }), 6);
t.end();
});
53 changes: 53 additions & 0 deletions test/test-vat-imports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { test } from 'tape-promise/tape';
import { buildVatController } from '../src/index';

async function requireNat(t, withSES) {
const config = { bootstrapIndexJS: require.resolve('./vat-imports-1.js') };
const c = await buildVatController(config, withSES, ['nat']);
await c.step();
t.deepEqual(c.dump().log, ['nat-1', '2']);
}

test('vat can require nat with SES', async t => {
await requireNat(t, true);
t.end();
});

test('vat can require nat without SES', async t => {
await requireNat(t, false);
t.end();
});

async function requireHarden(t, withSES) {
const config = { bootstrapIndexJS: require.resolve('./vat-imports-1.js') };
const c = await buildVatController(config, withSES, ['harden']);
await c.step();
t.deepEqual(c.dump().log, ['harden-1', 'true', 'true']);
}

test('vat can require harden with SES', async t => {
await requireHarden(t, true);
t.end();
});

test('vat can require harden without SES', async t => {
await requireHarden(t, false);
t.end();
});

async function requireEvaluate(t, withSES) {
const config = { bootstrapIndexJS: require.resolve('./vat-imports-1.js') };
const c = await buildVatController(config, withSES, ['evaluate']);
await c.step();
t.deepEqual(c.dump().log, ['evaluate-1', '3', '4', '5']);
}

test('vat can require evaluate with SES', async t => {
await requireEvaluate(t, true);
t.end();
});

test('vat can require evaluate without SES', async t => {
await requireEvaluate(t, false);
t.end();
});
34 changes: 34 additions & 0 deletions test/vat-imports-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import harden from '@agoric/harden';

export default function setup(syscall, helpers) {
const { log, makeLiveSlots } = helpers;
const { dispatch, registerRoot } = makeLiveSlots(syscall, helpers.vatID);
const obj0 = {
bootstrap(argv, _vats) {
if (argv[0] === 'nat') {
log('nat-1');
// eslint-disable-next-line global-require
const nat = require('@agoric/nat');
log(nat(2));
} else if (argv[0] === 'harden') {
log('harden-1');
// eslint-disable-next-line global-require
const harden2 = require('@agoric/harden');
const o1 = { o2: {} };
harden2(o1);
log(Object.isFrozen(o1));
log(Object.isFrozen(o1.o2));
} else if (argv[0] === 'evaluate') {
log('evaluate-1');
// eslint-disable-next-line global-require
const evaluate = require('@agoric/evaluate');
log(evaluate('1+2'));
log(evaluate('a+b', { a: 0, b: 4 }));
log(evaluate('(a) => a+b', { b: 3 })(2));
}
},
};

registerRoot(harden(obj0));
return dispatch;
}

0 comments on commit d4cf5e4

Please sign in to comment.