Skip to content

Commit 79cc13c

Browse files
committed
feat(swingset): handle vc syscalls during transcript replay
1 parent 2c812d2 commit 79cc13c

File tree

3 files changed

+75
-10
lines changed

3 files changed

+75
-10
lines changed

packages/SwingSet/src/kernel/vat-loader/manager-helper.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ import { makeTranscriptManager } from './transcript.js';
103103
* @param {KernelSlog} kernelSlog
104104
* @param {(vso: VatSyscallObject) => VatSyscallResult} vatSyscallHandler
105105
* @param {boolean} workerCanBlock
106-
* @param {(vatID: any, originalSyscall: any, newSyscall: any) => Error | undefined} [compareSyscalls]
106+
* @param {(vatID: any, originalSyscall: any, newSyscall: any) => import('./transcript.js').CompareSyscallsResult} [compareSyscalls]
107107
* @param {boolean} [useTranscript]
108108
* @returns {ManagerKit}
109109
*/
@@ -247,7 +247,9 @@ function makeManagerKit(
247247
// but if the puppy deviates one inch from previous twitches, explode
248248
kernelSlog.syscall(vatID, undefined, vso);
249249
const vres = transcriptManager.simulateSyscall(vso);
250-
return vres;
250+
if (vres) {
251+
return vres;
252+
}
251253
}
252254

253255
const vres = vatSyscallHandler(vso);
@@ -256,7 +258,7 @@ function makeManagerKit(
256258
if (successFlag === 'ok' && data && !workerCanBlock) {
257259
console.log(`warning: syscall returns data, but worker cannot get it`);
258260
}
259-
if (transcriptManager) {
261+
if (transcriptManager && !transcriptManager.inReplay()) {
260262
transcriptManager.addSyscall(vso, vres);
261263
}
262264
return vres;

packages/SwingSet/src/kernel/vat-loader/manager-subprocess-xsnap.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { assert, details as X, q } from '@agoric/assert';
33
import { ExitCode } from '@agoric/xsnap/api.js';
44
import { makeManagerKit } from './manager-helper.js';
5+
import { requireIdenticalExceptStableVCSyscalls } from './transcript.js';
56

67
import {
78
insistVatSyscallObject,
@@ -55,7 +56,7 @@ export function makeXsSubprocessFactory({
5556
const {
5657
name: vatName,
5758
metered,
58-
compareSyscalls,
59+
compareSyscalls = requireIdenticalExceptStableVCSyscalls,
5960
useTranscript,
6061
sourcedConsole,
6162
} = managerOptions;

packages/SwingSet/src/kernel/vat-loader/transcript.js

+68-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
import djson from '../../lib/djson.js';
22

3+
const missingSyscall = Symbol('missing transcript syscall');
4+
const extraSyscall = Symbol('extra transcript syscall');
5+
6+
/** @typedef {typeof missingSyscall | typeof extraSyscall | Error | undefined} CompareSyscallsResult */
7+
8+
/**
9+
* @param {any} vatID
10+
* @param {object} originalSyscall
11+
* @param {object} newSyscall
12+
* @returns {CompareSyscallsResult}
13+
*/
314
export function requireIdentical(vatID, originalSyscall, newSyscall) {
415
if (djson.stringify(originalSyscall) !== djson.stringify(newSyscall)) {
516
console.error(`anachrophobia strikes vat ${vatID}`);
@@ -10,6 +21,39 @@ export function requireIdentical(vatID, originalSyscall, newSyscall) {
1021
return undefined;
1122
}
1223

24+
const vcSyscallRE = /^vc\.\d+\.\|(?:schemata|label)$/;
25+
26+
/**
27+
* @param {any} vatID
28+
* @param {object} originalSyscall
29+
* @param {object} newSyscall
30+
* @returns {CompareSyscallsResult}
31+
*/
32+
export function requireIdenticalExceptStableVCSyscalls(
33+
vatID,
34+
originalSyscall,
35+
newSyscall,
36+
) {
37+
const error = requireIdentical(vatID, originalSyscall, newSyscall);
38+
39+
if (error) {
40+
if (
41+
originalSyscall[0] === 'vatstoreGet' &&
42+
vcSyscallRE.test(originalSyscall[1])
43+
) {
44+
console.warn(` mitigation: ignoring extra vc syscall`);
45+
return extraSyscall;
46+
}
47+
48+
if (newSyscall[0] === 'vatstoreGet' && vcSyscallRE.test(newSyscall[1])) {
49+
console.warn(` mitigation: falling through to syscall handler`);
50+
return missingSyscall;
51+
}
52+
}
53+
54+
return error;
55+
}
56+
1357
export function makeTranscriptManager(
1458
vatKeeper,
1559
vatID,
@@ -59,13 +103,31 @@ export function makeTranscriptManager(
59103
let replayError;
60104

61105
function simulateSyscall(newSyscall) {
62-
const s = playbackSyscalls.shift();
63-
const newReplayError = compareSyscalls(vatID, s.d, newSyscall);
64-
if (newReplayError) {
65-
replayError = newReplayError;
66-
throw replayError;
106+
while (playbackSyscalls.length) {
107+
const compareError = compareSyscalls(
108+
vatID,
109+
playbackSyscalls[0].d,
110+
newSyscall,
111+
);
112+
113+
if (compareError === missingSyscall) {
114+
return undefined;
115+
}
116+
117+
const s = playbackSyscalls.shift();
118+
119+
if (!compareError) {
120+
return s.response;
121+
} else if (compareError !== extraSyscall) {
122+
replayError = compareError;
123+
break;
124+
}
125+
}
126+
127+
if (!replayError) {
128+
replayError = new Error(`historical inaccuracy in replay of ${vatID}`);
67129
}
68-
return s.response;
130+
throw replayError;
69131
}
70132

71133
function finishReplayDelivery(dnum) {

0 commit comments

Comments
 (0)