git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit d6ecef73fd6edc80197140774535f1adea617314

cleanup

wanderer committed on 4/24/2017, 9:51:16 AM
Parent: 1171580743394a34306e2a12800ea5606f7e5d67

Files changed

README.mdchanged
index.jschanged
kernel.jschanged
package.jsonchanged
port.jschanged
portManager.jschanged
tests/index.jschanged
common.jsdeleted
crypto.jsadded
tools/wabtdeleted
README.mdView
@@ -36,4 +36,9 @@
3636 todo
3737
3838 # LICENSE
3939 [MPL-2.0](https://tldrlegal.com/license/mozilla-public-license-2.0-(mpl-2))
40+
41+
42+The Kernel enforces IPC and starts the VM
43+The hypervisor start and stops kernels
44+the VM acts as a sandbox for some given code and expose and interface to the kernel
index.jsView
@@ -1,48 +1,69 @@
1-const Kernel = require('./index.js')
1+const Graph = require('ipld-graph-builder')
2+const Kernel = require('./kernel.js')
3+const crypto = require('./crypto')
24
35 module.exports = class Hypervisor {
46 constructor (opts) {
57 this._opts = {
6- state: {},
7- imports: [],
8- hypervisor: this
8+ hypervisor: this,
9+ VMs: {}
910 }
1011
12+ this.graph = new Graph(opts.dag)
13+ this._vmInstances = new Map()
1114 Object.assign(this._opts, opts)
12- this._runningVMs = new Map()
1315 }
1416
15- set (path, value) {
16- return this._opts.graph.set(this._opts.state, path, value)
17- }
18-
19- sendMessage (portObj, message) {
20- const vm = this.getInstaceFromPort(portObj)
21- vm.queue(message)
22- }
23-
24- async getVMFromPort (port) {
25- const id = Kernel.id(port)
26- let kernel = this._vms.get(id)
17+ async getInstance (port) {
18+ const id = await this.generateID(port.id)
19+ let kernel = this._vmInstances.get(id)
2720 if (!kernel) {
2821 // load the container from the state
2922 await this.graph.tree(port, 2)
30- kernel = new Kernel()
23+
24+ // create a new kernel instance
25+ const opts = Object.assign({
26+ state: port.vm,
27+ id: port.id
28+ }, this._opts)
29+
30+ kernel = new Kernel(opts)
31+ await kernel.start()
3132 kernel.on('idle', () => {
32- this._vms.delete(id)
33+ this._vmInstances.delete(id)
3334 })
34- this._vms.set(id, kernel)
35+ this._vmInstances.set(id, kernel)
3536 }
37+ return kernel
3638 }
3739
40+ async send (port, message) {
41+ const vm = await this.getInstance(port)
42+ const id = await this.generateID(port.id)
43+ message._fromPort = id
44+ vm.queue(message)
45+ }
46+
3847 // given a port, wait untill its source contract has reached the threshold
3948 // tick count
40- async waitOnPort (port, ticks) {
41- let kernel = await this.getVMFromPort(port)
42- return kernel.wait(ticks)
49+ async wait (port, ticks) {
50+ let kernel = await this.getInstance(port)
51+ await kernel.wait(ticks)
52+ return kernel
4353 }
4454
45- addVM (container) {
46- this._vms.type = container.type
55+ async createStateRoot (port, ticks) {
56+ const kernel = await this.wait(port, ticks)
57+ return this.graph.flush(kernel.state)
4758 }
59+
60+ async generateID (port) {
61+ let id = Buffer.concat([port.nonce, port.parent])
62+ id = await crypto.subtle.digest('SHA-256', id)
63+ return new Buffer(id).toString('hex')
64+ }
65+
66+ addVM (type, vm) {
67+ this._opts.VMs[type] = vm
68+ }
4869 }
kernel.jsView
@@ -1,44 +1,46 @@
1-const crypto = require('webcrypto-liner')
21 const PriorityQueue = require('fastpriorityqueue')
32 const EventEmitter = require('events')
3+const BN = require('bn.js')
44 const PortManager = require('./portManager.js')
55
6-const STATES = ['idle', 'running', 'result']
6+const VMSTATES = ['idle', 'running', 'result']
77
88 module.exports = class Kernel extends EventEmitter {
9- constructor (opts = {}) {
9+ constructor (opts) {
1010 super()
11- // set up the state
12- this.opts = {}
13- this._stateIndex = 0
14- Object.assign(this.opts, opts)
11+ this._opts = opts
12+ this._vmStateIndex = 0
1513 this.ports = new PortManager(this)
1614 this._waitingQueue = new PriorityQueue((a, b) => {
1715 return a.threshold > b.threshold
1816 })
1917 this.on('result', this._runNextMessage)
2018 }
2119
22- _updateState (message) {
23- this._stateIndex++
24- const state = STATES[this._stateIndex]
25- this._emit(state, message)
20+ start () {
21+ return this.ports.start()
2622 }
2723
28- get state () {
29- return STATES[this._stateIndex]
24+ _updateVmState (message) {
25+ this._vmStateIndex++
26+ const vmState = VMSTATES[this._stateVmIndex]
27+ this._emit(vmState, message)
3028 }
3129
30+ get vmState () {
31+ return VMSTATES[this._stateVmIndex]
32+ }
33+
3234 queue (message) {
33- this.portManager.queue(message)
34- if (this.state === 'idle') {
35+ this.ports.queue(message)
36+ if (this.vmState === 'idle') {
3537 this._runNextMessage()
3638 }
3739 }
3840
3941 _runNextMessage () {
40- this.portManager.getNextMessage(this.ticks).then(message => {
42+ this.ports.getNextMessage(this.ticks).then(message => {
4143 if (message) {
4244 this.run(message)
4345 } else {
4446 this._updateState()
@@ -52,9 +54,9 @@
5254 * to by the VM to retrive infromation from the Environment.
5355 */
5456 async run (message, imports = this.imports) {
5557 // shallow copy
56- const oldState = Object.assign({}, this.state)
58+ const oldState = Object.assign({}, this._opts.state)
5759 let result
5860 this._updateState(message)
5961 try {
6062 result = await this._vm.run(message, this, imports) || {}
@@ -66,20 +68,20 @@
6668 }
6769
6870 if (result.exception) {
6971 // revert to the old state
70- clearObject(this.opts.state)
71- Object.assign(this.opts.state, oldState)
72+ clearObject(this._opts.state)
73+ Object.assign(this._opts.state, oldState)
7274 }
7375
74- this._updateState(result)
76+ this._updateVmState(result)
7577 return result
7678 }
7779
7880 // returns a promise that resolves once the kernel hits the threshould tick
7981 // count
8082 async wait (threshold) {
81- if (this._state === 'idle' && threshold > this.ticks) {
83+ if (this._vmState === 'idle' && threshold > this.ticks) {
8284 // the cotract is at idle so wait
8385 return this.portManager.wait(threshold)
8486 } else {
8587 return new Promise((resolve, reject) => {
@@ -102,29 +104,27 @@
102104 }
103105 }
104106
105107 createPort () {
108+ const nonce = new BN(this.nonce)
109+ nonce.iaddn(1)
110+ this.nonce = nonce.toArrayLike(Uint8Array)
106111 return {
107112 id: {
108- '/': [this.nonce++, this.id]
113+ '/': {
114+ nonce: this.nonce,
115+ parent: this.id
116+ }
109117 },
110118 link: {
111119 '/': {}
112120 }
113121 }
114122 }
115123
116124 async send (port, message) {
117- return this.opts.hypervisor.send(port, message)
125+ return this._opts.hypervisor.send(port, message)
118126 }
119-
120- id () {
121- return Kernel.id(this._opts, this._opts)
122- }
123-
124- static id (id) {
125- return crypto.subtle.digest('SHA-256', Buffer.concat(id.parentId, id.nonce))
126- }
127127 }
128128
129129 function clearObject (myObject) {
130130 for (var member in myObject) {
package.jsonView
@@ -1,8 +1,8 @@
11 {
2- "name": "ewasm-kernel",
2+ "name": "primea-hypervisor",
33 "version": "0.0.0",
4- "description": "This is a JS prototype of the eWASM kernal.",
4+ "description": "this is a JS implemention of the primea hypervisor",
55 "scripts": {
66 "coverage": "node --harmony ./node_modules/istanbul/lib/cli.js cover ./tests/apiTests.js",
77 "coveralls": "npm run coverage && coveralls <coverage/lcov.info",
88 "lint": "standard",
@@ -17,40 +17,27 @@
1717 "url": "https://github.com/ewasm/ewasm-kernel/issues"
1818 },
1919 "homepage": "https://github.com/ewasm/ewasm-kernel",
2020 "keywords": [
21- "ethereum",
22- "webassembly",
23- "wasm",
24- "ewasm"
21+ "primea",
22+ "hypervisor",
23+ "kernel"
2524 ],
2625 "author": "mjbecze <mjbecze@gmail.com>",
2726 "contributors": "Alex Beregszaszi <alex@rtfs.hu>",
2827 "license": "MPL-2.0",
28+ "dependencies": {
29+ "bn.js": "^4.11.6",
30+ "deepcopy": "^0.6.3",
31+ "fastpriorityqueue": "^0.2.4",
32+ "ipld-graph-builder": "1.0.1",
33+ "node-webcrypto-ossl": "^1.0.21",
34+ "primea-message": "0.0.0"
35+ },
2936 "devDependencies": {
3037 "coveralls": "^2.13.0",
3138 "ipfs": "^0.23.1",
3239 "istanbul": "^1.1.0-alpha.1",
3340 "standard": "10.0.1",
3441 "tape": "^4.5.1"
35- },
36- "standard": {
37- "ignore": [
38- "/tools/"
39- ],
40- "globals": [
41- "WebAssembly"
42- ]
43- },
44- "dependencies": {
45- "deepcopy": "^0.6.3",
46- "ethereumjs-block": "^1.5.0",
47- "ethereumjs-tx": "^1.2.5",
48- "ethereumjs-util": "^5.1.0",
49- "file-type": "^4.2.0",
50- "fixed-bn.js": "0.0.2",
51- "ipld-graph-builder": "1.0.1",
52- "primea-message": "0.0.0",
53- "primea-wasm-container": "0.0.0",
54- "webcrypto-liner": "^0.1.20"
5542 }
5643 }
port.jsView
@@ -9,9 +9,9 @@
99 this.ticks = message.ticks
1010 if (this._resolve) {
1111 return this._resolve(message)
1212 } else {
13- this.queue.push(message)
13+ this._queue.push(message)
1414 }
1515 }
1616
1717 // this only workls for one Promise
portManager.jsView
@@ -1,44 +1,35 @@
11 const Port = require('./port.js')
2-const common = require('./common.js')
32
43 module.exports = class PortManager {
5- constructor (ports, kernel) {
4+ constructor (kernel) {
65 this.kernel = kernel
7- this.ports = ports
6+ this.hypervisor = kernel._opts.hypervisor
7+ this.ports = kernel._opts.state.ports
88 this._portMap = new Map()
9- this._hasMappedPorts = false
10- this._tempQueue = []
11- this._mapPorts(this.ports).then(ports => {
12- this._portMap = ports
13- this.queue = this._queue
14- for (const message of this._tempQueue) {
15- this.queue(message)
16- }
17- })
189 }
1910
20- // temporaly queue message untill the ports have been mapped. Mapping the
21- // ports is async since the ports could just be merkle links
22- queue (message) {
23- this._tempQueue.push(message)
24- }
25-
26- _queue (message) {
27- this._portMap.get(message.from).push(message)
28- }
29-
30- async _mapPorts (ports) {
31- ports = Object.key(ports).map(name => {
32- const port = ports[name]
33- this.kernel.id(port).then(id => {
11+ async start () {
12+ // map ports to thier id's
13+ let ports = Object.keys(this.ports).map(name => {
14+ const port = this.ports[name]
15+ this.hypervisor.generateID(port).then(id => {
3416 return [id, new Port(name)]
3517 })
3618 })
19+
20+ // create the parent port
21+ ports.push(this.hypervisor.generateID(this.kernel._opts.id).then(id => {
22+ return [id, new Port('parent')]
23+ }))
3724 ports = await Promise.all(ports)
38- return new Map(ports)
25+ this._portMap = new Map(ports)
3926 }
4027
28+ queue (message) {
29+ this._portMap.get(message.fromPort).queue(message)
30+ }
31+
4132 create (name, value) {
4233 this.ports[name] = value
4334 }
4435
@@ -51,13 +42,18 @@
5142 delete this.ports[from]
5243 }
5344
5445 async get (name) {
55- const port = await name === common.PARENT ? this.graph.get(this.state.ports, name) : this.parentId
56- const id = await this.kernel.id(port)
46+ const port = await this.graph.get(this.state.ports, name)
47+ const id = await this.hypervisor.generateID(port)
5748 return this._portMap.get(id)
5849 }
5950
51+ async getParent () {
52+ const id = await this.hypervisor.generateID(this.kernel._opts.id)
53+ return this._portMap.get(id)
54+ }
55+
6056 // waits till all ports have reached a threshold tick count
6157 async wait (threshold) {
6258 // find the ports that have a smaller tick count then the threshold tick count
6359 const unkownPorts = [...this._ports].filter((id, port) => {
@@ -65,9 +61,9 @@
6561 return !message || message.ticks < threshold
6662 })
6763
6864 const promises = unkownPorts.map(port => {
69- this.hypervisor.waitOnVM(port, threshold).then(ticks => {
65+ this.hypervisor.wait(port, threshold).then(ticks => {
7066 // update the port's tick count
7167 port.ticks = ticks
7268 })
7369 })
@@ -75,9 +71,9 @@
7571 }
7672
7773 async getNextMessage (ticks) {
7874 await this.wait(ticks)
79- return [...this._ports].reduce(messageArbiter).shift()
75+ return [...this._portMap].reduce(messageArbiter).shift()
8076 }
8177 }
8278
8379 // decides which message to go firts
tests/index.jsView
@@ -1,10 +1,74 @@
11 const tape = require('tape')
2-const ipfs = require('ipfs')
3-const graph = require('ipld-graph-builder')
2+const IPFS = require('ipfs')
43 const Hypervisor = require('../')
4+const Message = require('primea-message')
55
6-tape('base kernel tests', t => {
7- const state = {}
8- const hypervisor = new Hypervisor()
9- t.equal()
6+const node = new IPFS()
7+node.on('error', err => {
8+ console.log(err)
109 })
10+
11+node.on('start', () => {
12+ tape.only('basic', async t => {
13+ const testVM = {
14+ run (message) {
15+ console.log('made it!!!!')
16+ }
17+ }
18+
19+ try {
20+ const state = {
21+ id: {
22+ nonce: new Uint8Array([0]),
23+ parent: new Uint8Array()
24+ },
25+ type: 'test',
26+ vm: {
27+ ports: {}
28+ }
29+ }
30+
31+ const hypervisor = new Hypervisor(node.dag)
32+ hypervisor.addVM('test', testVM)
33+
34+ const message = new Message()
35+ await hypervisor.send(state, message)
36+
37+ await hypervisor.createStateRoot(state, Infinity)
38+ console.log(state)
39+
40+ node.stop(() => {
41+ t.end()
42+ process.exit()
43+ })
44+ } catch (e) {
45+ console.log(e)
46+ }
47+ })
48+
49+ tape('messaging', t => {
50+ // const state = {
51+ // id: {},
52+ // ports: {
53+ // first: {
54+ // id: {
55+ // nonce: 1,
56+ // parent: 'hash'
57+ // },
58+ // code: 'js code',
59+ // type: 'test',
60+ // ports: {
61+
62+ // }
63+ // }
64+ // }
65+ // }
66+ // const message = new Message({
67+ // type: 'create',
68+ // path: 'first',
69+ // data: jsCode
70+ // })
71+ // hypervisor.send(port, message)
72+
73+ })
74+})
common.jsView
@@ -1,16 +1,0 @@
1-const Message = require('primea-message')
2-
3-exports.PARENT = '..'
4-exports.ROOT = '/'
5-exports.getterMessage = (name, path) => {
6- const message = new Message({
7- data: {
8- getValue: name
9- },
10- sync: true
11- })
12- if (path) {
13- message.to = path
14- }
15- return message
16-}
crypto.jsView
@@ -1,0 +1,4 @@
1+const WebCrypto = require('node-webcrypto-ossl')
2+module.exports = new WebCrypto({
3+ directory: `${__dirname}/.webcrypto`
4+})
tools/wabtView
@@ -1,1 +1,0 @@
1-Subproject commit 2177e7517b857d557cbf9b8477c31f96a8ed66bb

Built with git-ssb-web