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