git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 000f34b577eb112f2692b0c577052f065087f96c

Files: 000f34b577eb112f2692b0c577052f065087f96c / interface.js

11959 bytesRaw
1/**
2 * This is the Ethereum interface that is exposed to the WASM instance which
3 * enables to interact with the Ethereum Environment
4 */
5const constants = require('./constants.js')
6// const Graph = require('generic-digraph')
7// function.bind is not working corretly whith Wasm imports. So instead create
8// a global for now. TODO REMOVE
9let ENV
10let MOD
11// The interface exposed to the WebAessembly Core
12module.exports = class Interface {
13 print (a) {
14 console.log(a)
15 }
16
17 memPrint () {
18 console.log((new Uint8Array(MOD.exports.memory)).toString())
19 }
20
21 constructor (environment) {
22 ENV = this.environment = environment
23 }
24
25 setModule (mod) {
26 this.module = MOD = mod
27 }
28
29 /**
30 * Subtracts an amount to the gas counter
31 * @param {integer} amount the amount to subtract to the gas counter
32 */
33 useGas (amount) {
34 if (amount > 0) {
35 ENV.gasLimit -= amount
36 }
37 }
38
39 /**
40 * Returns the current amount of gas
41 * @return {integer}
42 */
43 gas () {
44 return ENV.gasLimit
45 }
46
47 /**
48 * Gets address of currently executing account and loads it into memory at
49 * the given offset.
50 * @param {integer} offset
51 */
52 address (offset) {
53 const address = ENV.address
54 const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
55 memory.set(address)
56 }
57
58 /**
59 * Gets balance of the given account and loads it into memory at the given
60 * offset.
61 * @param {integer} addressOffset the memory offset to laod the address
62 * @param {integer} resultOffset
63 */
64 balance (addressOffset, offset) {
65 const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
66 const memory = new Uint8Array(MOD.exports.memory, offset, constants.MAX_BAL_BYTES)
67 // call the parent contract and ask for the balance of one of its child contracts
68 const balance = ENV.parent.environment.getBalance(address)
69 memory.set(balance)
70 }
71
72 /**
73 * Gets the execution's origination address and loads it into memory at the
74 * given offset. This is the sender of original transaction; it is never an
75 * account with non-empty associated code.
76 * @param {integer} offset
77 */
78 origin (offset) {
79 const origin = ENV.origin
80 const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
81 memory.set(origin)
82 }
83
84 /**
85 * Gets caller address and loads it into memory at the given offset. This is
86 * the address of the account that is directly responsible for this execution.
87 * @param {integer} offset
88 */
89 caller (offset) {
90 const caller = ENV.caller
91 const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
92 memory.set(caller)
93 }
94
95 /**
96 * Gets the deposited value by the instruction/transaction responsible for
97 * this execution and loads it into memory at the given location.
98 * @param {integer} offset
99 */
100 callValue (offset) {
101 const callValue = ENV.callValue
102 const memory = new Uint8Array(MOD.exports.memory, offset, constants.MAX_BAL_BYTES)
103 memory.set(callValue)
104 }
105
106 /**
107 * Get size of input data in current environment. This pertains to the input
108 * data passed with the message call instruction or transaction.
109 * @return {integer}
110 */
111 callDataSize () {
112 return ENV.callData.byteLength
113 }
114
115 /**
116 * Copys the input data in current environment to memory. This pertains to
117 * the input data passed with the message call instruction or transaction.
118 * @param {integer} offset the offset in memory to load into
119 * @param {integer} dataOffset the offset in the input data
120 * @param {integer} length the length of data to copy
121 */
122 callDataCopy (offset, dataOffset, length) {
123 const callData = new Uint8Array(ENV.callData, offset, length)
124 const memory = new Uint8Array(MOD.exports.memory, offset, length)
125 memory.set(callData)
126 }
127
128 /**
129 * Gets the size of code running in current environment.
130 * @return {interger}
131 */
132 codeSize () {
133 return ENV.code.byteLength
134 }
135
136 /**
137 * Copys the code running in current environment to memory.
138 * @param {integer} offset the memory offset
139 * @param {integer} codeOffset the code offset
140 * @param {integer} length the length of code to copy
141 */
142 codeCopy (offset, codeOffset, length) {
143 const code = new Uint8Array(ENV.code, codeOffset, length)
144 const memory = new Uint8Array(MOD.exports.memory, offset, length)
145 memory.set(code)
146 }
147
148 /**
149 * Get size of an account’s code.
150 * @param {integer} addressOffset the offset in memory to load the address from
151 * @return {integer}
152 */
153 extCodeSize (addressOffset) {
154 const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
155 const code = this.environment.getCode(address)
156 return code.byteLength
157 }
158
159 /**
160 * Copys the code of an account to memory.
161 * @param {integer} addressOffset the memory offset of the address
162 * @param {integer} offset the memory offset
163 * @param {integer} codeOffset the code offset
164 * @param {integer} length the length of code to copy
165 */
166 extCodeCopy (addressOffset, offset, codeOffset, length) {
167 const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
168 let code = this.environment.getCode(address)
169 code = new Uint8Array(code, codeOffset, length)
170 const memory = new Uint8Array(MOD.exports.memory, offset, length)
171 memory.set(code)
172 }
173
174 /**
175 * Gets price of gas in current environment.
176 * @return {integer}
177 */
178 gasPrice () {
179 return ENV.gasPrice
180 }
181
182 /**
183 * Gets the hash of one of the 256 most recent complete blocks.
184 * @param {integer} number which block to load
185 * @param {integer} offset the offset to load the hash into
186 */
187 blockHash (number, offset) {
188 const hash = this.environment.getBlockHash(number)
189 const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
190 memory.set(hash)
191 }
192
193 /**
194 * Gets the block’s beneficiary address and loads into memory.
195 * @param offset
196 */
197 coinbase (offset) {
198 const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
199 memory.set(ENV.coinbase)
200 }
201
202 /**
203 * Get the block’s timestamp.
204 * @return {integer}
205 */
206 timestamp () {
207 return ENV.timestamp
208 }
209
210 /**
211 * Get the block’s number.
212 * @return {integer}
213 */
214 number () {
215 return ENV.number
216 }
217
218 /**
219 * Get the block’s difficulty.
220 * @return {integer}
221 */
222 difficulty () {
223 return ENV.difficulty
224 }
225
226 /**
227 * Get the block’s gas limit.
228 * @return {integer}
229 */
230 gasLimit () {
231 return ENV.gasLimit
232 }
233
234 /**
235 * Creates a new log in the current environment
236 * @param {integer} dataOffset the offset in memory to load the memory
237 * @param {integer} length the data length
238 * TODO: replace with variadic
239 */
240 log (dataOffset, length, topic1, topic2, topic3, topic4, topic5) {
241 const data = new Uint8Array(MOD.exports.memory, dataOffset, length)
242 ENV.logs.push({
243 data: data,
244 topics: [topic1, topic2, topic3, topic4, topic5]
245 })
246 }
247
248 /**
249 * Creates a new contract with a given value.
250 * @param {integer} valueOffset the offset in memory to the value from
251 * @param {integer} dataOffset the offset to load the code for the new contract from
252 * @param {integer} length the data length
253 */
254 create (valueOffset, dataOffset, length) {
255 const value = new Uint8Array(MOD.exports.memory, valueOffset, constants.MAX_BAL_BYTES)
256 const data = new Uint8Array(MOD.exports.memory, dataOffset, length)
257 const result = ENV.create(value, data)
258 return result
259 }
260
261 /**
262 * Sends a message with arbiatary data to a given address path
263 * @param {integer} addressOffset the offset to load the address path from
264 * @param {integer} valueOffset the offset to load the value from
265 * @param {integer} dataOffset the offset to load data from
266 * @param {integer} dataLength the length of data
267 * @param {integer} resultOffset the offset to store the result data at
268 * @param {integer} resultLength
269 * @param {integer} gas
270 * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
271 * TODO: add proper gas counting
272 */
273 call (addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength, gas) {
274 if (gas === undefined) {
275 gas = this.gasLeft()
276 }
277 // Load the params from mem
278 const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
279 const value = new Uint8Array(MOD.exports.memory, valueOffset, constants.MAX_BAL_BYTES)
280 const data = new Uint8Array(MOD.exports.memory, dataOffset, dataLength)
281 // Run the call
282 const [result, errorCode] = ENV.call(gas, address, value, data)
283 const memory = new Uint8Array(MOD.exports.memory, resultOffset, resultLength)
284 memory.set(result)
285
286 return errorCode
287 }
288
289 /**
290 * Message-call into this account with an alternative account’s code, but
291 * persisting the current values for sender and value.
292 * @param {integer} gas
293 * @param {integer} addressOffset the offset to load the address path from
294 * @param {integer} valueOffset the offset to load the value from
295 * @param {integer} dataOffset the offset to load data from
296 * @param {integer} dataLength the length of data
297 * @param {integer} resultOffset the offset to store the result data at
298 * @param {integer} resultLength
299 * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
300 */
301 callDelegate (gas, addressOffset, dataOffset, dataLength, resultOffset, resultLength) {
302 const data = new Uint8Array(MOD.exports.memory, dataOffset, dataLength)
303 const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
304 const [result, errorCode] = this.environment.callDelegate(gas, address, data)
305 const memory = new Uint8Array(MOD.exports.memory, resultOffset, resultLength)
306 memory.set(result)
307
308 return errorCode
309 }
310
311 /**
312 * store a value at a given path in long term storage which are both loaded
313 * from Memory
314 * @param {interger} pathOffest the memory offset to load the the path from
315 * @param {interger} valueOffset the memory offset to load the value from
316 */
317 sstore (pathOffest, valueOffset) {
318 const path = new Buffer(MOD.exports.memory, pathOffest, 32).toString('hex')
319 const value = new Uint8Array(MOD.exports.memory, valueOffset, 32)
320 const oldValue = ENV.state.get(path)
321 const valIsZero = value.every((i) => i === 0)
322
323 // write
324 if (!valIsZero && !oldValue) {
325 ENV.gasLimit -= 15000
326 }
327
328 // delete
329 if (valIsZero && oldValue) {
330 ENV.gasRefund += 15000
331 ENV.state.delete(path)
332 } else {
333 ENV.state.set(path, value)
334 }
335 }
336
337 /**
338 * reterives a value at a given path in long term storage
339 * @param {interger} pathOffest the memory offset to load the the path from
340 * @param {interger} resultOffset the memory offset to load the value from
341 */
342 sload (pathOffest, resultOffset) {
343 const path = new Buffer(MOD.exports.memory, pathOffest, 32).toString('hex')
344 const result = ENV.state.get(path)
345 const memory = new Uint8Array(MOD.exports.memory, resultOffset, 32)
346 memory.set(result)
347 }
348
349 /**
350 * Halt execution returning output data.
351 * @param {integer} offset the offset of the output data.
352 * @param {integer} length the length of the output data.
353 */
354 return (offset, length) {
355 this.environment.returnValue = new Uint8Array(MOD.exports.memory, offset, length)
356 }
357
358 /**
359 * Halt execution and register account for later deletion giving the remaining
360 * balance to an address path
361 * @param {integer} offset the offset to load the address from
362 */
363 suicide (addressOffset) {
364 const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
365 this.environment.suicideAddress = address
366 }
367}
368

Built with git-ssb-web