-
Notifications
You must be signed in to change notification settings - Fork 219
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
kernel-on-new-SES #477
Comments
Re dynamic module loading in xs, see https://gist.github.com/dckc/cbbd3e8469723b342cc90799ace7a287 |
The branch
I disabled a lot of code: tildot expansion, default-evaluate-options, probably others. All the |
your journey is remarkably similar to my path getting this stuff to run on xs :) |
reminder to self: remove the disable-the-SES-warning code that was added to |
Yesterday I checked in with @warner about this, which is blocking SwingSet-on-xs #47; I learned that that modulo metering, "take 6" i.e. #1078 on the For example, as of a7eb63d: I think this is far enough along to unblock XS work; metering can come along later. |
This switches the entire agoric-sdk to use the new SES (0.8.0). This is a pretty substantial change: the developer-visible details are listed in #1201 This PR is broken up into basically one commit per package. It touches most of them. Some negative consequences of this PR: * tests run more slowly: On my home machine, `yarn test` took 4.5 minutes on trunk, and now takes 6 minutes with this PR. The packages which use SES in their tests (anything using Zoe, spawner, or swingset: `bundle-source`, `cosmic-swingset`, `ERTP`, `import-bundle`, `sharing-service`, `spawner`, `SwingSet`, `swing-store-lmdb`, `transform-metering`, `zoe`) now install SES at startup, adding overhead to each test process. They also now use `tap` as a runner, rather than `tape`, and `tap` uses a separate process per test file, so that overhead is multiplied by the number of test files. `tap` has a default test timeout of 30 seconds, which I've had to increase for both Zoe and SwingSet to overcome some slow CI servers (AppVeyor in particular). `tap` can run test files in parallel, but 1: this doesn't seem to help all that much, and 2: some of our test suites (I'm looking at `cosmic-swingset` and `agoric-cli`) cannot tolerate parallel execution. SwingSet takes the most time by far, so you may not see a big change in other packages. * `tap` has a different output format: there are half a dozen reporter formats to choose from, feel free to find something different than the default. The arrangement of console messages and test results is different, and I'm not quite sure I like it. * `tap` and `tape` have intermittent problems with SES when they try to show exception tracebacks. This will probably get fixed within the next few weeks as SES changes the way it tames the `Error` object. * ag-solo and ag-chain-cosmos run more slowly: these processes are now SES-enabled, which adds overhead to many built-ins, and they also have global metering installed, which adds even more. Some good things about this PR: * stack traces (when they work) seem to be more useful, and the line numbers seem to be more accurate * no more `yarn build` steps! (except for the React code in `wallet-frontend`, and an integration test in `eventual-send`). No more worrying about whether you ran `yarn build` after making some important change in some other package * new SES is great! The security improvement mostly affects SwingSet, but trust me it's way easier to write defensive code when there's only one kind of `Object` to worry about refs #477
The first phase of this was completed yesterday with the landing of #1201. The kernel is now all-SES-all-the-time, and the host application is responsible for providing a SES environment (by importing the new |
This is sufficiently done. We'll add module support in some later ticket. |
(capturing today's meeting)
@jfparadis has made great progress with the new SES implementation (the one with
Compartment
). The current code lets you do:The endowments are added to the new compartment's global (rather than merely being visible in the top-level global scope).
c.evaluate()
currently takes a second argument, which might be options, or might be per-eval endowments, or might be options which can include endowments. It seems likely that we'll get rid of per-eval endowments because they're annoying. From within a Compartment, plaineval()
behaves the same way as a one-argument call toc.evaluate
from outside the compartment. If/when we wanted to provide a two-argumentevaluate()
inside, we could provide an endowment that wrapsc.evaluate
(probably taming some of the options for safety).Eventually the
new Compartment
API will grow to include a module map, andc.import(module_name)
. But for now we just get strings.We're going to assume we can get full/enough debugging information despite using SES, and drop support for
--no-ses
because it would interfere with this plan.First Step
The swingset plan (first step) is:
So we're using
rollup
at runtime, rather than having annpm build
step to flatten the kernel code. (actually the zeroth step might be to flatten at build time, but removing that build step would be nice).We have to bundle the builtin and genesis vats ahead of time, because the kernel still doesn't get access to the filesystem and cannot run rollup itself. This matches what we're currently doing in
controller.js
.By removing
--no-ses
, we can get rid of@agoric/evaluate
, and change both the kernel (in vat-creation code) and the contract-host vat (in the contract-evaluation code) to create a new Compartment and then callc.evaluate
. The new SES putsharden
into the globals, so we can removerequire('harden')
, andNat
can be flattened by rollup. So we removemakeRequire
and all instances ofrequire()
from the flattened/rolluped vat source string. No holes.Second Step: XS
XS currently gives us a
Compartment
API whose first argument is a module name, and whose second argument is a module map. The map can only point to module objects that were available at compile time (no dynamic modules right now). The XS crew is hard at work implementing the new API, but in the meantime we can shim it by creating an empty module (and compiling it into the app), then callingc = new Compartment('empty', modulemap); const c_eval = harden(c.global.eval); c_eval(newcode);
. We'll need to addharden
to the global first, and freeze/stash things before evaluating any untrusted code.We'll need a build step that crawls the kernel source tree and builds a manifest file, which is fed into the XS build process to create the baked-in module map. We don't need to use rollup on these static sources (kernel, built-in vats/devices, probably genesis vats) because XS's compartment has a module loader. We just need to make sure the
import
statements in the kernel sources match the module specifiers that make it into the module map. We should probably make sure that the static vats get a map that only gives them access to their own vat code (and shared dependencies like Nat), not for safety reasons (each Compartment gets a separate instance of each module), but for clarity.Then we'll need some startup code that creates a hostDB and a config object. This config object needs to point at module names, rather than source code, since we'll be loading them as modules. Then inside
buildSwingset
we'll do e.g.new Compartment('kernel')
andnew Compartment('genesisvat1')
instead of evaluating rollup'ed strings.Later Step: node + modules
Eventually, the SES-on-Node API will grow module support. Each Compartment will get a module map (passed as an argument to
new Compartment
), and the new compartment object will get ac.import(module_name)
method. The module map answers the question "if X saysimport Y
, give it Z", as well as information about how to build Z (perhaps source code that should be evaluated, perhaps a function that acquires it, maybe a hash of the expected source code and some sort of implicit loader, or something). Callingc.import('first')
causesfirst
to be looked up in the module map used to createc
. TheY
argument might be relative (../other
) or absolute (moment
) or whatever: the semantics ofY
are left up to whoever created the module map. All the Compartment does is extract thefoo
inimport 'foo'
and look it up in theY
column of the module map.The
Z
argument names a module, which is looked up in the parent Compartment's module map. Compartments can only grant access to a module if they themselves were given access to it. (Modulo dynamically-created modules which is still being worked out). But we can still do multi-level dependency injection: iffirst
saysimport 'second'
, andsecond
saysimport 'third'
, we can putthird -> pseudothird
in the child Compartment's module map and it will getpseudothird
.With modules working on Node, we can stop rollup-ing the kernel source (and the static vat/device sources). We need a build step that constructs a manifest somehow, and uses that manifest to create a module map, which is used to create the kernel's compartment.
dynamic vats
For now, the source code for dynamic vats must be delivered as a single string. The kernel's create-dynamic-vat function will make a new Compartment and
c.evaluate
the source code inside it.Eventually, dynamic vats will be delivered as a bundle (maybe a zipfile) of modules, with enough metadata to build a module map for the new compartment. @michaelfig has a tool (a module translator) that converts a tree full of ES6 module files into a set of metadata+sourcecode objects, one at a time, and a second tool (a module loader) which takes this set and evaluates them and wires them together correctly. We can run the first tool on the developer's machine, send the zipfile over to the chain/server, and run the second tool inside the chain to load the new vat. The first tool involves babel and is too big to safely run on the chain, but the second tool is much smaller.
On XS, we either need to shim dynamic modules in (using some portion of these tools), or get dynamic module support added to the core. The latter sounds hard: XS currently compiles modules into C code, so building them dynamically might involve spawning a copy of
gcc
and then somehow usingdlopen()
to load the resulting ELF file.The text was updated successfully, but these errors were encountered: