(First) Draft Spec for Standalone SES
MODIFY
docs/draft-standalone-spec.md
docs/draft-standalone-spec.md
# Draft Spec for Standalone SES
-In the Realms, Frozen Realms, Realms shim, and SES shim work, we've generally worked towards standardizing
-the APIs for dynamically *creating* a SES world from within a standard EcmaScript world. For IoT purposes,
-the more relevant question is: What is the resulting standard SES world, independent of whether it was created from
-within a standard ES world, or whether it was implemented directly by a standalone SES engine that supports only SES?
+In the Realms, Frozen Realms, Realms shim, and SES shim work, we've
+generally worked towards standardizing the APIs for dynamically
+*creating* a SES world from within a standard EcmaScript world. For
+IoT or blockchain purposes, the more relevant question is: What is the
+resulting standard SES world, independent of whether it was created
+from within a standard EcmaScript world, or whether it was implemented
+directly by a standalone SES engine that supports only SES?
+
+(We use "blockchain" here as shorthand for the more general category
+of deterministically replicated SES computation, whether on a
+blockchain, permissioned BFT system, or whatever.)
## Omissions and Simplifications
-Since the primary purpose of the existing Realms/SES APIs and shims are to dynamically suppress parts of standard ES,
-a standalone SES engine would simply omit these elements, resulting in a simpler and smaller engine.
-Starting from standard ES, the simplification or omissions for the default configuration of SES are
+Since the primary purpose of the existing Realms/SES APIs and shims
+are to dynamically suppress parts of standard EcmaScript, a standalone
+SES engine would simply omit these elements, resulting in a simpler
+and smaller engine. Starting from standard EcmaScript, the
+simplification or omissions for the default configuration of SES are
* Omit all support for sloppy mode
- * Omit everything outside the EcmaScript 2018 spec
- * In particular, omit the `import()` and `import.meta` expressions.
- * Omit annex B
+ * Aside from `BigInt`, omit everything else outside the EcmaScript
+ 2018 spec.
+ * In particular, omit the `import()` and `import.meta`
+ expressions.
+ * Omit annex B (except those our whitelist allows)
+ * In particular, omit the `RegExp` static properties that
+ provide a global communications channel.
* Omit `Math.random()`
* Omit ambient access to current date/time:
* `Date.now()` returns `NaN`
* `new Date()` return equivalent of `new Date(NaN)`
* By default, omit `Intl`, the internationalization APIs
- * If included, must suppress ambient authority and non-determinism.
- * For all forms of function expressible by syntax (function, generator, async-function, async-generator)
- * *func*`.__proto__.constructor` is a function constructor that always throws. Because these function
- constructors always throw, we do consider them to be evaluators.
-
-We define the *shared globals* as all the standard shared globals defined above
-(i.e., without `Intl` by default) + `Realm` (see below) - `eval` - `Function`. We define the
-*shared primordials* as all the objects transitively reachable from the shared
-globals. Note that no global objects or evaluators are reachable from the shared primordials.
+ * If some of `Intl` is included, it must suppress ambient
+ authority and non-determinism.
+ * For all forms of function expressible by syntax (function,
+ generator, async-function, async-generator)
+ * *func*`.[[Prototype]].constructor` is a function constructor that
+ always throws. Because these function constructors always
+ throw, we do consider them to be evaluators.
+
+We define the *shared globals* as all the standard shared global
+variable bindings defined by the above, i.e., without `Intl` by
+default, with `Realm` (see below), without `eval`, without `Function`,
+without anything outside the EcmaScript 2018 spec, and with
+`BigInt`. We define the *shared primordials* as all the objects
+transitively reachable from the shared globals. Note that no global
+objects or evaluators are reachable from the shared primordials.
## Additions
-Some IoT configurations will omit all runtime evaluators. For standalone SES configurations that
-include runtime evaluators, they would appear as follows.
-
-We include the portion of the Realm API for creating compartments, and for evaluating script code
-in a compartment with endowments:
- * `Realm.makeCompartment(options={})` -> aRealm instance representing a new compartment
- * `Realm.prototype.global` ---> global object of compartment. This is a getter-only accessor.
- * `Realm.prototype.evaluateProgram(programSrcString, endowments={})` --> completion value
- * The own properties of the endowments which are legal variable names become the const variable
- bindings of the global lexical scope in which the program is evaluated. Unlike standard
- EcmaScript, there is no shared global lexical scope. Each global lexical scope comes *only*
- from the endowments.
- * `Realm.prototype.evaluateExpr(exprSrcString, endowments={})` --> value of expression
+Some IoT and blockchain configurations may omit all runtime
+evaluators. For standalone SES configurations that include runtime
+evaluators, they would appear as follows.
+
+ 1. Include the portion of the Realm API for creating
+ compartments, and for evaluating script code in a compartment with
+ endowments:
+ * `Realm.makeCompartment(options={})` -> aRealm instance
+ representing a new compartment
+ * `Realm.prototype.global` ---> global object of compartment. This
+ is a getter-only accessor.
+ * `Realm.prototype.evaluateProgram(programSrcString,
+ endowments={})` --> completion value
+ * The own properties of the endowments which are legal variable
+ names become the const variable bindings of the global lexical
+ scope in which the program is evaluated. Unlike standard
+ EcmaScript, there is no shared global lexical scope. Each
+ global lexical scope comes *only* from the endowments.
+ * `Realm.prototype.evaluateExpr(exprSrcString, endowments={})` -->
+ value of expression
* Given that `exprSrcString` parses as an expression,
```js
aRealm.evaluateExpr(exprSrcString, endowments)
@@ -55,47 +81,78 @@ in a compartment with endowments:
aRealm.evaluateProgram(`(${exprSrcString});`, endowments)
```
- 1. Freeze all shared primordials. With the above omissions, there is no hidden
- state or ambient authority among the shared primordials, so transitive freezing means that the shared
- primordials are immutable and rom-able.
+ The additional element from the proposed Realm API is
+ `Realm.makeRootRealm(options={})`. SES allows but does not
+ require this static method. IoT and blockchain uses of SES
+ generally have no need for multiple root realms. However,
+ browser-based and Node-based use of SES will often be coupled
+ with creating multiple confined root realms. On platforms that
+ do not support `Realm.makeRootRealm`, the property must be
+ absent so that SES code can feature-test for it.
+
+ 1. Freeze all shared primordials. With the above omissions, there
+ is no hidden state or ambient authority among the shared
+ primordials, so transitive freezing means that the shared
+ primordials are immutable and rom-able. Since no global objects
+ or evaluators are reachable from the shared primordials. They can
+ be placed in ROM without the bookkeeping needed for them to point
+ at any objects not in ROM.
1. For each compartment, create a new global populated by:
* The shared globals with their standard global property names.
- * An `eval` function and `Function` constructor that evaluates code in the scope of that global
- * Both this `eval` function and `Function` constructor inherit from the shared
- %FunctionPrototype% primordial.
- * Each of these `eval` functions is considered an initial eval function for
- purposes of determining whether an apparent direct-eval is indeed a direct-eval.
- (The direct-eval feature is impossible to shim, and so is low priority.
- When omitted, the direct-eval syntax should also be statically rejected.)
- * `Function.prototype` is initialized to the same %FunctionPrototype%.
- * All of these global properties are made non-configurable non-writable data properties.
- The new per-global objects (the eval function and Function constructor) are frozen.
- Since they have no hidden state, they are immutable and rom-able.
- * This new global object is *not* frozen. It remains extensible. However,
- the global's [[Prototype]] slot cannot be altered.
- 1. The host creates a start-compartment whose start-global is populated as above.
- 1. To that start-global object, the host adds global bindings to those host objects
- that provide initial access to the program's outside world, e.g., the I/O environment
- of the device.
- 1. The program's start scripts are then evaluated as program code in that start-compartment.
-
-Note that, in all compartment scopes,
-
+ * An `eval` function and `Function` constructor that evaluates
+ code in the scope of that global
+ * Both this `eval` function and `Function` constructor
+ inherit from the shared %FunctionPrototype% primordial.
+ * Each of these `eval` functions is considered an initial
+ eval function for purposes of determining whether a
+ an expression in direct-eval syntax is indeed a
+ direct-eval. (The direct-eval feature is impossible to shim
+ and rarely needed anyway, and so is low priority. When
+ omitted, the direct-eval syntax should also be statically
+ rejected with an early error.)
+ * `Function.prototype` is initialized to point at the same
+ shared %FunctionPrototype% primordial.
+ * All of these global properties are made non-configurable
+ non-writable data properties. The new per-global objects (the
+ eval function and Function constructor) are frozen. Since they
+ have no hidden state, they are immutable and rom-able.
+ * This new global object is *not* frozen. It remains
+ extensible. However, the global's [[Prototype]] slot cannot be
+ altered.
+ 1. The host creates a start-compartment whose start-global is
+ populated as above.
+ 1. To that start-global object, the host adds global bindings to
+ those host objects that provide initial access to the program's
+ outside world, e.g., the I/O environment of the device.
+ 1. The program's start scripts are then evaluated as program code
+ in that start-compartment.
+
+Each compartment scope has its own `Function`, which does
+evaluate. All compartment scopes share the same `Function.prototype`
+and therefore the same `Function.prototype.constructor` which is a
+function that only throws. Thus, in all compartment scopes,
```js
Function !== Function.prototype.constructor
```
-Each compartment scope has its own `Function`, which does evaluate. All compartment scopes share the
-same `Function.prototype` and therefore the same `Function.prototype.constructor`, which only throws.
+
+TBD:
+ * What portion of the additions above are relevant to a
+ standalone SES without runtime evaluators?
+ * Should `eval` and `Function` actually be on a compartment's
+ global object, or should we include them in the compartment's
+ global lexical scope?
## Work in Progress
-We are still working towards specifying how SES supports modules. Indeed, this is the main
-topic of the SES-strategy sessions. Somehow, whether by import, require, or otherwise, a SES
-environment must provide access to the exports of the packages currently named
-'@agoric/nat' and '@agoric/harden', which will normally be bound to const variable
-named `Nat` and `harden`. We'll revisit all this is a separate document.
+We are still working towards specifying how SES supports
+modules. Indeed, this is the main topic of the SES-strategy
+sessions. Somehow, whether by import, require, or otherwise, a SES
+environment must provide access to the exports of the packages
+currently named '@agoric/nat' and '@agoric/harden', which will
+normally be bound to const variable named `Nat` and `harden`. We'll
+revisit all this is a separate document.
TBD:
* `System`
@@ -110,21 +167,31 @@ TBD:
## Stage Separated SES
-Full SES supports running vetted customization code in a freezable realm prior to freezing it into a SES realm.
-Such vetted customization code runs in an environment like that described above except:
+Full SES, as embedded into EcmaScript, supports running vetted
+customization code in a freezable realm prior to freezing it into a
+SES realm. Such vetted customization code runs in an environment like
+that described above except:
* The shared primordials are not yet frozen
- * No host objects have been added to the global. Thus the vetted customizations run fully confined,
- without access to any external world.
-
-Although the custoimizations run confined, because they can arbitrarily mutate the shared primordial state
-before other code runs, all later code is fully vulnerable to these custiomizations. This is why we
-refer to them as *vetted customization code*. Once the shared primordial state is transitively frozen,
-then we can support the standalone SES environment described above, where compartments are units of
-protection between subgraphs of mutually suspicious objects.
-
-(A loose analogy is that vetted customizations run in an analog of Unix single-user mode,
-or that they are what a shopkeeper does to their shop in preparation for opening for business.)
-
-In an IoT context, we should associate these two stages with build-time and runtime. The build-time
-environment should support more of the Realms and SES APIs for creating a SES world, that would be
-absent from within the standalone SES world they are creating.
+ * No host objects have been added to the global. Thus the vetted
+ customizations run fully confined, without access to any external
+ world.
+
+Although the custoimizations run confined, because they can
+arbitrarily mutate the shared primordial state before other code runs,
+all later code is fully vulnerable to these custiomizations. This is
+why we refer to them as *vetted customization code*. Once the shared
+primordial state is transitively frozen, then we can support the
+standalone SES environment described above, where compartments are
+units of protection between subgraphs of mutually suspicious objects.
+
+A analogy is that vetted customizations are what a shopkeeper
+does to their shop in preparation for opening for business. Freezing
+the primordials is the last step before opening the doors and allowing
+in untrusted customers.
+
+In an IoT context, we should associate these two stages with
+build-time and runtime. The build-time environment should support more
+of the Realms and SES APIs for creating a SES world, that would be
+absent from within the standalone SES world they are creating. The
+freezing of the primordials is the snapshotting of the
+post-constomization primordial state for transfer to ROM.

(First) Draft Spec for Standalone SES