git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 4deaaf0620b832ca0e463a1327d1d7d0ee6c8d6e

rewrote core kernel api, and added internel kernel api

wanderer committed on 11/4/2016, 6:59:56 PM
Parent: c4a3c214a45ab12b8140aa229f758297f1051af2

Files changed

deps/address.jschanged
deps/kernelVertex.jsadded
deps/rootVertex.jsadded
index.jschanged
interface.jschanged
debugKernel.jsdeleted
kernelInterface.jsdeleted
precompiles/create.jsadded
precompiles/precompile.jsadded
precompile.jsdeleted
deps/address.jsView
@@ -22,8 +22,12 @@
2222 toBuffer () {
2323 return super.toBuffer(20)
2424 }
2525
26+ toArray () {
27+ return [...this.toBuffer()]
28+ }
29+
2630 // Needs to be displayed as a hex always
2731 toString () {
2832 return '0x' + this._value.toString('hex', 40)
2933 }
deps/kernelVertex.jsView
@@ -1,0 +1,12 @@
1+const Vertex = require('merkle-trie')
2+
3+module.exports = class KernelVertex extends Vertex {
4+ get kernel () {
5+ return this._cache.kernel
6+ }
7+
8+ set kernel (instance) {
9+ this._cache.kernel = instance
10+ }
11+}
12+
deps/rootVertex.jsView
@@ -1,0 +1,50 @@
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+// }
index.jsView
@@ -1,6 +1,6 @@
11 /**
2- * This implements the Ethereum Kernel
2+ * This implements the Kernel
33 * Kernels must implement two methods `codeHandler` and `callHandler` (and `linkHandler` for sharding)
44 * The Kernel Contract handles the following
55 * - Interprocess communications
66 * - Intializing the VM and exposes ROM to it (codeHandler)
@@ -8,175 +8,64 @@
88 * - Provides some built in contract (runTx, runBlock)
99 * - Provides resource sharing and limiting via gas
1010 *
1111 * All State should be stored in the Environment.
12- *
1312 */
1413
15-const Vertex = require('merkle-trie')
14+const Vertex = require('./deps/kernelVertex')
1615 // The Kernel Exposes this Interface to VM instances it makes
1716 const Interface = require('./interface.js')
18-const KernelInterface = require('./kernelInterface.js')
17+const InterfaceAPI = require('./interfaceAPI.js')
1918
2019 // The Kernel Stores all of its state in the Environment. The Interface is used
2120 // to by the VM to retrive infromation from the Environment.
2221 const Environment = require('./environment.js')
23-const Address = require('./deps/address.js')
24-const U256 = require('./deps/u256.js')
25-const Utils = require('./deps/utils.js')
26-const Precompile = require('./precompile.js')
22+module.exports = class Kernel {
23+ constructor (opts = {}) {
24+ this.state = opts.state || new Vertex()
25+ this.parent = opts.parent
2726
28-const identityContract = new Address('0x0000000000000000000000000000000000000004')
29-const meteringContract = new Address('0x000000000000000000000000000000000000000A')
30-const transcompilerContract = new Address('0x000000000000000000000000000000000000000B')
27+ if (opts.code) {
28+ this.interfaceAPI = new InterfaceAPI(opts.code)
29+ }
30+ this.imports = this.buildImports(opts.interfaces)
31+ }
3132
32-module.exports = class Kernel {
33- // runs some code in the VM
34- constructor (state = new Vertex(), interfaces = [Interface]) {
35- this.state = state
36- this.interfaces = interfaces
33+ buildImports (interfaces = [Interface]) {
34+ return interfaces.reduce((obj, Interface) => {
35+ obj[Interface.name] = new Interface(this.interfaceAPI).exports
36+ return obj
37+ }, {})
3738 }
3839
39- // handles running code.
40- codeHandler (code, environment = new Environment({state: this.state})) {
41- const kernelInterface = new KernelInterface(this, environment)
42- return kernelInterface.run(code)
40+ // run the kernels code with a given enviroment
41+ async run (environment = new Environment({state: this.state}), imports = this.imports) {
42+ await this.interfaceAPI.run(environment, imports)
43+ return environment
4344 }
4445
45- // loads code from the merkle trie and delegates the message
46- // Detects if code is EVM or WASM
47- // Detects if the code injection is needed
48- // Detects if transcompilation is needed
49- messageHandler (call) {
50- // FIXME: this is here until these two contracts are compiled to WASM
51- // The two special contracts (precompiles now, but will be real ones later)
52- if (call.to.equals(meteringContract)) {
53- return Precompile.meteringInjector(call)
54- } else if (call.to.equals(transcompilerContract)) {
55- return Precompile.transcompiler(call)
56- } else if (call.to.equals(identityContract)) {
57- return Precompile.identity(call)
58- }
59-
60- let account = this.environment.state.get(call.to.toString())
61- if (!account) {
62- throw new Error('Account not found: ' + call.to.toString())
63- }
64-
65- let code = Uint8Array.from(account.get('code'))
66- if (code.length === 0) {
67- throw new Error('Contract not found')
68- }
69-
70- if (!Utils.isWASMCode(code)) {
71- // throw new Error('Not an eWASM contract')
72-
73- // Transcompile code
74- // FIXME: decide if these are the right values here: from: 0, gasLimit: 0, value: 0
75- code = this.messageHandler({ from: Address.zero(), to: transcompilerContract, gasLimit: 0, value: new U256(0), data: code }).returnValue
76-
77- if (code[0] === 0) {
78- code = code.slice(1)
79- } else {
80- throw new Error('Transcompilation failed: ' + Buffer.from(code).slice(1).toString())
46+ async messageReceiver (message) {
47+ // let the code handle the message if there is code
48+ if (this.code) {
49+ const environment = new Environment(message)
50+ let result = await this.run(environment)
51+ if (!result.execption) {
52+ this.state = result.state
8153 }
54+ } else if (message.to.length) {
55+ // else forward the message on to the destination contract
56+ let [vertex, done] = await this.state.update(message.to)
57+ message.to = []
58+ await vertex.kernel.messageReceiver(message)
59+ done(vertex)
8260 }
83-
84- // creats a new Kernel
85- const environment = new Environment()
86- environment.parent = this
87-
88- // copy the transaction details
89- environment.code = code
90- environment.address = call.to
91- // FIXME: make distinction between origin and caller
92- environment.origin = call.from
93- environment.caller = call.from
94- environment.callData = call.data
95- environment.callValue = call.value
96- environment.gasLeft = call.gasLimit
97-
98- environment.callHandler = this.callHandler.bind(this)
99- environment.createHandler = this.createHandler.bind(this)
100-
101- const kernel = new Kernel(environment)
102- kernel.codeHandler(code, new Interface(environment))
103-
104- // self destructed
105- if (environment.selfDestruct) {
106- const balance = this.state.get(call.to.toString()).get('balance')
107- const beneficiary = this.state.get(environment.selfDestructAddress)
108- beneficiary.set('balance', beneficiary.get('balance').add(balance))
109- this.state.delete(call.to.toString())
110- }
111-
112- // generate new stateroot
113- // this.environment.state.set(address, { stateRoot: stateRoot })
114-
115- return {
116- executionOutcome: 1, // success
117- gasLeft: new U256(environment.gasLeft),
118- gasRefund: new U256(environment.gasRefund),
119- returnValue: environment.returnValue,
120- selfDestruct: environment.selfDestruct,
121- selfDestructAddress: environment.selfDestructAddress,
122- logs: environment.logs
123- }
12461 }
12562
126- createHandler (create) {
127- let code = create.data
128-
129- // Inject metering
130- if (Utils.isWASMCode(code)) {
131- // FIXME: decide if these are the right values here: from: 0, gasLimit: 0, value: 0
132- code = this.callHandler({
133- from: Address.zero(),
134- to: meteringContract,
135- gasLimit: 0,
136- value: new U256(0),
137- data: code
138- }).returnValue
139-
140- if (code[0] === 0) {
141- code = code.slice(1)
142- } else {
143- throw new Error('Metering injection failed: ' + Buffer.from(code).slice(1).toString())
144- }
145- }
146-
147- let account = this.environment.state.get(create.from.toString())
148- if (!account) {
149- throw new Error('Account not found: ' + create.from.toString())
150- }
151-
152- let address = Utils.newAccountAddress(create.from, account.get('nonce'))
153-
154- this.environment.addAccount(address.toString(), {
155- balance: create.value,
156- code: code
63+ copy () {
64+ return new Kernel({
65+ state: this.state.copy(),
66+ code: this.code,
67+ interfaces: this.interfaces,
68+ parent: this.parent
15769 })
158-
159- // Run code and take return value as contract code
160- // FIXME: decide if these are the right values here: value: 0, data: ''
161- code = this.messageHandler({
162- from: create.from,
163- to: address,
164- gasLimit: create.gasLimit,
165- value: new U256(0),
166- data: new Uint8Array()
167- }).returnValue
168-
169- // FIXME: special handling for selfdestruct
170-
171- this.environment.state.get(address.toString()).set('code', code)
172-
173- return {
174- executionOutcome: 1, // success
175- gasLeft: new U256(this.environment.gasLeft),
176- gasRefund: new U256(this.environment.gasRefund),
177- accountCreated: address,
178- logs: this.environment.logs
179- }
18070 }
18171 }
182-
interface.jsView
@@ -14,9 +14,8 @@
1414 // The interface exposed to the WebAessembly Core
1515 module.exports = class Interface {
1616 constructor (kernel) {
1717 this.kernel = kernel
18- this.environment = kernel.environment
1918 const shimBin = fs.readFileSync(path.join(__dirname, '/wasm/interface.wasm'))
2019 const shimMod = WebAssembly.Module(shimBin)
2120 this.shims = WebAssembly.Instance(shimMod, {
2221 'interface': {
@@ -91,17 +90,17 @@
9190 * Returns the current amount of gas
9291 * @return {integer}
9392 */
9493 _getGasLeftHigh () {
95- return Math.floor(this.environment.gasLeft / 4294967296)
94+ return Math.floor(this.kernel.environment.gasLeft / 4294967296)
9695 }
9796
9897 /**
9998 * Returns the current amount of gas
10099 * @return {integer}
101100 */
102101 _getGasLeftLow () {
103- return this.environment.gasLeft
102+ return this.kernel.environment.gasLeft
104103 }
105104
106105 /**
107106 * Gets address of currently executing account and loads it into memory at
@@ -110,9 +109,9 @@
110109 */
111110 getAddress (offset) {
112111 this.takeGas(2)
113112
114- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.environment.address.toMemory())
113+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.address.toMemory())
115114 }
116115
117116 /**
118117 * Gets balance of the given account and loads it into memory at the given
@@ -124,9 +123,9 @@
124123 this.takeGas(20)
125124
126125 const address = Address.fromMemory(this.getMemory(addressOffset, ADDRESS_SIZE_BYTES))
127126 // call the parent contract and ask for the balance of one of its child contracts
128- const balance = this.environment.getBalance(address)
127+ const balance = this.kernel.environment.getBalance(address)
129128 this.setMemory(offset, U128_SIZE_BYTES, balance.toMemory(U128_SIZE_BYTES))
130129 }
131130
132131 /**
@@ -137,9 +136,9 @@
137136 */
138137 getTxOrigin (offset) {
139138 this.takeGas(2)
140139
141- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.environment.origin.toMemory())
140+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.origin.toMemory())
142141 }
143142
144143 /**
145144 * Gets caller address and loads it into memory at the given offset. This is
@@ -148,9 +147,9 @@
148147 */
149148 getCaller (offset) {
150149 this.takeGas(2)
151150
152- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.environment.caller.toMemory())
151+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.caller.toMemory())
153152 }
154153
155154 /**
156155 * Gets the deposited value by the instruction/transaction responsible for
@@ -159,9 +158,9 @@
159158 */
160159 getCallValue (offset) {
161160 this.takeGas(2)
162161
163- this.setMemory(offset, U128_SIZE_BYTES, this.environment.callValue.toMemory(U128_SIZE_BYTES))
162+ this.setMemory(offset, U128_SIZE_BYTES, this.kernel.environment.callValue.toMemory(U128_SIZE_BYTES))
164163 }
165164
166165 /**
167166 * Get size of input data in current environment. This pertains to the input
@@ -170,9 +169,9 @@
170169 */
171170 getCallDataSize () {
172171 this.takeGas(2)
173172
174- return this.environment.callData.length
173+ return this.kernel.environment.callData.length
175174 }
176175
177176 /**
178177 * Copys the input data in current environment to memory. This pertains to
@@ -184,9 +183,9 @@
184183 callDataCopy (offset, dataOffset, length) {
185184 this.takeGas(3 + Math.ceil(length / 32) * 3)
186185
187186 if (length) {
188- const callData = this.environment.callData.slice(dataOffset, dataOffset + length)
187+ const callData = this.kernel.environment.callData.slice(dataOffset, dataOffset + length)
189188 this.setMemory(offset, length, callData)
190189 }
191190 }
192191
@@ -197,9 +196,9 @@
197196 * @param {integer} dataOffset the offset in the input data
198197 */
199198 callDataCopy256 (offset, dataOffset) {
200199 this.takeGas(3)
201- const callData = this.environment.callData.slice(dataOffset, dataOffset + 32)
200+ const callData = this.kernel.environment.callData.slice(dataOffset, dataOffset + 32)
202201 this.setMemory(offset, U256_SIZE_BYTES, callData)
203202 }
204203
205204 /**
@@ -208,9 +207,9 @@
208207 */
209208 getCodeSize () {
210209 this.takeGas(2)
211210
212- return this.environment.code.length
211+ return this.kernel.environment.code.length
213212 }
214213
215214 /**
216215 * Copys the code running in current environment to memory.
@@ -221,9 +220,9 @@
221220 codeCopy (resultOffset, codeOffset, length) {
222221 this.takeGas(3 + Math.ceil(length / 32) * 3)
223222
224223 if (length) {
225- const code = this.environment.code.slice(codeOffset, codeOffset + length)
224+ const code = this.kernel.environment.code.slice(codeOffset, codeOffset + length)
226225 this.setMemory(resultOffset, length, code)
227226 }
228227 }
229228
@@ -235,9 +234,9 @@
235234 getExternalCodeSize (addressOffset) {
236235 this.takeGas(20)
237236
238237 const address = Address.fromMemory(this.getMemory(addressOffset, ADDRESS_SIZE_BYTES))
239- const code = this.environment.getCode(address)
238+ const code = this.kernel.environment.getCode(address)
240239 return code.length
241240 }
242241
243242 /**
@@ -251,9 +250,9 @@
251250 this.takeGas(20 + Math.ceil(length / 32) * 3)
252251
253252 if (length) {
254253 const address = Address.fromMemory(this.getMemory(addressOffset, ADDRESS_SIZE_BYTES))
255- let code = this.environment.getCode(address)
254+ let code = this.kernel.environment.getCode(address)
256255 code = code.slice(codeOffset, codeOffset + length)
257256 this.setMemory(resultOffset, length, code)
258257 }
259258 }
@@ -264,9 +263,9 @@
264263 */
265264 getTxGasPrice () {
266265 this.takeGas(2)
267266
268- return this.environment.gasPrice
267+ return this.kernel.environment.gasPrice
269268 }
270269
271270 /**
272271 * Gets the hash of one of the 256 most recent complete blocks.
@@ -275,15 +274,15 @@
275274 */
276275 getBlockHash (number, offset, cbOffset) {
277276 this.takeGas(20)
278277
279- const diff = this.environment.block.number - number
278+ const diff = this.kernel.environment.block.number - number
280279 let opPromise
281280
282281 if (diff > 256 || diff <= 0) {
283282 opPromise = Promise.resolve(new U256(0))
284283 } else {
285- opPromise = this.environment.getBlockHash(number)
284+ opPromise = this.kernel.environment.getBlockHash(number)
286285 }
287286
288287 // wait for all the prevouse async ops to finish before running the callback
289288 this.kernel.pushOpsQueue(opPromise, cbOffset, hash => {
@@ -297,9 +296,9 @@
297296 */
298297 getBlockCoinbase (offset) {
299298 this.takeGas(2)
300299
301- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.environment.block.coinbase.toMemory())
300+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.block.coinbase.toMemory())
302301 }
303302
304303 /**
305304 * Get the block’s timestamp.
@@ -307,9 +306,9 @@
307306 */
308307 getBlockTimestamp () {
309308 this.takeGas(2)
310309
311- return this.environment.block.timestamp
310+ return this.kernel.environment.block.timestamp
312311 }
313312
314313 /**
315314 * Get the block’s number.
@@ -317,9 +316,9 @@
317316 */
318317 getBlockNumber () {
319318 this.takeGas(2)
320319
321- return this.environment.block.number
320+ return this.kernel.environment.block.number
322321 }
323322
324323 /**
325324 * Get the block’s difficulty.
@@ -327,9 +326,9 @@
327326 */
328327 getBlockDifficulty (offset) {
329328 this.takeGas(2)
330329
331- this.setMemory(offset, U256_SIZE_BYTES, this.environment.block.difficulty.toMemory())
330+ this.setMemory(offset, U256_SIZE_BYTES, this.kernel.environment.block.difficulty.toMemory())
332331 }
333332
334333 /**
335334 * Get the block’s gas limit.
@@ -337,9 +336,9 @@
337336 */
338337 getBlockGasLimit () {
339338 this.takeGas(2)
340339
341- return this.environment.block.gasLimit
340+ return this.kernel.environment.block.gasLimit
342341 }
343342
344343 /**
345344 * Creates a new log in the current environment
@@ -372,9 +371,9 @@
372371 if (numberOfTopics > 3) {
373372 topics.push(U256.fromMemory(this.getMemory(topic4, U256_SIZE_BYTES)))
374373 }
375374
376- this.environment.logs.push({
375+ this.kernel.environment.logs.push({
377376 data: data,
378377 topics: topics
379378 })
380379 }
@@ -395,9 +394,9 @@
395394 const data = this.getMemory(dataOffset, length).slice(0)
396395 // const [errorCode, address] = this.environment.create(value, data)
397396 }
398397 let address
399- if (value.gt(this.environment.value)) {
398+ if (value.gt(this.kernel.environment.value)) {
400399 address = new Address()
401400 } else {
402401 address = new Address('0x945304eb96065b2a98b57a48a06ae28d285a71b5')
403402 }
@@ -517,9 +516,9 @@
517516 const path = [...this.getMemory(pathOffset, U256_SIZE_BYTES)]
518517 // copy the value
519518 const value = this.getMemory(valueOffset, U256_SIZE_BYTES).slice(0)
520519 const valIsZero = value.every((i) => i === 0)
521- const opPromise = this.environment.state.get(path)
520+ const opPromise = this.kernel.environment.state.get(path)
522521 .catch(() => {
523522 // TODO: handle errors
524523 // the value was not found
525524 return null
@@ -527,17 +526,17 @@
527526
528527 this.kernel.pushOpsQueue(opPromise, cbDest, oldValue => {
529528 if (valIsZero && oldValue) {
530529 // delete a value
531- this.environment.gasRefund += 15000
532- this.environment.state.del(path)
530+ this.kernel.environment.gasRefund += 15000
531+ this.kernel.environment.state.del(path)
533532 } else {
534533 if (!valIsZero && !oldValue) {
535534 // creating a new value
536535 this.takeGas(15000)
537536 }
538537 // update
539- this.environment.state.set(path, value)
538+ this.kernel.environment.state.set(path, value)
540539 }
541540 })
542541 }
543542
@@ -550,9 +549,9 @@
550549 this.takeGas(50)
551550
552551 // convert the path to an array
553552 const path = [...this.getMemory(pathOffset, U256_SIZE_BYTES)]
554- const opPromise = this.environment.state.get(path)
553+ const opPromise = this.kernel.environment.state.get(path)
555554 .catch(() => {
556555 // TODO: handle other possible errors
557556 // if the value was not found return a empty array
558557 return new Uint8Array(32)
@@ -569,9 +568,9 @@
569568 * @param {integer} length the length of the output data.
570569 */
571570 return (offset, length) {
572571 if (length) {
573- this.environment.returnValue = this.getMemory(offset, length).slice(0)
572+ this.kernel.environment.returnValue = this.getMemory(offset, length).slice(0)
574573 }
575574 }
576575
577576 /**
@@ -579,11 +578,11 @@
579578 * balance to an address path
580579 * @param {integer} offset the offset to load the address from
581580 */
582581 selfDestruct (addressOffset) {
583- this.environment.selfDestruct = true
584- this.environment.selfDestructAddress = Address.fromMemory(this.getMemory(addressOffset, ADDRESS_SIZE_BYTES))
585- this.environment.gasRefund += 24000
582+ this.kernel.environment.selfDestruct = true
583+ this.kernel.environment.selfDestructAddress = Address.fromMemory(this.getMemory(addressOffset, ADDRESS_SIZE_BYTES))
584+ this.kernel.environment.gasRefund += 24000
586585 }
587586
588587 getMemory (offset, length) {
589588 return new Uint8Array(this.kernel.memory, offset, length)
@@ -598,12 +597,12 @@
598597 * Takes gas from the tank. Only needs to check if there's gas left to be taken,
599598 * because every caller of this method is trusted.
600599 */
601600 takeGas (amount) {
602- if (this.environment.gasLeft < amount) {
601+ if (this.kernel.environment.gasLeft < amount) {
603602 throw new Error('Ran out of gas')
604603 }
605- this.environment.gasLeft -= amount
604+ this.kernel.environment.gasLeft -= amount
606605 }
607606 }
608607
609608 // converts a 64 bit number to a JS number
debugKernel.jsView
@@ -1,15 +1,0 @@
1-const Kernel = require('./index.js')
2-const KernelInterface = require('./kernelInterface.js')
3-const Environment = require('./environment.js')
4-
5-module.exports = class DebugKernel extends Kernel {
6- codeHandler (code, environment = new Environment({state: this.state})) {
7- const kernelInterface = new KernelInterface(this, environment)
8- const promise = kernelInterface.run(code)
9- // expose the memory for debugging
10- this.memory = kernelInterface.memory
11- this.instance = kernelInterface._instance
12- this.onDone = kernelInterface.onDone.bind(kernelInterface)
13- return promise
14- }
15-}
kernelInterface.jsView
@@ -1,50 +1,0 @@
1-module.exports = class KernelInterface {
2- constructor (kernel, environment) {
3- this._kernel = kernel
4- this._environment = environment
5- }
6-
7- run (code) {
8- const imports = this._kernel.interfaces.reduce((obj, Interface) => {
9- obj[Interface.name] = new Interface(this).exports
10- return obj
11- }, {})
12-
13- const module = WebAssembly.Module(code)
14- const instance = this._instance = WebAssembly.Instance(module, imports)
15-
16- if (instance.exports.main) {
17- instance.exports.main()
18- }
19- return this.onDone()
20- }
21-
22- // returns a promise that resolves when the wasm instance is done running
23- async onDone () {
24- let prevOps
25- while (prevOps !== this._opsQueue) {
26- prevOps = this._opsQueue
27- await this._opsQueue
28- }
29- }
30-
31- pushOpsQueue (promise, callbackIndex, intefaceCallback) {
32- this._opsQueue = Promise.all([this._opsQueue, promise]).then(values => {
33- intefaceCallback(values.pop())
34- this._instance.exports[callbackIndex.toString()]()
35- })
36- }
37-
38- sendMessage (message) {
39-
40- }
41-
42- get environment () {
43- return this._environment
44- }
45-
46- get memory () {
47- return this._instance.exports.memory
48- }
49-
50-}
precompiles/create.jsView
@@ -1,0 +1,55 @@
1+ createHandler (create) {
2+ let code = create.data
3+
4+ // Inject metering
5+ if (Utils.isWASMCode(code)) {
6+ // FIXME: decide if these are the right values here: from: 0, gasLimit: 0, value: 0
7+ code = this.callHandler({
8+ from: Address.zero(),
9+ to: meteringContract,
10+ gasLimit: 0,
11+ value: new U256(0),
12+ data: code
13+ }).returnValue
14+
15+ if (code[0] === 0) {
16+ code = code.slice(1)
17+ } else {
18+ throw new Error('Metering injection failed: ' + Buffer.from(code).slice(1).toString())
19+ }
20+ }
21+
22+ let account = this.environment.state.get(create.from.toString())
23+ if (!account) {
24+ throw new Error('Account not found: ' + create.from.toString())
25+ }
26+
27+ let address = Utils.newAccountAddress(create.from, account.get('nonce'))
28+
29+ this.environment.addAccount(address.toString(), {
30+ balance: create.value,
31+ code: code
32+ })
33+
34+ // Run code and take return value as contract code
35+ // FIXME: decide if these are the right values here: value: 0, data: ''
36+ code = this.messageHandler({
37+ from: create.from,
38+ to: address,
39+ gasLimit: create.gasLimit,
40+ value: new U256(0),
41+ data: new Uint8Array()
42+ }).returnValue
43+
44+ // FIXME: special handling for selfdestruct
45+
46+ this.environment.state.get(address.toString()).set('code', code)
47+
48+ return {
49+ executionOutcome: 1, // success
50+ gasLeft: new U256(this.environment.gasLeft),
51+ gasRefund: new U256(this.environment.gasRefund),
52+ accountCreated: address,
53+ logs: this.environment.logs
54+ }
55+ }
precompiles/precompile.jsView
@@ -1,0 +1,29 @@
1+// const evm2wasm = require('evm2wasm')
2+// const metering = require('wasm-metering')
3+
4+function craftResponse (status, msg) {
5+ // NOTE: why does this has to be so hard?
6+ return Uint8Array.from(Buffer.concat([ new Buffer([ status ]), new Buffer(msg) ]))
7+}
8+
9+module.exports.meteringInjector = function (call) {
10+ console.log('Executing metering injector')
11+ return {
12+ // returnValue: metering.injectWAST(call.data, 2).slice(0)
13+ returnValue: craftResponse(0, call.data)
14+ }
15+}
16+
17+module.exports.transcompiler = function (call) {
18+ console.log('Executing transcompiler')
19+ return {
20+ // returnValue: evm2wasm.compileEVM(call.data).slice(0)
21+ returnValue: craftResponse(1, 'Code not supported: ' + Buffer.from(call.data.slice(0, 8)).toString('hex') + '...')
22+ }
23+}
24+
25+module.exports.identity = function (call) {
26+ return {
27+ returnValue: call.data.slice(0)
28+ }
29+}
precompile.jsView
@@ -1,29 +1,0 @@
1-// const evm2wasm = require('evm2wasm')
2-// const metering = require('wasm-metering')
3-
4-function craftResponse (status, msg) {
5- // NOTE: why does this has to be so hard?
6- return Uint8Array.from(Buffer.concat([ new Buffer([ status ]), new Buffer(msg) ]))
7-}
8-
9-module.exports.meteringInjector = function (call) {
10- console.log('Executing metering injector')
11- return {
12- // returnValue: metering.injectWAST(call.data, 2).slice(0)
13- returnValue: craftResponse(0, call.data)
14- }
15-}
16-
17-module.exports.transcompiler = function (call) {
18- console.log('Executing transcompiler')
19- return {
20- // returnValue: evm2wasm.compileEVM(call.data).slice(0)
21- returnValue: craftResponse(1, 'Code not supported: ' + Buffer.from(call.data.slice(0, 8)).toString('hex') + '...')
22- }
23-}
24-
25-module.exports.identity = function (call) {
26- return {
27- returnValue: call.data.slice(0)
28- }
29-}

Built with git-ssb-web