Skip to content

Commit

Permalink
fix: cope with delivery failures after replay due to dead vats
Browse files Browse the repository at this point in the history
  • Loading branch information
FUDCo committed Aug 20, 2020
1 parent 9d6ff42 commit 37dba42
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 25 deletions.
7 changes: 3 additions & 4 deletions packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,10 @@ export default function buildKernel(kernelEndowments) {
async function deliverToVat(vatID, target, msg) {
insistMessage(msg);
const vat = ephemeral.vats.get(vatID);
assert(vat, details`unknown vatID ${vatID}`);
kernelKeeper.incStat('dispatches');
kernelKeeper.incStat('dispatchDeliver');
if (vat.dead) {
resolveToError(msg.result, makeError('vat is dead'));
if (!vat || vat.dead) {
resolveToError(msg.result, makeError('unknown vat'));
} else {
const kd = harden(['message', target, msg]);
const vd = vat.translators.kernelDeliveryToVatDelivery(kd);
Expand Down Expand Up @@ -378,7 +377,7 @@ export default function buildKernel(kernelEndowments) {
insistVatID(vatID);
insistKernelType('promise', kpid);
const vat = ephemeral.vats.get(vatID);
assert(vat, details`unknown vatID ${vatID}`);
assert(vat, details`notify unknown vatID ${vatID}`);
kernelKeeper.incStat('dispatches');
if (vat.dead) {
kdebug(`dropping notify of ${kpid} to ${vatID} because vat is dead`);
Expand Down
18 changes: 0 additions & 18 deletions packages/SwingSet/test/test-terminate.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* global harden */
import { E } from '@agoric/eventual-send';

export function buildRootObject(vatPowers) {
const { testLog } = vatPowers;
let mediumRoot;
let weatherwaxRoot;

const self = harden({
async bootstrap(vats, devices) {
const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin);
mediumRoot = vats.medium;

// create a dynamic vat, then kill it, then try to send it a message

const weatherwax = await E(vatMaker).createVatByName('weatherwax');
weatherwaxRoot = weatherwax.root;

E(weatherwax.adminNode).terminate();
await E(weatherwax.adminNode).done();

try {
await E(mediumRoot).speak(weatherwaxRoot, '1');
} catch (e) {
testLog(`speak failed: ${e}`);
}

return 'bootstrap done';
},
async speakAgain() {
try {
await E(mediumRoot).speak(weatherwaxRoot, '2');
} catch (e) {
testLog(`respeak failed: ${e}`);
}
},
});
return self;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"bootstrap": "bootstrap",
"bundles": {
"weatherwax": {
"sourceSpec": "vat-weatherwax-terminate.js"
}
},
"vats": {
"bootstrap": {
"sourceSpec": "bootstrap-speak-to-dead.js"
},
"medium": {
"sourceSpec": "vat-medium-terminate.js"
}
}
}
42 changes: 39 additions & 3 deletions packages/SwingSet/test/vat-admin/terminate/test-terminate.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,51 @@ test('terminate', async t => {
'GOT QUERY 3',
'foreverP.catch vat terminated',
'query3P.catch vat terminated',
'foo4P.catch vat is dead',
'foo4P.catch unknown vat',
'afterForeverP.catch vat terminated',
'done',
]);
t.end();
});

test('vat referencing the dead does not harm kernel', async t => {
const configPath = path.resolve(__dirname, 'swingset-speak-to-dead.json');
const config = loadSwingsetConfigFile(configPath);

const { storage: storage1 } = initSwingStore();
{
const c1 = await buildVatController(copy(config), [], {
hostStorage: storage1,
});
await c1.run();
t.deepEqual(c1.bootstrapResult.resolution(), capargs('bootstrap done'));
t.deepEqual(c1.dump().log, ['live 1 failed: unknown vat']);
}
const state1 = getAllState(storage1);
const { storage: storage2 } = initSwingStore();
setAllState(storage2, state1);
{
const c2 = await buildVatController(copy(config), [], {
hostStorage: storage2,
});
const r2 = c2.queueToVatExport(
'bootstrap',
'o+0',
'speakAgain',
capargs([]),
'panic',
);
await c2.run();
t.equal(r2.status(), 'fulfilled');
t.deepEqual(c2.dump().log, [
'live 1 failed: unknown vat',
'live 2 failed: unknown vat',
]);
}

t.end();
});

test('replay does not resurrect dead vat', async t => {
const configPath = path.resolve(__dirname, 'swingset-no-zombies.json');
const config = loadSwingsetConfigFile(configPath);
Expand All @@ -59,9 +97,7 @@ test('replay does not resurrect dead vat', async t => {
const c1 = await buildVatController(copy(config), [], {
hostStorage: storage1,
});
t.equal(c1.bootstrapResult.status(), 'pending');
await c1.run();
t.equal(c1.bootstrapResult.status(), 'fulfilled');
t.deepEqual(c1.bootstrapResult.resolution(), capargs('bootstrap done'));
// this comes from the dynamic vat...
t.deepEqual(c1.dump().log, [`I ate'nt dead`]);
Expand Down
16 changes: 16 additions & 0 deletions packages/SwingSet/test/vat-admin/terminate/vat-medium-terminate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* global harden */
import { E } from '@agoric/eventual-send';

export function buildRootObject(vatPowers) {
const { testLog } = vatPowers;

return harden({
async speak(target, tag) {
try {
await E(target).live();
} catch (e) {
testLog(`live ${tag} failed: ${e}`);
}
},
});
}

0 comments on commit 37dba42

Please sign in to comment.