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