Skip to content

Commit e390c35

Browse files
committed
fix(spawner): fail-stop meter exhaustion
1 parent f1410f9 commit e390c35

File tree

1 file changed

+23
-13
lines changed

1 file changed

+23
-13
lines changed

packages/spawner/src/contractHost.js

+23-13
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,15 @@ function makeContractHost(E, evaluate, additionalEndowments = {}) {
7474
// Refill a meter each crank.
7575
const { meter, refillFacet } = makeMeter();
7676
const doRefill = () => {
77-
// Refill the meter, since we're leaving a crank.
78-
refillFacet.combined();
77+
if (!meter.isExhausted()) {
78+
// We'd like to have fail-stop semantics, which means we associate
79+
// a meter with a spawn and not with an installation, and failed
80+
// spawns die forever. Check functions, on the other hand, should
81+
// be billed to the installation, which may die forever.
82+
83+
// Refill the meter, since we're leaving a crank.
84+
refillFacet.combined();
85+
}
7986
};
8087

8188
// Make an endowment to get our meter.
@@ -131,21 +138,13 @@ function makeContractHost(E, evaluate, additionalEndowments = {}) {
131138
// contract.
132139
install(contractSrcs, moduleFormat = 'object') {
133140
let installation;
134-
let startFn;
135141
if (moduleFormat === 'object') {
136142
installation = extractCheckFunctions(contractSrcs);
137-
startFn = evaluateStringToFn(contractSrcs.start);
138143
} else if (moduleFormat === 'getExport') {
139-
const getExports = evaluateStringToFn(contractSrcs);
140-
const ns = getExports();
144+
// We don't support 'check' functions in getExport format,
145+
// because we only do a single evaluate, and the whole
146+
// contract must be metered per-spawn, not per-installation.
141147
installation = {};
142-
for (const fname of Object.getOwnPropertyNames(ns)) {
143-
if (typeof fname === 'string' && fname.startsWith('check')) {
144-
const fn = ns[fname];
145-
installation[fname] = (...args) => fn(installation, ...args);
146-
}
147-
}
148-
startFn = ns.default;
149148
} else {
150149
assert.fail(details`Unrecognized moduleFormat ${moduleFormat}`);
151150
}
@@ -160,6 +159,17 @@ function makeContractHost(E, evaluate, additionalEndowments = {}) {
160159
// source code itself. The check... methods must be evaluated on install,
161160
// since they become properties of the installation.
162161
function spawn(termsP) {
162+
let startFn;
163+
if (moduleFormat === 'object') {
164+
startFn = evaluateStringToFn(contractSrcs.start);
165+
} else if (moduleFormat === 'getExport') {
166+
const getExports = evaluateStringToFn(contractSrcs);
167+
const ns = getExports();
168+
startFn = ns.default;
169+
} else {
170+
assert.fail(details`Unrecognized moduleFormat ${moduleFormat}`);
171+
}
172+
163173
return Promise.resolve(allComparable(termsP)).then(terms => {
164174
const inviteMaker = harden({
165175
// Used by the contract to make invites for credibly

0 commit comments

Comments
 (0)