git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit a01401f258acd7e0b1f4ecbe82cdd1bc26048b4c

renamed imports to interfacee

wanderer committed on 1/9/2017, 7:47:18 PM
Parent: e0a962d924b51e646934cc30ae1c50df8f1ef31a

Files changed

index.jschanged
tests/interfaceRunner.jschanged
vm.jschanged
EVMimports.jsdeleted
EVMinterface.jsadded
index.jsView
@@ -1,42 +1,47 @@
11 const Vertex = require('merkle-trie')
22 // The Kernel Exposes this Interface to VM instances it makes
3-const Imports = require('./EVMimports.js')
3+const defaultInterface = require('./EVMinterface.js')
44 const VM = require('./vm.js')
55 const Environment = require('./environment.js')
66
77 module.exports = class Kernel {
88 constructor (opts = {}) {
9- opts.state = opts.state || new Vertex(opts.code)
10- opts.code = opts.state.value || opts.code
11-
12- // if code is bound to this kernel then create the interfaceAPI and the imports
13- this._vm = new VM(opts.code)
14- this.imports = buildImports(this._vm, opts.interfaces)
15-
16- /**
17- * Builds a import map with an array of given interfaces
18- */
19- function buildImports (api, imports = [Imports]) {
20- return imports.reduce((obj, InterfaceConstuctor) => {
21- obj[InterfaceConstuctor.name] = new InterfaceConstuctor(api).exports
22- return obj
23- }, {})
24- }
9+ this.state = opts.state || new Vertex()
10+ this.state.value = opts.code || this.state.value
11+ this.interfaces = opts.interfaces || [defaultInterface]
12+ this._vm = new VM(this.state.value)
2513 }
2614
2715 /**
2816 * run the kernels code with a given enviroment
2917 * The Kernel Stores all of its state in the Environment. The Interface is used
3018 * to by the VM to retrive infromation from the Environment.
3119 */
32- async run (environment = new Environment({state: this}), imports = this.imports) {
33- await this._vm.run(environment, imports)
20+ async run (environment = new Environment({state: this}), interfaces = this.interfaces) {
21+ /**
22+ * Builds a import map with an array of given interfaces
23+ */
24+ async function buildImports (kernelApi, imports, state) {
25+ const result = {}
26+ for (const Import of imports) {
27+ const newIterface = new Import(kernelApi)
28+ result[Import.name] = newIterface.exports
29+ // initailize the import
30+ await newIterface.initialize(state)
31+ }
32+ return result
33+ }
34+
35+ const initializedImports = await buildImports(this._vm, interfaces, this.state)
36+ return await this._vm.run(environment, initializedImports)
3437 }
3538
3639 async messageReceiver (message) {
3740 // let the code handle the message if there is code
38- const environment = new Environment(message)
41+ const environment = new Environment({
42+ message: message
43+ })
3944 let result = await this.run(environment)
4045 if (!result.execption) {
4146 this.state = result.state
4247 }
tests/interfaceRunner.jsView
@@ -25,9 +25,8 @@
2525 const envData = JSON.parse(fs.readFileSync(`${dir}/${testName}.json`).toString())
2626
2727 envData.caller = new Address(envData.caller)
2828 envData.address = new Address(envData.address)
29- envData.coinbase = new Address(envData.coinbase)
3029 envData.origin = new Address(envData.origin)
3130 envData.callData = new Buffer(envData.callData.slice(2), 'hex')
3231 envData.callValue = new U256(envData.callValue)
3332
@@ -52,13 +51,21 @@
5251 const path = ['accounts', ...new Buffer(address.slice(2), 'hex')]
5352 rootVertex.set(path, accountVertex)
5453 }
5554
56- envData.state = await rootVertex.get(['accounts', ...envData.address.toBuffer()])
55+ const state = envData.state = await rootVertex.get(['accounts', ...envData.address.toBuffer()])
56+ state.value = code
57+
58+ const env = new Environment(envData)
59+ env.block.header.coinbase = new Address(envData.coinbase)
60+
61+ rootVertex.set('block', new Vertex({
62+ value: env.block
63+ }))
64+
5765 const kernel = new Kernel({
58- code: code
66+ state: state
5967 })
60- const env = new Environment(envData)
6168
6269 try {
6370 await kernel.run(env)
6471 } catch (e) {
vm.jsView
@@ -9,16 +9,19 @@
99
1010 /**
1111 * Runs the core VM with a given environment and imports
1212 */
13- run (environment, imports) {
13+ async run (environment, imports) {
1414 this._environment = environment
1515 // TODO, delete the instance once done.
1616 const instance = this._instance = WebAssembly.Instance(this._module, imports)
1717 if (instance.exports.main) {
1818 instance.exports.main()
1919 }
20- return this.onDone()
20+ await this.onDone()
21+ const env = this._environment
22+ delete this._environment
23+ return env
2124 }
2225
2326 /**
2427 * returns a promise that resolves when the wasm instance is done running
EVMimports.jsView
@@ -1,656 +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 path = require('path')
7-const ethUtil = require('ethereumjs-util')
8-const Vertex = require('merkle-trie')
9-const U256 = require('./deps/u256.js')
10-
11-const U128_SIZE_BYTES = 16
12-const ADDRESS_SIZE_BYTES = 20
13-const U256_SIZE_BYTES = 32
14-
15-// The interface exposed to the WebAessembly Core
16-module.exports = class Interface {
17- constructor (kernel) {
18- this.kernel = kernel
19- const shimBin = fs.readFileSync(path.join(__dirname, '/wasm/interface.wasm'))
20- const shimMod = WebAssembly.Module(shimBin)
21- this.shims = WebAssembly.Instance(shimMod, {
22- 'interface': {
23- 'useGas': this._useGas.bind(this),
24- 'getGasLeftHigh': this._getGasLeftHigh.bind(this),
25- 'getGasLeftLow': this._getGasLeftLow.bind(this),
26- 'call': this._call.bind(this)
27- }
28- })
29- }
30-
31- static get name () {
32- return 'ethereum'
33- }
34-
35- get exports () {
36- let exportMethods = [
37- // include all the public methods according to the Ethereum Environment Interface (EEI) r1
38- 'getAddress',
39- 'getBalance',
40- 'getTxOrigin',
41- 'getCaller',
42- 'getCallValue',
43- 'getCallDataSize',
44- 'callDataCopy',
45- 'callDataCopy256',
46- 'getCodeSize',
47- 'codeCopy',
48- 'getExternalCodeSize',
49- 'externalCodeCopy',
50- 'getTxGasPrice',
51- 'getBlockHash',
52- 'getBlockCoinbase',
53- 'getBlockTimestamp',
54- 'getBlockNumber',
55- 'getBlockDifficulty',
56- 'getBlockGasLimit',
57- 'log',
58- 'create',
59- 'callCode',
60- 'callDelegate',
61- 'storageStore',
62- 'storageLoad',
63- 'return',
64- 'selfDestruct'
65- ]
66- let ret = {}
67- exportMethods.forEach((method) => {
68- ret[method] = this[method].bind(this)
69- })
70-
71- // add shims
72- ret.useGas = this.shims.exports.useGas
73- ret.getGasLeft = this.shims.exports.getGasLeft
74- ret.call = this.shims.exports.call
75- return ret
76- }
77-
78- setModule (mod) {
79- this.module = mod
80- }
81-
82- /**
83- * Subtracts an amount to the gas counter
84- * @param {integer} amount the amount to subtract to the gas counter
85- */
86- _useGas (high, low) {
87- this.takeGas(from64bit(high, low))
88- }
89-
90- /**
91- * Returns the current amount of gas
92- * @return {integer}
93- */
94- _getGasLeftHigh () {
95- return Math.floor(this.kernel.environment.gasLeft / 4294967296)
96- }
97-
98- /**
99- * Returns the current amount of gas
100- * @return {integer}
101- */
102- _getGasLeftLow () {
103- return this.kernel.environment.gasLeft
104- }
105-
106- /**
107- * Gets address of currently executing account and loads it into memory at
108- * the given offset.
109- * @param {integer} offset
110- */
111- getAddress (offset) {
112- this.takeGas(2)
113-
114- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.address.toMemory())
115- }
116-
117- /**
118- * Gets balance of the given account and loads it into memory at the given
119- * offset.
120- * @param {integer} addressOffset the memory offset to laod the address
121- * @param {integer} resultOffset
122- */
123- getBalance (addressOffset, offset, cbIndex) {
124- this.takeGas(20)
125-
126- const path = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'balance']
127- const opPromise = this.kernel.environment.state.root.get(path)
128- .then(vertex => new U256(vertex.value))
129- .catch(() => new U256(0))
130-
131- this.kernel.pushOpsQueue(opPromise, cbIndex, balance => {
132- this.setMemory(offset, U128_SIZE_BYTES, balance.toMemory(U128_SIZE_BYTES))
133- })
134- }
135-
136- /**
137- * Gets the execution's origination address and loads it into memory at the
138- * given offset. This is the sender of original transaction; it is never an
139- * account with non-empty associated code.
140- * @param {integer} offset
141- */
142- getTxOrigin (offset) {
143- this.takeGas(2)
144-
145- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.origin.toMemory())
146- }
147-
148- /**
149- * Gets caller address and loads it into memory at the given offset. This is
150- * the address of the account that is directly responsible for this execution.
151- * @param {integer} offset
152- */
153- getCaller (offset) {
154- this.takeGas(2)
155-
156- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.caller.toMemory())
157- }
158-
159- /**
160- * Gets the deposited value by the instruction/transaction responsible for
161- * this execution and loads it into memory at the given location.
162- * @param {integer} offset
163- */
164- getCallValue (offset) {
165- this.takeGas(2)
166-
167- this.setMemory(offset, U128_SIZE_BYTES, this.kernel.environment.callValue.toMemory(U128_SIZE_BYTES))
168- }
169-
170- /**
171- * Get size of input data in current environment. This pertains to the input
172- * data passed with the message call instruction or transaction.
173- * @return {integer}
174- */
175- getCallDataSize () {
176- this.takeGas(2)
177-
178- return this.kernel.environment.callData.length
179- }
180-
181- /**
182- * Copys the input data in current environment to memory. This pertains to
183- * the input data passed with the message call instruction or transaction.
184- * @param {integer} offset the offset in memory to load into
185- * @param {integer} dataOffset the offset in the input data
186- * @param {integer} length the length of data to copy
187- */
188- callDataCopy (offset, dataOffset, length) {
189- this.takeGas(3 + Math.ceil(length / 32) * 3)
190-
191- if (length) {
192- const callData = this.kernel.environment.callData.slice(dataOffset, dataOffset + length)
193- this.setMemory(offset, length, callData)
194- }
195- }
196-
197- /**
198- * Copys the input data in current environment to memory. This pertains to
199- * the input data passed with the message call instruction or transaction.
200- * @param {integer} offset the offset in memory to load into
201- * @param {integer} dataOffset the offset in the input data
202- */
203- callDataCopy256 (offset, dataOffset) {
204- this.takeGas(3)
205- const callData = this.kernel.environment.callData.slice(dataOffset, dataOffset + 32)
206- this.setMemory(offset, U256_SIZE_BYTES, callData)
207- }
208-
209- /**
210- * Gets the size of code running in current environment.
211- * @return {interger}
212- */
213- getCodeSize (cbIndex) {
214- this.takeGas(2)
215-
216- const opPromise = this.kernel.environment.state
217- .get('code')
218- .then(vertex => vertex.value.length)
219-
220- // wait for all the prevouse async ops to finish before running the callback
221- this.kernel.pushOpsQueue(opPromise, cbIndex, length => length)
222- }
223-
224- /**
225- * Copys the code running in current environment to memory.
226- * @param {integer} offset the memory offset
227- * @param {integer} codeOffset the code offset
228- * @param {integer} length the length of code to copy
229- */
230- codeCopy (resultOffset, codeOffset, length, cbIndex) {
231- this.takeGas(3 + Math.ceil(length / 32) * 3)
232-
233- let opPromise
234-
235- if (length) {
236- opPromise = this.kernel.environment.state
237- .get('code')
238- .then(vertex => vertex.value)
239- } else {
240- opPromise = Promise.resolve([])
241- }
242-
243- // wait for all the prevouse async ops to finish before running the callback
244- this.kernel.pushOpsQueue(opPromise, cbIndex, code => {
245- if (code.length) {
246- code = code.slice(codeOffset, codeOffset + length)
247- this.setMemory(resultOffset, length, code)
248- }
249- })
250- }
251-
252- /**
253- * Get size of an account’s code.
254- * @param {integer} addressOffset the offset in memory to load the address from
255- * @return {integer}
256- */
257- getExternalCodeSize (addressOffset, cbOffset) {
258- this.takeGas(20)
259- const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code']
260- const opPromise = this.kernel.environment.state.root
261- .get(address)
262- .then(vertex => vertex.value.length)
263- .catch(() => 0)
264-
265- // wait for all the prevouse async ops to finish before running the callback
266- this.kernel.pushOpsQueue(opPromise, cbOffset, length => length)
267- }
268-
269- /**
270- * Copys the code of an account to memory.
271- * @param {integer} addressOffset the memory offset of the address
272- * @param {integer} resultOffset the memory offset
273- * @param {integer} codeOffset the code offset
274- * @param {integer} length the length of code to copy
275- */
276- externalCodeCopy (addressOffset, resultOffset, codeOffset, length, cbIndex) {
277- this.takeGas(20 + Math.ceil(length / 32) * 3)
278-
279- const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code']
280- let opPromise
281-
282- if (length) {
283- opPromise = this.kernel.environment.state.root
284- .get(address)
285- .then(vertex => vertex.value)
286- .catch(() => [])
287- } else {
288- opPromise = Promise.resolve([])
289- }
290-
291- // wait for all the prevouse async ops to finish before running the callback
292- this.kernel.pushOpsQueue(opPromise, cbIndex, code => {
293- if (code.length) {
294- code = code.slice(codeOffset, codeOffset + length)
295- this.setMemory(resultOffset, length, code)
296- }
297- })
298- }
299-
300- /**
301- * Gets price of gas in current environment.
302- * @return {integer}
303- */
304- getTxGasPrice () {
305- this.takeGas(2)
306-
307- return this.kernel.environment.gasPrice
308- }
309-
310- /**
311- * Gets the hash of one of the 256 most recent complete blocks.
312- * @param {integer} number which block to load
313- * @param {integer} offset the offset to load the hash into
314- */
315- getBlockHash (number, offset, cbOffset) {
316- this.takeGas(20)
317-
318- const diff = this.kernel.environment.block.number - number
319- let opPromise
320-
321- if (diff > 256 || diff <= 0) {
322- opPromise = Promise.resolve(new U256(0))
323- } else {
324- opPromise = this.kernel.environment.getBlockHash(number)
325- }
326-
327- // wait for all the prevouse async ops to finish before running the callback
328- this.kernel.pushOpsQueue(opPromise, cbOffset, hash => {
329- this.setMemory(offset, U256_SIZE_BYTES, hash.toMemory())
330- })
331- }
332-
333- /**
334- * Gets the block’s beneficiary address and loads into memory.
335- * @param offset
336- */
337- getBlockCoinbase (offset) {
338- this.takeGas(2)
339-
340- this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.coinbase.toMemory())
341- }
342-
343- /**
344- * Get the block’s timestamp.
345- * @return {integer}
346- */
347- getBlockTimestamp () {
348- this.takeGas(2)
349-
350- return this.kernel.environment.block.timestamp
351- }
352-
353- /**
354- * Get the block’s number.
355- * @return {integer}
356- */
357- getBlockNumber () {
358- this.takeGas(2)
359-
360- return this.kernel.environment.block.number
361- }
362-
363- /**
364- * Get the block’s difficulty.
365- * @return {integer}
366- */
367- getBlockDifficulty (offset) {
368- this.takeGas(2)
369-
370- this.setMemory(offset, U256_SIZE_BYTES, this.kernel.environment.block.difficulty.toMemory())
371- }
372-
373- /**
374- * Get the block’s gas limit.
375- * @return {integer}
376- */
377- getBlockGasLimit () {
378- this.takeGas(2)
379-
380- return this.kernel.environment.block.gasLimit
381- }
382-
383- /**
384- * Creates a new log in the current environment
385- * @param {integer} dataOffset the offset in memory to load the memory
386- * @param {integer} length the data length
387- * @param {integer} number of topics
388- */
389- log (dataOffset, length, numberOfTopics, topic1, topic2, topic3, topic4) {
390- if (numberOfTopics < 0 || numberOfTopics > 4) {
391- throw new Error('Invalid numberOfTopics')
392- }
393-
394- this.takeGas(375 + length * 8 + numberOfTopics * 375)
395-
396- const data = length ? this.getMemory(dataOffset, length).slice(0) : new Uint8Array([])
397- const topics = []
398-
399- if (numberOfTopics > 0) {
400- topics.push(U256.fromMemory(this.getMemory(topic1, U256_SIZE_BYTES)))
401- }
402-
403- if (numberOfTopics > 1) {
404- topics.push(U256.fromMemory(this.getMemory(topic2, U256_SIZE_BYTES)))
405- }
406-
407- if (numberOfTopics > 2) {
408- topics.push(U256.fromMemory(this.getMemory(topic3, U256_SIZE_BYTES)))
409- }
410-
411- if (numberOfTopics > 3) {
412- topics.push(U256.fromMemory(this.getMemory(topic4, U256_SIZE_BYTES)))
413- }
414-
415- this.kernel.environment.logs.push({
416- data: data,
417- topics: topics
418- })
419- }
420-
421- /**
422- * Creates a new contract with a given value.
423- * @param {integer} valueOffset the offset in memory to the value from
424- * @param {integer} dataOffset the offset to load the code for the new contract from
425- * @param {integer} length the data length
426- * @param (integer} resultOffset the offset to write the new contract address to
427- * @return {integer} Return 1 or 0 depending on if the VM trapped on the message or not
428- */
429- create (valueOffset, dataOffset, length, resultOffset, cbIndex) {
430- this.takeGas(32000)
431-
432- const value = U256.fromMemory(this.getMemory(valueOffset, U128_SIZE_BYTES))
433- // if (length) {
434- // const code = this.getMemory(dataOffset, length).slice(0)
435- // }
436-
437- let opPromise
438-
439- if (value.gt(this.kernel.environment.value)) {
440- opPromise = Promise.resolve(new Buffer(20).fill(0))
441- } else {
442- // todo actully run the code
443- opPromise = Promise.resolve(ethUtil.generateAddress(this.kernel.environment.address, this.kernel.environment.nonce))
444- }
445-
446- // wait for all the prevouse async ops to finish before running the callback
447- this.kernel.pushOpsQueue(opPromise, cbIndex, address => {
448- this.setMemory(resultOffset, ADDRESS_SIZE_BYTES, address)
449- })
450- }
451-
452- /**
453- * Sends a message with arbiatary data to a given address path
454- * @param {integer} addressOffset the offset to load the address path from
455- * @param {integer} valueOffset the offset to load the value from
456- * @param {integer} dataOffset the offset to load data from
457- * @param {integer} dataLength the length of data
458- * @param {integer} resultOffset the offset to store the result data at
459- * @param {integer} resultLength
460- * @param {integer} gas
461- * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
462- */
463- _call (gasHigh, gasLow, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, cbIndex) {
464- this.takeGas(40)
465-
466- const gas = from64bit(gasHigh, gasLow)
467- // Load the params from mem
468- const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
469- const value = new U256(this.getMemory(valueOffset, U128_SIZE_BYTES))
470-
471- // Special case for non-zero value; why does this exist?
472- if (!value.isZero()) {
473- this.takeGas(9000 - 2300 + gas)
474- this.takeGas(-gas)
475- }
476-
477- let opPromise = this.kernel.environment.state.root.get(address)
478- .catch(() => {
479- // why does this exist?
480- this.takeGas(25000)
481- })
482-
483- // wait for all the prevouse async ops to finish before running the callback
484- this.kernel.pushOpsQueue(opPromise, cbIndex, () => {
485- return 1
486- })
487- }
488-
489- /**
490- * Message-call into this account with an alternative account’s code.
491- * @param {integer} addressOffset the offset to load the address path from
492- * @param {integer} valueOffset the offset to load the value from
493- * @param {integer} dataOffset the offset to load data from
494- * @param {integer} dataLength the length of data
495- * @param {integer} resultOffset the offset to store the result data at
496- * @param {integer} resultLength
497- * @param {integer} gas
498- * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
499- */
500- callCode (gas, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, cbIndex) {
501- this.takeGas(40)
502- // Load the params from mem
503- const path = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code']
504- const value = U256.fromMemory(this.getMemory(valueOffset, U128_SIZE_BYTES))
505-
506- // Special case for non-zero value; why does this exist?
507- if (!value.isZero()) {
508- this.takeGas(6700)
509- }
510-
511- // TODO: should be message?
512- const opPromise = this.kernel.environment.state.root.get(path)
513- .catch(() => {
514- // TODO: handle errors
515- // the value was not found
516- return null
517- })
518-
519- this.kernel.pushOpsQueue(opPromise, cbIndex, oldValue => {
520- return 1
521- })
522- }
523-
524- /**
525- * Message-call into this account with an alternative account’s code, but
526- * persisting the current values for sender and value.
527- * @param {integer} gas
528- * @param {integer} addressOffset the offset to load the address path from
529- * @param {integer} valueOffset the offset to load the value from
530- * @param {integer} dataOffset the offset to load data from
531- * @param {integer} dataLength the length of data
532- * @param {integer} resultOffset the offset to store the result data at
533- * @param {integer} resultLength
534- * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
535- */
536- callDelegate (gas, addressOffset, dataOffset, dataLength, resultOffset, resultLength) {
537- // FIXME: count properly
538- this.takeGas(40)
539-
540- const data = this.getMemory(dataOffset, dataLength).slice(0)
541- const address = [...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
542- const [errorCode, result] = this.environment.callDelegate(gas, address, data)
543- this.setMemory(resultOffset, resultLength, result)
544- return errorCode
545- }
546-
547- /**
548- * store a value at a given path in long term storage which are both loaded
549- * from Memory
550- * @param {interger} pathOffest the memory offset to load the the path from
551- * @param {interger} valueOffset the memory offset to load the value from
552- */
553- storageStore (pathOffset, valueOffset, cbIndex) {
554- this.takeGas(5000)
555- const path = ['storage', ...this.getMemory(pathOffset, U256_SIZE_BYTES)]
556- // copy the value
557- const value = this.getMemory(valueOffset, U256_SIZE_BYTES).slice(0)
558- const valIsZero = value.every((i) => i === 0)
559- const opPromise = this.kernel.environment.state.get(path)
560- .then(vertex => vertex.value)
561- .catch(() => null)
562-
563- this.kernel.pushOpsQueue(opPromise, cbIndex, oldValue => {
564- if (valIsZero && oldValue) {
565- // delete a value
566- this.kernel.environment.gasRefund += 15000
567- this.kernel.environment.state.del(path)
568- } else {
569- if (!valIsZero && !oldValue) {
570- // creating a new value
571- this.takeGas(15000)
572- }
573- // update
574- this.kernel.environment.state.set(path, new Vertex({
575- value: value
576- }))
577- }
578- })
579- }
580-
581- /**
582- * reterives a value at a given path in long term storage
583- * @param {interger} pathOffest the memory offset to load the the path from
584- * @param {interger} resultOffset the memory offset to load the value from
585- */
586- storageLoad (pathOffset, resultOffset, cbIndex) {
587- this.takeGas(50)
588-
589- // convert the path to an array
590- const path = ['storage', ...this.getMemory(pathOffset, U256_SIZE_BYTES)]
591- // get the value from the state
592- const opPromise = this.kernel.environment.state.get(path)
593- .then(vertex => vertex.value)
594- .catch(() => new Uint8Array(32))
595-
596- this.kernel.pushOpsQueue(opPromise, cbIndex, value => {
597- this.setMemory(resultOffset, U256_SIZE_BYTES, value)
598- })
599- }
600-
601- /**
602- * Halt execution returning output data.
603- * @param {integer} offset the offset of the output data.
604- * @param {integer} length the length of the output data.
605- */
606- return (offset, length) {
607- if (length) {
608- this.kernel.environment.returnValue = this.getMemory(offset, length).slice(0)
609- }
610- }
611-
612- /**
613- * Halt execution and register account for later deletion giving the remaining
614- * balance to an address path
615- * @param {integer} offset the offset to load the address from
616- */
617- selfDestruct (addressOffset) {
618- this.kernel.environment.selfDestruct = true
619- this.kernel.environment.selfDestructAddress = this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)
620- this.kernel.environment.gasRefund += 24000
621- }
622-
623- getMemory (offset, length) {
624- return new Uint8Array(this.kernel.memory, offset, length)
625- }
626-
627- setMemory (offset, length, value) {
628- const memory = new Uint8Array(this.kernel.memory, offset, length)
629- memory.set(value)
630- }
631-
632- /*
633- * Takes gas from the tank. Only needs to check if there's gas left to be taken,
634- * because every caller of this method is trusted.
635- */
636- takeGas (amount) {
637- if (this.kernel.environment.gasLeft < amount) {
638- throw new Error('Ran out of gas')
639- }
640- this.kernel.environment.gasLeft -= amount
641- }
642-}
643-
644-// converts a 64 bit number to a JS number
645-function from64bit (high, low) {
646- if (high < 0) {
647- // convert from a 32-bit two's compliment
648- high = 0x100000000 - high
649- }
650- if (low < 0) {
651- // convert from a 32-bit two's compliment
652- low = 0x100000000 - low
653- }
654- // JS only bitshift 32bits, so instead of high << 32 we have high * 2 ^ 32
655- return (high * 4294967296) + low
656-}
EVMinterface.jsView
@@ -1,0 +1,661 @@
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 path = require('path')
7+const ethUtil = require('ethereumjs-util')
8+const Vertex = require('merkle-trie')
9+const U256 = require('./deps/u256.js')
10+
11+const U128_SIZE_BYTES = 16
12+const ADDRESS_SIZE_BYTES = 20
13+const U256_SIZE_BYTES = 32
14+
15+// The interface exposed to the WebAessembly VM
16+module.exports = class Interface {
17+ constructor (kernel) {
18+ this.kernel = kernel
19+ const shimBin = fs.readFileSync(path.join(__dirname, '/wasm/interface.wasm'))
20+ const shimMod = WebAssembly.Module(shimBin)
21+ this.shims = WebAssembly.Instance(shimMod, {
22+ 'interface': {
23+ 'useGas': this._useGas.bind(this),
24+ 'getGasLeftHigh': this._getGasLeftHigh.bind(this),
25+ 'getGasLeftLow': this._getGasLeftLow.bind(this),
26+ 'call': this._call.bind(this)
27+ }
28+ })
29+ }
30+
31+ async initialize (state) {
32+ this.block = await state.root.get(['block'])
33+ // this.blockchain = await state.get(['blockchain'])
34+ }
35+
36+ static get name () {
37+ return 'ethereum'
38+ }
39+
40+ get exports () {
41+ let exportMethods = [
42+ // include all the public methods according to the Ethereum Environment Interface (EEI) r1
43+ 'getAddress',
44+ 'getBalance',
45+ 'getTxOrigin',
46+ 'getCaller',
47+ 'getCallValue',
48+ 'getCallDataSize',
49+ 'callDataCopy',
50+ 'callDataCopy256',
51+ 'getCodeSize',
52+ 'codeCopy',
53+ 'getExternalCodeSize',
54+ 'externalCodeCopy',
55+ 'getTxGasPrice',
56+ 'getBlockHash',
57+ 'getBlockCoinbase',
58+ 'getBlockTimestamp',
59+ 'getBlockNumber',
60+ 'getBlockDifficulty',
61+ 'getBlockGasLimit',
62+ 'log',
63+ 'create',
64+ 'callCode',
65+ 'callDelegate',
66+ 'storageStore',
67+ 'storageLoad',
68+ 'return',
69+ 'selfDestruct'
70+ ]
71+ let ret = {}
72+ exportMethods.forEach((method) => {
73+ ret[method] = this[method].bind(this)
74+ })
75+
76+ // add shims
77+ ret.useGas = this.shims.exports.useGas
78+ ret.getGasLeft = this.shims.exports.getGasLeft
79+ ret.call = this.shims.exports.call
80+ return ret
81+ }
82+
83+ setModule (mod) {
84+ this.module = mod
85+ }
86+
87+ /**
88+ * Subtracts an amount to the gas counter
89+ * @param {integer} amount the amount to subtract to the gas counter
90+ */
91+ _useGas (high, low) {
92+ this.takeGas(from64bit(high, low))
93+ }
94+
95+ /**
96+ * Returns the current amount of gas
97+ * @return {integer}
98+ */
99+ _getGasLeftHigh () {
100+ return Math.floor(this.kernel.environment.gasLeft / 4294967296)
101+ }
102+
103+ /**
104+ * Returns the current amount of gas
105+ * @return {integer}
106+ */
107+ _getGasLeftLow () {
108+ return this.kernel.environment.gasLeft
109+ }
110+
111+ /**
112+ * Gets address of currently executing account and loads it into memory at
113+ * the given offset.
114+ * @param {integer} offset
115+ */
116+ getAddress (offset) {
117+ this.takeGas(2)
118+
119+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.address.toMemory())
120+ }
121+
122+ /**
123+ * Gets balance of the given account and loads it into memory at the given
124+ * offset.
125+ * @param {integer} addressOffset the memory offset to laod the address
126+ * @param {integer} resultOffset
127+ */
128+ getBalance (addressOffset, offset, cbIndex) {
129+ this.takeGas(20)
130+
131+ const path = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'balance']
132+ const opPromise = this.kernel.environment.state.root.get(path)
133+ .then(vertex => new U256(vertex.value))
134+ .catch(() => new U256(0))
135+
136+ this.kernel.pushOpsQueue(opPromise, cbIndex, balance => {
137+ this.setMemory(offset, U128_SIZE_BYTES, balance.toMemory(U128_SIZE_BYTES))
138+ })
139+ }
140+
141+ /**
142+ * Gets the execution's origination address and loads it into memory at the
143+ * given offset. This is the sender of original transaction; it is never an
144+ * account with non-empty associated code.
145+ * @param {integer} offset
146+ */
147+ getTxOrigin (offset) {
148+ this.takeGas(2)
149+
150+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.origin.toMemory())
151+ }
152+
153+ /**
154+ * Gets caller address and loads it into memory at the given offset. This is
155+ * the address of the account that is directly responsible for this execution.
156+ * @param {integer} offset
157+ */
158+ getCaller (offset) {
159+ this.takeGas(2)
160+
161+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.caller.toMemory())
162+ }
163+
164+ /**
165+ * Gets the deposited value by the instruction/transaction responsible for
166+ * this execution and loads it into memory at the given location.
167+ * @param {integer} offset
168+ */
169+ getCallValue (offset) {
170+ this.takeGas(2)
171+
172+ this.setMemory(offset, U128_SIZE_BYTES, this.kernel.environment.callValue.toMemory(U128_SIZE_BYTES))
173+ }
174+
175+ /**
176+ * Get size of input data in current environment. This pertains to the input
177+ * data passed with the message call instruction or transaction.
178+ * @return {integer}
179+ */
180+ getCallDataSize () {
181+ this.takeGas(2)
182+
183+ return this.kernel.environment.callData.length
184+ }
185+
186+ /**
187+ * Copys the input data in current environment to memory. This pertains to
188+ * the input data passed with the message call instruction or transaction.
189+ * @param {integer} offset the offset in memory to load into
190+ * @param {integer} dataOffset the offset in the input data
191+ * @param {integer} length the length of data to copy
192+ */
193+ callDataCopy (offset, dataOffset, length) {
194+ this.takeGas(3 + Math.ceil(length / 32) * 3)
195+
196+ if (length) {
197+ const callData = this.kernel.environment.callData.slice(dataOffset, dataOffset + length)
198+ this.setMemory(offset, length, callData)
199+ }
200+ }
201+
202+ /**
203+ * Copys the input data in current environment to memory. This pertains to
204+ * the input data passed with the message call instruction or transaction.
205+ * @param {integer} offset the offset in memory to load into
206+ * @param {integer} dataOffset the offset in the input data
207+ */
208+ callDataCopy256 (offset, dataOffset) {
209+ this.takeGas(3)
210+ const callData = this.kernel.environment.callData.slice(dataOffset, dataOffset + 32)
211+ this.setMemory(offset, U256_SIZE_BYTES, callData)
212+ }
213+
214+ /**
215+ * Gets the size of code running in current environment.
216+ * @return {interger}
217+ */
218+ getCodeSize (cbIndex) {
219+ this.takeGas(2)
220+
221+ const opPromise = this.kernel.environment.state
222+ .get('code')
223+ .then(vertex => vertex.value.length)
224+
225+ // wait for all the prevouse async ops to finish before running the callback
226+ this.kernel.pushOpsQueue(opPromise, cbIndex, length => length)
227+ }
228+
229+ /**
230+ * Copys the code running in current environment to memory.
231+ * @param {integer} offset the memory offset
232+ * @param {integer} codeOffset the code offset
233+ * @param {integer} length the length of code to copy
234+ */
235+ codeCopy (resultOffset, codeOffset, length, cbIndex) {
236+ this.takeGas(3 + Math.ceil(length / 32) * 3)
237+
238+ let opPromise
239+
240+ if (length) {
241+ opPromise = this.kernel.environment.state
242+ .get('code')
243+ .then(vertex => vertex.value)
244+ } else {
245+ opPromise = Promise.resolve([])
246+ }
247+
248+ // wait for all the prevouse async ops to finish before running the callback
249+ this.kernel.pushOpsQueue(opPromise, cbIndex, code => {
250+ if (code.length) {
251+ code = code.slice(codeOffset, codeOffset + length)
252+ this.setMemory(resultOffset, length, code)
253+ }
254+ })
255+ }
256+
257+ /**
258+ * Get size of an account’s code.
259+ * @param {integer} addressOffset the offset in memory to load the address from
260+ * @return {integer}
261+ */
262+ getExternalCodeSize (addressOffset, cbOffset) {
263+ this.takeGas(20)
264+ const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code']
265+ const opPromise = this.kernel.environment.state.root
266+ .get(address)
267+ .then(vertex => vertex.value.length)
268+ .catch(() => 0)
269+
270+ // wait for all the prevouse async ops to finish before running the callback
271+ this.kernel.pushOpsQueue(opPromise, cbOffset, length => length)
272+ }
273+
274+ /**
275+ * Copys the code of an account to memory.
276+ * @param {integer} addressOffset the memory offset of the address
277+ * @param {integer} resultOffset the memory offset
278+ * @param {integer} codeOffset the code offset
279+ * @param {integer} length the length of code to copy
280+ */
281+ externalCodeCopy (addressOffset, resultOffset, codeOffset, length, cbIndex) {
282+ this.takeGas(20 + Math.ceil(length / 32) * 3)
283+
284+ const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code']
285+ let opPromise
286+
287+ if (length) {
288+ opPromise = this.kernel.environment.state.root
289+ .get(address)
290+ .then(vertex => vertex.value)
291+ .catch(() => [])
292+ } else {
293+ opPromise = Promise.resolve([])
294+ }
295+
296+ // wait for all the prevouse async ops to finish before running the callback
297+ this.kernel.pushOpsQueue(opPromise, cbIndex, code => {
298+ if (code.length) {
299+ code = code.slice(codeOffset, codeOffset + length)
300+ this.setMemory(resultOffset, length, code)
301+ }
302+ })
303+ }
304+
305+ /**
306+ * Gets price of gas in current environment.
307+ * @return {integer}
308+ */
309+ getTxGasPrice () {
310+ this.takeGas(2)
311+
312+ return this.kernel.environment.gasPrice
313+ }
314+
315+ /**
316+ * Gets the hash of one of the 256 most recent complete blocks.
317+ * @param {integer} number which block to load
318+ * @param {integer} offset the offset to load the hash into
319+ */
320+ getBlockHash (number, offset, cbOffset) {
321+ this.takeGas(20)
322+
323+ const diff = this.kernel.environment.block.number - number
324+ let opPromise
325+
326+ if (diff > 256 || diff <= 0) {
327+ opPromise = Promise.resolve(new U256(0))
328+ } else {
329+ opPromise = this.kernel.environment.getBlockHash(number)
330+ }
331+
332+ // wait for all the prevouse async ops to finish before running the callback
333+ this.kernel.pushOpsQueue(opPromise, cbOffset, hash => {
334+ this.setMemory(offset, U256_SIZE_BYTES, hash.toMemory())
335+ })
336+ }
337+
338+ /**
339+ * Gets the block’s beneficiary address and loads into memory.
340+ * @param offset
341+ */
342+ getBlockCoinbase (offset) {
343+ this.takeGas(2)
344+
345+ this.setMemory(offset, ADDRESS_SIZE_BYTES, this.kernel.environment.block.header.coinbase)
346+ }
347+
348+ /**
349+ * Get the block’s timestamp.
350+ * @return {integer}
351+ */
352+ getBlockTimestamp () {
353+ this.takeGas(2)
354+
355+ return this.kernel.environment.block.timestamp
356+ }
357+
358+ /**
359+ * Get the block’s number.
360+ * @return {integer}
361+ */
362+ getBlockNumber () {
363+ this.takeGas(2)
364+
365+ return this.kernel.environment.block.number
366+ }
367+
368+ /**
369+ * Get the block’s difficulty.
370+ * @return {integer}
371+ */
372+ getBlockDifficulty (offset) {
373+ this.takeGas(2)
374+
375+ this.setMemory(offset, U256_SIZE_BYTES, this.kernel.environment.block.difficulty.toMemory())
376+ }
377+
378+ /**
379+ * Get the block’s gas limit.
380+ * @return {integer}
381+ */
382+ getBlockGasLimit () {
383+ this.takeGas(2)
384+
385+ return this.kernel.environment.block.gasLimit
386+ }
387+
388+ /**
389+ * Creates a new log in the current environment
390+ * @param {integer} dataOffset the offset in memory to load the memory
391+ * @param {integer} length the data length
392+ * @param {integer} number of topics
393+ */
394+ log (dataOffset, length, numberOfTopics, topic1, topic2, topic3, topic4) {
395+ if (numberOfTopics < 0 || numberOfTopics > 4) {
396+ throw new Error('Invalid numberOfTopics')
397+ }
398+
399+ this.takeGas(375 + length * 8 + numberOfTopics * 375)
400+
401+ const data = length ? this.getMemory(dataOffset, length).slice(0) : new Uint8Array([])
402+ const topics = []
403+
404+ if (numberOfTopics > 0) {
405+ topics.push(U256.fromMemory(this.getMemory(topic1, U256_SIZE_BYTES)))
406+ }
407+
408+ if (numberOfTopics > 1) {
409+ topics.push(U256.fromMemory(this.getMemory(topic2, U256_SIZE_BYTES)))
410+ }
411+
412+ if (numberOfTopics > 2) {
413+ topics.push(U256.fromMemory(this.getMemory(topic3, U256_SIZE_BYTES)))
414+ }
415+
416+ if (numberOfTopics > 3) {
417+ topics.push(U256.fromMemory(this.getMemory(topic4, U256_SIZE_BYTES)))
418+ }
419+
420+ this.kernel.environment.logs.push({
421+ data: data,
422+ topics: topics
423+ })
424+ }
425+
426+ /**
427+ * Creates a new contract with a given value.
428+ * @param {integer} valueOffset the offset in memory to the value from
429+ * @param {integer} dataOffset the offset to load the code for the new contract from
430+ * @param {integer} length the data length
431+ * @param (integer} resultOffset the offset to write the new contract address to
432+ * @return {integer} Return 1 or 0 depending on if the VM trapped on the message or not
433+ */
434+ create (valueOffset, dataOffset, length, resultOffset, cbIndex) {
435+ this.takeGas(32000)
436+
437+ const value = U256.fromMemory(this.getMemory(valueOffset, U128_SIZE_BYTES))
438+ // if (length) {
439+ // const code = this.getMemory(dataOffset, length).slice(0)
440+ // }
441+
442+ let opPromise
443+
444+ if (value.gt(this.kernel.environment.value)) {
445+ opPromise = Promise.resolve(new Buffer(20).fill(0))
446+ } else {
447+ // todo actully run the code
448+ opPromise = Promise.resolve(ethUtil.generateAddress(this.kernel.environment.address, this.kernel.environment.nonce))
449+ }
450+
451+ // wait for all the prevouse async ops to finish before running the callback
452+ this.kernel.pushOpsQueue(opPromise, cbIndex, address => {
453+ this.setMemory(resultOffset, ADDRESS_SIZE_BYTES, address)
454+ })
455+ }
456+
457+ /**
458+ * Sends a message with arbiatary data to a given address path
459+ * @param {integer} addressOffset the offset to load the address path from
460+ * @param {integer} valueOffset the offset to load the value from
461+ * @param {integer} dataOffset the offset to load data from
462+ * @param {integer} dataLength the length of data
463+ * @param {integer} resultOffset the offset to store the result data at
464+ * @param {integer} resultLength
465+ * @param {integer} gas
466+ * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
467+ */
468+ _call (gasHigh, gasLow, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, cbIndex) {
469+ this.takeGas(40)
470+
471+ const gas = from64bit(gasHigh, gasLow)
472+ // Load the params from mem
473+ const address = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
474+ const value = new U256(this.getMemory(valueOffset, U128_SIZE_BYTES))
475+
476+ // Special case for non-zero value; why does this exist?
477+ if (!value.isZero()) {
478+ this.takeGas(9000 - 2300 + gas)
479+ this.takeGas(-gas)
480+ }
481+
482+ let opPromise = this.kernel.environment.state.root.get(address)
483+ .catch(() => {
484+ // why does this exist?
485+ this.takeGas(25000)
486+ })
487+
488+ // wait for all the prevouse async ops to finish before running the callback
489+ this.kernel.pushOpsQueue(opPromise, cbIndex, () => {
490+ return 1
491+ })
492+ }
493+
494+ /**
495+ * Message-call into this account with an alternative account’s code.
496+ * @param {integer} addressOffset the offset to load the address path from
497+ * @param {integer} valueOffset the offset to load the value from
498+ * @param {integer} dataOffset the offset to load data from
499+ * @param {integer} dataLength the length of data
500+ * @param {integer} resultOffset the offset to store the result data at
501+ * @param {integer} resultLength
502+ * @param {integer} gas
503+ * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
504+ */
505+ callCode (gas, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, cbIndex) {
506+ this.takeGas(40)
507+ // Load the params from mem
508+ const path = ['accounts', ...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES), 'code']
509+ const value = U256.fromMemory(this.getMemory(valueOffset, U128_SIZE_BYTES))
510+
511+ // Special case for non-zero value; why does this exist?
512+ if (!value.isZero()) {
513+ this.takeGas(6700)
514+ }
515+
516+ // TODO: should be message?
517+ const opPromise = this.kernel.environment.state.root.get(path)
518+ .catch(() => {
519+ // TODO: handle errors
520+ // the value was not found
521+ return null
522+ })
523+
524+ this.kernel.pushOpsQueue(opPromise, cbIndex, oldValue => {
525+ return 1
526+ })
527+ }
528+
529+ /**
530+ * Message-call into this account with an alternative account’s code, but
531+ * persisting the current values for sender and value.
532+ * @param {integer} gas
533+ * @param {integer} addressOffset the offset to load the address path from
534+ * @param {integer} valueOffset the offset to load the value from
535+ * @param {integer} dataOffset the offset to load data from
536+ * @param {integer} dataLength the length of data
537+ * @param {integer} resultOffset the offset to store the result data at
538+ * @param {integer} resultLength
539+ * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
540+ */
541+ callDelegate (gas, addressOffset, dataOffset, dataLength, resultOffset, resultLength) {
542+ // FIXME: count properly
543+ this.takeGas(40)
544+
545+ const data = this.getMemory(dataOffset, dataLength).slice(0)
546+ const address = [...this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)]
547+ const [errorCode, result] = this.environment.callDelegate(gas, address, data)
548+ this.setMemory(resultOffset, resultLength, result)
549+ return errorCode
550+ }
551+
552+ /**
553+ * store a value at a given path in long term storage which are both loaded
554+ * from Memory
555+ * @param {interger} pathOffest the memory offset to load the the path from
556+ * @param {interger} valueOffset the memory offset to load the value from
557+ */
558+ storageStore (pathOffset, valueOffset, cbIndex) {
559+ this.takeGas(5000)
560+ const path = ['storage', ...this.getMemory(pathOffset, U256_SIZE_BYTES)]
561+ // copy the value
562+ const value = this.getMemory(valueOffset, U256_SIZE_BYTES).slice(0)
563+ const valIsZero = value.every((i) => i === 0)
564+ const opPromise = this.kernel.environment.state.get(path)
565+ .then(vertex => vertex.value)
566+ .catch(() => null)
567+
568+ this.kernel.pushOpsQueue(opPromise, cbIndex, oldValue => {
569+ if (valIsZero && oldValue) {
570+ // delete a value
571+ this.kernel.environment.gasRefund += 15000
572+ this.kernel.environment.state.del(path)
573+ } else {
574+ if (!valIsZero && !oldValue) {
575+ // creating a new value
576+ this.takeGas(15000)
577+ }
578+ // update
579+ this.kernel.environment.state.set(path, new Vertex({
580+ value: value
581+ }))
582+ }
583+ })
584+ }
585+
586+ /**
587+ * reterives a value at a given path in long term storage
588+ * @param {interger} pathOffest the memory offset to load the the path from
589+ * @param {interger} resultOffset the memory offset to load the value from
590+ */
591+ storageLoad (pathOffset, resultOffset, cbIndex) {
592+ this.takeGas(50)
593+
594+ // convert the path to an array
595+ const path = ['storage', ...this.getMemory(pathOffset, U256_SIZE_BYTES)]
596+ // get the value from the state
597+ const opPromise = this.kernel.environment.state.get(path)
598+ .then(vertex => vertex.value)
599+ .catch(() => new Uint8Array(32))
600+
601+ this.kernel.pushOpsQueue(opPromise, cbIndex, value => {
602+ this.setMemory(resultOffset, U256_SIZE_BYTES, value)
603+ })
604+ }
605+
606+ /**
607+ * Halt execution returning output data.
608+ * @param {integer} offset the offset of the output data.
609+ * @param {integer} length the length of the output data.
610+ */
611+ return (offset, length) {
612+ if (length) {
613+ this.kernel.environment.returnValue = this.getMemory(offset, length).slice(0)
614+ }
615+ }
616+
617+ /**
618+ * Halt execution and register account for later deletion giving the remaining
619+ * balance to an address path
620+ * @param {integer} offset the offset to load the address from
621+ */
622+ selfDestruct (addressOffset) {
623+ this.kernel.environment.selfDestruct = true
624+ this.kernel.environment.selfDestructAddress = this.getMemory(addressOffset, ADDRESS_SIZE_BYTES)
625+ this.kernel.environment.gasRefund += 24000
626+ }
627+
628+ getMemory (offset, length) {
629+ return new Uint8Array(this.kernel.memory, offset, length)
630+ }
631+
632+ setMemory (offset, length, value) {
633+ const memory = new Uint8Array(this.kernel.memory, offset, length)
634+ memory.set(value)
635+ }
636+
637+ /*
638+ * Takes gas from the tank. Only needs to check if there's gas left to be taken,
639+ * because every caller of this method is trusted.
640+ */
641+ takeGas (amount) {
642+ if (this.kernel.environment.gasLeft < amount) {
643+ throw new Error('Ran out of gas')
644+ }
645+ this.kernel.environment.gasLeft -= amount
646+ }
647+}
648+
649+// converts a 64 bit number to a JS number
650+function from64bit (high, low) {
651+ if (high < 0) {
652+ // convert from a 32-bit two's compliment
653+ high = 0x100000000 - high
654+ }
655+ if (low < 0) {
656+ // convert from a 32-bit two's compliment
657+ low = 0x100000000 - low
658+ }
659+ // JS only bitshift 32bits, so instead of high << 32 we have high * 2 ^ 32
660+ return (high * 4294967296) + low
661+}

Built with git-ssb-web