git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 865f135bbd80624eceea4b85923acc13137ffd39

Merge pull request #30 from ewasm/gas

Calculate gas for every method
Alex Beregszaszi authored on 8/18/2016, 10:40:24 PM
GitHub committed on 8/18/2016, 10:40:24 PM
Parent: f488805c0df12c74d2cb8ed0c5d0e439495676df
Parent: db70561842aa908ed95d11fc1aea28b6835dde37

Files changed

interface.jschanged
tests/interface/basic_gas_ops.wastchanged
interface.jsView
@@ -60,21 +60,22 @@
6060 * Subtracts an amount to the gas counter
6161 * @param {integer} amount the amount to subtract to the gas counter
6262 */
6363 useGas (amount) {
64- if (amount > 0) {
65- if (this.environment.gasLimit < amount) {
66- throw new Error('Ran out of gas')
67- }
68- this.environment.gasLimit -= amount
64+ if (amount < 0) {
65+ throw new Error('Negative gas deduction requested')
6966 }
67+
68+ this.takeGas(amount)
7069 }
7170
7271 /**
7372 * Returns the current amount of gas
7473 * @return {integer}
7574 */
7675 getGasLeft () {
76+ this.takeGas(2)
77+
7778 return this.environment.gasLimit
7879 }
7980
8081 /**
@@ -82,8 +83,10 @@
8283 * the given offset.
8384 * @param {integer} offset
8485 */
8586 getAddress (offset) {
87+ this.takeGas(2)
88+
8689 this.setMemory(offset, constants.ADDRESS_SIZE_BYTES, this.environment.address)
8790 }
8891
8992 /**
@@ -92,8 +95,10 @@
9295 * @param {integer} addressOffset the memory offset to laod the address
9396 * @param {integer} resultOffset
9497 */
9598 getBalance (addressOffset, offset) {
99+ this.takeGas(20)
100+
96101 const address = new Address(this.getMemory(addressOffset, constants.ADDRESS_SIZE_BYTES))
97102 // call the parent contract and ask for the balance of one of its child contracts
98103 const balance = this.environment.parent.environment.getBalance(address)
99104 this.setMemory(offset, constants.BALANCE_SIZE_BYTES, balance.toBuffer(constants.BALANCE_SIZE_BYTES))
@@ -105,8 +110,10 @@
105110 * account with non-empty associated code.
106111 * @param {integer} offset
107112 */
108113 getTxOrigin (offset) {
114+ this.takeGas(2)
115+
109116 this.setMemory(offset, constants.ADDRESS_SIZE_BYTES, this.environment.origin)
110117 }
111118
112119 /**
@@ -114,8 +121,10 @@
114121 * the address of the account that is directly responsible for this execution.
115122 * @param {integer} offset
116123 */
117124 getCaller (offset) {
125+ this.takeGas(2)
126+
118127 this.setMemory(offset, constants.ADDRESS_SIZE_BYTES, this.environment.caller)
119128 }
120129
121130 /**
@@ -123,8 +132,10 @@
123132 * this execution and loads it into memory at the given location.
124133 * @param {integer} offset
125134 */
126135 getCallValue (offset) {
136+ this.takeGas(2)
137+
127138 this.setMemory(offset, constants.BALANCE_SIZE_BYTES, this.environment.callValue.toBuffer(constants.BALANCE_SIZE_BYTES))
128139 }
129140
130141 /**
@@ -132,8 +143,10 @@
132143 * data passed with the message call instruction or transaction.
133144 * @return {integer}
134145 */
135146 getCallDataSize () {
147+ this.takeGas(2)
148+
136149 return this.environment.callData.length
137150 }
138151
139152 /**
@@ -143,8 +156,10 @@
143156 * @param {integer} dataOffset the offset in the input data
144157 * @param {integer} length the length of data to copy
145158 */
146159 callDataCopy (offset, dataOffset, length) {
160+ this.takeGas(3 + ((length / 32) * 3))
161+
147162 const callData = this.environment.callData.slice(dataOffset, dataOffset + length)
148163 this.setMemory(offset, length, callData)
149164 }
150165
@@ -152,8 +167,10 @@
152167 * Gets the size of code running in current environment.
153168 * @return {interger}
154169 */
155170 getCodeSize () {
171+ this.takeGas(2)
172+
156173 return this.environment.code.length
157174 }
158175
159176 /**
@@ -162,8 +179,10 @@
162179 * @param {integer} codeOffset the code offset
163180 * @param {integer} length the length of code to copy
164181 */
165182 codeCopy (resultOffset, codeOffset, length) {
183+ this.takeGas(3 + ((length / 32) * 3))
184+
166185 const code = new Uint8Array(this.environment.code, codeOffset, length)
167186 this.setMemory(resultOffset, length, code)
168187 }
169188
@@ -172,8 +191,10 @@
172191 * @param {integer} addressOffset the offset in memory to load the address from
173192 * @return {integer}
174193 */
175194 getExternalCodeSize (addressOffset) {
195+ this.takeGas(20)
196+
176197 const address = new Address(this.getMemory(addressOffset, constants.ADDRESS_SIZE_BYTES))
177198 const code = this.environment.getCode(address)
178199 return code.length
179200 }
@@ -185,8 +206,10 @@
185206 * @param {integer} codeOffset the code offset
186207 * @param {integer} length the length of code to copy
187208 */
188209 externalCodeCopy (addressOffset, resultOffset, codeOffset, length) {
210+ this.takeGas(20 + ((length / 32) * 3))
211+
189212 const address = new Address(this.getMemory(addressOffset, constants.ADDRESS_SIZE_BYTES))
190213 let code = this.environment.getCode(address)
191214 code = new Uint8Array(code, codeOffset, length)
192215 this.setMemory(resultOffset, length, code)
@@ -196,8 +219,10 @@
196219 * Gets price of gas in current environment.
197220 * @return {integer}
198221 */
199222 getTxGasPrice () {
223+ this.takeGas(2)
224+
200225 return this.environment.gasPrice
201226 }
202227
203228 /**
@@ -205,8 +230,10 @@
205230 * @param {integer} number which block to load
206231 * @param {integer} offset the offset to load the hash into
207232 */
208233 getBlockHash (number, offset) {
234+ this.takeGas(20)
235+
209236 const diff = this.environment.number - number
210237 let hash
211238
212239 if (diff > 256 || diff <= 0) {
@@ -221,40 +248,50 @@
221248 * Gets the block’s beneficiary address and loads into memory.
222249 * @param offset
223250 */
224251 getBlockCoinbase (offset) {
252+ this.takeGas(2)
253+
225254 this.setMemory(offset, constants.ADDRESS_SIZE_BYTES, this.environment.coinbase)
226255 }
227256
228257 /**
229258 * Get the block’s timestamp.
230259 * @return {integer}
231260 */
232261 getBlockTimestamp () {
262+ this.takeGas(2)
263+
233264 return this.environment.timestamp
234265 }
235266
236267 /**
237268 * Get the block’s number.
238269 * @return {integer}
239270 */
240271 getBlockNumber () {
272+ this.takeGas(2)
273+
241274 return this.environment.number
242275 }
243276
244277 /**
245278 * Get the block’s difficulty.
246279 * @return {integer}
247280 */
248281 getBlockDifficulty () {
282+ this.takeGas(2)
283+
249284 return this.environment.difficulty
250285 }
251286
252287 /**
253288 * Get the block’s gas limit.
254289 * @return {integer}
255290 */
256291 getBlockGasLimit () {
292+ this.takeGas(2)
293+
257294 return this.environment.gasLimit
258295 }
259296
260297 /**
@@ -263,8 +300,11 @@
263300 * @param {integer} length the data length
264301 * TODO: replace with variadic
265302 */
266303 log (dataOffset, length, topic1, topic2, topic3, topic4, topic5) {
304+ // FIXME: calculate gas for topics set
305+ this.takeGas(375 + length * 8)
306+
267307 const data = this.getMemory(dataOffset, length)
268308 this.environment.logs.push({
269309 data: data,
270310 topics: [topic1, topic2, topic3, topic4, topic5]
@@ -277,8 +317,10 @@
277317 * @param {integer} dataOffset the offset to load the code for the new contract from
278318 * @param {integer} length the data length
279319 */
280320 create (valueOffset, dataOffset, length) {
321+ this.takeGas(32000)
322+
281323 const value = new U256(this.getMemory(valueOffset, constants.BALANCE_SIZE_BYTES))
282324 const data = this.getMemory(dataOffset, length)
283325 const result = this.environment.create(value, data)
284326 return result
@@ -293,11 +335,13 @@
293335 * @param {integer} resultOffset the offset to store the result data at
294336 * @param {integer} resultLength
295337 * @param {integer} gas
296338 * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
297- * TODO: add proper gas counting
298339 */
299340 call (gas, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength) {
341+ // FIXME: count properly
342+ this.takeGas(40)
343+
300344 if (gas === undefined) {
301345 gas = this.gasLeft()
302346 }
303347 // Load the params from mem
@@ -319,11 +363,13 @@
319363 * @param {integer} resultOffset the offset to store the result data at
320364 * @param {integer} resultLength
321365 * @param {integer} gas
322366 * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
323- * TODO: add proper gas counting
324367 */
325368 callCode (gas, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength) {
369+ // FIXME: count properly
370+ this.takeGas(40)
371+
326372 // Load the params from mem
327373 const address = new Address(this.getMemory(addressOffset, constants.ADDRESS_SIZE_BYTES))
328374 const value = new U256(this.getMemory(valueOffset, constants.BALANCE_SIZE_BYTES))
329375 const data = this.getMemory(dataOffset, dataLength)
@@ -345,8 +391,11 @@
345391 * @param {integer} resultLength
346392 * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
347393 */
348394 callDelegate (gas, addressOffset, dataOffset, dataLength, resultOffset, resultLength) {
395+ // FIXME: count properly
396+ this.takeGas(40)
397+
349398 const data = this.getMemory(dataOffset, dataLength)
350399 const address = new Address(this.getMemory(addressOffset, constants.ADDRESS_SIZE_BYTES))
351400 const [result, errorCode] = this.environment.callDelegate(gas, address, data)
352401 this.setMemory(resultOffset, resultLength, result)
@@ -365,11 +414,13 @@
365414 const value = this.getMemory(valueOffset, 32).slice(0)
366415 const oldValue = this.environment.state.get(path)
367416 const valIsZero = value.every((i) => i === 0)
368417
418+ // FIXME: gas counting has more cases then the below
419+
369420 // write
370421 if (!valIsZero && !oldValue) {
371- this.environment.gasLimit -= 15000
422+ this.takeGas(15000)
372423 }
373424
374425 // delete
375426 if (valIsZero && oldValue) {
@@ -385,8 +436,10 @@
385436 * @param {interger} pathOffest the memory offset to load the the path from
386437 * @param {interger} resultOffset the memory offset to load the value from
387438 */
388439 storageLoad (pathOffset, resultOffset) {
440+ this.takeGas(50)
441+
389442 const path = new Buffer(this.getMemory(pathOffset, 32)).toString('hex')
390443 const result = this.environment.state.get(path)
391444 this.setMemory(resultOffset, 32, result)
392445 }
@@ -406,8 +459,9 @@
406459 * @param {integer} offset the offset to load the address from
407460 */
408461 selfDestruct (addressOffset) {
409462 this.environment.suicideAddress = new Address(this.getMemory(addressOffset, constants.ADDRESS_SIZE_BYTES))
463+ this.environment.gasRefund += 24000
410464 }
411465
412466 getMemory (offset, length) {
413467 return new Uint8Array(this.module.exports.memory, offset, length)
@@ -416,8 +470,19 @@
416470 setMemory (offset, length, value) {
417471 const memory = new Uint8Array(this.module.exports.memory, offset, length)
418472 memory.set(value)
419473 }
474+
475+ /*
476+ * Takes gas from the tank. Only needs to check if there's gas left to be taken,
477+ * because every caller of this method is trusted.
478+ */
479+ takeGas (amount) {
480+ if (this.environment.gasLimit < amount) {
481+ throw new Error('Ran out of gas')
482+ }
483+ this.environment.gasLimit -= amount
484+ }
420485 }
421486
422487 //
423488 // Polyfill required unless this is sorted: https://bugs.chromium.org/p/chromium/issues/detail?id=633895
tests/interface/basic_gas_ops.wastView
@@ -7,26 +7,18 @@
77 (func
88 ;; test adding gas
99 (block
1010 (call_import $useGas (i32.const 1))
11- (if (i32.eq (call_import $gas) (i32.const 999))
11+ (if (i32.eq (call_import $gas) (i32.const 997))
1212 (return)
1313 )
1414 (unreachable)
1515 )
1616 (block
1717 (call_import $useGas (i32.const 1))
18- (if (i32.eq (call_import $gas) (i32.const 998))
18+ (if (i32.eq (call_import $gas) (i32.const 996))
1919 (return)
2020 )
2121 (unreachable)
2222 )
23- ;; should disregard negative values
24- (block
25- (call_import $useGas (i32.const -1))
26- (if (i32.eq (call_import $gas) (i32.const 998))
27- (return)
28- )
29- (unreachable)
30- )
3123 )
3224 )

Built with git-ssb-web