Commit 04dbe177869d576e3ab383ecd787fc9c1aed4f0d
updated evm interface
wanderer committed on 1/25/2017, 6:59:52 PMParent: 90c78a592cb45542546f035167e39d219a6eaaf1
Files changed
EVMinterface.js | changed |
codeHandler.js | changed |
common.js | changed |
index.js | changed |
vm.js | deleted |
wasmAgent.js | added |
EVMinterface.js | ||
---|---|---|
@@ -15,14 +15,14 @@ | ||
15 | 15 | const U256_SIZE_BYTES = 32 |
16 | 16 | |
17 | 17 | // The interface exposed to the WebAessembly VM |
18 | 18 | module.exports = class Interface { |
19 | - constructor (api, message) { | |
19 | + constructor (api, message, results) { | |
20 | + results.gasRefund = 0 | |
20 | 21 | this.message = message |
21 | 22 | this.kernel = api.kernel |
22 | - this.state = api.kernel.state | |
23 | 23 | this.api = api |
24 | - this._results = {} | |
24 | + this.results = results | |
25 | 25 | const shimBin = fs.readFileSync(path.join(__dirname, '/wasm/interface.wasm')) |
26 | 26 | const shimMod = WebAssembly.Module(shimBin) |
27 | 27 | this.shims = WebAssembly.Instance(shimMod, { |
28 | 28 | 'interface': { |
@@ -34,27 +34,12 @@ | ||
34 | 34 | }) |
35 | 35 | } |
36 | 36 | |
37 | 37 | async initialize () { |
38 | - this.block = await this.kernel.send(common.ROOT, new Message({ | |
39 | - data: { | |
40 | - getValue: 'block' | |
41 | - }, | |
42 | - sync: true | |
43 | - })) | |
44 | - | |
45 | - this.blockchain = await this.kernel.send(common.ROOT, new Message({ | |
46 | - data: { | |
47 | - getValue: 'blockchain' | |
48 | - }, | |
49 | - sync: true | |
50 | - })) | |
38 | + this.block = await this.kernel.send(common.ROOT, common.getterMessage('block')) | |
39 | + this.blockchain = await this.kernel.send(common.ROOT, common.getterMessage('blockchain')) | |
51 | 40 | } |
52 | 41 | |
53 | - get results () { | |
54 | - return this._results | |
55 | - } | |
56 | - | |
57 | 42 | static get name () { |
58 | 43 | return 'ethereum' |
59 | 44 | } |
60 | 45 | |
@@ -246,14 +231,10 @@ | ||
246 | 231 | */ |
247 | 232 | getCodeSize (cbIndex) { |
248 | 233 | this.takeGas(2) |
249 | 234 | |
250 | - const opPromise = this.state | |
251 | - .get('code') | |
252 | - .then(vertex => vertex.value.length) | |
253 | - | |
254 | 235 | // wait for all the prevouse async ops to finish before running the callback |
255 | - this.kernel.pushOpsQueue(opPromise, cbIndex, length => length) | |
236 | + this.kernel.pushOpsQueue(this.kernel.code.length, cbIndex, length => length) | |
256 | 237 | } |
257 | 238 | |
258 | 239 | /** |
259 | 240 | * Copys the code running in current environment to memory. |
@@ -263,20 +244,10 @@ | ||
263 | 244 | */ |
264 | 245 | codeCopy (resultOffset, codeOffset, length, cbIndex) { |
265 | 246 | this.takeGas(3 + Math.ceil(length / 32) * 3) |
266 | 247 | |
267 | - let opPromise | |
268 | - | |
269 | - if (length) { | |
270 | - opPromise = this.state | |
271 | - .get('code') | |
272 | - .then(vertex => vertex.value) | |
273 | - } else { | |
274 | - opPromise = Promise.resolve([]) | |
275 | - } | |
276 | - | |
277 | 248 | // wait for all the prevouse async ops to finish before running the callback |
278 | - this.kernel.pushOpsQueue(opPromise, cbIndex, code => { | |
249 | + this.kernel.pushOpsQueue(this.kernel.code, cbIndex, code => { | |
279 | 250 | if (code.length) { |
280 | 251 | code = code.slice(codeOffset, codeOffset + length) |
281 | 252 | this.setMemory(resultOffset, length, code) |
282 | 253 | } |
@@ -289,11 +260,10 @@ | ||
289 | 260 | * @return {integer} |
290 | 261 | */ |
291 | 262 | getExternalCodeSize (addressOffset, cbOffset) { |
292 | 263 | this.takeGas(20) |
293 | - const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code'] | |
294 | - const opPromise = this.state.root | |
295 | - .get(address) | |
264 | + const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)] | |
265 | + const opPromise = this.kernel.sendMessage(common.ROOT, common.getterMessage('code', address)) | |
296 | 266 | .then(vertex => vertex.value.length) |
297 | 267 | .catch(() => 0) |
298 | 268 | |
299 | 269 | // wait for all the prevouse async ops to finish before running the callback |
@@ -309,13 +279,13 @@ | ||
309 | 279 | */ |
310 | 280 | externalCodeCopy (addressOffset, resultOffset, codeOffset, length, cbIndex) { |
311 | 281 | this.takeGas(20 + Math.ceil(length / 32) * 3) |
312 | 282 | |
313 | - const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code'] | |
283 | + const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)] | |
314 | 284 | let opPromise |
315 | 285 | |
316 | 286 | if (length) { |
317 | - opPromise = this.state.root | |
287 | + opPromise = this.kernel.sendMessage(common.ROOT, common.getterMessage('code', address)) | |
318 | 288 | .get(address) |
319 | 289 | .then(vertex => vertex.value) |
320 | 290 | .catch(() => []) |
321 | 291 | } else { |
@@ -348,9 +318,9 @@ | ||
348 | 318 | */ |
349 | 319 | getBlockHash (number, offset, cbOffset) { |
350 | 320 | this.takeGas(20) |
351 | 321 | |
352 | - const diff = this.kernel.environment.block.number - number | |
322 | + const diff = this.block.number - number | |
353 | 323 | let opPromise |
354 | 324 | |
355 | 325 | if (diff > 256 || diff <= 0) { |
356 | 326 | opPromise = Promise.resolve(new U256(0)) |
@@ -380,9 +350,9 @@ | ||
380 | 350 | */ |
381 | 351 | getBlockTimestamp () { |
382 | 352 | this.takeGas(2) |
383 | 353 | |
384 | - return this.kernel.environment.block.timestamp | |
354 | + return this.block.timestamp | |
385 | 355 | } |
386 | 356 | |
387 | 357 | /** |
388 | 358 | * Get the block’s number. |
@@ -390,9 +360,9 @@ | ||
390 | 360 | */ |
391 | 361 | getBlockNumber () { |
392 | 362 | this.takeGas(2) |
393 | 363 | |
394 | - return this.kernel.environment.block.number | |
364 | + return this.block.number | |
395 | 365 | } |
396 | 366 | |
397 | 367 | /** |
398 | 368 | * Get the block’s difficulty. |
@@ -400,9 +370,9 @@ | ||
400 | 370 | */ |
401 | 371 | getBlockDifficulty (offset) { |
402 | 372 | this.takeGas(2) |
403 | 373 | |
404 | - this.setMemory(offset, U256_SIZE_BYTES, this.kernel.environment.block.difficulty.toMemory()) | |
374 | + this.setMemory(offset, U256_SIZE_BYTES, this.block.difficulty.toMemory()) | |
405 | 375 | } |
406 | 376 | |
407 | 377 | /** |
408 | 378 | * Get the block’s gas limit. |
@@ -410,9 +380,9 @@ | ||
410 | 380 | */ |
411 | 381 | getBlockGasLimit () { |
412 | 382 | this.takeGas(2) |
413 | 383 | |
414 | - return this.kernel.environment.block.gasLimit | |
384 | + return this.message.gasLimit | |
415 | 385 | } |
416 | 386 | |
417 | 387 | /** |
418 | 388 | * Creates a new log in the current environment |
@@ -593,24 +563,24 @@ | ||
593 | 563 | const path = [new Buffer(this.getMemory(pathOffset, U256_SIZE_BYTES)).toString('hex')] |
594 | 564 | // copy the value |
595 | 565 | const value = this.getMemory(valueOffset, U256_SIZE_BYTES).slice(0) |
596 | 566 | const valIsZero = value.every((i) => i === 0) |
597 | - const opPromise = this.state.get(path) | |
567 | + const opPromise = this.kernel.getValue(path) | |
598 | 568 | .then(vertex => vertex.value) |
599 | 569 | .catch(() => null) |
600 | 570 | |
601 | 571 | this.api.pushOpsQueue(opPromise, cbIndex, oldValue => { |
602 | 572 | if (valIsZero && oldValue) { |
603 | 573 | // delete a value |
604 | - this.kernel.environment.gasRefund += 15000 | |
605 | - this.state.del(path) | |
574 | + this.results.gasRefund += 15000 | |
575 | + this.kernel.deleteValue(path) | |
606 | 576 | } else { |
607 | 577 | if (!valIsZero && !oldValue) { |
608 | 578 | // creating a new value |
609 | 579 | this.takeGas(15000) |
610 | 580 | } |
611 | 581 | // update |
612 | - this.state.set(path, new Vertex({ | |
582 | + this.kernel.setValue(path, new Vertex({ | |
613 | 583 | value: value |
614 | 584 | })) |
615 | 585 | } |
616 | 586 | }) |
@@ -626,9 +596,9 @@ | ||
626 | 596 | |
627 | 597 | // convert the path to an array |
628 | 598 | const path = [new Buffer(this.getMemory(pathOffset, U256_SIZE_BYTES)).toString('hex')] |
629 | 599 | // get the value from the state |
630 | - const opPromise = this.state.get(path) | |
600 | + const opPromise = this.kernel.getValue(path) | |
631 | 601 | .then(vertex => vertex.value) |
632 | 602 | .catch(() => new Uint8Array(32)) |
633 | 603 | |
634 | 604 | this.api.pushOpsQueue(opPromise, cbIndex, value => { |
@@ -642,9 +612,9 @@ | ||
642 | 612 | * @param {integer} length the length of the output data. |
643 | 613 | */ |
644 | 614 | return (offset, length) { |
645 | 615 | if (length) { |
646 | - this.kernel.environment.returnValue = this.getMemory(offset, length).slice(0) | |
616 | + this.results.returnValue = this.getMemory(offset, length).slice(0) | |
647 | 617 | } |
648 | 618 | } |
649 | 619 | |
650 | 620 | /** |
@@ -652,11 +622,11 @@ | ||
652 | 622 | * balance to an address path |
653 | 623 | * @param {integer} offset the offset to load the address from |
654 | 624 | */ |
655 | 625 | selfDestruct (addressOffset) { |
656 | - this.kernel.environment.selfDestruct = true | |
657 | - this.kernel.environment.selfDestructAddress = this.getMemory(addressOffset, ADDRESS_SIZE_BYTES) | |
658 | - this.kernel.environment.gasRefund += 24000 | |
626 | + this.results.selfDestruct = true | |
627 | + this.results.selfDestructAddress = this.getMemory(addressOffset, ADDRESS_SIZE_BYTES) | |
628 | + this.results.gasRefund += 24000 | |
659 | 629 | } |
660 | 630 | |
661 | 631 | getMemory (offset, length) { |
662 | 632 | return new Uint8Array(this.api.memory(), offset, length) |
codeHandler.js | ||
---|---|---|
@@ -1,5 +1,5 @@ | ||
1 | -const Wasm = require('./vm.js') | |
1 | +const Wasm = require('./wasmAgent.js') | |
2 | 2 | |
3 | 3 | const defaultHandler = { |
4 | 4 | test: (code) => { |
5 | 5 | return !code |
common.js | ||
---|---|---|
@@ -1,2 +1,13 @@ | ||
1 | +const Message = require('./message') | |
2 | + | |
1 | 3 | exports.PARENT = Symbol('parent') |
2 | 4 | exports.ROOT = Symbol('root') |
5 | +exports.getterMessage = (name, path) => { | |
6 | + return new Message({ | |
7 | + to: path, | |
8 | + data: { | |
9 | + getValue: name | |
10 | + }, | |
11 | + sync: true | |
12 | + }) | |
13 | +} |
index.js | ||
---|---|---|
@@ -22,14 +22,14 @@ | ||
22 | 22 | * The Kernel Stores all of its state in the Environment. The Interface is used |
23 | 23 | * to by the VM to retrive infromation from the Environment. |
24 | 24 | */ |
25 | 25 | async run (message, imports = this.imports) { |
26 | - const state = this.state.copy() | |
27 | - const result = await this._vm.run(message, this, imports, state) | |
28 | - if (!result.execption) { | |
29 | - // update the state | |
30 | - this.state.set([], state) | |
31 | - } | |
26 | + // const state = this.state.copy() | |
27 | + const result = await this._vm.run(message, this, imports) | |
28 | + // if (!result.execption) { | |
29 | + // // update the state | |
30 | + // this.state.set([], state) | |
31 | + // } | |
32 | 32 | return result |
33 | 33 | } |
34 | 34 | |
35 | 35 | async recieve (message) { |
@@ -58,5 +58,9 @@ | ||
58 | 58 | |
59 | 59 | getValue (name) { |
60 | 60 | return this.state.get(name) |
61 | 61 | } |
62 | + | |
63 | + deleteValue (name) { | |
64 | + return this.state.del(name) | |
65 | + } | |
62 | 66 | } |
vm.js | ||
---|---|---|
@@ -1,66 +1,0 @@ | ||
1 | -module.exports = class Wasm { | |
2 | - /** | |
3 | - * The interface API is the api the exposed to interfaces. All queries about | |
4 | - * the enviroment and call to the kernel go through this API | |
5 | - */ | |
6 | - constructor (code) { | |
7 | - this._module = WebAssembly.Module(code) | |
8 | - } | |
9 | - /** | |
10 | - * Runs the core VM with a given environment and imports | |
11 | - */ | |
12 | - async run (message, kernel, imports, state) { | |
13 | - const responses = {} | |
14 | - /** | |
15 | - * Builds a import map with an array of given interfaces | |
16 | - */ | |
17 | - async function buildImports (kernelApi, kernel, imports) { | |
18 | - const importMap = {} | |
19 | - for (const Import of imports) { | |
20 | - const response = responses[Import.name] = {} | |
21 | - const newIterface = new Import(kernelApi, message, response, state) | |
22 | - importMap[Import.name] = newIterface.exports | |
23 | - // initailize the import | |
24 | - await newIterface.initialize() | |
25 | - } | |
26 | - return importMap | |
27 | - } | |
28 | - | |
29 | - let instance | |
30 | - const interfaceApi = { | |
31 | - /** | |
32 | - * adds an aync operation to the operations queue | |
33 | - */ | |
34 | - pushOpsQueue: (promise, callbackIndex, intefaceCallback) => { | |
35 | - this._opsQueue = Promise.all([this._opsQueue, promise]).then(values => { | |
36 | - const result = intefaceCallback(values.pop()) | |
37 | - instance.exports.callback.get(callbackIndex)(result) | |
38 | - }) | |
39 | - }, | |
40 | - memory: () => { | |
41 | - return instance.exports.memory.buffer | |
42 | - }, | |
43 | - kernel: kernel | |
44 | - } | |
45 | - | |
46 | - const initializedImports = await buildImports(interfaceApi, kernel, imports) | |
47 | - instance = WebAssembly.Instance(this._module, initializedImports) | |
48 | - | |
49 | - if (instance.exports.main) { | |
50 | - instance.exports.main() | |
51 | - } | |
52 | - await this.onDone() | |
53 | - return responses | |
54 | - } | |
55 | - | |
56 | - /** | |
57 | - * returns a promise that resolves when the wasm instance is done running | |
58 | - */ | |
59 | - async onDone () { | |
60 | - let prevOps | |
61 | - while (prevOps !== this._opsQueue) { | |
62 | - prevOps = this._opsQueue | |
63 | - await this._opsQueue | |
64 | - } | |
65 | - } | |
66 | -} |
wasmAgent.js | ||
---|---|---|
@@ -1,0 +1,66 @@ | ||
1 | +module.exports = class Wasm { | |
2 | + /** | |
3 | + * The interface API is the api the exposed to interfaces. All queries about | |
4 | + * the enviroment and call to the kernel go through this API | |
5 | + */ | |
6 | + constructor (code) { | |
7 | + this._module = WebAssembly.Module(code) | |
8 | + } | |
9 | + /** | |
10 | + * Runs the core VM with a given environment and imports | |
11 | + */ | |
12 | + async run (message, kernel, imports) { | |
13 | + const responses = {} | |
14 | + /** | |
15 | + * Builds a import map with an array of given interfaces | |
16 | + */ | |
17 | + async function buildImports (kernelApi, kernel, imports) { | |
18 | + const importMap = {} | |
19 | + for (const Import of imports) { | |
20 | + const response = responses[Import.name] = {} | |
21 | + const newIterface = new Import(kernelApi, message, response) | |
22 | + importMap[Import.name] = newIterface.exports | |
23 | + // initailize the import | |
24 | + await newIterface.initialize() | |
25 | + } | |
26 | + return importMap | |
27 | + } | |
28 | + | |
29 | + let instance | |
30 | + const interfaceApi = { | |
31 | + /** | |
32 | + * adds an aync operation to the operations queue | |
33 | + */ | |
34 | + pushOpsQueue: (promise, callbackIndex, intefaceCallback) => { | |
35 | + this._opsQueue = Promise.all([this._opsQueue, promise]).then(values => { | |
36 | + const result = intefaceCallback(values.pop()) | |
37 | + instance.exports.callback.get(callbackIndex)(result) | |
38 | + }) | |
39 | + }, | |
40 | + memory: () => { | |
41 | + return instance.exports.memory.buffer | |
42 | + }, | |
43 | + kernel: kernel | |
44 | + } | |
45 | + | |
46 | + const initializedImports = await buildImports(interfaceApi, kernel, imports) | |
47 | + instance = WebAssembly.Instance(this._module, initializedImports) | |
48 | + | |
49 | + if (instance.exports.main) { | |
50 | + instance.exports.main() | |
51 | + } | |
52 | + await this.onDone() | |
53 | + return responses | |
54 | + } | |
55 | + | |
56 | + /** | |
57 | + * returns a promise that resolves when the wasm instance is done running | |
58 | + */ | |
59 | + async onDone () { | |
60 | + let prevOps | |
61 | + while (prevOps !== this._opsQueue) { | |
62 | + prevOps = this._opsQueue | |
63 | + await this._opsQueue | |
64 | + } | |
65 | + } | |
66 | +} |
Built with git-ssb-web