Skip to content

Commit

Permalink
fix: move ExitCode processing into worker
Browse files Browse the repository at this point in the history
Previously, the SwingSet-side `manager-subprocess-xsnap.js` asked the
`xsnap` package for the integers corresponding to the three
meter-based error exits: E_TOO_MUCH_COMPUTATION, E_STACK_OVERFLOW, and
E_NOT_ENOUGH_MEMORY. It needs these to distinguish an in-consensus vat
termination from a random I-don't-know-why-so-panic-the-kernel worker
exit.

However, that required SwingSet to have a direct dependency on
`@agoric/xsnap`, whereas we really want the xsnap version to be
entirely encapsulated by the new swingset-worker-xsnap-v1
package. Imagine how this would work when we introduce a -v2 package,
which e.g. uses a new xsnap that has changed the exit code values.

This commit adds a new `trapMeteringFailure()` method to the workers
created by `swingset-worker-xsnap-v1`. This method inspects the error
object (including the exit code), and either converts it into a
termination-reason string (for the three recognized meter-based
exits), or throws an error (for anything else). The manager can call
this worker method instead of needing to know the exact exit codes,
delegating knowledge of the details to the specific worker version.

This allows SwingSet to lose the direct dependency upon @agoric/xsnap,
relegating it to `devDependencies`.
  • Loading branch information
warner committed Mar 11, 2023
1 parent 116e586 commit 2a7780a
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/SwingSet/misc-tools/measure-metering/measure.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable import/no-extraneous-dependencies */
// run as `node tools/measure-metering/measure.js`

// eslint-disable-next-line import/order
Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"devDependencies": {
"@agoric/swingset-xsnap-supervisor": "^0.9.0",
"@agoric/xsnap": "^0.13.2",
"@agoric/xsnap-lockdown": "^0.13.2",
"@types/better-sqlite3": "^7.5.0",
"@types/microtime": "^2.1.0",
Expand All @@ -39,7 +40,6 @@
"@agoric/swingset-worker-xsnap-v1": "^0.9.0",
"@agoric/time": "^0.2.1",
"@agoric/vat-data": "^0.4.3",
"@agoric/xsnap": "^0.13.2",
"@endo/base64": "^0.2.28",
"@endo/bundle-source": "^2.4.2",
"@endo/captp": "^2.0.18",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { assert, Fail, q } from '@agoric/assert';
import { ExitCode } from '@agoric/xsnap/api.js';
import { makeManagerKit } from './manager-helper.js';

import {
Expand Down Expand Up @@ -187,21 +186,8 @@ export function makeXsSubprocessFactory({
result = await issueTagged(['deliver', delivery]);
} catch (err) {
parentLog('issueTagged error:', err.code, err.message);
let message;
switch (err.code) {
case ExitCode.E_TOO_MUCH_COMPUTATION:
message = 'Compute meter exceeded';
break;
case ExitCode.E_STACK_OVERFLOW:
message = 'Stack meter exceeded';
break;
case ExitCode.E_NOT_ENOUGH_MEMORY:
message = 'Allocate meter exceeded';
break;
default:
// non-metering failure. crash.
throw err;
}
// get an error message for metering failures, else throw
const message = worker.trapMeteringFailure(err);
return harden(['error', message, null]);
}

Expand Down
3 changes: 2 additions & 1 deletion packages/SwingSet/src/types-external.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ export {};
* @typedef { { transcriptCount: number } } VatStats
* @typedef { ReturnType<typeof import('./kernel/state/vatKeeper').makeVatKeeper> } VatKeeper
* @typedef { ReturnType<typeof import('./kernel/state/kernelKeeper').default> } KernelKeeper
* @typedef { ReturnType<typeof import('@agoric/xsnap').xsnap> } XSnap
* @typedef { (err: {}) => string } TrapMeteringFailure
* @typedef { ReturnType<typeof import('@agoric/xsnap').xsnap> & { trapMeteringFailure: TrapMeteringFailure } } XSnap
* @typedef { (dr: VatDeliveryResult) => void } SlogFinishDelivery
* @typedef { (ksr: KernelSyscallResult, vsr: VatSyscallResult) => void } SlogFinishSyscall
* @typedef { { write: ({}) => void,
Expand Down
18 changes: 17 additions & 1 deletion packages/swingset-worker-xsnap-v1/src/make-v1.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import fs from 'fs';
import { Fail } from '@agoric/assert';
import { type as osType } from 'os';
import { xsnap, recordXSnap } from '@agoric/xsnap';
import { ExitCode } from '@agoric/xsnap/api.js';
import { getLockdownBundle } from '@agoric/xsnap-lockdown';
import { getSupervisorBundle } from '@agoric/swingset-xsnap-supervisor';

Expand Down Expand Up @@ -102,7 +103,22 @@ export function makeStartXSnapV1(options) {
// eslint-disable-next-line no-await-in-loop, @jessie.js/no-nested-await
await worker.evaluate(`(${bundle.source}\n)()`.trim());
}
return worker;

const trapMeteringFailure = err => {
switch (err.code) {
case ExitCode.E_TOO_MUCH_COMPUTATION:
return 'Compute meter exceeded';
case ExitCode.E_STACK_OVERFLOW:
return 'Stack meter exceeded';
case ExitCode.E_NOT_ENOUGH_MEMORY:
return 'Allocate meter exceeded';
default:
// non-metering failure. crash.
throw err;
}
};

return harden({ ...worker, trapMeteringFailure });
}
return startXSnapV1;
}

0 comments on commit 2a7780a

Please sign in to comment.