git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 6c97c88b95f43dea4cf265dbbc93e6e3cc5cba97

Files: 6c97c88b95f43dea4cf265dbbc93e6e3cc5cba97 / interface.js

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

Built with git-ssb-web