-
Notifications
You must be signed in to change notification settings - Fork 207
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
build prototype XS-based VatWorker process, define kernel-vatworker protocol #1299
Comments
progress:
https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 for reference: |
@warner how is I started on dispatch. At first I had
|
1st achievement unlocked.
|
🔥 |
made substantial progress on porting to xs.
|
tee hee... fwrite failed because I didn't open the file for writing @warner @michaelfig any chance you can reproduce my results?
|
Ugh... I back-ported the synchronous
but now (EDIT: unless I move
|
Try searching for |
the demo vat makes an I'd look at what |
The |
It's working end-to-end now...
Perhaps tomorrow we can see if one of you can reproduce my work... and then maybe get bold and try non-trivial vats. |
Tonight we were able to get this working on my machine too. We tested it against the encouragement bot demo (one message) and it worked. We then tried to test it against the zoe test (30 messages), and something is failing as it tries to parse the bundle (which is about 320kB, much larger than the other demos). One task is to get a better readline() in C (XS is using static int bytes_read = 0;
void xs_file_read(xsMachine *the)
{
fprintf(stderr, "in xs_file_read\n");
FILE *file = getFile(the);
int32_t result;
int argc = xsmcArgc;
int dstLen = (argc < 2) ? -1 : xsmcToInteger(xsArg(1));
fprintf(stderr, " dstLen is %d\n", dstLen);
void *dst;
xsSlot *s1, *s2;
struct stat buf;
int32_t position = ftell(file);
fprintf(stderr, " ftell says %d\n", position);
fstat(fileno(file), &buf);
if ((-1 == dstLen) || (buf.st_size < (position + dstLen))) {
if (position >= buf.st_size) {
fprintf(stderr, " read past end of file\n");
xsUnknownError("read past end of file");
}
dstLen = buf.st_size - position;
dstLen = 10000;
fprintf(stderr, " dstLen is now %d\n", dstLen);
}
char *inbuf = malloc(10000);
int offset;
for (offset=0; offset < 10000; offset++) {
char intc = fgetc(file);
if (intc == '\n') {
fprintf(stderr, " got LF at offset %d", offset);
inbuf[offset] = intc;
offset += 1;
break;
}
if (intc == EOF) {
fprintf(stderr, " got EOF at offset %d", offset);
break;
}
inbuf[offset] = intc;
}
fprintf(stderr, " finished loop with offset %d", offset);
dstLen = offset;
s1 = &xsArg(0);
xsmcVars(1);
xsmcGet(xsVar(0), xsGlobal, xsID_String);
s2 = &xsVar(0);
if (s1->data[2] == s2->data[2]) {
fprintf(stderr, " option 1\n");
//xsResult = xsStringBuffer(NULL, dstLen);
//dst = xsmcToString(xsResult);
}
else {
fprintf(stderr, " option 2\n");
xsmcSetArrayBuffer(xsResult, NULL, dstLen);
dst = xsmcToArrayBuffer(xsResult);
}
xsResult = xsStringBuffer(inbuf, dstLen);
dst = xsmcToString(xsResult);
//result = fread(dst, 1, dstLen, file);
fprintf(stderr, " result %d %.100s %d\n", dstLen, (char *)dst, bytes_read);
bytes_read += dstLen;
//if (result != dstLen)
// xsUnknownError("file read failed");
} To generate the zoe bundle, I started from
const argv2 = ['automaticRefundOk',
[[3, 0, 0],
[0, 17, 0]],
];
const [testName, startingValues] = argv2;
const { aliceP, bobP, carolP, daveP } = makeVats(
log,
vats,
zoe,
installations,
startingValues,
); and ran swingset-runner: import sys
lines = open("transcript-zoe.txt").readlines()
lines.sort(key=lambda line: int(line.split(" ", 1)[0].split(".")[2]))
for line in lines:
sys.stdout.write(line) We had to update the XS manifest because I'd added I'm continuing to work on refactoring the kernel so that we can plug this in. |
Is using netstrings the answer, or just another problem to add to this one? |
I'm inclined towards netstrings, but @dckc said he was going to hack on a line-oriented reader a bit longer. |
getline(3) fits pretty well@warner writes:
getline(3) seems to be just what the doctor ordered as long as we can rely on It works in at least one case:
Considering netstringsnetstrings start with a variable length string of digits, so we'd still have to use Is there a canonical C implementation of netstrings in a dozen lines or so? I suppose so... Netstrings 19970201 by Bernstein includes:
The lack of |
If you use
🎉
djb's netstring decoder |
sure... it's just that |
zoe test fails with
|
that looks like it's still using the demo bundle, not the zoe bundle.. try adding |
ok... fixed VAT1
Now I get
This is with a little extra logging that I'm not committing just yet because I don't have
|
My |
liveSlots version skewyes, I think my >64K JSONI think xs or my This looks like an argument for netstrings:
|
Unfortunately, the multiple layers of json are not easily converted to netstrings. It may be necessary to lift the limit. |
I'm sure I'll have to lift the limit, but just to diagnose what's going on, I'm trying netstrings. I get
When I increase the parser.buffer, I get:
I guess I should use gdb to attach to the running xs vatWorker... for reference:
|
zoe-node loses at v5.t.12with the vatrunner running under node, I get:
|
zoe is intermittent around v5.t.12 (
|
vatWorker runs a vat in its own process. We have drivers for both node and xs, though only the node driver is working as of this commit. We also have a kernelSimulator that takes a vat transcript (as from swingset-runner/bin/kerneldump) and simulates a swingset kernel vat manager. Earlier vatWorker work was done in a gist: https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 This commit is based on: 2020-08-02 a32f30e simple transcript runs as integration test The xs driver was working, to some extent, in: 2020-08-01 5b80235 agoric-sdk catch-up See also Agoric#1299
vatWorker runs a vat in its own process. We have drivers for both node and xs, though only the node driver is working as of this commit. We also have a kernelSimulator that takes a vat transcript (as from swingset-runner/bin/kerneldump) and simulates a swingset kernel vat manager. Earlier vatWorker work was done in a gist: https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 This commit is based on: 2020-08-02 a32f30e simple transcript runs as integration test The xs driver was working, to some extent, in: 2020-08-01 5b80235 agoric-sdk catch-up See also Agoric#1299
got this part added to #1407 tonight, along with syncing with upstream moddable:
I'm inclined to switch to this design:
|
vatWorker runs a vat in its own process. We have drivers for both node and xs, though only the node driver is working as of this commit. We also have a kernelSimulator that takes a vat transcript (as from swingset-runner/bin/kerneldump) and simulates a swingset kernel vat manager. Earlier vatWorker work was done in a gist: https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 This commit is based on: 2020-08-02 a32f30e simple transcript runs as integration test The xs driver was working, to some extent, in: 2020-08-01 5b80235 agoric-sdk catch-up See also Agoric#1299
vatWorker runs a vat in its own process. We have drivers for both node and xs, though only the node driver is working as of this commit. We also have a kernelSimulator that takes a vat transcript (as from swingset-runner/bin/kerneldump) and simulates a swingset kernel vat manager. Earlier vatWorker work was done in a gist: https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 This commit is based on: 2020-07-16 b17fae8 thru 2020-08-02 a32f30e simple transcript runs as integration test The xs driver was working, to some extent, in: 2020-08-01 5b80235 agoric-sdk catch-up See also Agoric#1299
vatWorker runs a vat in its own process. We have drivers for both node and xs, though only the node driver is working as of this commit. We also have a kernelSimulator that takes a vat transcript (as from swingset-runner/bin/kerneldump) and simulates a swingset kernel vat manager. Earlier vatWorker work was done in a gist: https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 This commit is based on: 2020-07-16 b17fae8 thru 2020-08-02 a32f30e simple transcript runs as integration test The xs driver was working, to some extent, in: 2020-08-01 5b80235 agoric-sdk catch-up See also Agoric#1299
vatWorker runs a vat in its own process. We have drivers for both node and xs, though only the node driver is working as of this commit. We also have a kernelSimulator that takes a vat transcript (as from swingset-runner/bin/kerneldump) and simulates a swingset kernel vat manager. Earlier vatWorker work was done in a gist: https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 This commit is based on: 2020-07-16 b17fae8 thru 2020-08-02 a32f30e simple transcript runs as integration test The xs driver was working, to some extent, in: 2020-08-01 5b80235 agoric-sdk catch-up See also Agoric#1299
prototype XS-based VatWorker process refs #1299
vatWorker runs a vat in its own process. We have drivers for both node and xs, though only the node driver is working as of this commit. We also have a kernelSimulator that takes a vat transcript (as from swingset-runner/bin/kerneldump) and simulates a swingset kernel vat manager. Earlier vatWorker work was done in a gist: https://gist.github.com/dckc/f8e0b5d838079a994784d599c282cce7 This commit is based on: 2020-07-16 b17fae8 thru 2020-08-02 a32f30e simple transcript runs as integration test The xs driver was working, to some extent, in: 2020-08-01 5b80235 agoric-sdk catch-up See also #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
This fixes the two ends of the netstring-based "kernel-worker" protocol: the previous version failed to parse large inbound messages, such as non-trivial vat bundles. The replacement netstring parser is based on Node.js "Streams", in their "object mode". We intend to replace this with one based on async iterators, once I can figure out some other problems with that branch. We re-enable test-worker.js for all worker types, now that the decoding problem is fixed. refs #1299 refs #1127
This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299
* test: new CI job to test the XS vat worker This changes the "test swingset" CI job to additionally build the XS toolkit (written in C), and then use that toolkit to compile the `xs-vat-worker` program. The SwingSet unit tests will then exercise this program (they skip the test unless the program is available). To make the results more visible, another small step was added to run just the one unit test that exercises `xs-vat-worker`. The `git clone` steps were changed to include submodules, since the xs-vat-worker package uses a git submodule to fetch our modified version of the XS source tree. refs #1299 * chore: rename xs-vat-worker Makefile The original name came from the XS build tool convention, but required annoying `-f` flags every time you use it, and we're only ever building for linux/unix here. * fix: xs-vat-worker/Makefile 'clean': there is no .bin/xs-vat-worker
I'm getting 'running.get(...)' is undefined at vatAdminWrapper.js:70:13 In the kernel, I see that Or is the failure here from something else altogether? run log: https://gist.github.com/dckc/3031523281d25fbf735bd2b69f7a8625 current code: https://github.com/dckc/agoric-sdk/tree/xs-vat-worker 5fe2224 |
Yesterday @dckc @michaelfig and I walked through a way to get started on the #1107 #1127 plan. The first step is probably to define the protocol to be spoken between the kernel and the VatWorker (something that can be sent over pipes). Then the next one is to build a VatWorker process: something that speaks this protocol over stdin/stdout, knows how to load a Bundle of vat code, can attach an instance of liveslots to it, and then wait for instructions on stdin.
This process will expect dispatch messages on stdin. Each one turns into a
dispatch.something
call into liveslots (which then invokes methods on various objects exported by the vat code). When liveslots callssyscall.something
, that turns into a syscall message sent back over stdout. The process then blocks waiting for stdin to return the syscall results (which are almost always"undefined"
). When the results come back, the process returns from the syscall, and liveslots continues.The process is responsible for using
setImmediate
to detect when the vat becomes quiescent. At that point, the process should finally respond to the dispatch message over stdout. After that, the process goes back to waiting for the next dispatch.This process should probably be written in Node first, but the goal is to quickly get it written in XS instead.
The idea is that we could eventually change the kernel's
vatManager
to spawn off one of these processes, instead of running the vat in the same process as the kernel.The other idea is to start doing some meaningful integration with XS, so we can all keep learning about it. Our current XS prototype starts "from the top", putting the entire swingset (in fact the whole ag-solo, I think) in XS. But we know that our most important XS goals (safer TCB, checkpointing vats, efficient metering) will all be better satisfied "from the bottom", one vat at a time.
We could get to a point where we run some vats, perhaps the dynamic vats created to host contracts, in separate XS-based processes, while the static vats and the kernel continue to run in a single shared Node.js process. Or we might rewrite the kernel in a different language (Rust being my perennial favorite), and put the vats in something different, that is capable of running JS (WASM boxes running XS being my other favorite). Or we might start with VatWorkers being merely separate Workers in Node (which will probably help a lot with debugging, since DevTools knows a lot more about Workers than it does about bespoke child processes).
All of those cases will be helped by isolating the code necessary to run a vat, and separating it from the rest of the kernel. We don't necessarily want to run each vat in a separate process, in the long run, but if we can get to that point, then we can easily move that code back into a shared process later. The important thing is figuring out how to draw the line between vat and kernel.
We're not aiming to build the kernel side of this tool right now. This ticket is about building the vatWorker side. We'll drive it with a mock kernel (perhaps just a shell script that copies things to stdin at the right times, and checks the stdout responses for a match). For now, the only vat is has to handle is the demo one (vat-target in the gist below), and the only messages are the ones in the demo transcript.
kernel-vatworker protocol
I can think of three messages that we need, plus acks:
loadVat(bundle)
, plus ackdispatch(type, args)
, plus (eventual) acksyscall(type, args)
, plus (prompt but async) responseloadVat
The first message the vatWorker receives is
loadVat
. This will include the "vat bundle", in the same format thatdynamicVat.js
receives them (the result of callingbundleSource(filename, 'nestedEvaluate')
). The bundle is a JSON-serializable object; if the kernel-vatworker protocol just JSONs a message like{type: 'loadVat', bundle}
, then the serialization is trivial.The vatWorker will need to have a copy of liveSlots available. The vat bundle yields a
buildRootObject
function, which should be passed tomakeLiveSlots
.Look at
dynamicVat.js
for some structure. If written in Node, this will useimportBundle
.The vatWorker should send back a
loadVat
-specific ACK when the vat has been loaded successfully. If the bundle cannot be loaded (syntax error, runtime exception whne callingbuildRootObject
), the NAK should include the error details.dispatch
On each crank, the kernel will send a dispatch message to the vatWorker. This will be one of
dispatch.deliver
,dispatch.notifyFulfillToData
,dispatch.notifyFulfillToPresence
, ordispatch.notifyReject
. The vatWorker will parse the message and invoke the vat'sdispatch
object (really the liveslotsdispatch
object). The vatWorker won't ack the dispatch until the vat becomes quiescent (which will require asetImmediate
check). In the meantime, the vat may make one or more syscalls. The protocol must be able to distinguish between outbound syscalls and the dispatch ack.The dispatch might NAK if the vat explodes during processing. This could be a metering fault, or some deeper problem in the JS engine. The dispatch function may throw an exception: that is not grounds for a NAK (although it'd help to log the problem somewhere, maybe stderr).
Once the dispatch is ACKed, the vatWorker is expected to remain idle until the next dispatch arrives. The vat code is not given access to IO or the timer queue, so it should have no way to regain control until the next dispatch wakes it up.
syscall
While a dispatch is running, the vat can make syscalls (really the vat performs eventual-sends and resolves Promises, and liveslots turns these into syscalls). When liveslots invokes
syscall.send
orsyscall.fulfillToDat
or whatever, the vatWorker should serialize the details into a syscall message and write it to stdout, where the kernel will receive the syscall request and execute it. The vatWorker should perform a blocking read of stdin, waiting for the results of the syscall. We need liveslots to believe that it is making a synchronous invocation of the syscall method. No further vat code or liveslots code should execute until the kernel responds to the syscall request with the results.The results of a syscall are almost always empty, just
undefined
. The exceptions are device invocations (syscall.callNow
), and we aren't yet trying to support any of those in the vatWorker. We're also trying to get rid of synchronous syscalls entirely, but there are a lot of barriers. But, for now, the vatWorker should pretend that there are important results to be had; it should wait patiently for the kernel to respond to the syscall request, then deserialize the results and return them to the liveslots caller.finishing the dispatch
The vatWorker must not ACK the kernel's dispatch message until the vat is idle. The vat might have returned from the initial dispatch call, but it might have performed local Promise operations that leave an arbitrary number of callbacks sitting on the promise queue. So the real test of the vat being idle is that a
setImmediate
callback can fire.In the regular kernel, we call
setImmediate
, then invoke the vat's dispatch function (in a Promise chain), then use the setImmediate to trigger the callback chain that allows the kernel to move on to the next message. It is left as an exercise to the reader to figure out how to make this work well in a vatWorker communicating over stdin/stdout. The blocking read we use to let liveslots think it has a synchronous syscall might not play nicely with the idea of using setImmediate to detect an idle vat.demo transcript
https://gist.github.com/warner/ee5168d1afc4679ef92ce5164cb982b7 has a simple
vat-target
and a bootstrap function which sends it a series of five dispatches. Thevat-target
reacts to these with a set of syscalls. Combined, they exercise all of the vat/kernel interactions we're trying to implement for this vatWorker experiment. The gist also has a copy of the transcript this generates. We should be able to parse that in a simple program that feeds in the simulated kernel-vatworker protocol messages, and checks that the responses are correct.pieces
A Node.js-based vatworker will need to include a copy of liveslots,
importBundle
, some mechanism to detect the vat being idle, some protocol handlers, and something to get the whole process started.I'd bet that the simplest protocol to pursue is to JSON-serialize an object containing the message type, and the message body as a copy of the arguments of the original dispatch function. For example, the original kernel/vat boundary
dispatch
method has a signature ofdispatch.deliver(target, method, argsdata, result)
(wheretarget
andmethod
are both strings,result
is either a string orundefined
/null
, andargsdata
is a "capdata" structure which is a string.body
and an array-of-strings.slots
). When the kernel wants to make the VatWorker do this, it could send:and when the kernel wants to ACK a syscall, it could send:
At the beginning of the connection, the kernel would also send:
and the VatWorker would eventually send:
or something.
VatPowers
The real kernel provides a couple of extra objects to the vat's
buildRootObject()
function, in an argument namedvatPowers
. This includes a pair of string-to-string transformation functions (transformTildot
andtransformMetering
), which are powerless but require Babel to build, and don't run so well in a powerless SES compartment. We don't need these for this prototype, andtransformMetering
will be removed from vatPowers soon anyways. The VatWorker will be responsible fortransformMetering
, but we can figure out how to bake that into the Compartments it builds later.There are also some other
vatPowers
related to metering that we don't need to support for now.subsequent steps
I'm going to see if I can split the kernel/vatManager code up to facilitate the VatWorker connection. My goal is to make the code that builds a static or dynamic vat provide a way to specify where that new vat ought to live. This is the place that could fork off a new Node.js or XS process, tell it to load the vat bundle, and then start sending dispatch messages to it. It could also create a new in-process
Worker
to host the vat, communicating via structured-clonepostMessage
channels (same kernel-vatworker protocol, but not serialized all the way down into strings).The text was updated successfully, but these errors were encountered: