Commit 2f1d81adf2eec8e0c13058fae79efee1a6af4a58
clean up system objects
wanderer committed on 3/23/2018, 12:06:24 AMParent: aafe96ace826878428496f61ad0f8a93f9fccd2e
Files changed
index.js | changed |
package-lock.json | changed |
package.json | changed |
systemObjects.js | changed |
tests/index.js | changed |
tests/wasmContainer.js | changed |
wasmContainer.js | changed |
index.js | ||
---|---|---|
@@ -1,16 +1,17 @@ | ||
1 | 1 | const crypto = require('crypto') |
2 | 2 | const Actor = require('./actor.js') |
3 | 3 | const Scheduler = require('./scheduler.js') |
4 | -const {ID} = require('./systemObjects.js') | |
4 | +const {ID, decoder} = require('./systemObjects.js') | |
5 | 5 | |
6 | 6 | module.exports = class Hypervisor { |
7 | 7 | /** |
8 | 8 | * The Hypervisor manages the container instances by instantiating them and |
9 | 9 | * destorying them when possible. It also facilitates localating Containers |
10 | 10 | * @param {Tree} tree - a [radix tree](https://github.com/dfinity/js-dfinity-radix-tree) to store the state |
11 | 11 | */ |
12 | 12 | constructor (tree, containers = [], drivers = [], nonce = 0) { |
13 | + tree.dag.decoder = decoder | |
13 | 14 | this.tree = tree |
14 | 15 | this.scheduler = new Scheduler(this) |
15 | 16 | this._containerTypes = {} |
16 | 17 | this.nonce = nonce |
@@ -47,9 +48,9 @@ | ||
47 | 48 | id, |
48 | 49 | nonce, |
49 | 50 | type, |
50 | 51 | code, |
51 | - storage: storage || [], | |
52 | + storage, | |
52 | 53 | tree: this.tree |
53 | 54 | }) |
54 | 55 | |
55 | 56 | await actor.startup() |
@@ -100,18 +101,14 @@ | ||
100 | 101 | * @param {Number} ticks the number of ticks at which to create the state root |
101 | 102 | * @returns {Promise} |
102 | 103 | */ |
103 | 104 | async createStateRoot () { |
104 | - const promise = new Promise((resolve, reject) => { | |
105 | - if (!this.scheduler._running) { | |
106 | - this.tree.flush().then(resolve) | |
107 | - } else { | |
108 | - this.scheduler.once('idle', () => { | |
109 | - this.tree.flush().then(resolve) | |
110 | - }) | |
111 | - } | |
112 | - }) | |
113 | - return promise | |
105 | + if (this.scheduler._running) { | |
106 | + await new Promise((resolve, reject) => { | |
107 | + this.scheduler.once('idle', resolve) | |
108 | + }) | |
109 | + } | |
110 | + return this.tree.flush() | |
114 | 111 | } |
115 | 112 | |
116 | 113 | /** |
117 | 114 | * regirsters a container with the hypervisor |
package-lock.json | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 369221 bytes New file size: 369767 bytes |
package.json | ||
---|---|---|
@@ -30,9 +30,9 @@ | ||
30 | 30 | "contributors": "Alex Beregszaszi <alex@rtfs.hu>", |
31 | 31 | "license": "MPL-2.0", |
32 | 32 | "dependencies": { |
33 | 33 | "binary-search-insert": "^1.0.3", |
34 | - "borc": "^2.0.2", | |
34 | + "borc": "git+ssh://git@github.com:dignifiedquire/borc.git#fix/nested-array", | |
35 | 35 | "events": "^2.0.0", |
36 | 36 | "primea-annotations": "0.0.1", |
37 | 37 | "reference-map": "^1.2.3", |
38 | 38 | "safe-buffer": "^5.1.1", |
@@ -41,9 +41,9 @@ | ||
41 | 41 | }, |
42 | 42 | "devDependencies": { |
43 | 43 | "levelup": "^2.0.2", |
44 | 44 | "coveralls": "^3.0.0", |
45 | - "dfinity-radix-tree": "^0.1.5", | |
45 | + "dfinity-radix-tree": "^0.2.1", | |
46 | 46 | "documentation": "^6.0.0", |
47 | 47 | "level-browserify": "^1.1.2", |
48 | 48 | "nyc": "^11.6.0", |
49 | 49 | "standard": "11.0.1", |
systemObjects.js | ||
---|---|---|
@@ -11,60 +11,50 @@ | ||
11 | 11 | elem: [], |
12 | 12 | data: Buffer.from([]), |
13 | 13 | id: new cbor.Tagged(TAGS.id, 0), |
14 | 14 | mod: new cbor.Tagged(TAGS.mod, [{}, new cbor.Tagged(TAGS.id, 0)]), |
15 | - link: {'/': null}, | |
15 | + link: new cbor.Tagged(TAGS.link, null), | |
16 | 16 | func: new cbor.Tagged(TAGS.func, 0) |
17 | 17 | } |
18 | 18 | |
19 | 19 | const decoder = new cbor.Decoder({ |
20 | 20 | tags: { |
21 | 21 | [TAGS.id]: val => new ID(val), |
22 | - [TAGS.func]: val => new FunctionRef(...val), | |
23 | - [TAGS.mod]: val => new ModuleRef(...val) | |
22 | + [TAGS.func]: val => new FunctionRef({ | |
23 | + identifier: val[0], | |
24 | + params: val[1], | |
25 | + id: val[2], | |
26 | + gas: val[3] | |
27 | + }), | |
28 | + [TAGS.mod]: val => new ModuleRef(...val), | |
29 | + [TAGS.link]: val => { | |
30 | + return { | |
31 | + '/': val | |
32 | + } | |
33 | + } | |
24 | 34 | } |
25 | 35 | }) |
26 | 36 | |
27 | -class Serializable { | |
28 | - serialize () { | |
29 | - const encoder = new cbor.Encoder() | |
30 | - this.encodeCBOR(encoder) | |
31 | - return encoder.finalize() | |
32 | - } | |
33 | - | |
34 | - static deserialize (serialized) { | |
35 | - return decoder.decodeFirst(serialized) | |
36 | - } | |
37 | -} | |
38 | - | |
39 | -class FunctionRef extends Serializable { | |
37 | +class FunctionRef { | |
40 | 38 | constructor (opts) { |
41 | - super() | |
42 | 39 | this.identifier = opts.identifier |
43 | - if (!(opts.id instanceof ID)) { | |
44 | - opts.id = new ID(opts.id) | |
45 | - } | |
46 | 40 | this.destId = opts.id |
47 | 41 | this.params = opts.params |
48 | - this.gas = opts.gas | |
42 | + this.gas = opts.gas || 0 | |
49 | 43 | } |
50 | 44 | |
51 | 45 | encodeCBOR (gen) { |
52 | 46 | return gen.write(new cbor.Tagged(TAGS.func, [ |
53 | 47 | this.identifier, |
54 | 48 | this.params, |
55 | - this.destId | |
49 | + this.destId, | |
50 | + this.gas | |
56 | 51 | ])) |
57 | 52 | } |
58 | - | |
59 | - set container (container) { | |
60 | - this._container = container | |
61 | - } | |
62 | 53 | } |
63 | 54 | |
64 | -class ModuleRef extends Serializable { | |
55 | +class ModuleRef { | |
65 | 56 | constructor (ex, id) { |
66 | - super() | |
67 | 57 | this.exports = ex |
68 | 58 | this.id = id |
69 | 59 | } |
70 | 60 | |
@@ -78,22 +68,12 @@ | ||
78 | 68 | |
79 | 69 | encodeCBOR (gen) { |
80 | 70 | return gen.write(new cbor.Tagged(TAGS.mod, [this.exports, this.id])) |
81 | 71 | } |
82 | - | |
83 | - static fromMetaJSON (json, id) { | |
84 | - const exports = {} | |
85 | - for (const ex in json.exports) { | |
86 | - const type = json.types[json.indexes[json.exports[ex].toString()]].params | |
87 | - exports[ex] = type | |
88 | - } | |
89 | - return new ModuleRef(exports, id) | |
90 | - } | |
91 | 72 | } |
92 | 73 | |
93 | -class ID extends Serializable { | |
74 | +class ID { | |
94 | 75 | constructor (id) { |
95 | - super() | |
96 | 76 | this.id = id |
97 | 77 | } |
98 | 78 | |
99 | 79 | encodeCBOR (gen) { |
@@ -104,6 +84,7 @@ | ||
104 | 84 | module.exports = { |
105 | 85 | ID, |
106 | 86 | FunctionRef, |
107 | 87 | ModuleRef, |
108 | - DEFAULTS | |
88 | + DEFAULTS, | |
89 | + decoder | |
109 | 90 | } |
tests/index.js | ||
---|---|---|
@@ -1,8 +1,8 @@ | ||
1 | 1 | const tape = require('tape') |
2 | 2 | const Message = require('../message.js') |
3 | 3 | const Hypervisor = require('../') |
4 | -const {FunctionRef} = require('../systemObjects') | |
4 | +const {FunctionRef, ModuleRef} = require('../systemObjects') | |
5 | 5 | |
6 | 6 | const level = require('level-browserify') |
7 | 7 | const EgressDriver = require('../egressDriver') |
8 | 8 | const RadixTree = require('dfinity-radix-tree') |
@@ -30,14 +30,58 @@ | ||
30 | 30 | return 9 |
31 | 31 | } |
32 | 32 | } |
33 | 33 | |
34 | +tape('system objects', async t => { | |
35 | + t.plan(4) | |
36 | + const tree = new RadixTree({ | |
37 | + db | |
38 | + }) | |
39 | + | |
40 | + let id | |
41 | + let mod | |
42 | + let funcref | |
43 | + | |
44 | + class testVMContainer extends BaseContainer { | |
45 | + store () { | |
46 | + id = this.actor.id.id.toString('hex') | |
47 | + mod = new ModuleRef({'test': ['i32', 'i64']}, this.actor.id) | |
48 | + funcref = mod.getFuncRef('test') | |
49 | + this.actor.storage = [this.actor.id, {'/': 'test'}, mod, funcref] | |
50 | + } | |
51 | + load () { | |
52 | + const loadedID = this.actor.storage[0].id.toString('hex') | |
53 | + const link = this.actor.storage[1] | |
54 | + const loadedMod = this.actor.storage[2] | |
55 | + const loadedFuncref = this.actor.storage[3] | |
56 | + t.equals(id, loadedID, 'should load id correctly') | |
57 | + t.equals(link['/'].toString('hex'), '6fe3180f700090697285ac1e0e8dc400259373d7', 'should load link correctly') | |
58 | + t.deepEquals(loadedMod, mod) | |
59 | + t.deepEquals(funcref, loadedFuncref) | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + const hypervisor = new Hypervisor(tree, [testVMContainer]) | |
64 | + const {module} = hypervisor.createActor(testVMContainer.typeId) | |
65 | + | |
66 | + const message = new Message({ | |
67 | + funcRef: module.store | |
68 | + }) | |
69 | + | |
70 | + hypervisor.send(message) | |
71 | + await hypervisor.createStateRoot() | |
72 | + | |
73 | + const message2 = new Message({ | |
74 | + funcRef: module.load | |
75 | + }) | |
76 | + hypervisor.send(message2) | |
77 | + await hypervisor.createStateRoot() | |
78 | + t.end() | |
79 | +}) | |
80 | + | |
34 | 81 | tape('basic', async t => { |
35 | 82 | t.plan(2) |
36 | - const expectedState = { | |
37 | - '/': Buffer.from('1602fe14ee1e95c9d5cf10e809d0615cb21927a2', 'hex') | |
38 | - } | |
39 | - | |
83 | + const expectedState = Buffer.from('1602fe14ee1e95c9d5cf10e809d0615cb21927a2', 'hex') | |
40 | 84 | const tree = new RadixTree({ |
41 | 85 | db |
42 | 86 | }) |
43 | 87 | |
@@ -47,25 +91,25 @@ | ||
47 | 91 | } |
48 | 92 | } |
49 | 93 | |
50 | 94 | const hypervisor = new Hypervisor(tree, [testVMContainer]) |
95 | + await hypervisor.createStateRoot() | |
96 | + | |
51 | 97 | const {module} = hypervisor.createActor(testVMContainer.typeId) |
52 | 98 | |
53 | 99 | const message = new Message({ |
54 | 100 | funcRef: module.main, |
55 | 101 | funcArguments: [1] |
56 | 102 | }) |
57 | 103 | hypervisor.send(message) |
58 | 104 | |
59 | - const stateRoot = await hypervisor.createStateRoot() | |
60 | - t.deepEquals(stateRoot, expectedState, 'expected root!') | |
105 | + const stateRoot2 = await hypervisor.createStateRoot() | |
106 | + t.deepEquals(stateRoot2, expectedState, 'expected root!') | |
61 | 107 | }) |
62 | 108 | |
63 | 109 | tape('two communicating actors', async t => { |
64 | 110 | t.plan(2) |
65 | - const expectedState = { | |
66 | - '/': Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
67 | - } | |
111 | + const expectedState = Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
68 | 112 | |
69 | 113 | const tree = new RadixTree({ |
70 | 114 | db |
71 | 115 | }) |
@@ -107,12 +151,9 @@ | ||
107 | 151 | }) |
108 | 152 | |
109 | 153 | tape('three communicating actors', async t => { |
110 | 154 | t.plan(3) |
111 | - const expectedState = { | |
112 | - '/': Buffer.from('7b659c263363b0b9c461a432aac8d8bf0d351788', 'hex') | |
113 | - } | |
114 | - | |
155 | + const expectedState = Buffer.from('7b659c263363b0b9c461a432aac8d8bf0d351788', 'hex') | |
115 | 156 | const tree = new RadixTree({ |
116 | 157 | db: db |
117 | 158 | }) |
118 | 159 | |
@@ -160,12 +201,9 @@ | ||
160 | 201 | }) |
161 | 202 | |
162 | 203 | tape('three communicating actors, with tick counting', async t => { |
163 | 204 | t.plan(3) |
164 | - const expectedState = { | |
165 | - '/': Buffer.from('7b659c263363b0b9c461a432aac8d8bf0d351788', 'hex') | |
166 | - } | |
167 | - | |
205 | + const expectedState = Buffer.from('7b659c263363b0b9c461a432aac8d8bf0d351788', 'hex') | |
168 | 206 | const tree = new RadixTree({ |
169 | 207 | db: db |
170 | 208 | }) |
171 | 209 | |
@@ -213,12 +251,9 @@ | ||
213 | 251 | }) |
214 | 252 | |
215 | 253 | tape('errors', async t => { |
216 | 254 | t.plan(3) |
217 | - const expectedState = { | |
218 | - '/': Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
219 | - } | |
220 | - | |
255 | + const expectedState = Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
221 | 256 | const tree = new RadixTree({ |
222 | 257 | db: db |
223 | 258 | }) |
224 | 259 | |
@@ -261,11 +296,9 @@ | ||
261 | 296 | }) |
262 | 297 | |
263 | 298 | tape('actor creation', async t => { |
264 | 299 | t.plan(2) |
265 | - const expectedState = { | |
266 | - '/': Buffer.from('f1803a4188890e205e2e6480159d504d149d8910', 'hex') | |
267 | - } | |
300 | + const expectedState = Buffer.from('f1803a4188890e205e2e6480159d504d149d8910', 'hex') | |
268 | 301 | |
269 | 302 | const tree = new RadixTree({ |
270 | 303 | db: db |
271 | 304 | }) |
@@ -310,12 +343,9 @@ | ||
310 | 343 | }) |
311 | 344 | |
312 | 345 | tape('simple message arbiter test', async t => { |
313 | 346 | t.plan(4) |
314 | - const expectedState = { | |
315 | - '/': Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
316 | - } | |
317 | - | |
347 | + const expectedState = Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
318 | 348 | const tree = new RadixTree({ |
319 | 349 | db: db |
320 | 350 | }) |
321 | 351 | |
@@ -379,11 +409,9 @@ | ||
379 | 409 | |
380 | 410 | tape('arbiter test for id comparision', async t => { |
381 | 411 | t.plan(4) |
382 | 412 | let message |
383 | - const expectedState = { | |
384 | - '/': Buffer.from('7b659c263363b0b9c461a432aac8d8bf0d351788', 'hex') | |
385 | - } | |
413 | + const expectedState = Buffer.from('7b659c263363b0b9c461a432aac8d8bf0d351788', 'hex') | |
386 | 414 | |
387 | 415 | const tree = new RadixTree({ |
388 | 416 | db: db |
389 | 417 | }) |
@@ -446,11 +474,9 @@ | ||
446 | 474 | }) |
447 | 475 | |
448 | 476 | tape('async work', async t => { |
449 | 477 | t.plan(3) |
450 | - const expectedState = { | |
451 | - '/': Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
452 | - } | |
478 | + const expectedState = Buffer.from('3cdad3b1024074e7edafadbb98ee162cc8cfe565', 'hex') | |
453 | 479 | |
454 | 480 | const tree = new RadixTree({ |
455 | 481 | db: db |
456 | 482 | }) |
tests/wasmContainer.js | ||
---|---|---|
@@ -36,11 +36,9 @@ | ||
36 | 36 | |
37 | 37 | tape('basic', async t => { |
38 | 38 | t.plan(1) |
39 | 39 | tester = t |
40 | - const expectedState = { | |
41 | - '/': Buffer.from('4494963fb0e02312510e675fbca8b60b6e03bd00', 'hex') | |
42 | - } | |
40 | + const expectedState = Buffer.from('4494963fb0e02312510e675fbca8b60b6e03bd00', 'hex') | |
43 | 41 | |
44 | 42 | const tree = new RadixTree({ |
45 | 43 | db |
46 | 44 | }) |
@@ -67,11 +65,9 @@ | ||
67 | 65 | |
68 | 66 | tape('empty', async t => { |
69 | 67 | t.plan(1) |
70 | 68 | tester = t |
71 | - const expectedState = { | |
72 | - '/': Buffer.from('3ac226eb0a4809e7f0b3d7ba1e0bb6d57e0378a8', 'hex') | |
73 | - } | |
69 | + const expectedState = Buffer.from('aeb5418328108a82b7a2a57712bddc989d513f5d', 'hex') | |
74 | 70 | |
75 | 71 | const tree = new RadixTree({ |
76 | 72 | db |
77 | 73 | }) |
wasmContainer.js | ||
---|---|---|
@@ -9,8 +9,17 @@ | ||
9 | 9 | |
10 | 10 | const nativeTypes = new Set(['i32', 'i64', 'f32', 'f64']) |
11 | 11 | const FUNC_INDEX_OFFSET = 1 |
12 | 12 | |
13 | +function fromMetaJSON (json, id) { | |
14 | + const exports = {} | |
15 | + for (const ex in json.exports) { | |
16 | + const type = json.types[json.indexes[json.exports[ex].toString()]].params | |
17 | + exports[ex] = type | |
18 | + } | |
19 | + return new ModuleRef(exports, id) | |
20 | +} | |
21 | + | |
13 | 22 | function generateWrapper (funcRef, container) { |
14 | 23 | let wrapper = typeCheckWrapper(funcRef.params) |
15 | 24 | const wasm = json2wasm(wrapper) |
16 | 25 | const mod = WebAssembly.Module(wasm) |
@@ -63,9 +72,9 @@ | ||
63 | 72 | moduleJSON = injectGlobals(moduleJSON, json.persist) |
64 | 73 | } |
65 | 74 | // recompile the wasm |
66 | 75 | wasm = json2wasm(moduleJSON) |
67 | - const modRef = ModuleRef.fromMetaJSON(json, id) | |
76 | + const modRef = fromMetaJSON(json, id) | |
68 | 77 | return { |
69 | 78 | wasm, |
70 | 79 | json, |
71 | 80 | modRef |
Built with git-ssb-web