Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Switch default archive format to endoZipBase64 #3273

Merged
merged 10 commits into from
Sep 23, 2021
Merged

Conversation

kriskowal
Copy link
Member

@kriskowal kriskowal commented Jun 9, 2021

Fixes: #2684

@kriskowal kriskowal force-pushed the kris-zip branch 2 times, most recently from 145ac71 to c688fd8 Compare June 9, 2021 16:34
Base automatically changed from kris-sync-endo to master June 9, 2021 17:01
@kriskowal kriskowal force-pushed the kris-zip branch 5 times, most recently from ee4fd38 to 534641f Compare June 11, 2021 17:16
@kriskowal kriskowal force-pushed the kris-zip branch 2 times, most recently from a11d96e to eb0def8 Compare June 15, 2021 02:42
kriskowal added a commit to endojs/endo that referenced this pull request Jun 15, 2021
The import and archive functions now accepta `dev` flag that indicates that the `devDependencies` of the entry module's package should be included in the compartment graph.  This must be passed explicitly and is off by default since that will be the norm for applications.

This is the bug of the day blocking Agoric/agoric-sdk#3273

In furtherance of Agoric/agoric-sdk#2684
@kriskowal kriskowal force-pushed the kris-zip branch 2 times, most recently from c74a8cd to a049acb Compare June 16, 2021 23:03
@kriskowal kriskowal changed the base branch from master to kris-bundle-source-dev-syms June 20, 2021 18:21
@kriskowal kriskowal force-pushed the kris-bundle-source-dev-syms branch 2 times, most recently from 2d36ee8 to 7bfa155 Compare June 21, 2021 04:12
@kriskowal kriskowal force-pushed the kris-bundle-source-dev-syms branch from 7bfa155 to 4bf1772 Compare June 21, 2021 04:12
@kriskowal kriskowal force-pushed the kris-bundle-source-dev-syms branch from 4bf1772 to be0d555 Compare June 21, 2021 04:26
@@ -286,6 +286,9 @@ function makeWorker(port) {
assert,
// bootstrap provides HandledPromise
HandledPromise: globalThis.HandledPromise,
TextEncoder,
TextDecoder,
Base64: globalThis.Base64, // Present only in XSnap
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absent from this list is URL, which is never present inside XSnap.

@@ -15,7 +15,7 @@ import { SourceMapConsumer } from 'source-map';

import './types.js';

const DEFAULT_MODULE_FORMAT = 'nestedEvaluate';
const DEFAULT_MODULE_FORMAT = 'endoZipBase64';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the biggest/riskiest line in the diff. cc @warner

Comment on lines +11 to +24
/*
* Getting the properties of a SES-shim module exports namespace object throws
* an error if inspected before the module initializes.
* Allowing this case is necessary for the compartment mapper to be hosted by
* the compartment mapper under metering.
*/
const maybeGetOwnPropertyDescriptors = object => {
try {
return getOwnPropertyDescriptors(object);
} catch (_error) {
return {};
}
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is necessary for making Zip files work on Node.js with metering. We might not be exercising this anymore, but I include the change for completeness. cc @michaelfig

Comment on lines +6 to +7
* Forked from npm polycrc@1.1.0 for module system compatibility, then trimmed
* down to a version that assumes TypedArrays are universal.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedding CRC6 is a reversible expedient. The existing polycrc doesn’t work with Endo because of a bad interaction with named exports. I may be able to fix that with more work on the Endo side. Otherwise, bringing this in-house and getting it past lint and tsc increased my confidence in the code, so there’s an upside. The downside is that I don’t think it’s worthwhile to also bring in the tests from polycrc. So, if this isn’t palatable, the alternatives are:

  • Do more work on Endo until the CommonJS/ESM boundary works for this particular case. That is, an ESM importing a CJS with the previously working incantation import { models as crcmodels } from 'polycrc', which requires detecting that models is an export detected by module.exports = { models } (approximately) in the lexical analysis.
  • Patch polycrc so it’s "type": "module" and uses the appropriate ESM gestures.

@@ -73,7 +73,7 @@ const makeZoeKit = (
},
meteringConfig = {
incrementBy: 25_000_000n,
initial: 50_000_000n, // executeContract for treasury is 13.5M
initial: 75_000_000n, // executeContract for treasury is 13.5M
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@katelynsills This was enough of a boost to clear CI. More boost might be necessary to preserve more overhead. The comment is probably stale now. Do we have a tool for measuring computron cost? cc @warner

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kriskowal does it seem plausible that zip archives are 50% more compute-intensive? What is it doing that take so much more computrons?

Copy link
Member Author

@kriskowal kriskowal Sep 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nestedEvaluate format is a string, whereas the endoZipArchive is a string in base64, which we then convert to a TypedArray with Base64.decode (which is probably free regardless of size since it’s native and I assume not metered), but then we slice the TypedArray into small files and UTF-8 decode them (which might be metered, but should be close to free on XS).

Some of this overhead should turn in our favor when we switch CapTP to a binary protocol, which will reduce the size of setBundle messages by about 25% and eliminate the base64 decode. The UTF-8 decode might not change.

The nestedEvaluate format is a code string that contains code strings. The link phase is expressed as code, whereas with endoZipBase64, it’s expressed as a JSON blob that creates a Compartment graph and links them. That’s overhead. The overhead could probably be reduced by translating the JSON compartment map into code.

There would remain some overhead though because nestedEvaluate is a single-compartment runtime and endoZipBase64 puts us on footing for LavaMoat style dependency sandboxing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah. right. Compartment-per-package for least-authority linkage is why we would pay this cost.

I wonder whether Base64.decode should be metered... or if all uses of it are going to cost enough to build the input so that it doesn't matter. I probably should open an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opening an issue sounds good to me. Where does Moddable want us to open issues?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should be an agoric-sdk issue.

We probably don't need help from Moddable. We should be able to just combine the native base64 implementation that does something O(n) on the length of the input... for example, since regexps are already metered: s.match(/.*/)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent. Filed #3874

@@ -415,7 +418,7 @@ test(`zoe.getConfiguration`, async t => {
},
meteringConfig: {
incrementBy: 25000000n,
initial: 50000000n,
initial: 75000000n,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test detects any change to the default metering config, which isn’t terribly valuable. Could this instead import the defaults and inject them back here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that's a good idea. I'll make an issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue here: #3884

Copy link
Contributor

@katelynsills katelynsills left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me as per @dtribble's decision that we will add validation to Zoe later! Some small requests to leave in code that I think got wrongly deleted.

Comment on lines 92 to 99
assert(installation === installations.atomicSwap, X`wrong installation`);
assert(
sameStructure(
harden({ Asset: invitationIssuer, Price: bucksIssuer }),
issuerKeywordRecord,
),
X`issuerKeywordRecord were not as expected`,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these lines are wrongly removed. They're unrelated to the changes in this PR.

Comment on lines 78 to 81
// const instance = await E(zoe).getInstance(invitation);
// const installation = await E(zoe).getInstallation(invitation);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// const instance = await E(zoe).getInstance(invitation);
// const installation = await E(zoe).getInstallation(invitation);
// const installation = await E(zoe).getInstallation(invitation);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why instance is gotten here if it's the source/hash that we care about

Comment on lines 71 to 73
const instance = await E(zoe).getInstance(invitation);
const installation = await E(zoe).getInstallation(invitation);
const issuerKeywordRecord = await E(zoe).getIssuers(instance);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines should remain in.

const [moolaIssuer, simoleanIssuer, bucksIssuer] = issuers;
const [moolaIssuer, simoleanIssuer] = issuers;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remain the same

@@ -415,7 +418,7 @@ test(`zoe.getConfiguration`, async t => {
},
meteringConfig: {
incrementBy: 25000000n,
initial: 50000000n,
initial: 75000000n,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that's a good idea. I'll make an issue.

@@ -415,7 +418,7 @@ test(`zoe.getConfiguration`, async t => {
},
meteringConfig: {
incrementBy: 25000000n,
initial: 50000000n,
initial: 75000000n,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue here: #3884

@katelynsills
Copy link
Contributor

I should add, I did not look closely at the crc code. That is probably best for @michaelfig

*BREAKING CHANGE*: This change switches the default bundle format from
`nestedEvaluate` to `endoZipBase64`.
The new bundle format has a fundamentally different shape and content,
so any existing code that depends on being able to inspect the `source`
string of the bundle will break.
This functionality will be replaced with a new feature for
consistent-hash integrity checking. #3859
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use Endo archives between bundleSource and importBundle
3 participants