Commit 60b86f48100a3b8a9db14f54689cabe117acdff3
fix tests
wanderer committed on 3/1/2017, 2:29:46 PMParent: 8ced6c46cc8f744d128a65d00c117a79e68918b8
Files changed
EVMinterface.js | changed |
hypervisor.js | changed |
index.js | changed |
message.js | changed |
port.js | changed |
portManager.js | changed |
tests/interfaceRunner.js | changed |
EVMinterface.js | ||
---|---|---|
@@ -458,32 +458,32 @@ | ||
458 | 458 | * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not |
459 | 459 | */ |
460 | 460 | _call (gasHigh, gasLow, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, cbIndex) { |
461 | 461 | this.takeGas(40) |
462 | - | |
463 | 462 | const gas = from64bit(gasHigh, gasLow) |
464 | 463 | // Load the params from mem |
465 | - const address = [common.PARENT, ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)] | |
464 | + const address = [common.PARENT, common.PARENT, ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)] | |
466 | 465 | const value = new U256(this.getMemory(valueOffset, U128_SIZE_BYTES)) |
467 | 466 | |
468 | 467 | // Special case for non-zero value; why does this exist? |
469 | 468 | if (!value.isZero()) { |
470 | 469 | this.takeGas(9000 - 2300 + gas) |
471 | 470 | this.takeGas(-gas) |
472 | 471 | } |
473 | 472 | |
474 | - // should be | |
475 | - let opPromise = this.kernel.send(new Message({ | |
473 | + const message = new Message({ | |
476 | 474 | to: address, |
477 | 475 | value: value |
478 | - })) | |
479 | - .catch(() => { | |
480 | - // why does this exist? | |
481 | - this.takeGas(25000) | |
482 | 476 | }) |
483 | 477 | |
478 | + const messagePromise = this.kernel.send(message).then(result => { | |
479 | + if (result.exception) { | |
480 | + this.takeGas(25000) | |
481 | + } | |
482 | + }) | |
483 | + | |
484 | 484 | // wait for all the prevouse async ops to finish before running the callback |
485 | - this.api.pushOpsQueue(opPromise, cbIndex, () => { | |
485 | + this.api.pushOpsQueue(messagePromise, cbIndex, () => { | |
486 | 486 | return 1 |
487 | 487 | }) |
488 | 488 | } |
489 | 489 |
hypervisor.js | ||
---|---|---|
@@ -1,21 +1,21 @@ | ||
1 | 1 | const Kernel = require('./index.js') |
2 | 2 | const Vertex = require('merkle-trie') |
3 | -const Block = require('./deps/block.js') | |
4 | -const blockchain = require('./fakeBlockChain.js') | |
3 | +// const Block = require('./deps/block.js') | |
4 | +// const blockchain = require('./fakeBlockChain.js') | |
5 | 5 | const codeHandlers = require('./codeHandler.js') |
6 | 6 | |
7 | 7 | module.exports = class Hypervisor { |
8 | 8 | constructor (state = new Vertex()) { |
9 | 9 | this.state = state |
10 | - if (state.isEmpty) { | |
11 | - state.set('block', new Vertex({ | |
12 | - value: new Block() | |
13 | - })) | |
14 | - state.set('blockchain', new Vertex({ | |
15 | - value: blockchain | |
16 | - })) | |
17 | - } | |
10 | + // if (state.isEmpty) { | |
11 | + // state.set('block', new Vertex({ | |
12 | + // value: new Block() | |
13 | + // })) | |
14 | + // state.set('blockchain', new Vertex({ | |
15 | + // value: blockchain | |
16 | + // })) | |
17 | + // } | |
18 | 18 | this.root = new Kernel({ |
19 | 19 | state: state |
20 | 20 | }) |
21 | 21 | } |
@@ -26,10 +26,9 @@ | ||
26 | 26 | })) |
27 | 27 | } |
28 | 28 | |
29 | 29 | send (message) { |
30 | - this.root.send(message) | |
31 | - return message.result() | |
30 | + return this.root.send(message) | |
32 | 31 | } |
33 | 32 | |
34 | 33 | addVM (type, handler) { |
35 | 34 | codeHandlers.handlers.type = handler |
index.js | ||
---|---|---|
@@ -3,30 +3,34 @@ | ||
3 | 3 | const PortManager = require('./portManager.js') |
4 | 4 | const StateInterface = require('./stateInterface.js') |
5 | 5 | const imports = require('./EVMinterface.js') |
6 | 6 | const codeHandler = require('./codeHandler.js') |
7 | -const common = require('./common.js') | |
8 | 7 | |
9 | 8 | module.exports = class Kernel extends EventEmitter { |
10 | 9 | constructor (opts = {}) { |
11 | 10 | super() |
11 | + // set up the state | |
12 | 12 | const state = this.state = opts.state || new Vertex() |
13 | 13 | this.stateInterface = new StateInterface(state) |
14 | - this.code = opts.code || state.value | |
15 | 14 | this.path = state.path |
15 | + | |
16 | + // set up the vm | |
16 | 17 | this.imports = opts.imports || [imports] |
17 | - this.ports = new PortManager(state, opts.parent, Kernel) | |
18 | + this._vm = (opts.codeHandler || codeHandler).init(opts.code || state.value) | |
19 | + this._state = 'idle' | |
20 | + | |
21 | + // set up ports | |
22 | + this.ports = new PortManager(state, opts.parentPort, Kernel) | |
18 | 23 | this._sentAtomicMessages = [] |
19 | - this._vm = (opts.codeHandler || codeHandler).init(this.code) | |
20 | - this._state = 'idle' | |
21 | 24 | this.ports.on('message', index => { |
22 | 25 | this.runNextMessage(index) |
23 | 26 | }) |
24 | 27 | } |
25 | 28 | |
26 | 29 | runNextMessage (index = 0) { |
27 | 30 | return this.ports.peek(index).then(message => { |
28 | - if (message && (message.isCyclic(this) || this._state === 'idle')) { | |
31 | + if (message && (message._isCyclic(this) || this._state === 'idle')) { | |
32 | + this._currentMessage = message | |
29 | 33 | this.ports.remove(index) |
30 | 34 | return this.run(message) |
31 | 35 | } else { |
32 | 36 | this._state = 'idle' |
@@ -40,34 +44,35 @@ | ||
40 | 44 | * The Kernel Stores all of its state in the Environment. The Interface is used |
41 | 45 | * to by the VM to retrive infromation from the Environment. |
42 | 46 | */ |
43 | 47 | async run (message, imports = this.imports) { |
44 | - function revert () { | |
48 | + function revert (oldState) { | |
45 | 49 | // revert the state |
46 | 50 | this.state.set([], oldState) |
47 | 51 | // revert all the sent messages |
48 | 52 | for (let msg in this._sentAtomicMessages) { |
49 | 53 | msg.revert() |
50 | 54 | } |
51 | - this.runNextMessage(0) | |
52 | 55 | } |
53 | 56 | |
54 | 57 | const oldState = this.state.copy() |
55 | 58 | let result |
56 | 59 | this._state = 'running' |
57 | 60 | try { |
58 | 61 | result = await this._vm.run(message, this, imports) || {} |
59 | 62 | } catch (e) { |
60 | - console.log(e) | |
61 | 63 | result = { |
62 | - exception: true | |
64 | + exception: true, | |
65 | + exceptionError: e | |
63 | 66 | } |
64 | 67 | } |
65 | - if (result.execption) { | |
66 | - // failed messages | |
67 | - revert() | |
68 | - } else if (message.atomic) { | |
69 | - // messages | |
68 | + | |
69 | + if (message.atomic) { | |
70 | + // if we trapped revert all the sent messages | |
71 | + if (result.execption) { | |
72 | + // revert to the old state | |
73 | + revert(oldState) | |
74 | + } | |
70 | 75 | message._finish() |
71 | 76 | message.result().then(result => { |
72 | 77 | if (result.execption) { |
73 | 78 | revert() |
@@ -75,9 +80,9 @@ | ||
75 | 80 | this.runNextMessage(0) |
76 | 81 | } |
77 | 82 | }) |
78 | 83 | |
79 | - if (message.hops === message.to.length) { | |
84 | + if (message.hops === message.to.length || result.exception) { | |
80 | 85 | message._respond(result) |
81 | 86 | } |
82 | 87 | } else { |
83 | 88 | // non-atomic messages |
@@ -86,25 +91,16 @@ | ||
86 | 91 | return result |
87 | 92 | } |
88 | 93 | |
89 | 94 | async send (message) { |
90 | - let portName = message.nextPort() | |
91 | - // replace root with parent path to root | |
92 | - if (portName === common.ROOT) { | |
93 | - message.to.shift() | |
94 | - message.to = new Array(this.path.length).fill(common.PARENT).concat(message.to) | |
95 | - portName = common.PARENT | |
96 | - } | |
97 | - message.addVistedKernel(this) | |
98 | - this.lastMessage = message | |
99 | - // console.log(portName, message) | |
100 | - const port = await this.ports.get(portName) | |
101 | - // save the atomic messages for possible reverts | |
102 | 95 | if (message.atomic) { |
96 | + // record that this message has traveled thourgh this kernel. This is used | |
97 | + // to detect re-entry | |
98 | + message._visited(this, this._currentMessage) | |
99 | + // recoded that this message was sent, so that we can revert it if needed | |
103 | 100 | this._sentAtomicMessages.push(message) |
104 | 101 | } |
105 | - port.send(message) | |
106 | - return message.result() | |
102 | + return this.ports.send(message) | |
107 | 103 | } |
108 | 104 | |
109 | 105 | shutdown () {} |
110 | 106 | } |
message.js | ||
---|---|---|
@@ -13,38 +13,37 @@ | ||
13 | 13 | gasPrices: new U256(0) |
14 | 14 | } |
15 | 15 | Object.assign(this, defaults, opts) |
16 | 16 | this.hops = 0 |
17 | - this._vistedKernels = [] | |
17 | + this._visitedKernels = [] | |
18 | 18 | this._resultPromise = new Promise((resolve, reject) => { |
19 | 19 | this._resolve = resolve |
20 | 20 | }) |
21 | 21 | } |
22 | 22 | |
23 | - _finish () { | |
24 | - if (this.atomic) { | |
25 | - this._vistedKernels.pop() | |
26 | - } | |
23 | + result () { | |
24 | + return this._resultPromise | |
27 | 25 | } |
28 | 26 | |
27 | + nextPort () { | |
28 | + return this.to[this.hops] | |
29 | + } | |
30 | + | |
29 | 31 | _respond (result) { |
30 | 32 | this._resolve(result) |
31 | 33 | } |
32 | 34 | |
33 | - result () { | |
34 | - return this._resultPromise | |
35 | + _finish () { | |
36 | + this._visitedKernels.pop() | |
35 | 37 | } |
36 | 38 | |
37 | - nextPort () { | |
38 | - return this.to[this.hops++] | |
39 | - } | |
40 | - | |
41 | - addVistedKernel (kernel) { | |
42 | - if (this.atomic) { | |
43 | - this._vistedKernels.push(kernel) | |
39 | + _visited (kernel, currentMessage) { | |
40 | + if (currentMessage && this !== currentMessage) { | |
41 | + this._visitedKernels = currentMessage._visitedKernels | |
44 | 42 | } |
43 | + this._visitedKernels.push(kernel) | |
45 | 44 | } |
46 | 45 | |
47 | - isCyclic (kernel) { | |
48 | - return this.atomic && this._vistedKernels.some(process => process === kernel) | |
46 | + _isCyclic (kernel) { | |
47 | + return this.atomic && this._visitedKernels.some(process => process === kernel) | |
49 | 48 | } |
50 | 49 | } |
port.js | ||
---|---|---|
@@ -15,8 +15,9 @@ | ||
15 | 15 | } |
16 | 16 | } |
17 | 17 | |
18 | 18 | async send (message) { |
19 | + message.hops++ | |
19 | 20 | this.destPort.recieve(message) |
20 | 21 | } |
21 | 22 | |
22 | 23 | async recieve (message) { |
portManager.js | ||
---|---|---|
@@ -24,9 +24,8 @@ | ||
24 | 24 | this.emit('message', index) |
25 | 25 | } |
26 | 26 | |
27 | 27 | async get (name) { |
28 | - console.log(name) | |
29 | 28 | let port = this.cache.get(name) |
30 | 29 | if (!port) { |
31 | 30 | port = new Port(name) |
32 | 31 | port.on('message', message => { |
@@ -35,9 +34,9 @@ | ||
35 | 34 | // create destination kernel |
36 | 35 | const state = await this.state.get(name) |
37 | 36 | const destKernel = new this.Kernel({ |
38 | 37 | state: state, |
39 | - parent: port | |
38 | + parentPort: port | |
40 | 39 | }) |
41 | 40 | |
42 | 41 | // shutdown the kernel when it is done doing it work |
43 | 42 | destKernel.on('idle', () => { |
@@ -60,8 +59,15 @@ | ||
60 | 59 | remove (index) { |
61 | 60 | return this._queue.splice(index, index + 1) |
62 | 61 | } |
63 | 62 | |
63 | + async send (message) { | |
64 | + let portName = message.nextPort() | |
65 | + const port = await this.get(portName) | |
66 | + port.send(message) | |
67 | + return message.result() | |
68 | + } | |
69 | + | |
64 | 70 | close () { |
65 | 71 | for (let port in this.cache) { |
66 | 72 | port.emit('close') |
67 | 73 | } |
tests/interfaceRunner.js | ||
---|---|---|
@@ -13,9 +13,9 @@ | ||
13 | 13 | |
14 | 14 | const dir = path.join(__dirname, '/interface') |
15 | 15 | // get the test names |
16 | 16 | let tests = fs.readdirSync(dir).filter((file) => file.endsWith('.wast')) |
17 | -tests = ['call.wast'] | |
17 | +// tests = ['call.wast'] | |
18 | 18 | |
19 | 19 | runTests(tests) |
20 | 20 | |
21 | 21 | function runTests (tests) { |
@@ -67,13 +67,10 @@ | ||
67 | 67 | message.gas = 1000000 |
68 | 68 | |
69 | 69 | try { |
70 | 70 | await hypervisor.send(message) |
71 | - console.log('done') | |
72 | 71 | } catch (e) { |
73 | 72 | t.fail('Exception: ' + e) |
74 | - console.error('FAIL') | |
75 | - console.error(e) | |
76 | 73 | } finally { |
77 | 74 | t.pass(testName) |
78 | 75 | } |
79 | 76 | t.end() |
Built with git-ssb-web