Skip to content

Commit

Permalink
feat(import-bundle): Preliminary support Endo zip hex bundle format (A…
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal authored Nov 19, 2020
1 parent c3cca70 commit 983681b
Show file tree
Hide file tree
Showing 43 changed files with 235 additions and 33 deletions.
3 changes: 3 additions & 0 deletions packages/ERTP/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/ertp",
"version": "0.8.0",
"description": "Electronic Rights Transfer Protocol (ERTP). A smart contract framework for exchanging electronic rights",
"parsers": {
"js": "mjs"
},
"main": "src/index.js",
"engines": {
"node": ">=11.0"
Expand Down
5 changes: 4 additions & 1 deletion packages/SwingSet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/swingset-vat",
"version": "0.10.0",
"description": "Vat/Container Launcher",
"parsers": {
"js": "mjs"
},
"main": "src/main.js",
"module": "src/index.js",
"engines": {
Expand Down Expand Up @@ -29,8 +32,8 @@
},
"dependencies": {
"@agoric/assert": "^0.1.0",
"@agoric/base64": "^0.0.0+1-dev",
"@agoric/babel-parser": "^7.6.4",
"@agoric/base64": "^0.0.0+1-dev",
"@agoric/bundle-source": "^1.1.10",
"@agoric/captp": "^1.6.0",
"@agoric/eventual-send": "^0.12.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/acorn-eventual-send/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/acorn-eventual-send",
"version": "2.0.10",
"description": "Eventual send (wavy dot) parser plugin for Acorn",
"parsers": {
"js": "mjs"
},
"main": "index.js",
"scripts": {
"build": "exit 0",
Expand Down
3 changes: 3 additions & 0 deletions packages/agoric-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "agoric",
"version": "0.10.1",
"description": "Manage the Agoric Javascript smart contract platform",
"parsers": {
"js": "mjs"
},
"main": "lib/main.js",
"bin": "bin/agoric",
"files": [
Expand Down
3 changes: 3 additions & 0 deletions packages/assert/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/assert",
"version": "0.1.0",
"description": "Assert expression support that protects sensitive data",
"parsers": {
"js": "mjs"
},
"main": "src/assert.js",
"engines": {
"node": ">=11.0"
Expand Down
3 changes: 3 additions & 0 deletions packages/base64/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/base64",
"version": "0.0.0+1-dev",
"description": "Transcodes base64",
"parsers": {
"js": "mjs"
},
"author": "Agoric",
"license": "Apache-2.0",
"type": "module",
Expand Down
5 changes: 5 additions & 0 deletions packages/bundle-source/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/bundle-source",
"version": "1.1.10",
"description": "Create source bundles from ES Modules",
"parsers": {
"js": "mjs"
},
"main": "src/index.js",
"scripts": {
"build": "exit 0",
Expand All @@ -19,7 +22,9 @@
},
"dependencies": {
"@agoric/acorn-eventual-send": "^2.0.10",
"@agoric/base64": "0.0.0+1-dev",
"@agoric/babel-parser": "^7.6.4",
"@agoric/compartment-mapper": "^0.2.3",
"@agoric/transform-eventual-send": "^1.3.5",
"@babel/generator": "^7.6.4",
"@babel/traverse": "^7.8.3",
Expand Down
19 changes: 18 additions & 1 deletion packages/bundle-source/src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import fs from 'fs';
import { rollup as rollup0 } from 'rollup';
import path from 'path';
import resolve0 from '@rollup/plugin-node-resolve';
Expand All @@ -6,17 +7,21 @@ import * as babelParser from '@agoric/babel-parser';
import babelGenerate from '@babel/generator';
import babelTraverse from '@babel/traverse';
import { makeTransform } from '@agoric/transform-eventual-send';
import { makeArchive } from '@agoric/compartment-mapper';
import { encodeBase64 } from '@agoric/base64';

import { SourceMapConsumer } from 'source-map';

const DEFAULT_MODULE_FORMAT = 'nestedEvaluate';
const DEFAULT_FILE_PREFIX = '/bundled-source';
const SUPPORTED_FORMATS = ['getExport', 'nestedEvaluate'];
const SUPPORTED_FORMATS = ['getExport', 'nestedEvaluate', 'endoZipBase64'];

const IMPORT_RE = new RegExp('\\b(import)(\\s*(?:\\(|/[/*]))', 'sg');
const HTML_COMMENT_START_RE = new RegExp(`${'<'}!--`, 'g');
const HTML_COMMENT_END_RE = new RegExp(`--${'>'}`, 'g');

const read = async location => fs.promises.readFile(new URL(location).pathname);

export function tildotPlugin() {
const transformer = makeTransform(babelParser, babelGenerate);
return {
Expand All @@ -37,6 +42,18 @@ export default async function bundleSource(
if (!SUPPORTED_FORMATS.includes(moduleFormat)) {
throw Error(`moduleFormat ${moduleFormat} is not implemented`);
}
if (moduleFormat === 'endoZipBase64') {
// TODO endoZipBase64 format does not yet support the tildot transform, as
// Compartment Mapper does not yet reveal a pre-archive transform facility.
// Such a facility might be better served by a transform specified in
// individual package.jsons and driven by the compartment mapper.
const base = new URL(`file://${process.cwd()}`).toString();
const entry = new URL(startFilename, base).toString();
const bytes = await makeArchive(read, entry);
const endoZipBase64 = encodeBase64(bytes);
return { endoZipBase64, moduleFormat };
}

const {
commonjsPlugin = commonjs0,
rollup = rollup0,
Expand Down
19 changes: 19 additions & 0 deletions packages/bundle-source/test/test-sanity.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* global Compartment */

import '@agoric/install-ses';
import { decodeBase64 } from '@agoric/base64';
import { parseArchive } from '@agoric/compartment-mapper';
import test from 'ava';
import bundleSource from '..';

Expand All @@ -9,6 +11,23 @@ function evaluate(src, endowments) {
return c.evaluate(src);
}

test('endoZipBase64', async t => {
const { endoZipBase64 } = await bundleSource(
`${__dirname}/../demo/dir1/encourage.js`,
'endoZipBase64',
);

const bytes = decodeBase64(endoZipBase64);
const archive = await parseArchive(bytes);
// Call import by property to bypass SES censoring for dynamic import.
// eslint-disable-next-line dot-notation
const { namespace } = await archive['import']('.');
const { message, encourage } = namespace;

t.is(message, `You're great!`);
t.is(encourage('you'), `Hey you! You're great!`);
});

test('nestedEvaluate', async t => {
const {
moduleFormat: mf1,
Expand Down
3 changes: 3 additions & 0 deletions packages/captp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/captp",
"version": "1.6.0",
"description": "Capability Transfer Protocol for distributed objects",
"parsers": {
"js": "mjs"
},
"keywords": [
"agoric",
"captp",
Expand Down
3 changes: 3 additions & 0 deletions packages/cosmic-swingset/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/cosmic-swingset",
"version": "0.23.0",
"description": "Agoric's Cosmos blockchain integration",
"parsers": {
"js": "mjs"
},
"main": "lib/ag-solo/main.js",
"repository": "https://github.com/Agoric/agoric-sdk",
"scripts": {
Expand Down
3 changes: 3 additions & 0 deletions packages/dapp-svelte-wallet/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"name": "@agoric/dapp-svelte-wallet",
"version": "0.5.0",
"parsers": {
"js": "mjs"
},
"main": "index.js",
"license": "Apache-2.0",
"author": "Agoric",
Expand Down
2 changes: 1 addition & 1 deletion packages/dapp-svelte-wallet/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dev": "rollup -c -w",
"start": "sirv public",
"lint-check": "yarn lint",
"lint-fix": "yarn lint --fix",
"lint-fix": "exit 0",
"lint": "exit 0",
"test": "exit 0"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/deployment/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/deployment",
"version": "1.23.0",
"description": "Set up Agoric public chain nodes",
"parsers": {
"js": "mjs"
},
"private": true,
"main": "main.js",
"scripts": {
Expand Down
3 changes: 3 additions & 0 deletions packages/eventual-send/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/eventual-send",
"version": "0.12.0",
"description": "Extend a Promise class to implement the eventual-send API",
"parsers": {
"js": "mjs"
},
"main": "src/no-shim.js",
"types": "src/index.d.ts",
"scripts": {
Expand Down
8 changes: 8 additions & 0 deletions packages/import-bundle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@agoric/import-bundle",
"version": "0.1.0",
"description": "load modules created by @agoric/bundle-source",
"parsers": {
"js": "mjs"
},
"main": "src/index.js",
"module": "src/index.js",
"engines": {
Expand All @@ -14,6 +17,11 @@
"lint-fix": "eslint --fix '**/*.js'",
"lint-check": "eslint '**/*.js'"
},
"dependencies": {
"@agoric/base64": "^0.0.0+1-dev",
"@agoric/assert": "^0.1.0",
"@agoric/compartment-mapper": "^0.2.3"
},
"devDependencies": {
"@agoric/bundle-source": "^1.1.10",
"@agoric/install-ses": "^0.4.0",
Expand Down
57 changes: 42 additions & 15 deletions packages/import-bundle/src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* global harden Compartment */
import { parseArchive } from '@agoric/compartment-mapper';
import { decodeBase64 } from '@agoric/base64';
import { wrapInescapableCompartment } from './compartment-wrapper';

// importBundle takes the output of bundle-source, and returns a namespace
Expand All @@ -8,13 +10,49 @@ export async function importBundle(bundle, options = {}) {
const {
filePrefix,
endowments: optEndowments = {},
globalLexicals = {},
// transforms are indeed __shimTransforms__, intended to apply to both
// evaluated programs and modules shimmed to programs.
transforms = [],
inescapableTransforms = [],
inescapableGlobalLexicals = {},
...compartmentOptions
} = options;
const endowments = { ...optEndowments };
const { source, sourceMap, moduleFormat } = bundle;
const endowments = {
TextEncoder,
TextDecoder,
...optEndowments,
};

let CompartmentToUse = Compartment;
if (
inescapableTransforms.length ||
Object.keys(inescapableGlobalLexicals).length
) {
CompartmentToUse = wrapInescapableCompartment(
Compartment,
inescapableTransforms,
inescapableGlobalLexicals,
);
}

const { moduleFormat } = bundle;
if (moduleFormat === 'endoZipBase64') {
const { endoZipBase64 } = bundle;
const bytes = decodeBase64(endoZipBase64);
const archive = await parseArchive(bytes);
// Call import by property to bypass SES censoring for dynamic import.
// eslint-disable-next-line dot-notation
const { namespace } = await archive['import']({
globals: endowments,
__shimTransforms__: transforms,
Compartment: CompartmentToUse,
});
// namespace.default has the default export
return namespace;
}

let c;
const { source, sourceMap } = bundle;
if (moduleFormat === 'getExport') {
// The 'getExport' format is a string which defines a wrapper function
// named `getExport()`. This function provides a `module` to the
Expand All @@ -40,18 +78,7 @@ export async function importBundle(bundle, options = {}) {
throw Error(`unrecognized moduleFormat '${moduleFormat}'`);
}

let CompartmentToUse = Compartment;
if (
inescapableTransforms.length ||
Object.keys(inescapableGlobalLexicals).length
) {
CompartmentToUse = wrapInescapableCompartment(
Compartment,
inescapableTransforms,
inescapableGlobalLexicals,
);
}
c = new CompartmentToUse(endowments, {}, compartmentOptions);
c = new CompartmentToUse(endowments, {}, { globalLexicals, transforms });
harden(c.globalThis);
const actualSource = `(${source})\n${sourceMap || ''}`;
const namespace = c.evaluate(actualSource)(filePrefix);
Expand Down
7 changes: 1 addition & 6 deletions packages/import-bundle/test/bundle1.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ export function f6ReadGlobal() {
return globalThis.sneakyChannel;
}

export function f7WriteGlobal(a) {
// this will throw TypeError
globalThis.sneakyChannel = a;
}

export function f8ReadGlobalSubmodule() {
export function f7ReadGlobalSubmodule() {
return bundle2ReadGlobal();
}
28 changes: 21 additions & 7 deletions packages/import-bundle/test/test-import-bundle.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
/* global harden */
import '@agoric/install-ses';
import { encodeBase64 } from '@agoric/base64';
import * as fs from 'fs';
import { makeArchive } from '@agoric/compartment-mapper';

import bundleSource from '@agoric/bundle-source';
import test from 'ava';
import { importBundle } from '../src/index.js';

const read = async location =>
fs.promises.readFile(new URL(location, 'file:///').pathname);

function transform1(src) {
return src
.replace('replaceme', 'substitution')
Expand Down Expand Up @@ -38,14 +44,8 @@ async function testBundle1(t, b1, mode, ew) {
const endowments4 = { sneakyChannel: 3, ...ew };
const ns4 = await importBundle(b1, { endowments: endowments4 });
t.is(ns4.f6ReadGlobal(), 3, `ns3.f6 ${mode} ok`);
t.is(ns4.f8ReadGlobalSubmodule(), 3, `ns3.f8 ${mode} ok`);
t.throws(
() => ns4.f7WriteGlobal(5),
{ message: /Cannot assign to read only property/ },
`ns4.f7 ${mode} ok`,
);
t.is(ns4.f6ReadGlobal(), 3, `ns4.f6 ${mode} ok`);
t.is(ns4.f8ReadGlobalSubmodule(), 3, `ns3.f8 ${mode} ok`);
t.is(ns4.f7ReadGlobalSubmodule(), 3, `ns3.f8 ${mode} ok`);
}

test('test import', async function testImport(t) {
Expand Down Expand Up @@ -75,6 +75,20 @@ test('test import', async function testImport(t) {
await testBundle1(t, b1NestedEvaluate, 'nestedEvaluate', endowments);
});

test('test import archive', async function testImportArchive(t) {
const endowments = { console };
const b1EndoZip = await makeArchive(
read,
`file://${require.resolve('./bundle1.js')}`,
);
const b1EndoZipBase64 = encodeBase64(b1EndoZip);
const b1EndoZipBase64Bundle = {
moduleFormat: 'endoZipBase64',
endoZipBase64: b1EndoZipBase64,
};
await testBundle1(t, b1EndoZipBase64Bundle, 'endoZipBase64', endowments);
});

test('test missing sourceMap', async function testImport(t) {
function req(what) {
console.log(`require(${what})`);
Expand Down
Loading

0 comments on commit 983681b

Please sign in to comment.