git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit a12fcbf698618cd91b74a1da931067ede4b57f45

use primea messaging

wanderer committed on 4/3/2017, 10:03:46 PM
Parent: 0e68cbae9b8717bdfa591e624e3135e8a84ecea5

Files changed

EVMinterface.jschanged
codeHandler.jschanged
common.jschanged
defaultAgent.jschanged
hypervisor.jschanged
index.jschanged
package.jsonchanged
port.jschanged
portManager.jschanged
tests/apiTests.jschanged
tests/interfaceRunner.jschanged
message.jsdeleted
EVMinterface.jsView
@@ -3,12 +3,12 @@
33 * enables to interact with the Ethereum Environment
44 */
55 const fs = require('fs')
66 const ethUtil = require('ethereumjs-util')
7-const Vertex = require('merkle-trie')
7+const Vertex = require('ipld-graph-builder')
88 const U256 = require('fixed-bn.js').U256
99 const U128 = require('fixed-bn.js').U128
10-const Message = require('./message.js')
10+const Message = require('primea-message')
1111 const common = require('./common.js')
1212
1313 const U128_SIZE_BYTES = 16
1414 const ADDRESS_SIZE_BYTES = 20
codeHandler.jsView
@@ -1,31 +1,33 @@
11 const Wasm = require('primea-wasm-container')
22
33 const defaultHandler = {
4- test: (code) => {
5- return !code
4+ test: (state) => {
5+ return !state.code
66 },
77 init: () => {
88 return require('./defaultAgent.js')
99 }
1010 }
1111
1212 const wasm = {
13- test: (code) => {
14- code = new Buffer(code)
13+ test: (state) => {
14+ const code = new Buffer(state.code)
1515 return code && code.slice(0, 4).toString() === '\x00asm'
1616 },
1717 init: (code) => {
1818 return new Wasm(code)
1919 }
2020 }
2121
2222 const javascript = {
23- test: (code) => {
24- return typeof code === 'object'
23+ test: (state) => {
24+ return typeof state.code === 'function'
2525 },
26- init: (code) => {
27- return code
26+ init: (state) => {
27+ return {
28+ run: state.code
29+ }
2830 }
2931 }
3032
3133 let codeHandlers = exports.handlers = {
common.jsView
@@ -1,8 +1,8 @@
1-const Message = require('./message')
1+const Message = require('primea-message')
22
3-exports.PARENT = 0
4-exports.ROOT = 1
3+exports.PARENT = '..'
4+exports.ROOT = '/'
55 exports.getterMessage = (name, path) => {
66 const message = new Message({
77 data: {
88 getValue: name
defaultAgent.jsView
@@ -1,9 +1,9 @@
11 exports.run = async (message, kernel) => {
2- const to = message.to[message.hops]
2+ const to = message.nextPort()
33 if (to !== undefined) {
4- return kernel.send(message)
4+ await kernel.send(message)
5+ return
56 } else if (message.data.getValue) {
6- console.log('get value')
77 return (await kernel.state.get(message.data.getValue)).value
88 }
99 }
hypervisor.jsView
@@ -1,23 +1,20 @@
11 const Kernel = require('./index.js')
2-const Vertex = require('merkle-trie')
3-// const Block = require('./deps/block.js')
4-// const blockchain = require('./fakeBlockChain.js')
52 const codeHandlers = require('./codeHandler.js')
63
74 module.exports = class Hypervisor {
8- constructor (state = new Vertex(), imports = []) {
5+ constructor (graph, state, imports = []) {
96 this.state = state
7+ this.graph = graph
108 this.root = new Kernel({
119 imports: imports,
10+ graph: graph,
1211 state: state
1312 })
1413 }
1514
16- set (path, kernel) {
17- this.state.set(path, new Vertex({
18- value: kernel
19- }))
15+ set (path, value) {
16+ return this.graph.set(this.state, path, value)
2017 }
2118
2219 send (message) {
2320 return this.root.send(message)
index.jsView
@@ -1,33 +1,40 @@
11 const EventEmitter = require('events')
2-const Vertex = require('merkle-trie')
32 const PortManager = require('./portManager.js')
43 const codeHandler = require('./codeHandler.js')
54
65 module.exports = class Kernel extends EventEmitter {
76 constructor (opts = {}) {
87 super()
98 // set up the state
10- const state = this.state = opts.state || new Vertex()
11- this.path = state.path
9+ this.graph = opts.graph
10+ this.path = opts.path || ''
11+ this.imports = opts.imports
12+ const state = this.state = opts.state || {}
1213
1314 // set up the vm
14- this.imports = opts.imports
15- this._vm = (opts.codeHandler || codeHandler).init(opts.code || state.value)
15+ this._vm = (opts.codeHandler || codeHandler).init(opts.code || state)
1616 this._vmstate = 'idle'
1717
1818 // set up ports
19- this.ports = new PortManager(state, opts.parentPort, Kernel, this.imports)
19+ this.ports = new PortManager({
20+ state: state,
21+ graph: this.graph,
22+ parentPort: opts.parentPort,
23+ Kernel: Kernel,
24+ imports: this.imports,
25+ path: this.path
26+ })
27+
2028 this.ports.on('message', index => {
2129 this.runNextMessage(index)
2230 })
23- this._sentAtomicMessages = []
2431 }
2532
2633 runNextMessage (index = 0) {
2734 // load the next message from port space
2835 return this.ports.peek(index).then(message => {
29- if (message && (message._isCyclic(this) || this._vmstate === 'idle')) {
36+ if (message && (message.isCyclic(this) || this._vmstate === 'idle')) {
3037 this._currentMessage = message
3138 this.ports.remove(index)
3239 return this.run(message)
3340 } else {
@@ -42,18 +49,17 @@
4249 * The Kernel Stores all of its state in the Environment. The Interface is used
4350 * to by the VM to retrive infromation from the Environment.
4451 */
4552 async run (message, imports = this.imports) {
53+ const self = this
4654 function revert (oldState) {
4755 // revert the state
48- this.state.set([], oldState)
49- // revert all the sent messages
50- for (let msg in this._sentAtomicMessages) {
51- msg.revert()
52- }
56+ clearObject(self.state)
57+ Object.assign(self.state, oldState)
5358 }
5459
55- const oldState = this.state.copy()
60+ // shallow copy
61+ const oldState = Object.assign({}, this.state)
5662 let result
5763 this._vmstate = 'running'
5864 try {
5965 result = await this._vm.run(message, this, imports) || {}
@@ -63,44 +69,40 @@
6369 exceptionError: e
6470 }
6571 }
6672
67- if (message.atomic) {
68- // if we trapped revert all the sent messages
69- if (result.execption) {
70- // revert to the old state
71- revert(oldState)
72- }
73- message._finish()
74- message.result().then(result => {
75- if (result.execption) {
76- revert()
77- } else {
78- this.runNextMessage(0)
79- }
80- })
73+ // if we trapped revert all the sent messages
74+ if (result.exception) {
75+ // revert to the old state
76+ revert(oldState)
77+ message.reject(result)
78+ } else if (!message.hasResponded) {
79+ message.respond(result)
80+ }
8181
82- if (message.hops === message.to.length || result.exception) {
83- message._respond(result)
84- }
85- } else {
86- // non-atomic messages
82+ message.committed().then(() => {
8783 this.runNextMessage(0)
88- }
84+ }).catch((e) => {
85+ revert(oldState)
86+ })
8987 return result
9088 }
9189
9290 async send (message) {
9391 if (message.atomic) {
9492 // record that this message has traveled thourgh this kernel. This is used
9593 // to detect re-entry
9694 message._visited(this, this._currentMessage)
97- // recoded that this message was sent, so that we can revert it if needed
98- this._sentAtomicMessages.push(message)
9995 }
10096 return this.ports.send(message)
10197 }
10298
10399 shutdown () {
104100 this.ports.close()
105101 }
106102 }
103+
104+function clearObject (myObject) {
105+ for (var member in myObject) {
106+ delete myObject[member]
107+ }
108+}
package.jsonView
@@ -27,8 +27,9 @@
2727 "contributors": "Alex Beregszaszi <alex@rtfs.hu>",
2828 "license": "MPL-2.0",
2929 "devDependencies": {
3030 "coveralls": "^2.11.16",
31+ "ipfs": "^0.23.1",
3132 "istanbul": "^1.1.0-alpha.1",
3233 "standard": "10.0.0-beta.0",
3334 "tape": "^4.5.1"
3435 },
@@ -40,8 +41,9 @@
4041 "WebAssembly"
4142 ]
4243 },
4344 "dependencies": {
45+ "deepcopy": "^0.6.3",
4446 "ethereumjs-block": "^1.5.0",
4547 "ethereumjs-tx": "^1.2.5",
4648 "ethereumjs-util": "^5.1.0",
4749 "fixed-bn.js": "0.0.2",
port.jsView
@@ -15,9 +15,9 @@
1515 }
1616 }
1717
1818 async send (message) {
19- message.hops++
19+ message._hops++
2020 this.destPort.recieve(message)
2121 }
2222
2323 async recieve (message) {
portManager.jsView
@@ -1,15 +1,14 @@
11 const EventEmitter = require('events')
2+const path = require('path')
23 const Port = require('./port.js')
34 const common = require('./common.js')
45
56 module.exports = class PortManager extends EventEmitter {
6- constructor (state, destParentPort, KernelContructor, imports) {
7+ constructor (opts) {
78 super()
9+ Object.assign(this, opts)
810 this._queue = []
9- this.state = state
10- this.imports = imports
11- this.Kernel = KernelContructor
1211 // set up the parent port
1312 const parentPort = new Port(common.PARENT)
1413 parentPort.on('message', message => {
1514 this._recieveMessage(message)
@@ -32,13 +31,16 @@
3231 port.on('message', message => {
3332 this._recieveMessage(message)
3433 })
3534 // create destination kernel
36- const state = await this.state.get(name)
35+ const state = await this.graph.get(this.state, name)
36+
3737 const destKernel = new this.Kernel({
3838 state: state,
39+ graph: this.graph,
3940 parentPort: port,
40- imports: this.imports
41+ imports: this.imports,
42+ path: path.join(this.path, name)
4143 })
4244
4345 // shutdown the kernel when it is done doing it work
4446 destKernel.on('idle', () => {
tests/apiTests.jsView
@@ -1,53 +1,65 @@
11 const tape = require('tape')
22 const Hypervisor = require('../hypervisor.js')
3-const Message = require('../message.js')
4-const Vertex = require('merkle-trie')
3+const Message = require('primea-message')
4+const IPFS = require('ipfs')
5+const Graph = require('ipld-graph-builder')
56
6-tape('send and reciving messages', async t => {
7- try {
8- const hypervisor = new Hypervisor()
9- const path = ['one', 'two', 'three']
10- hypervisor.set(path, {
11- run: message => {
12- t.pass('got message')
13- t.end()
14- return {}
15- }
16- })
17- hypervisor.send(new Message({
18- to: path
19- }))
20- } catch (e) {
21- console.log(e)
22- }
23-})
7+const ipfs = new IPFS()
8+const graph = new Graph(ipfs)
249
25-tape('reverts', async t => {
26- const hypervisor = new Hypervisor()
27- const path = ['one', 'two', 'three']
28- const path2 = ['one', 'two', 'three', 'four']
29- hypervisor.set(path, {
30- run: async (message, kernel) => {
31- await kernel.send(new Message({
32- to: ['four']
10+ipfs.on('start', async () => {
11+ tape('send and reciving messages', async t => {
12+ const root = {}
13+ try {
14+ const hypervisor = new Hypervisor(graph, root)
15+ const path = 'one/two/three'
16+ await hypervisor.set(path, {
17+ code: message => {
18+ t.pass('got message')
19+ t.end()
20+ return {}
21+ }
22+ })
23+ hypervisor.send(new Message({
24+ to: path
3325 }))
34- throw new Error('vm exception')
26+ } catch (e) {
27+ // console.log(e)
3528 }
3629 })
3730
38- hypervisor.set(path2, {
39- run: (message, kernel) => {
40- kernel.stateInterface.set('key', new Vertex({
41- value: 'value'
42- }))
43- }
44- })
31+ tape('reverts', async t => {
32+ const root = {}
33+ const hypervisor = new Hypervisor(graph, root)
34+ const path = 'one/two/three'
35+ const path2 = 'one/two/three/four'
36+ await hypervisor.set(path, {
37+ code: async (message, kernel) => {
38+ await kernel.send(new Message({
39+ to: 'four'
40+ }))
41+ throw new Error('vm exception')
42+ }
43+ })
4544
46- const message = new Message({
47- to: path
45+ await hypervisor.set(path2, {
46+ code: (message, kernel) => {
47+ kernel.graph.set(kernel.state, 'something', {
48+ somevalue: 'value'
49+ })
50+ return 'done!'
51+ }
52+ })
53+
54+ const message = new Message({
55+ to: path
56+ })
57+ hypervisor.send(message)
58+ const result = await message.result()
59+ t.equals(result.exception, true)
60+ const expectedRoot = '{"one":{"two":{"three":{"/":{"four":{"/":{}}}}}}}'
61+ t.equals(JSON.stringify(root), expectedRoot, 'should produce correct root')
62+ t.end()
63+ process.exit()
4864 })
49- hypervisor.send(message)
50- const result = await message.result()
51- t.equals(result.exception, true)
52- t.end()
5365 })
tests/interfaceRunner.jsView
@@ -1,14 +1,14 @@
11 const tape = require('tape')
22 const fs = require('fs')
3-const Vertex = require('merkle-trie')
3+const Vertex = require('ipld-graph-builder')
44 const Block = require('../deps/block')
55 const U128 = require('fixed-bn.js').U128
66 const Address = require('fixed-bn.js').Address
77 // TODO remove fakeblockchain
88 const fakeBlockChain = require('../fakeBlockChain.js')
99 const Hypervisor = require('../hypervisor.js')
10-const Message = require('../message.js')
10+const Message = require('primea-message')
1111 const common = require('../common')
1212 const EVMinterface = require('../EVMinterface.js')
1313
1414 const dir = `${__dirname}/interface`
message.jsView
@@ -1,49 +1,0 @@
1-const U128 = require('fixed-bn.js').U128
2-
3-module.exports = class Message {
4- constructor (opts = {}) {
5- const defaults = {
6- // call infromation
7- to: [],
8- from: [],
9- data: new Uint8Array(),
10- atomic: true,
11- // resource info
12- gas: new U128(0),
13- gasPrices: new U128(0)
14- }
15- Object.assign(this, defaults, opts)
16- this.hops = 0
17- this._visitedKernels = []
18- this._resultPromise = new Promise((resolve, reject) => {
19- this._resolve = resolve
20- })
21- }
22-
23- result () {
24- return this._resultPromise
25- }
26-
27- nextPort () {
28- return this.to[this.hops]
29- }
30-
31- _respond (result) {
32- this._resolve(result)
33- }
34-
35- _finish () {
36- this._visitedKernels.pop()
37- }
38-
39- _visited (kernel, currentMessage) {
40- if (currentMessage && this !== currentMessage) {
41- this._visitedKernels = currentMessage._visitedKernels
42- }
43- this._visitedKernels.push(kernel)
44- }
45-
46- _isCyclic (kernel) {
47- return this.atomic && this._visitedKernels.some(process => process === kernel)
48- }
49-}

Built with git-ssb-web