git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 97de846fb83df689a7ca6fed41f902c652d2a33e

Merge pull request #113 from primea/non-atomic

Non atomic
wanderer authored on 4/28/2017, 6:01:58 PM
GitHub committed on 4/28/2017, 6:01:58 PM
Parent: 9224a38130d9646acdb70e89eadcd3de8b626082
Parent: eacc6aefd1d880bdcfc1c451260d67651c742adb

Files changed

README.mdchanged
index.jschanged
package.jsonchanged
port.jschanged
portManager.jschanged
tests/apiTests.jsdeleted
tests/index.jsadded
tests/buildTests.jsdeleted
tests/interface/address.jsondeleted
tests/interface/address.wasmdeleted
tests/interface/address.wastdeleted
tests/interface/balance.jsondeleted
tests/interface/balance.wasmdeleted
tests/interface/balance.wastdeleted
tests/interface/basic_gas_ops.jsondeleted
tests/interface/basic_gas_ops.wasmdeleted
tests/interface/basic_gas_ops.wastdeleted
tests/interface/call.jsondeleted
tests/interface/call.wasmdeleted
tests/interface/call.wastdeleted
tests/interface/callDataCopy.jsondeleted
tests/interface/callDataCopy.wasmdeleted
tests/interface/callDataCopy.wastdeleted
tests/interface/callDataSize.jsondeleted
tests/interface/callDataSize.wasmdeleted
tests/interface/callDataSize.wastdeleted
tests/interface/callValue.jsondeleted
tests/interface/callValue.wasmdeleted
tests/interface/callValue.wastdeleted
tests/interface/caller.jsondeleted
tests/interface/caller.wasmdeleted
tests/interface/caller.wastdeleted
tests/interface/coinbase.jsondeleted
tests/interface/coinbase.wasmdeleted
tests/interface/coinbase.wastdeleted
tests/interface/default_enviroment.jsondeleted
tests/interface/origin.jsondeleted
tests/interface/origin.wasmdeleted
tests/interface/origin.wastdeleted
tests/interface/sstore.jsondeleted
tests/interface/sstore.wasmdeleted
tests/interface/sstore.wastdeleted
tests/interfaceRunner.jsdeleted
EVMinterface.jsdeleted
codeHandler.jsdeleted
common.jsdeleted
debugInterface.jsdeleted
kernel.jsadded
defaultAgent.jsdeleted
deps/block.jsdeleted
deps/rootVertex.jsdeleted
deps/transaction.jsdeleted
deps/utils.jsdeleted
fakeBlockChain.jsdeleted
hypervisor.jsdeleted
opcodes.jsdeleted
runBlock.jsdeleted
tools/wabtdeleted
wasm/interface.wasmdeleted
wasm/interface.wastdeleted
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,111 +1,87 @@
1-const EventEmitter = require('events')
2-const PortManager = require('./portManager.js')
3-const codeHandler = require('./codeHandler.js')
4-const AtomicMessage = require('primea-message/atomic')
1+const Graph = require('ipld-graph-builder')
2+const multibase = require('multibase')
3+const Kernel = require('./kernel.js')
54
6-module.exports = class Kernel extends EventEmitter {
7- constructor (opts = {}) {
8- super()
9- // set up the state
10- this.graph = opts.graph
11- this.path = opts.path || ''
12- this.imports = opts.imports
13- const state = this.state = opts.state || {}
5+module.exports = class Hypervisor {
6+ constructor (opts) {
7+ this._opts = {
8+ VMs: {}
9+ }
1410
15- // set up the vm
16- this._vm = (opts.codeHandler || codeHandler).init(opts.code || state)
17- this._vmstate = 'idle'
11+ this.graph = new Graph(opts.dag)
12+ delete opts.dag
13+ this._vmInstances = new Map()
14+ Object.assign(this._opts, opts)
15+ }
1816
19- // set up ports
20- this.ports = new PortManager({
21- state: state,
22- graph: this.graph,
23- parentPort: opts.parentPort,
24- Kernel: Kernel,
25- imports: this.imports,
26- path: this.path
27- })
17+ async getInstance (port) {
18+ let id = await this.generateID(port)
19+ let kernel = this._vmInstances.get(id)
20+ if (!kernel) {
21+ // load the container from the state
22+ await this.graph.tree(port, 2)
2823
29- this.ports.on('message', index => {
30- this.runNextMessage(index)
31- })
24+ // create a new kernel instance
25+ const VM = this._opts.VMs[port.type]
26+
27+ kernel = new Kernel({
28+ parentPort: port,
29+ hypervisor: this,
30+ VM: VM
31+ })
32+
33+ await kernel.start()
34+ kernel.on('idle', () => {
35+ this._vmInstances.delete(id)
36+ })
37+ this._vmInstances.set(id, kernel)
38+ }
39+ return kernel
3240 }
3341
34- runNextMessage (index = 0) {
35- // load the next message from port space
36- return this.ports.peek(index).then(message => {
37- if (message &&
38- (this._vmstate === 'idle' ||
39- (AtomicMessage.isAtomic(message) && message.isCyclic(this)))) {
40- this._currentMessage = message
41- this.ports.remove(index)
42- return this.run(message)
43- } else {
44- this._vmstate = 'idle'
45- this.emit('idle')
46- }
47- })
42+ async send (port, message) {
43+ const vm = await this.getInstance(port)
44+ const id = await this.generateID(port)
45+ message._fromPort = id
46+ vm.queue(message)
4847 }
4948
50- /**
51- * run the kernels code with a given enviroment
52- * The Kernel Stores all of its state in the Environment. The Interface is used
53- * to by the VM to retrive infromation from the Environment.
54- */
55- async run (message, imports = this.imports) {
56- const self = this
57- function revert (oldState) {
58- // revert the state
59- clearObject(self.state)
60- Object.assign(self.state, oldState)
61- }
49+ // given a port, wait untill its source contract has reached the threshold
50+ // tick count
51+ async wait (port, threshold) {
52+ let kernel = await this.getInstance(port)
53+ return kernel.wait(threshold)
54+ }
6255
63- // shallow copy
64- const oldState = Object.assign({}, this.state)
65- let result
66- this._vmstate = 'running'
67- try {
68- result = await this._vm.run(message, this, imports) || {}
69- } catch (e) {
70- result = {
71- exception: true,
72- exceptionError: e
56+ createPort (type, id = {nonce: [0], parent: null}) {
57+ const VM = this._opts.VMs[type]
58+ return {
59+ 'messages': [],
60+ 'id': {
61+ '/': id
62+ },
63+ 'type': type,
64+ 'link': {
65+ '/': VM.createState()
7366 }
7467 }
68+ }
7569
76- // if we trapped revert all the sent messages
77- if (result.exception) {
78- // revert to the old state
79- revert(oldState)
80- message._reject(result)
81- } else if (AtomicMessage.isAtomic(message) && !message.hasResponded) {
82- message.respond(result)
83- }
84-
85- message._committed().then(() => {
86- this.runNextMessage(0)
87- }).catch((e) => {
88- revert(oldState)
89- })
90- return result
70+ async createStateRoot (port, ticks) {
71+ await this.wait(port, ticks)
72+ return this.graph.flush(port)
9173 }
9274
93- async send (portName, message) {
94- if (AtomicMessage.isAtomic(message)) {
95- // record that this message has traveled thourgh this kernel. This is used
96- // to detect re-entry
97- message._visited(this, this._currentMessage)
75+ async generateID (port) {
76+ let id = await this.graph.flush(port.id)
77+ id = id['/']
78+ if (Buffer.isBuffer(id)) {
79+ id = multibase.encode('base58btc', id).toString()
9880 }
99- return this.ports.send(portName, message)
81+ return id
10082 }
10183
102- shutdown () {
103- this.ports.close()
84+ addVM (type, vm) {
85+ this._opts.VMs[type] = vm
10486 }
10587 }
106-
107-function clearObject (myObject) {
108- for (var member in myObject) {
109- delete myObject[member]
110- }
111-}
package.jsonView
@@ -1,13 +1,13 @@
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": {
6- "coverage": "node --harmony ./node_modules/istanbul/lib/cli.js cover ./tests/apiTests.js",
6+ "coverage": "node ./node_modules/istanbul/lib/cli.js cover ./tests/index.js",
77 "coveralls": "npm run coverage && coveralls <coverage/lcov.info",
88 "lint": "standard",
9- "test": "node --harmony --expose-wasm ./tests/interfaceRunner.js",
9+ "test": "node ./tests/index.js",
1010 "build": "node ./tests/buildTests.js && ./tools/wabt/out/wast2wasm ./wasm/interface.wast -o ./wasm/interface.wasm"
1111 },
1212 "repository": {
1313 "type": "git",
@@ -17,38 +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+ "multibase": "^0.3.4",
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- "fixed-bn.js": "0.0.2",
50- "ipld-graph-builder": "1.0.1",
51- "primea-message": "0.0.0",
52- "primea-wasm-container": "0.0.0"
5342 }
5443 }
port.jsView
@@ -1,26 +1,38 @@
1-const EventEmitter = require('events')
2-
3-module.exports = class Port extends EventEmitter {
1+module.exports = class Port {
42 constructor (name) {
5- super()
63 this.name = name
7- this.connected = false
4+ this.hasSent = false
5+ this._queue = []
6+ this.ticks = 0
87 }
98
10- connect (destPort) {
11- if (!this.connected) {
12- this.destPort = destPort
13- destPort.destPort = this
14- this.connected = true
9+ queue (message) {
10+ this.ticks = message._ticks
11+ if (this._resolve) {
12+ return this._resolve(message)
13+ } else {
14+ this._queue.push(message)
1515 }
1616 }
1717
18- async send (message) {
19- message._hops++
20- this.destPort.recieve(message)
18+ // this only workls for one Promise
19+ nextMessage () {
20+ const message = this.queue.shift()
21+
22+ return new Promise((resolve, reject) => {
23+ if (message) {
24+ resolve(message)
25+ } else {
26+ this._resolve = resolve
27+ }
28+ })
2129 }
2230
23- recieve (message) {
24- this.emit('message', message)
31+ peek () {
32+ return this._queue[0]
2533 }
34+
35+ shift () {
36+ return this._queue.shift()
37+ }
2638 }
portManager.jsView
@@ -1,80 +1,94 @@
1-const EventEmitter = require('events')
2-const path = require('path')
3-const AtomicMessage = require('primea-message/atomic')
41 const Port = require('./port.js')
5-const common = require('./common.js')
2+const PARENT = Symbol('parent')
63
7-module.exports = class PortManager extends EventEmitter {
8- constructor (opts) {
9- super()
10- Object.assign(this, opts)
11- this._queue = []
12- // set up the parent port
13- const parentPort = new Port(common.PARENT)
14- parentPort.on('message', message => {
15- this._recieveMessage(message)
16- })
4+// decides which message to go firts
5+function messageArbiter (pairA, pairB) {
6+ const a = pairA[1].peek()
7+ const b = pairB[1].peek()
178
18- // create the cache
19- this.cache = new Map()
20- this.cache.set(common.PARENT, parentPort)
9+ if (!a) {
10+ return pairB
11+ } else if (!b) {
12+ return pairA
2113 }
2214
23- _recieveMessage (message) {
24- const index = this._queue.push(message) - 1
25- this.emit('message', index)
15+ const aGasPrice = a.resources.gasPrice
16+ const bGasPrice = b.resources.gasPrice
17+ if (a.ticks !== b.ticks) {
18+ return a.ticks < b.ticks ? pairA : pairB
19+ } else if (aGasPrice === bGasPrice) {
20+ return a.hash() > b.hash() ? pairA : pairB
21+ } else {
22+ return aGasPrice > bGasPrice ? pairA : pairB
2623 }
24+}
2725
28- async get (name) {
29- let port = this.cache.get(name)
30- if (!port) {
31- port = new Port(name)
32- port.on('message', message => {
33- this._recieveMessage(message)
34- })
35- // create destination kernel
36- const state = await this.graph.get(this.state, name)
26+module.exports = class PortManager {
27+ constructor (kernel) {
28+ this.kernel = kernel
29+ this.hypervisor = kernel._opts.hypervisor
30+ this.ports = kernel.state.ports
31+ this.parentPort = kernel._opts.parentPort
32+ this._portMap = new Map()
33+ }
3734
38- const destKernel = new this.Kernel({
39- state: state,
40- graph: this.graph,
41- parentPort: port,
42- imports: this.imports,
43- path: path.join(this.path, name)
44- })
35+ async start () {
36+ // map ports to thier id's
37+ let ports = Object.keys(this.ports).map(name => {
38+ const port = this.ports[name]
39+ this._mapPort(name, port)
40+ })
4541
46- // shutdown the kernel when it is done doing it work
47- destKernel.on('idle', () => {
48- destKernel.shutdown()
49- this.cache.delete(name)
50- })
42+ // create the parent port
43+ await Promise.all(ports)
44+ const parentID = await this.hypervisor.generateID(this.kernel._opts.parentPort)
45+ this._portMap.set(parentID, new Port(PARENT))
46+ }
5147
52- // find and connect the destination port
53- const destPort = await destKernel.ports.get(common.PARENT)
54- port.connect(destPort)
55- this.cache.set(name, port)
56- }
57- return port
48+ async _mapPort (name, port) {
49+ const id = await this.hypervisor.generateID(port)
50+ port = new Port(name)
51+ this._portMap.set(id, port)
5852 }
5953
60- async peek (index = 0) {
61- return this._queue[index]
54+ queue (message) {
55+ this._portMap.get(message.fromPort).queue(message)
6256 }
6357
64- remove (index) {
65- return this._queue.splice(index, index + 1)
58+ set (name, port) {
59+ this.ports[name] = port
60+ return this._mapPort(name, port)
6661 }
6762
68- async send (portName, message) {
69- const port = await this.get(portName)
70- port.send(message)
71- return AtomicMessage.isAtomic(message) ? message.result() : {}
63+ async get (port) {
64+ const id = await this.hypervisor.generateID(port)
65+ return this._portMap.get(id)
7266 }
7367
74- close () {
75- for (let port in this.cache) {
76- port.emit('close')
68+ getRef (key) {
69+ return this.ports[key]
70+ }
71+
72+ // waits till all ports have reached a threshold tick count
73+ async wait (threshold) {
74+ // find the ports that have a smaller tick count then the threshold tick count
75+ const unkownPorts = [...this._portMap].filter(([id, port]) => {
76+ return (port.hasSent || port.name === PARENT) && port.ticks < threshold
77+ })
78+
79+ const promises = unkownPorts.map(async ([id, port]) => {
80+ const portObj = port.name === PARENT ? this.parentPort : this.ports[port.name]
81+ // update the port's tick count
82+ port.ticks = await this.hypervisor.wait(portObj, threshold)
83+ })
84+ return Promise.all(promises)
85+ }
86+
87+ async getNextMessage (ticks) {
88+ await this.wait(ticks)
89+ const portMap = [...this._portMap].reduce(messageArbiter)
90+ if (portMap) {
91+ return portMap[1].shift()
7792 }
78- this.cache.clear()
7993 }
8094 }
tests/apiTests.jsView
@@ -1,68 +1,0 @@
1-const tape = require('tape')
2-const Hypervisor = require('../hypervisor.js')
3-const Message = require('primea-message/atomic')
4-const Graph = require('ipld-graph-builder')
5-const IPFS = require('ipfs')
6-
7-const ipfs = new IPFS()
8-const graph = new Graph(ipfs)
9-
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 = '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('one', new Message({
24- to: path
25- }))
26- } catch (e) {
27- console.log(e)
28- }
29- })
30-
31- tape('reverts', async t => {
32- try {
33- const root = {}
34- const hypervisor = new Hypervisor(graph, root)
35- const path = 'one/two/three'
36- const path2 = 'one/two/three/four'
37- await hypervisor.set(path, {
38- code: async (message, kernel) => {
39- console.log('here!!')
40- await kernel.send('four', new Message())
41- throw new Error('vm exception')
42- }
43- })
44-
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.split('/').slice(1)
56- })
57- hypervisor.send(path.split('/')[0], 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- } catch (e) {
63- console.log(e)
64- }
65- t.end()
66- process.exit()
67- })
68-})
tests/index.jsView
@@ -1,0 +1,107 @@
1+const tape = require('tape')
2+const IPFS = require('ipfs')
3+const Hypervisor = require('../')
4+const Message = require('primea-message')
5+
6+const node = new IPFS()
7+
8+class BaseContainer {
9+ constructor (kernel) {
10+ this.kernel = kernel
11+ }
12+
13+ static createState (code) {
14+ return {
15+ nonce: [0],
16+ ports: {}
17+ }
18+ }
19+}
20+
21+node.on('error', err => {
22+ console.log(err)
23+})
24+
25+node.on('start', () => {
26+ tape('basic', async t => {
27+ const message = new Message()
28+ const expectedState = {
29+ '/': 'zdpuB3eZQJuXMnQrdiF5seMvx3zC2xT1EqrQScoPcTs8ESxYx'
30+ }
31+
32+ class testVMContainer extends BaseContainer {
33+ run (m) {
34+ t.true(m === message, 'should recive a message')
35+ }
36+ }
37+
38+ const hypervisor = new Hypervisor({dag: node.dag})
39+ hypervisor.addVM('test', testVMContainer)
40+ const port = hypervisor.createPort('test')
41+
42+ await hypervisor.send(port, message)
43+ await hypervisor.createStateRoot(port, Infinity)
44+
45+ t.deepEquals(port, expectedState, 'expected')
46+ t.end()
47+ })
48+
49+ tape('one child contract', async t => {
50+ let message = new Message()
51+ const expectedState = { '/': 'zdpuAqtY43BMaTCB5nTt7kooeKAWibqGs44Uwy9jJQHjTnHRK' }
52+ let hasResolved = false
53+
54+ class testVMContainer2 extends BaseContainer {
55+ run (m) {
56+ t.true(m === message, 'should recive a message 2')
57+ return new Promise((resolve, reject) => {
58+ setTimeout(() => {
59+ this.kernel.incrementTicks(1)
60+ hasResolved = true
61+ resolve()
62+ }, 200)
63+ })
64+ }
65+ }
66+
67+ class testVMContainer extends BaseContainer {
68+ async run (m) {
69+ const port = await this.kernel.createPort(this.kernel.ports, 'test2', 'child')
70+ await this.kernel.send(port, m)
71+ this.kernel.incrementTicks(1)
72+ }
73+ }
74+
75+ const hypervisor = new Hypervisor({dag: node.dag})
76+ hypervisor.addVM('test', testVMContainer)
77+ hypervisor.addVM('test2', testVMContainer2)
78+ const port = hypervisor.createPort('test')
79+
80+ await hypervisor.send(port, message)
81+ await hypervisor.createStateRoot(port, Infinity)
82+ t.true(hasResolved, 'should resolve before generating the state root')
83+ t.deepEquals(port, expectedState, 'expected state')
84+
85+ // test reviving the state
86+ class testVMContainer3 extends BaseContainer {
87+ async run (m) {
88+ const port = this.kernel.getPort(this.kernel.ports, 'child')
89+ await this.kernel.send(port, m)
90+ this.kernel.incrementTicks(1)
91+ }
92+ }
93+
94+ hypervisor.addVM('test', testVMContainer3)
95+
96+ // revive ports
97+ message = new Message()
98+ await hypervisor.graph.tree(expectedState, 1)
99+ await hypervisor.send(expectedState['/'], message)
100+ await hypervisor.createStateRoot(expectedState['/'], Infinity)
101+
102+ t.end()
103+ node.stop(() => {
104+ process.exit()
105+ })
106+ })
107+})
tests/buildTests.jsView
@@ -1,15 +1,0 @@
1-const fs = require('fs')
2-const cp = require('child_process')
3-const path = require('path')
4-
5-const dir = path.join(__dirname, '/interface')
6-// get the test names
7-let tests = fs.readdirSync(dir).filter((file) => file.endsWith('.wast'))
8-// tests = ['balance.wast']
9-// run the tests
10-for (let testName of tests) {
11- console.log(testName)
12- testName = testName.split('.')[0]
13- // Compile Command
14- cp.execSync(`${__dirname}/../tools/wabt/out/wast2wasm ${dir}/${testName}.wast -o ${dir}/${testName}.wasm`)
15-}
tests/interface/address.jsonView
@@ -1,14 +1,0 @@
1-{
2- "callValue": "0x00",
3- "callData": "0x00",
4- "state": {
5- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
6- "balance": "0x056bc75e2d63100000",
7- "code": "0x00",
8- "nonce": "0x00"
9- }
10- },
11- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
12- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/address.wasmView
@@ -1,3 +1,0 @@
1-asm ``ethereum
2-getAddressmainmemory
3-!@AA)Bݐ�������Q@
tests/interface/address.wastView
@@ -1,18 +1,0 @@
1-;; starts with an address of 5d48c1018904a172886829bbbd9c6f4a2d06c47b
2-(module
3- (import "ethereum" "getAddress" (func $address (param i32)))
4-
5- (memory 1)
6- (export "main" (func 0))
7- (export "memory" (memory 0))
8- (func
9- (block
10- ;; loads the address into memory
11- (call $address (i32.const 0))
12- (if (i64.eq (i64.load (i32.const 0)) (i64.const 0x72a1048901c1485d))
13- (return)
14- )
15- (unreachable)
16- )
17- )
18-)
tests/interface/balance.jsonView
@@ -1,14 +1,0 @@
1-{
2- "callValue": "0x00",
3- "callData": "0x00",
4- "state": {
5- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
6- "balance": "0x056bc75e2d63100000",
7- "code": "0x00",
8- "nonce": "0x00"
9- }
10- },
11- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
12- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/balance.wasmView
@@ -1,5 +1,0 @@
1-asm 
2-``ethereum
3-getBalancepmemorymaincallback A 
4-'
5-AAA @A)B��������Q@ A ]H���r�h)���oJ-�{
tests/interface/balance.wastView
@@ -1,30 +1,0 @@
1-;; address of 5d48c1018904a172886829bbbd9c6f4a2d06c47b has a balance of 0x056bc75e2d63100000 (100 ETH)
2-(module
3- (import "ethereum" "getBalance" (func $balance (param i32 i32 i32)))
4- (memory 1 )
5- (data (i32.const 0) "\5d\48\c1\01\89\04\a1\72\88\68\29\bb\bd\9c\6f\4a\2d\06\c4\7b")
6- (export "memory" (memory 0))
7- (export "main" (func $main))
8-
9- (table
10- (export "callback")
11- anyfunc
12- (elem
13- $callback
14- )
15- )
16-
17- (func $main
18- (call $balance (i32.const 0) (i32.const 0) (i32.const 0))
19- )
20-
21- (func $callback
22- (block
23- (if (i64.eq (i64.load (i32.const 0)) (i64.const 0x0500000000000000))
24- (return)
25- )
26- (unreachable)
27- )
28- )
29-)
30-
tests/interface/basic_gas_ops.jsonView
@@ -1,15 +1,0 @@
1-{
2- "callValue": "0x00",
3- "callData": "0x00",
4- "state": {
5- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
6- "balance": "0x056bc75e2d63100000",
7- "code": "0x00",
8- "nonce": "0x00"
9- }
10- },
11- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
12- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
14- "gasLeft": 1000
15-}
tests/interface/basic_gas_ops.wasmView
@@ -1,3 +1,0 @@
1-asm  `~`~`)ethereumuseGasethereum
2-getGasLeftmain
3-@BB�Q@
tests/interface/basic_gas_ops.wastView
@@ -1,24 +1,0 @@
1-;; starts with 1000 gas
2-(module
3- (import "ethereum" "useGas" (func $useGas (param i64)))
4- (import "ethereum" "getGasLeft" (func $gas (result i64)))
5-
6- (export "main" (func $main))
7- (func $main
8- ;; test adding gas
9- (block
10- (call $useGas (i64.const 1))
11- (if (i64.eq (call $gas) (i64.const 997))
12- (return)
13- )
14- (unreachable)
15- )
16- (block
17- (call $useGas (i64.const 1))
18- (if (i64.eq (call $gas) (i64.const 996))
19- (return)
20- )
21- (unreachable)
22- )
23- )
24-)
tests/interface/call.jsonView
@@ -1,14 +1,0 @@
1-{
2- "callValue": "0x00",
3- "callData": "0x00",
4- "state": {
5- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
6- "balance": "0x056bc75e2d63100000",
7- "code": "0x00",
8- "nonce": "0x00"
9- }
10- },
11- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
12- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/call.wasmView
@@ -1,2 +1,0 @@
1-asm `~``ethereumcallpmemorymaincallback A 
2-:+@AA6A4A����6B�AAA4AA8AA A F@
tests/interface/call.wastView
@@ -1,36 +1,0 @@
1-;; starts with an address of 5d48c1018904a172886829bbbd9c6f4a2d06c47b
2-(module
3- (import "ethereum" "call" (func $call (param i64 i32 i32 i32 i32 i32 i32 i32) (result i32)))
4- (memory 1)
5- (export "memory" (memory 0))
6- (export "main" (func $main))
7-
8- (table
9- (export "callback")
10- anyfunc
11- (elem
12- $callback
13- )
14- )
15-
16- (func $main
17- (block
18- ;; Memory layout:
19- ;; 0 - 20 bytes: address (4)
20- ;; 20 - 52 bytes: value (0)
21- ;; 52 - 56 bytes: data (0x42004200)
22- ;; 56 - 60 bytes: result
23- (i32.store (i32.const 0) (i32.const 0x4))
24- (i32.store (i32.const 52) (i32.const 0x42004200))
25- (call $call (i64.const 2000) (i32.const 0) (i32.const 20) (i32.const 52) (i32.const 4) (i32.const 56) (i32.const 4) (i32.const 0))
26- drop
27- )
28- )
29-
30- (func $callback (param $result i32)
31- (if (i32.eq (i32.const 1) (get_local $result))
32- (return)
33- )
34- (unreachable)
35- )
36-)
tests/interface/callDataCopy.jsonView
@@ -1,14 +1,0 @@
1-{
2- "callValue": "0x00",
3- "callData": "0x596f75206172652077616974696e6720666f7220746865207265766f6c7574696f6e3f204c657420697420626521204d79206f776e20626567616e2061206c6f6e672074696d652061676f21205768656e20796f752077696c6c2062652072656164792e2e2e4920776f6ee2809974206d696e6420676f696e6720616c6f6e67207769746820796f7520666f722061207768696c652e20427574207768656e20796f75e280996c6c2073746f702c2049207368616c6c20636f6e74696e7565206f6e206d7920696e73616e6520616e6420747269756d7068616e742077617920746f776172642074686520677265617420616e64207375626c696d6520636f6e7175657374206f6620746865206e6f7468696e6721",
4- "state": {
5- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
6- "balance": "0x056bc75e2d63100000",
7- "code": "0x00",
8- "nonce": "0x00"
9- }
10- },
11- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
12- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/callDataCopy.wasmView
@@ -1,3 +1,0 @@
1-asm 
2-``ethereum callDataCopymemorymain
3-$"@AAAA)B��Ճ��ܲ Q@
tests/interface/callDataCopy.wastView
@@ -1,16 +1,0 @@
1-;; calldata is "596f75206172652077616974...", but i64.load works in LSB mode
2-(module
3- (import "ethereum" "callDataCopy" (func $callDataCopy (param i32 i32 i32)))
4- (memory 1)
5- (export "memory" (memory 0))
6- (export "main" (func $main))
7- (func $main
8- (block
9- (call $callDataCopy (i32.const 0) (i32.const 0) (i32.const 8))
10- (if (i64.eq (i64.load (i32.const 0)) (i64.const 0x2065726120756f59))
11- (return)
12- )
13- (unreachable)
14- )
15- )
16-)
tests/interface/callDataSize.jsonView
@@ -1,14 +1,0 @@
1-{
2- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
3- "callValue": "0x00",
4- "callData": "0x596f75206172652077616974696e6720666f7220746865207265766f6c7574696f6e3f204c657420697420626521204d79206f776e20626567616e2061206c6f6e672074696d652061676f21205768656e20796f752077696c6c2062652072656164792e2e2e4920776f6ee2809974206d696e6420676f696e6720616c6f6e67207769746820796f7520666f722061207768696c652e20427574207768656e20796f75e280996c6c2073746f702c2049207368616c6c20636f6e74696e7565206f6e206d7920696e73616e6520616e6420747269756d7068616e742077617920746f776172642074686520677265617420616e64207375626c696d6520636f6e7175657374206f6620746865206e6f7468696e6721",
5- "state": {
6- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
7- "balance": "0x056bc75e2d63100000",
8- "code": "0x00",
9- "nonce": "0x00"
10- }
11- },
12- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/callDataSize.wasmView
@@ -1,2 +1,0 @@
1-asm ``ethereumgetCallDataSizemain
2-@A�F@
tests/interface/callDataSize.wastView
@@ -1,13 +1,0 @@
1-(module
2- (import"ethereum" "getCallDataSize" (func $callDataSize (result i32)))
3- (memory 1)
4- (export "main" (func $main))
5- (func $main
6- (block
7- (if (i32.eq (call $callDataSize) (i32.const 277))
8- (return)
9- )
10- (unreachable)
11- )
12- )
13-)
tests/interface/callValue.jsonView
@@ -1,14 +1,0 @@
1-{
2- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
3- "callValue": "0x056bc75e2d63100000",
4- "callData": "0x596f75206172652077616974696e6720666f7220746865207265766f6c7574696f6e3f204c657420697420626521204d79206f776e20626567616e2061206c6f6e672074696d652061676f21205768656e20796f752077696c6c2062652072656164792e2e2e4920776f6ee2809974206d696e6420676f696e6720616c6f6e67207769746820796f7520666f722061207768696c652e20427574207768656e20796f75e280996c6c2073746f702c2049207368616c6c20636f6e74696e7565206f6e206d7920696e73616e6520616e6420747269756d7068616e742077617920746f776172642074686520677265617420616e64207375626c696d6520636f6e7175657374206f6620746865206e6f7468696e6721",
5- "state": {
6- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
7- "balance": "0x056bc75e2d63100000",
8- "code": "0x00",
9- "nonce": "0x00"
10- }
11- },
12- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/callValue.wasmView
@@ -1,2 +1,0 @@
1-asm ``ethereum getCallValuememorymain
2- @AA)B��������Q@
tests/interface/callValue.wastView
@@ -1,16 +1,0 @@
1-;; call value of 0x056bc75e2d63100000 (100 ETH)
2-(module
3- (import "ethereum" "getCallValue" (func $callValue (param i32)))
4- (memory 1)
5- (export "memory" (memory 0))
6- (export "main" (func $main))
7- (func $main
8- (block
9- (call $callValue (i32.const 0))
10- (if (i64.eq (i64.load (i32.const 0)) (i64.const 0x0500000000000000))
11- (return)
12- )
13- (unreachable)
14- )
15- )
16-)
tests/interface/caller.jsonView
@@ -1,14 +1,0 @@
1-{
2- "callValue": "0x00",
3- "callData": "0x00",
4- "state": {
5- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
6- "balance": "0x056bc75e2d63100000",
7- "code": "0x00",
8- "nonce": "0x00"
9- }
10- },
11- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
12- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/caller.wasmView
@@ -1,2 +1,0 @@
1-asm ``ethereum getCallermainmemory
2-!@AA)Bݐ�������Q@
tests/interface/caller.wastView
@@ -1,17 +1,0 @@
1-;; starts with an caller of 5d48c1018904a172886829bbbd9c6f4a2d06c47b
2-(module
3- (import "ethereum" "getCaller" (func $caller (param i32)))
4- (memory 1)
5- (export "main" (func $main))
6- (export "memory" (memory 0))
7- (func $main
8- (block
9- ;; loads the caller into memory
10- (call $caller (i32.const 0))
11- (if (i64.eq (i64.load (i32.const 0)) (i64.const 0x72a1048901c1485d))
12- (return)
13- )
14- (unreachable)
15- )
16- )
17-)
tests/interface/coinbase.jsonView
@@ -1,14 +1,0 @@
1-{
2- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
3- "callValue": "0x00",
4- "callData": "0x00",
5- "state": {
6- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
7- "balance": "0x056bc75e2d63100000",
8- "code": "0x00",
9- "nonce": "0x00"
10- }
11- },
12- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
14-}
tests/interface/coinbase.wasmView
@@ -1,2 +1,0 @@
1-asm ``ethereumgetBlockCoinbasemainmemory
2-!@AA)Bݐ�������Q@
tests/interface/coinbase.wastView
@@ -1,17 +1,0 @@
1-;; starts with a coinbase of 5d48c1018904a172886829bbbd9c6f4a2d06c47b
2-(module
3- (import "ethereum" "getBlockCoinbase" (func $coinbase (param i32)))
4- (memory 1)
5- (export "main" (func $main))
6- (export "memory" (memory 0))
7- (func $main
8- (block
9- ;; loads the coinbase into memory
10- (call $coinbase (i32.const 0))
11- (if (i64.eq (i64.load (i32.const 0)) (i64.const 0x72a1048901c1485d))
12- (return)
13- )
14- (unreachable)
15- )
16- )
17-)
tests/interface/default_enviroment.jsonView
@@ -1,13 +1,0 @@
1-enviroment: {
2- gasPrice: 0,
3- gasLeft: 0,
4- address: [],
5- origin: [],
6- coinbase: [],
7- difficulty: [],
8- caller: [],
9- callValue: [],
10- callData: [],
11- code: [],
12- logs: []
13-}
tests/interface/origin.jsonView
@@ -1,15 +1,0 @@
1-{
2- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
3- "callValue": "0x00",
4- "callData": "0x00",
5- "state": {
6- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
7- "balance": "0x056bc75e2d63100000",
8- "code": "0x00",
9- "nonce": "0x00"
10- }
11- },
12- "origin": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
14- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
15-}
tests/interface/origin.wasmView
@@ -1,2 +1,0 @@
1-asm ``ethereum getTxOriginmainmemory
2-!@AA)Bݐ�������Q@
tests/interface/origin.wastView
@@ -1,18 +1,0 @@
1-;; starts with an origin of 5d48c1018904a172886829bbbd9c6f4a2d06c47b
2-(module
3- (import "ethereum" "getTxOrigin" (func $origin (param i32)))
4- (memory 1)
5-
6- (export "main" (func $main))
7- (export "memory" (memory 0))
8- (func $main
9- (block
10- ;; loads the address into memory
11- (call $origin (i32.const 0))
12- (if (i64.eq (i64.load (i32.const 0)) (i64.const 0x72a1048901c1485d))
13- (return)
14- )
15- (unreachable)
16- )
17- )
18-)
tests/interface/sstore.jsonView
@@ -1,15 +1,0 @@
1-{
2- "caller": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
3- "callValue": "0x00",
4- "callData": "0x00",
5- "state": {
6- "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b": {
7- "balance": "0x056bc75e2d63100000",
8- "code": "0x00",
9- "nonce": "0x00"
10- }
11- },
12- "origin": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
13- "coinbase": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b",
14- "address": "0x5d48c1018904a172886829bbbd9c6f4a2d06c47b"
15-}
tests/interface/sstore.wasmView
@@ -1,3 +1,0 @@
1-asm 
2-``0ethereum storageStoreethereum storageLoadpmemorycallbackmain A 
3-L~@AB���݄ƥ�7A�AA @A�A�A @A�)B���݄ƥ�R@
tests/interface/sstore.wastView
@@ -1,41 +1,0 @@
1-;; starts with an caller of 5d48c1018904a172886829bbbd9c6f4a2d06c47b
2-(module
3- (import "ethereum" "storageStore" (func $sstore (param i32 i32 i32)))
4- (import "ethereum" "storageLoad" (func $sload (param i32 i32 i32)))
5-
6- (memory 1)
7- (export "memory" (memory 0))
8-
9- (table
10- (export "callback")
11- anyfunc
12- (elem
13- $callback
14- $callback2
15- )
16- )
17-
18- (func $main
19- (export "main")
20- (local $temp i64)
21- (block
22- ;; should roundtrip store and load a value from storage
23- (i64.store (i32.const 0) (i64.const 173553719826446289))
24- (call $sstore (i32.const 64) (i32.const 0) (i32.const 0))
25- )
26- )
27-
28- (func $callback
29- (block
30- (call $sload (i32.const 64) (i32.const 64) (i32.const 1))
31- )
32- )
33-
34- (func $callback2
35- (block
36- (if (i64.ne (i64.load (i32.const 64)) (i64.const 173553719826446289))
37- (unreachable))
38-
39- )
40- )
41-)
tests/interfaceRunner.jsView
@@ -1,59 +1,0 @@
1-const tape = require('tape')
2-const fs = require('fs')
3-const Graph = require('ipld-graph-builder')
4-const Block = require('../deps/block')
5-const U128 = require('fixed-bn.js').U128
6-const Address = require('fixed-bn.js').Address
7-// TODO remove fakeblockchain
8-const fakeBlockChain = require('../fakeBlockChain.js')
9-const Hypervisor = require('../hypervisor.js')
10-const Message = require('primea-message/atomic')
11-const common = require('../common')
12-const EVMinterface = require('../EVMinterface.js')
13-const IPFS = require('ipfs')
14-
15-const ipfs = new IPFS()
16-const graph = new Graph(ipfs)
17-
18-const dir = `${__dirname}/interface`
19-// get the test names
20-let tests = fs.readdirSync(dir).filter((file) => file.endsWith('.wast'))
21-// tests = ['address.js']
22-
23-ipfs.on('start', async () => {
24- runTests(tests)
25-})
26-
27-function runTests (tests) {
28- tape('EVM interface tests', async(t) => {
29- for (let testName of tests) {
30- t.comment(testName)
31- testName = testName.split('.')[0]
32- const hypervisor = new Hypervisor(graph, {}, [EVMinterface])
33- const envData = JSON.parse(fs.readFileSync(`${dir}/${testName}.json`).toString())
34- const code = fs.readFileSync(`${dir}/${testName}.wasm`)
35- envData.state[envData.address].code = code
36-
37- const block = new Block()
38- block.header.coinbase = new Address(envData.coinbase)
39-
40- const message = new Message({
41- to: `${envData.caller}/${common.PARENT}/${envData.address}/code`,
42- data: Buffer.from(envData.callData.slice(2), 'hex'),
43- value: new U128(envData.callValue),
44- gas: envData.gasLeft,
45- block: block,
46- blockchain: fakeBlockChain
47- })
48-
49- try {
50- const results = await hypervisor.send('accounts', message)
51- t.equals(results.exception, undefined)
52- } catch (e) {
53- console.log(e)
54- }
55- }
56- t.end()
57- process.exit()
58- })
59-}
EVMinterface.jsView
@@ -1,621 +1,0 @@
1-/**
2- * This is the Ethereum interface that is exposed to the WASM instance which
3- * enables to interact with the Ethereum Environment
4- */
5-const fs = require('fs')
6-const ethUtil = require('ethereumjs-util')
7-const Vertex = require('ipld-graph-builder')
8-const U256 = require('fixed-bn.js').U256
9-const U128 = require('fixed-bn.js').U128
10-const Message = require('primea-message')
11-const common = require('./common.js')
12-
13-const U128_SIZE_BYTES = 16
14-const ADDRESS_SIZE_BYTES = 20
15-const U256_SIZE_BYTES = 32
16-
17-// The interface exposed to the WebAessembly VM
18-module.exports = class Interface {
19- constructor (opts) {
20- opts.response.gasRefund = 0
21- this.message = opts.message
22- this.kernel = opts.kernel
23- this.vm = opts.vm
24- this.results = opts.response
25-
26- const shimBin = fs.readFileSync(`${__dirname}/wasm/interface.wasm`)
27- const shimMod = WebAssembly.Module(shimBin)
28-
29- this.shims = WebAssembly.Instance(shimMod, {
30- 'interface': {
31- 'useGas': this._useGas.bind(this),
32- 'getGasLeftHigh': this._getGasLeftHigh.bind(this),
33- 'getGasLeftLow': this._getGasLeftLow.bind(this),
34- 'call': this._call.bind(this)
35- }
36- })
37- this.useGas = this.shims.exports.useGas
38- this.getGasLeft = this.shims.exports.getGasLeft
39- this.call = this.shims.exports.call
40- }
41-
42- static get name () {
43- return 'ethereum'
44- }
45-
46- static get hostContainer () {
47- return 'wasm'
48- }
49-
50- /**
51- * Subtracts an amount to the gas counter
52- * @param {integer} amount the amount to subtract to the gas counter
53- */
54- _useGas (high, low) {
55- this.takeGas(from64bit(high, low))
56- }
57-
58- /**
59- * Returns the current amount of gas
60- * @return {integer}
61- */
62- _getGasLeftHigh () {
63- return Math.floor(this.message.gas / 4294967296)
64- }
65-
66- /**
67- * Returns the current amount of gas
68- * @return {integer}
69- */
70- _getGasLeftLow () {
71- return this.message.gas
72- }
73-
74- /**
75- * Gets address of currently executing account and loads it into memory at
76- * the given offset.
77- * @param {integer} offset
78- */
79- getAddress (offset) {
80- this.takeGas(2)
81- const path = this.kernel.path
82- this.setMemory(offset, ADDRESS_SIZE_BYTES, Buffer.from(path[1].slice(2), 'hex'))
83- }
84-
85- /**
86- * Gets balance of the given account and loads it into memory at the given
87- * offset.
88- * @param {integer} addressOffset the memory offset to laod the address
89- * @param {integer} resultOffset
90- */
91- getBalance (addressOffset, offset, cbIndex) {
92- this.takeGas(20)
93-
94- const path = [common.PARENT, common.PARENT, '0x' + Buffer.from(this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)).toString('hex')]
95- const opPromise = this.kernel.send(new Message({
96- to: path,
97- data: {
98- getValue: 'balance'
99- },
100- sync: true
101- }))
102- .catch(() => Buffer.from([]))
103-
104- this.vm.pushOpsQueue(opPromise, cbIndex, balance => {
105- this.setMemory(offset, U128_SIZE_BYTES, new U128(balance).toBuffer())
106- })
107- }
108-
109- /**
110- * Gets the execution's origination address and loads it into memory at the
111- * given offset. This is the sender of original transaction; it is never an
112- * account with non-empty associated code.
113- * @param {integer} offset
114- */
115- getTxOrigin (offset) {
116- this.takeGas(2)
117-
118- const origin = Buffer.from(this.message.from[2].slice(2), 'hex')
119- this.setMemory(offset, ADDRESS_SIZE_BYTES, origin)
120- }
121-
122- /**
123- * Gets caller address and loads it into memory at the given offset. This is
124- * the address of the account that is directly responsible for this execution.
125- * @param {integer} offset
126- */
127- getCaller (offset) {
128- this.takeGas(2)
129- const caller = this.message.from[2]
130- this.setMemory(offset, ADDRESS_SIZE_BYTES, Buffer.from(caller.slice(2), 'hex'))
131- }
132-
133- /**
134- * Gets the deposited value by the instruction/transaction responsible for
135- * this execution and loads it into memory at the given location.
136- * @param {integer} offset
137- */
138- getCallValue (offset) {
139- this.takeGas(2)
140-
141- this.setMemory(offset, U128_SIZE_BYTES, this.message.value.toBuffer())
142- }
143-
144- /**
145- * Get size of input data in current environment. This pertains to the input
146- * data passed with the message call instruction or transaction.
147- * @return {integer}
148- */
149- getCallDataSize () {
150- this.takeGas(2)
151-
152- return this.message.data.length
153- }
154-
155- /**
156- * Copys the input data in current environment to memory. This pertains to
157- * the input data passed with the message call instruction or transaction.
158- * @param {integer} offset the offset in memory to load into
159- * @param {integer} dataOffset the offset in the input data
160- * @param {integer} length the length of data to copy
161- */
162- callDataCopy (offset, dataOffset, length) {
163- this.takeGas(3 + (3 * Math.ceil(length / 32)))
164-
165- if (length) {
166- const callData = this.message.data.slice(dataOffset, dataOffset + length)
167- this.setMemory(offset, length, callData)
168- }
169- }
170-
171- /**
172- * Copys the input data in current environment to memory. This pertains to
173- * the input data passed with the message call instruction or transaction.
174- * @param {integer} offset the offset in memory to load into
175- * @param {integer} dataOffset the offset in the input data
176- */
177- callDataCopy256 (offset, dataOffset) {
178- this.takeGas(3)
179- const callData = this.message.data.slice(dataOffset, dataOffset + 32)
180- this.setMemory(offset, U256_SIZE_BYTES, callData)
181- }
182-
183- /**
184- * Gets the size of code running in current environment.
185- * @return {interger}
186- */
187- getCodeSize (cbIndex) {
188- this.takeGas(2)
189-
190- // wait for all the prevouse async ops to finish before running the callback
191- this.vm.pushOpsQueue(this.kernel.code.length, cbIndex, length => length)
192- }
193-
194- /**
195- * Copys the code running in current environment to memory.
196- * @param {integer} offset the memory offset
197- * @param {integer} codeOffset the code offset
198- * @param {integer} length the length of code to copy
199- */
200- codeCopy (resultOffset, codeOffset, length, cbIndex) {
201- this.takeGas(3 + (Math.ceil(length / 32) * 3))
202-
203- // wait for all the prevouse async ops to finish before running the callback
204- this.vm.pushOpsQueue(this.kernel.code, cbIndex, code => {
205- if (code.length) {
206- code = code.slice(codeOffset, codeOffset + length)
207- this.setMemory(resultOffset, length, code)
208- }
209- })
210- }
211-
212- /**
213- * Get size of an account’s code.
214- * @param {integer} addressOffset the offset in memory to load the address from
215- * @return {integer}
216- */
217- getExternalCodeSize (addressOffset, cbOffset) {
218- this.takeGas(20)
219- const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
220- const opPromise = this.kernel.sendMessage(common.ROOT, common.getterMessage('code', address))
221- .then(vertex => vertex.value.length)
222- .catch(() => 0)
223-
224- // wait for all the prevouse async ops to finish before running the callback
225- this.vm.pushOpsQueue(opPromise, cbOffset, length => length)
226- }
227-
228- /**
229- * Copys the code of an account to memory.
230- * @param {integer} addressOffset the memory offset of the address
231- * @param {integer} resultOffset the memory offset
232- * @param {integer} codeOffset the code offset
233- * @param {integer} length the length of code to copy
234- */
235- externalCodeCopy (addressOffset, resultOffset, codeOffset, length, cbIndex) {
236- this.takeGas(20 + (Math.ceil(length / 32) * 3))
237-
238- const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
239- let opPromise
240-
241- if (length) {
242- opPromise = this.kernel.sendMessage(common.ROOT, common.getterMessage('code', address))
243- .get(address)
244- .then(vertex => vertex.value)
245- .catch(() => [])
246- } else {
247- opPromise = Promise.resolve([])
248- }
249-
250- // wait for all the prevouse async ops to finish before running the callback
251- this.vm.pushOpsQueue(opPromise, cbIndex, code => {
252- if (code.length) {
253- code = code.slice(codeOffset, codeOffset + length)
254- this.setMemory(resultOffset, length, code)
255- }
256- })
257- }
258-
259- /**
260- * Gets price of gas in current environment.
261- * @return {integer}
262- */
263- getTxGasPrice () {
264- this.takeGas(2)
265-
266- return this.message.gasPrice
267- }
268-
269- /**
270- * Gets the hash of one of the 256 most recent complete blocks.
271- * @param {integer} number which block to load
272- * @param {integer} offset the offset to load the hash into
273- */
274- getBlockHash (number, offset, cbOffset) {
275- this.takeGas(20)
276-
277- const diff = this.message.block.number - number
278- let opPromise
279-
280- if (diff > 256 || diff <= 0) {
281- opPromise = Promise.resolve(new U256(0))
282- } else {
283- opPromise = this.state.get(['blockchain', number]).then(vertex => vertex.hash())
284- }
285-
286- // wait for all the prevouse async ops to finish before running the callback
287- this.vm.pushOpsQueue(opPromise, cbOffset, hash => {
288- this.setMemory(offset, U256_SIZE_BYTES, hash.toBuffer())
289- })
290- }
291-
292- /**
293- * Gets the block’s beneficiary address and loads into memory.
294- * @param offset
295- */
296- getBlockCoinbase (offset) {
297- this.takeGas(2)
298-
299- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.message.block.header.coinbase)
300- }
301-
302- /**
303- * Get the block’s timestamp.
304- * @return {integer}
305- */
306- getBlockTimestamp () {
307- this.takeGas(2)
308-
309- return this.message.block.timestamp
310- }
311-
312- /**
313- * Get the block’s number.
314- * @return {integer}
315- */
316- getBlockNumber () {
317- this.takeGas(2)
318-
319- return this.message.block.number
320- }
321-
322- /**
323- * Get the block’s difficulty.
324- * @return {integer}
325- */
326- getBlockDifficulty (offset) {
327- this.takeGas(2)
328-
329- this.setMemory(offset, U256_SIZE_BYTES, this.message.block.difficulty.toBuffer())
330- }
331-
332- /**
333- * Get the block’s gas limit.
334- * @return {integer}
335- */
336- getBlockGasLimit () {
337- this.takeGas(2)
338-
339- return this.message.gasLimit
340- }
341-
342- /**
343- * Creates a new log in the current environment
344- * @param {integer} dataOffset the offset in memory to load the memory
345- * @param {integer} length the data length
346- * @param {integer} number of topics
347- */
348- log (dataOffset, length, numberOfTopics, topic1, topic2, topic3, topic4) {
349- if (numberOfTopics < 0 || numberOfTopics > 4) {
350- throw new Error('Invalid numberOfTopics')
351- }
352-
353- this.takeGas(375 + (length * 8) + (numberOfTopics * 375))
354-
355- const data = length ? this.getMemory(dataOffset, length).slice(0) : new Uint8Array([])
356- const topics = []
357-
358- if (numberOfTopics > 0) {
359- topics.push(U256.fromBuffer(this.getMemory(topic1, U256_SIZE_BYTES)))
360- }
361-
362- if (numberOfTopics > 1) {
363- topics.push(U256.fromBuffer(this.getMemory(topic2, U256_SIZE_BYTES)))
364- }
365-
366- if (numberOfTopics > 2) {
367- topics.push(U256.fromBuffer(this.getMemory(topic3, U256_SIZE_BYTES)))
368- }
369-
370- if (numberOfTopics > 3) {
371- topics.push(U256.fromBuffer(this.getMemory(topic4, U256_SIZE_BYTES)))
372- }
373-
374- this.kernel.sendMessage([this.kernel.root, 'logs'], new Message({
375- data: data,
376- topics: topics
377- }))
378- }
379-
380- /**
381- * Creates a new contract with a given value.
382- * @param {integer} valueOffset the offset in memory to the value from
383- * @param {integer} dataOffset the offset to load the code for the new contract from
384- * @param {integer} length the data length
385- * @param (integer} resultOffset the offset to write the new contract address to
386- * @return {integer} Return 1 or 0 depending on if the VM trapped on the message or not
387- */
388- create (valueOffset, dataOffset, length, resultOffset, cbIndex) {
389- this.takeGas(32000)
390-
391- const value = U256.fromBuffer(this.getMemory(valueOffset, U128_SIZE_BYTES))
392- // if (length) {
393- // const code = this.getMemory(dataOffset, length).slice(0)
394- // }
395-
396- let opPromise
397-
398- if (value.gt(this.kernel.environment.value)) {
399- opPromise = Promise.resolve(Buffer.alloc(20).fill(0))
400- } else {
401- // todo actully run the code
402- opPromise = Promise.resolve(ethUtil.generateAddress(this.kernel.environment.address, this.kernel.environment.nonce))
403- }
404-
405- // wait for all the prevouse async ops to finish before running the callback
406- this.vm.pushOpsQueue(opPromise, cbIndex, address => {
407- this.setMemory(resultOffset, ADDRESS_SIZE_BYTES, address)
408- })
409- }
410-
411- /**
412- * Sends a message with arbiatary data to a given address path
413- * @param {integer} addressOffset the offset to load the address path from
414- * @param {integer} valueOffset the offset to load the value from
415- * @param {integer} dataOffset the offset to load data from
416- * @param {integer} dataLength the length of data
417- * @param {integer} resultOffset the offset to store the result data at
418- * @param {integer} resultLength
419- * @param {integer} gas
420- * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
421- */
422- _call (gasHigh, gasLow, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, cbIndex) {
423- this.takeGas(40)
424- const gas = from64bit(gasHigh, gasLow)
425- // Load the params from mem
426- const address = [common.PARENT, common.PARENT, ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
427- const value = new U256(this.getMemory(valueOffset, U128_SIZE_BYTES))
428-
429- // Special case for non-zero value; why does this exist?
430- if (!value.isZero()) {
431- this.takeGas(9000 - 2300 + gas)
432- this.takeGas(-gas)
433- }
434-
435- const message = new Message({
436- to: address,
437- value: value
438- })
439-
440- const messagePromise = this.kernel.send(message).then(result => {
441- if (result.exception) {
442- this.takeGas(25000)
443- }
444- })
445-
446- // wait for all the prevouse async ops to finish before running the callback
447- this.vm.pushOpsQueue(messagePromise, cbIndex, () => {
448- return 1
449- })
450- return 1
451- }
452-
453- /**
454- * Message-call into this account with an alternative account’s code.
455- * @param {integer} addressOffset the offset to load the address path from
456- * @param {integer} valueOffset the offset to load the value from
457- * @param {integer} dataOffset the offset to load data from
458- * @param {integer} dataLength the length of data
459- * @param {integer} resultOffset the offset to store the result data at
460- * @param {integer} resultLength
461- * @param {integer} gas
462- * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
463- */
464- callCode (gas, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, cbIndex) {
465- this.takeGas(40)
466- // Load the params from mem
467- const path = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code']
468- const value = U256.fromBuffer(this.getMemory(valueOffset, U128_SIZE_BYTES))
469-
470- // Special case for non-zero value; why does this exist?
471- if (!value.isZero()) {
472- this.takeGas(6700)
473- }
474-
475- // TODO: should be message?
476- const opPromise = this.state.root.get(path)
477- .catch(() => {
478- // TODO: handle errors
479- // the value was not found
480- return null
481- })
482-
483- this.vm.pushOpsQueue(opPromise, cbIndex, oldValue => {
484- return 1
485- })
486- }
487-
488- /**
489- * Message-call into this account with an alternative account’s code, but
490- * persisting the current values for sender and value.
491- * @param {integer} gas
492- * @param {integer} addressOffset the offset to load the address path from
493- * @param {integer} valueOffset the offset to load the value from
494- * @param {integer} dataOffset the offset to load data from
495- * @param {integer} dataLength the length of data
496- * @param {integer} resultOffset the offset to store the result data at
497- * @param {integer} resultLength
498- * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
499- */
500- callDelegate (gas, addressOffset, dataOffset, dataLength, resultOffset, resultLength) {
501- // FIXME: count properly
502- this.takeGas(40)
503-
504- const data = this.getMemory(dataOffset, dataLength).slice(0)
505- const address = [...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
506- const [errorCode, result] = this.environment.callDelegate(gas, address, data)
507- this.setMemory(resultOffset, resultLength, result)
508- return errorCode
509- }
510-
511- /**
512- * store a value at a given path in long term storage which are both loaded
513- * from Memory
514- * @param {interger} pathOffest the memory offset to load the the path from
515- * @param {interger} valueOffset the memory offset to load the value from
516- */
517- storageStore (pathOffset, valueOffset, cbIndex) {
518- this.takeGas(5000)
519- const key = Buffer.from(this.getMemory(pathOffset, U256_SIZE_BYTES)).toString('hex')
520- // copy the value
521- const value = this.getMemory(valueOffset, U256_SIZE_BYTES).slice(0)
522- const valIsZero = value.every((i) => i === 0)
523- const opPromise = this.kernel.state.get(key)
524- .then(vertex => vertex.value)
525- .catch(() => null)
526- .then()
527-
528- this.vm.pushOpsQueue(opPromise, cbIndex, oldValue => {
529- if (valIsZero && oldValue) {
530- // delete a value
531- this.results.gasRefund += 15000
532- this.kernel.state.del(key)
533- } else {
534- if (!valIsZero && !oldValue) {
535- // creating a new value
536- this.takeGas(15000)
537- }
538- // update
539- this.kernel.state.set(key, new Vertex({
540- value: value
541- }))
542- }
543- })
544- }
545-
546- /**
547- * reterives a value at a given path in long term storage
548- * @param {interger} pathOffest the memory offset to load the the path from
549- * @param {interger} resultOffset the memory offset to load the value from
550- */
551- storageLoad (pathOffset, resultOffset, cbIndex) {
552- this.takeGas(50)
553-
554- // convert the path to an array
555- const key = Buffer.from(this.getMemory(pathOffset, U256_SIZE_BYTES)).toString('hex')
556- // get the value from the state
557- const opPromise = this.kernel.state.get([key])
558- .then(vertex => vertex.value)
559- .catch(() => new Uint8Array(32))
560-
561- this.vm.pushOpsQueue(opPromise, cbIndex, value => {
562- this.setMemory(resultOffset, U256_SIZE_BYTES, value)
563- })
564- }
565-
566- /**
567- * Halt execution returning output data.
568- * @param {integer} offset the offset of the output data.
569- * @param {integer} length the length of the output data.
570- */
571- return (offset, length) {
572- if (length) {
573- this.results.returnValue = this.getMemory(offset, length).slice(0)
574- }
575- }
576-
577- /**
578- * Halt execution and register account for later deletion giving the remaining
579- * balance to an address path
580- * @param {integer} offset the offset to load the address from
581- */
582- selfDestruct (addressOffset) {
583- this.results.selfDestruct = true
584- this.results.selfDestructAddress = this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)
585- this.results.gasRefund += 24000
586- }
587-
588- getMemory (offset, length) {
589- return new Uint8Array(this.vm.memory(), offset, length)
590- }
591-
592- setMemory (offset, length, value) {
593- const memory = new Uint8Array(this.vm.memory(), offset, length)
594- memory.set(value)
595- }
596-
597- /*
598- * Takes gas from the tank. Only needs to check if there's gas left to be taken,
599- * because every caller of this method is trusted.
600- */
601- takeGas (amount) {
602- if (this.message.gas < amount) {
603- throw new Error('Ran out of gas')
604- }
605- this.message.gas -= amount
606- }
607-}
608-
609-// converts a 64 bit number to a JS number
610-function from64bit (high, low) {
611- if (high < 0) {
612- // convert from a 32-bit two's compliment
613- high = 0x100000000 - high
614- }
615- if (low < 0) {
616- // convert from a 32-bit two's compliment
617- low = 0x100000000 - low
618- }
619- // JS only bitshift 32bits, so instead of high << 32 we have high * 2 ^ 32
620- return (high * 4294967296) + low
621-}
codeHandler.jsView
@@ -1,48 +1,0 @@
1-const Wasm = require('primea-wasm-container')
2-
3-const defaultHandler = {
4- test: (state) => {
5- return !state.code
6- },
7- init: () => {
8- return require('./defaultAgent.js')
9- }
10-}
11-
12-const wasm = {
13- test: (state) => {
14- const code = Buffer.from(state.code)
15- return code && code.slice(0, 4).toString() === '\x00asm'
16- },
17- init: (code) => {
18- return new Wasm(code)
19- }
20-}
21-
22-const javascript = {
23- test: (state) => {
24- return typeof state.code === 'function'
25- },
26- init: (state) => {
27- return {
28- run: state.code
29- }
30- }
31-}
32-
33-let codeHandlers = exports.handlers = {
34- default: defaultHandler,
35- wasm: wasm,
36- javascript: javascript
37-}
38-
39-exports.init = (code) => {
40- for (let name in codeHandlers) {
41- try {
42- const handler = codeHandlers[name]
43- if (handler.test(code)) {
44- return handler.init(code)
45- }
46- } catch (e) {}
47- }
48-}
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-}
debugInterface.jsView
@@ -1,47 +1,0 @@
1-const opcodes = require('./opcodes.js')
2-
3-/**
4- * Debug Interface
5- * This expose some functions that can help with debugging wast
6- */
7-module.exports = class DebugInterface {
8- constructor (kernel) {
9- this.kernel = kernel
10- }
11-
12- static get name () {
13- return 'debug'
14- }
15-
16- get exports () {
17- return {
18- 'print': function (a) {
19- console.log(a)
20- },
21- 'printMem': function (offset, length) {
22- console.log(`<DEBUG(str): ${this.getMemoryBuffer(offset, length).toString()}>`)
23- }.bind(this),
24-
25- 'printMemHex': function (offset, length) {
26- console.log(`<DEBUG(hex): ${this.getMemoryBuffer(offset, length).toString('hex')}>`)
27- }.bind(this),
28-
29- 'evmStackTrace': function (sp, op) {
30- const opcode = opcodes(op)
31- if (opcode.number) {
32- opcode.name += opcode.number
33- }
34- console.error(`op: ${opcode.name} gas: ${this.kernel.environment.gasLeft} sp: ${sp}`)
35- console.log('-------------stack--------------')
36- for (let i = sp; i >= 0; i -= 32) {
37- console.log(`${(sp - i) / 32} ${this.getMemoryBuffer(i).toString('hex')}`)
38- }
39- }.bind(this)
40- }
41- }
42-
43- getMemoryBuffer (offset, length = 32) {
44- const mem = this.kernel.memory.slice(offset, offset + length)
45- return Buffer.from(mem).reverse()
46- }
47-}
kernel.jsView
@@ -1,0 +1,134 @@
1+const PriorityQueue = require('fastpriorityqueue')
2+const EventEmitter = require('events')
3+const BN = require('bn.js')
4+const PortManager = require('./portManager.js')
5+
6+module.exports = class Kernel extends EventEmitter {
7+ constructor (opts) {
8+ super()
9+ this._opts = opts
10+ this.state = opts.parentPort.link['/']
11+ this.vmState = 'idle'
12+ this.ticks = 0
13+ this.ports = new PortManager(this)
14+ this.vm = new opts.VM(this)
15+ this._waitingQueue = new PriorityQueue((a, b) => {
16+ return a.threshold > b.threshold
17+ })
18+ this.on('result', this._runNextMessage)
19+ this.on('idle', () => {
20+ while (!this._waitingQueue.isEmpty()) {
21+ this._waitingQueue.poll().resolve()
22+ }
23+ })
24+ }
25+
26+ start () {
27+ return this.ports.start()
28+ }
29+
30+ _updateVmState (vmState, message) {
31+ this.vmState = vmState
32+ this.emit(vmState, message)
33+ }
34+
35+ queue (message) {
36+ this.ports.queue(message)
37+ if (this.vmState === 'idle') {
38+ this._updateVmState('running')
39+ this._runNextMessage()
40+ }
41+ }
42+
43+ _runNextMessage () {
44+ this.ports.getNextMessage(this.ticks).then(message => {
45+ if (message) {
46+ this.run(message)
47+ } else {
48+ this._updateVmState('idle', message)
49+ }
50+ })
51+ }
52+
53+ /**
54+ * run the kernels code with a given enviroment
55+ * The Kernel Stores all of its state in the Environment. The Interface is used
56+ * to by the VM to retrive infromation from the Environment.
57+ */
58+ async run (message) {
59+ // shallow copy
60+ const oldState = Object.assign({}, this._opts.state)
61+ let result
62+ try {
63+ result = await this.vm.run(message) || {}
64+ } catch (e) {
65+ result = {
66+ exception: true,
67+ exceptionError: e
68+ }
69+ clearObject(this._opts.state)
70+ Object.assign(this._opts.state, oldState)
71+ }
72+
73+ this.emit('result', result)
74+ return result
75+ }
76+
77+ // returns a promise that resolves once the kernel hits the threshould tick
78+ // count
79+ async wait (threshold) {
80+ return new Promise((resolve, reject) => {
81+ if (this.vmState === 'idle' || threshold <= this.ticks) {
82+ resolve(this.ticks)
83+ } else {
84+ this._waitingQueue.add({
85+ threshold: threshold,
86+ resolve: resolve
87+ })
88+ }
89+ })
90+ }
91+
92+ incrementTicks (count) {
93+ this.ticks += count
94+ while (!this._waitingQueue.isEmpty()) {
95+ const waiter = this._waitingQueue.peek()
96+ if (waiter.threshold > this.ticks) {
97+ break
98+ } else {
99+ this._waitingQueue.poll().resolve(this.ticks)
100+ }
101+ }
102+ }
103+
104+ async createPort (manager, type, name) {
105+ // incerment the nonce
106+ const nonce = new BN(this.state.nonce)
107+ nonce.iaddn(1)
108+ this.state.nonce = nonce.toArray()
109+
110+ let portRef = this._opts.hypervisor.createPort(type, {
111+ nonce: this.state.nonce,
112+ parent: this._opts.parentPort.id
113+ })
114+ await manager.set(name, portRef)
115+ return portRef
116+ }
117+
118+ getPort (manager, name) {
119+ return manager.getRef(name)
120+ }
121+
122+ async send (portRef, message) {
123+ message._ticks = this.ticks
124+ const portInstance = await this.ports.get(portRef)
125+ portInstance.hasSent = true
126+ return this._opts.hypervisor.send(portRef, message)
127+ }
128+}
129+
130+function clearObject (myObject) {
131+ for (var member in myObject) {
132+ delete myObject[member]
133+ }
134+}
defaultAgent.jsView
@@ -1,9 +1,0 @@
1-exports.run = async (message, kernel) => {
2- const to = message.payload.to
3- const next = to.split('/')[message.hops - 1]
4- if (next !== undefined) {
5- return kernel.send(next, message)
6- } else if (message.payload.getValue) {
7- return (await kernel.state.get(message.data.getValue)).value
8- }
9-}
deps/block.jsView
@@ -1,26 +1,0 @@
1-const Address = require('fixed-bn.js').Address
2-const U256 = require('fixed-bn.js').U256
3-const ethUtil = require('ethereumjs-util')
4-const OldBlock = require('ethereumjs-block')
5-
6-module.exports = class Block extends OldBlock {
7- get number () {
8- return ethUtil.bufferToInt(this.header.number)
9- }
10-
11- get gasLimit () {
12- return ethUtil.bufferToInt(this.header.gasLimit)
13- }
14-
15- get difficulty () {
16- return new U256(this.header.difficulty)
17- }
18-
19- get timestamp () {
20- return ethUtil.bufferToInt(this.header.timestamp)
21- }
22-
23- get coinbase () {
24- return new Address(this.header.coinbase)
25- }
26-}
deps/rootVertex.jsView
@@ -1,50 +1,0 @@
1-const KernelVertex = require('./kernelVertex')
2-const Kernel = require('../')
3-const Precompiles = require('../precomiles/precompile.js')
4-const Address = require('./address')
5-
6-const identityAddress = new Address('0x0000000000000000000000000000000000000004')
7-const meteringAddress = new Address('0x000000000000000000000000000000000000000A')
8-const transcompilerAddress = new Address('0x000000000000000000000000000000000000000B')
9-
10-module.exports = class RootKernelVertex extends KernelVertex {
11- constructor (opts) {
12- super(opts)
13- if (opts.root) {
14- this.set(identityAddress.toArray(), new PrecomileVertex(Precompiles.identity))
15- this.set(meteringAddress.toArray(), new PrecomileVertex(Precompiles.meteringInjector))
16- this.set(transcompilerAddress.toArray(), new PrecomileVertex(Precompiles.transcompiler))
17- this.kernel = new Kernel({state: this})
18- }
19- }
20-}
21-
22-class PrecomileVertex extends KernelVertex {
23- /**
24- * Creates a Vertex for precomiles. This will alwasy return false when hashed
25- * so that its contents will never be stored in the merkle trie run serialized
26- */
27- constructor (precomiled) {
28- super()
29- this.kernel = precomiled
30- }
31-
32- hash () {
33- return false
34- }
35-}
36-
37-// detects the correct kernel to load given some code
38-KernelVertex.codeHandler = (code) => {
39- return KernelVertex['default']
40-}
41-
42-KernelVertex.codeHandles = {
43- 'default': Kernel
44-}
45-
46-// KernelVertex.linkHander = (link) => {
47-// }
48-
49-// KernelVertex.linkHanders = {
50-// }
deps/transaction.jsView
@@ -1,49 +1,0 @@
1-//
2-// This class parses a serialised Ethereum transaction
3-//
4-// The input is a Buffer.
5-//
6-const Address = require('./address.js')
7-const U256 = require('./u256.js')
8-const OldTx = require('ethereumjs-tx')
9-
10-module.exports = class Transaction {
11- constructor (tx) {
12- this._tx = new OldTx(tx)
13- }
14-
15- get valid () {
16- return this._tx.verifySignature()
17- }
18-
19- get nonce () {
20- return new U256(this._tx.nonce)
21- }
22-
23- get gasPrice () {
24- return new U256(this._tx.gasPrice)
25- }
26-
27- get gasLimit () {
28- return new U256(this._tx.gasLimit)
29- }
30-
31- get value () {
32- return new U256(this._tx.value)
33- }
34-
35- get data () {
36- return Uint8Array.from(this._tx.data)
37- }
38-
39- get from () {
40- return new Address(this._tx.getSenderAddress())
41- }
42-
43- get to () {
44- if (this._tx.to.length === 0) {
45- return new Address('0x0000000000000000000000000000000000000000')
46- }
47- return new Address(this._tx.to)
48- }
49-}
deps/utils.jsView
@@ -1,14 +1,0 @@
1-const ethUtil = require('ethereumjs-util')
2-const Address = require('./address.js')
3-
4-var Utils = {}
5-
6-Utils.isWASMCode = function (code) {
7- return code.slice(0, 4).toString() === new Uint8Array([0, 0x61, 0x73, 0x6d]).toString()
8-}
9-
10-Utils.newAccountAddress = function (sender, nonce) {
11- return new Address('0x' + ethUtil.generateAddress(sender.toString(), nonce.toString()).toString('hex'))
12-}
13-
14-module.exports = Utils
fakeBlockChain.jsView
@@ -1,14 +1,0 @@
1-const utils = require('ethereumjs-util')
2-const U256 = require('fixed-bn.js').U256
3-
4-module.exports = {
5- getBlock: (n) => {
6- const hash = utils.sha3(Buffer.from(utils.bufferToInt(n).toString()))
7- const block = {
8- hash: () => {
9- return new U256(hash)
10- }
11- }
12- return block
13- }
14-}
hypervisor.jsView
@@ -1,26 +1,0 @@
1-const Kernel = require('./index.js')
2-const codeHandlers = require('./codeHandler.js')
3-
4-module.exports = class Hypervisor {
5- constructor (graph, state, imports = []) {
6- this.state = state
7- this.graph = graph
8- this.root = new Kernel({
9- imports: imports,
10- graph: graph,
11- state: state
12- })
13- }
14-
15- set (path, value) {
16- return this.graph.set(this.state, path, value)
17- }
18-
19- send (portName, message) {
20- return this.root.send(portName, message)
21- }
22-
23- addVM (type, handler) {
24- codeHandlers.handlers.type = handler
25- }
26-}
opcodes.jsView
@@ -1,187 +1,0 @@
1-const codes = {
2- // 0x0 range - arithmetic ops
3- // name, baseCost, off stack, on stack, dynamic
4- 0x00: ['STOP', 0, 0, 0, false],
5- 0x01: ['ADD', 3, 2, 1, false],
6- 0x02: ['MUL', 5, 2, 1, false],
7- 0x03: ['SUB', 3, 2, 1, false],
8- 0x04: ['DIV', 5, 2, 1, false],
9- 0x05: ['SDIV', 5, 2, 1, false],
10- 0x06: ['MOD', 5, 2, 1, false],
11- 0x07: ['SMOD', 5, 2, 1, false],
12- 0x08: ['ADDMOD', 8, 3, 1, false],
13- 0x09: ['MULMOD', 8, 3, 1, false],
14- 0x0a: ['EXP', 10, 2, 1, false],
15- 0x0b: ['SIGNEXTEND', 5, 1, 1, false],
16-
17- // 0x10 range - bit ops
18- 0x10: ['LT', 3, 2, 1, false],
19- 0x11: ['GT', 3, 2, 1, false],
20- 0x12: ['SLT', 3, 2, 1, false],
21- 0x13: ['SGT', 3, 2, 1, false],
22- 0x14: ['EQ', 3, 2, 1, false],
23- 0x15: ['ISZERO', 3, 1, 1, false],
24- 0x16: ['AND', 3, 2, 1, false],
25- 0x17: ['OR', 3, 2, 1, false],
26- 0x18: ['XOR', 3, 2, 1, false],
27- 0x19: ['NOT', 3, 1, 1, false],
28- 0x1a: ['BYTE', 3, 2, 1, false],
29-
30- // 0x20 range - crypto
31- 0x20: ['SHA3', 30, 2, 1, false],
32-
33- // 0x30 range - closure state
34- 0x30: ['ADDRESS', 2, 0, 1, true],
35- 0x31: ['BALANCE', 20, 1, 1, true],
36- 0x32: ['ORIGIN', 2, 0, 1, true],
37- 0x33: ['CALLER', 2, 0, 1, true],
38- 0x34: ['CALLVALUE', 2, 0, 1, true],
39- 0x35: ['CALLDATALOAD', 3, 1, 1, true],
40- 0x36: ['CALLDATASIZE', 2, 0, 1, true],
41- 0x37: ['CALLDATACOPY', 3, 3, 0, true],
42- 0x38: ['CODESIZE', 2, 0, 1, false],
43- 0x39: ['CODECOPY', 3, 3, 0, false],
44- 0x3a: ['GASPRICE', 2, 0, 1, false],
45- 0x3b: ['EXTCODESIZE', 20, 1, 1, true],
46- 0x3c: ['EXTCODECOPY', 20, 4, 0, true],
47-
48- // '0x40' range - block operations
49- 0x40: ['BLOCKHASH', 20, 1, 1, true],
50- 0x41: ['COINBASE', 2, 0, 1, true],
51- 0x42: ['TIMESTAMP', 2, 0, 1, true],
52- 0x43: ['NUMBER', 2, 0, 1, true],
53- 0x44: ['DIFFICULTY', 2, 0, 1, true],
54- 0x45: ['GASLIMIT', 2, 0, 1, true],
55-
56- // 0x50 range - 'storage' and execution
57- 0x50: ['POP', 2, 1, 0, false],
58- 0x51: ['MLOAD', 3, 1, 1, false],
59- 0x52: ['MSTORE', 3, 2, 0, false],
60- 0x53: ['MSTORE8', 3, 2, 0, false],
61- 0x54: ['SLOAD', 0, 1, 1, true],
62- 0x55: ['SSTORE', 0, 2, 0, true],
63- 0x56: ['JUMP', 8, 1, 0, false],
64- 0x57: ['JUMPI', 10, 2, 0, false],
65- 0x58: ['PC', 2, 0, 1, false],
66- 0x59: ['MSIZE', 2, 0, 1, false],
67- 0x5a: ['GAS', 2, 0, 1, false],
68- 0x5b: ['JUMPDEST', 1, 0, 0, false],
69-
70- // 0x60, range
71- 0x60: ['PUSH', 3, 0, 1, false],
72- 0x61: ['PUSH', 3, 0, 1, false],
73- 0x62: ['PUSH', 3, 0, 1, false],
74- 0x63: ['PUSH', 3, 0, 1, false],
75- 0x64: ['PUSH', 3, 0, 1, false],
76- 0x65: ['PUSH', 3, 0, 1, false],
77- 0x66: ['PUSH', 3, 0, 1, false],
78- 0x67: ['PUSH', 3, 0, 1, false],
79- 0x68: ['PUSH', 3, 0, 1, false],
80- 0x69: ['PUSH', 3, 0, 1, false],
81- 0x6a: ['PUSH', 3, 0, 1, false],
82- 0x6b: ['PUSH', 3, 0, 1, false],
83- 0x6c: ['PUSH', 3, 0, 1, false],
84- 0x6d: ['PUSH', 3, 0, 1, false],
85- 0x6e: ['PUSH', 3, 0, 1, false],
86- 0x6f: ['PUSH', 3, 0, 1, false],
87- 0x70: ['PUSH', 3, 0, 1, false],
88- 0x71: ['PUSH', 3, 0, 1, false],
89- 0x72: ['PUSH', 3, 0, 1, false],
90- 0x73: ['PUSH', 3, 0, 1, false],
91- 0x74: ['PUSH', 3, 0, 1, false],
92- 0x75: ['PUSH', 3, 0, 1, false],
93- 0x76: ['PUSH', 3, 0, 1, false],
94- 0x77: ['PUSH', 3, 0, 1, false],
95- 0x78: ['PUSH', 3, 0, 1, false],
96- 0x79: ['PUSH', 3, 0, 1, false],
97- 0x7a: ['PUSH', 3, 0, 1, false],
98- 0x7b: ['PUSH', 3, 0, 1, false],
99- 0x7c: ['PUSH', 3, 0, 1, false],
100- 0x7d: ['PUSH', 3, 0, 1, false],
101- 0x7e: ['PUSH', 3, 0, 1, false],
102- 0x7f: ['PUSH', 3, 0, 1, false],
103-
104- 0x80: ['DUP', 3, 0, 1, false],
105- 0x81: ['DUP', 3, 0, 1, false],
106- 0x82: ['DUP', 3, 0, 1, false],
107- 0x83: ['DUP', 3, 0, 1, false],
108- 0x84: ['DUP', 3, 0, 1, false],
109- 0x85: ['DUP', 3, 0, 1, false],
110- 0x86: ['DUP', 3, 0, 1, false],
111- 0x87: ['DUP', 3, 0, 1, false],
112- 0x88: ['DUP', 3, 0, 1, false],
113- 0x89: ['DUP', 3, 0, 1, false],
114- 0x8a: ['DUP', 3, 0, 1, false],
115- 0x8b: ['DUP', 3, 0, 1, false],
116- 0x8c: ['DUP', 3, 0, 1, false],
117- 0x8d: ['DUP', 3, 0, 1, false],
118- 0x8e: ['DUP', 3, 0, 1, false],
119- 0x8f: ['DUP', 3, 0, 1, false],
120-
121- 0x90: ['SWAP', 3, 0, 0, false],
122- 0x91: ['SWAP', 3, 0, 0, false],
123- 0x92: ['SWAP', 3, 0, 0, false],
124- 0x93: ['SWAP', 3, 0, 0, false],
125- 0x94: ['SWAP', 3, 0, 0, false],
126- 0x95: ['SWAP', 3, 0, 0, false],
127- 0x96: ['SWAP', 3, 0, 0, false],
128- 0x97: ['SWAP', 3, 0, 0, false],
129- 0x98: ['SWAP', 3, 0, 0, false],
130- 0x99: ['SWAP', 3, 0, 0, false],
131- 0x9a: ['SWAP', 3, 0, 0, false],
132- 0x9b: ['SWAP', 3, 0, 0, false],
133- 0x9c: ['SWAP', 3, 0, 0, false],
134- 0x9d: ['SWAP', 3, 0, 0, false],
135- 0x9e: ['SWAP', 3, 0, 0, false],
136- 0x9f: ['SWAP', 3, 0, 0, false],
137-
138- 0xa0: ['LOG', 375, 2, 0, false],
139- 0xa1: ['LOG', 375, 3, 0, false],
140- 0xa2: ['LOG', 375, 4, 0, false],
141- 0xa3: ['LOG', 375, 5, 0, false],
142- 0xa4: ['LOG', 375, 6, 0, false],
143-
144- // '0xf0' range - closures
145- 0xf0: ['CREATE', 32000, 3, 1, true],
146- 0xf1: ['CALL', 40, 7, 1, true],
147- 0xf2: ['CALLCODE', 40, 7, 1, true],
148- 0xf3: ['RETURN', 0, 2, 0, false],
149- 0xf4: ['DELEGATECALL', 40, 6, 1, true],
150-
151- // '0x70', range - other
152- 0xff: ['SUICIDE', 0, 1, 0, false]
153-}
154-
155-module.exports = function (op) {
156- const code = codes[op] ? codes[op] : ['INVALID', 0]
157- let opcode = code[0]
158- let number
159-
160- switch (opcode) {
161- case 'LOG':
162- number = op - 0xa0
163- break
164-
165- case 'PUSH':
166- number = op - 0x5f
167- break
168-
169- case 'DUP':
170- number = op - 0x7f
171- break
172-
173- case 'SWAP':
174- number = op - 0x8f
175- break
176- }
177-
178- return {
179- name: opcode,
180- fee: code[1],
181- in: code[2],
182- out: code[3],
183- dynamic: code[4],
184- async: code[5],
185- number: number
186- }
187-}
runBlock.jsView
@@ -1,11 +1,0 @@
1-// run block; the block message handler:w
2-const Environment = require('./environment')
3-
4-module.exports = class runBlock {
5- constuctor (block, environment = new Environment()) {
6- // verify block then run each tx
7- block.tx.forEach((tx) => {
8- this.runTx(tx, environment)
9- })
10- }
11-}
tools/wabtView
@@ -1,1 +1,0 @@
1-Subproject commit 2177e7517b857d557cbf9b8477c31f96a8ed66bb
wasm/interface.wasmView
@@ -1,3 +1,0 @@
1-asm +``` `~`~`~Z interfaceuseGas interfacegetGasLeftHigh interface getGasLeftLow interfacecalluseGas
2-getGasLeftcall
3-? B �� � AA�B ��|  B �� �       
wasm/interface.wastView
@@ -1,46 +1,0 @@
1-(module
2- (import "interface" "useGas" (func $useGas (param i32 i32)))
3- (import "interface" "getGasLeftHigh" (func $getGasLeftHigh (result i32)))
4- (import "interface" "getGasLeftLow" (func $getGasLeftLow (result i32)))
5- (import "interface" "call" (func $call (param i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)))
6-
7- (export "useGas" (func $useGasShim))
8- (export "getGasLeft" (func $getGasLeft))
9- (export "call" (func $callShim))
10-
11- (func $useGasShim
12- (param $amount i64)
13- (call $useGas
14- (i32.wrap/i64
15- (i64.shr_u (get_local $amount) (i64.const 32)))
16- (i32.wrap/i64 (get_local $amount)))
17- )
18-
19- (func $getGasLeft
20- (result i64)
21- (call $useGas (i32.const 0) (i32.const 2))
22- (return
23- (i64.add
24- (i64.shl (i64.extend_u/i32 (call $getGasLeftHigh)) (i64.const 32))
25- (i64.extend_u/i32 (call $getGasLeftLow))))
26- )
27-
28- ;; call
29- ;; (import $call "ethereum" "call" (param i32 i32 i32 i32 i32 i32 i32 i32) (result i32))
30- (func $callShim
31- (param i64 i32 i32 i32 i32 i32 i32 i32)
32- (result i32)
33- (call $call
34- (i32.wrap/i64
35- (i64.shr_u (get_local 0) (i64.const 32)))
36- (i32.wrap/i64 (get_local 0))
37- (get_local 1)
38- (get_local 2)
39- (get_local 3)
40- (get_local 4)
41- (get_local 5)
42- (get_local 6)
43- (get_local 7)
44- )
45- )
46-)

Built with git-ssb-web