@@ -44,8 +44,8 @@ type EVM struct {
44
44
env Environment
45
45
jumpTable vmJumpTable
46
46
cfg Config
47
-
48
- logger * Logger
47
+ logger * Logger
48
+ gasTable params. GasTable
49
49
}
50
50
51
51
// New returns a new instance of the EVM.
@@ -60,6 +60,7 @@ func New(env Environment, cfg Config) *EVM {
60
60
jumpTable : newJumpTable (env .RuleSet (), env .BlockNumber ()),
61
61
cfg : cfg ,
62
62
logger : logger ,
63
+ gasTable : env .RuleSet ().GasTable (env .BlockNumber ()),
63
64
}
64
65
}
65
66
@@ -177,7 +178,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
177
178
// Get the memory location of pc
178
179
op = contract .GetOp (pc )
179
180
// calculate the new memory size and gas price for the current executing opcode
180
- newMemSize , cost , err = calculateGasAndSize (evm .env , contract , caller , op , statedb , mem , stack )
181
+ newMemSize , cost , err = calculateGasAndSize (evm .gasTable , evm . env , contract , caller , op , statedb , mem , stack )
181
182
if err != nil {
182
183
return nil , err
183
184
}
@@ -242,7 +243,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
242
243
243
244
// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
244
245
// the operation. This does not reduce gas or resizes the memory.
245
- func calculateGasAndSize (env Environment , contract * Contract , caller ContractRef , op OpCode , statedb Database , mem * Memory , stack * stack ) (* big.Int , * big.Int , error ) {
246
+ func calculateGasAndSize (gasTable params. GasTable , env Environment , contract * Contract , caller ContractRef , op OpCode , statedb Database , mem * Memory , stack * stack ) (* big.Int , * big.Int , error ) {
246
247
var (
247
248
gas = new (big.Int )
248
249
newMemSize * big.Int = new (big.Int )
@@ -254,6 +255,24 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
254
255
255
256
// stack Check, memory resize & gas phase
256
257
switch op {
258
+ case SUICIDE :
259
+ // if suicide is not nil: homestead gas fork
260
+ if gasTable .CreateBySuicide != nil {
261
+ gas .Set (gasTable .Suicide )
262
+ if ! env .Db ().Exist (common .BigToAddress (stack .data [len (stack .data )- 1 ])) {
263
+ gas .Add (gas , gasTable .CreateBySuicide )
264
+ }
265
+ }
266
+
267
+ if ! statedb .HasSuicided (contract .Address ()) {
268
+ statedb .AddRefund (params .SuicideRefundGas )
269
+ }
270
+ case EXTCODESIZE :
271
+ gas .Set (gasTable .ExtcodeSize )
272
+ case BALANCE :
273
+ gas .Set (gasTable .Balance )
274
+ case SLOAD :
275
+ gas .Set (gasTable .SLoad )
257
276
case SWAP1 , SWAP2 , SWAP3 , SWAP4 , SWAP5 , SWAP6 , SWAP7 , SWAP8 , SWAP9 , SWAP10 , SWAP11 , SWAP12 , SWAP13 , SWAP14 , SWAP15 , SWAP16 :
258
277
n := int (op - SWAP1 + 2 )
259
278
err := stack .require (n )
@@ -282,6 +301,8 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
282
301
gas .Add (gas , new (big.Int ).Mul (mSize , params .LogDataGas ))
283
302
284
303
newMemSize = calcMemSize (mStart , mSize )
304
+
305
+ quadMemGas (mem , newMemSize , gas )
285
306
case EXP :
286
307
gas .Add (gas , new (big.Int ).Mul (big .NewInt (int64 (len (stack .data [stack .len ()- 2 ].Bytes ()))), params .ExpByteGas ))
287
308
case SSTORE :
@@ -310,67 +331,100 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
310
331
g = params .SstoreClearGas
311
332
}
312
333
gas .Set (g )
313
- case SUICIDE :
314
- if ! statedb .HasSuicided (contract .Address ()) {
315
- statedb .AddRefund (params .SuicideRefundGas )
316
- }
317
334
case MLOAD :
318
335
newMemSize = calcMemSize (stack .peek (), u256 (32 ))
336
+ quadMemGas (mem , newMemSize , gas )
319
337
case MSTORE8 :
320
338
newMemSize = calcMemSize (stack .peek (), u256 (1 ))
339
+ quadMemGas (mem , newMemSize , gas )
321
340
case MSTORE :
322
341
newMemSize = calcMemSize (stack .peek (), u256 (32 ))
342
+ quadMemGas (mem , newMemSize , gas )
323
343
case RETURN :
324
344
newMemSize = calcMemSize (stack .peek (), stack .data [stack .len ()- 2 ])
345
+ quadMemGas (mem , newMemSize , gas )
325
346
case SHA3 :
326
347
newMemSize = calcMemSize (stack .peek (), stack .data [stack .len ()- 2 ])
327
348
328
349
words := toWordSize (stack .data [stack .len ()- 2 ])
329
350
gas .Add (gas , words .Mul (words , params .Sha3WordGas ))
351
+
352
+ quadMemGas (mem , newMemSize , gas )
330
353
case CALLDATACOPY :
331
354
newMemSize = calcMemSize (stack .peek (), stack .data [stack .len ()- 3 ])
332
355
333
356
words := toWordSize (stack .data [stack .len ()- 3 ])
334
357
gas .Add (gas , words .Mul (words , params .CopyGas ))
358
+
359
+ quadMemGas (mem , newMemSize , gas )
335
360
case CODECOPY :
336
361
newMemSize = calcMemSize (stack .peek (), stack .data [stack .len ()- 3 ])
337
362
338
363
words := toWordSize (stack .data [stack .len ()- 3 ])
339
364
gas .Add (gas , words .Mul (words , params .CopyGas ))
365
+
366
+ quadMemGas (mem , newMemSize , gas )
340
367
case EXTCODECOPY :
368
+ gas .Set (gasTable .ExtcodeCopy )
369
+
341
370
newMemSize = calcMemSize (stack .data [stack .len ()- 2 ], stack .data [stack .len ()- 4 ])
342
371
343
372
words := toWordSize (stack .data [stack .len ()- 4 ])
344
373
gas .Add (gas , words .Mul (words , params .CopyGas ))
345
374
375
+ quadMemGas (mem , newMemSize , gas )
346
376
case CREATE :
347
377
newMemSize = calcMemSize (stack .data [stack .len ()- 2 ], stack .data [stack .len ()- 3 ])
378
+
379
+ quadMemGas (mem , newMemSize , gas )
348
380
case CALL , CALLCODE :
349
- gas .Add ( gas , stack . data [ stack . len () - 1 ] )
381
+ gas .Set ( gasTable . Calls )
350
382
351
383
if op == CALL {
352
384
if ! env .Db ().Exist (common .BigToAddress (stack .data [stack .len ()- 2 ])) {
353
385
gas .Add (gas , params .CallNewAccountGas )
354
386
}
355
387
}
356
-
357
388
if len (stack .data [stack .len ()- 3 ].Bytes ()) > 0 {
358
389
gas .Add (gas , params .CallValueTransferGas )
359
390
}
360
-
361
391
x := calcMemSize (stack .data [stack .len ()- 6 ], stack .data [stack .len ()- 7 ])
362
392
y := calcMemSize (stack .data [stack .len ()- 4 ], stack .data [stack .len ()- 5 ])
363
393
364
394
newMemSize = common .BigMax (x , y )
395
+
396
+ quadMemGas (mem , newMemSize , gas )
397
+
398
+ cg := callGas (gasTable , contract .Gas , gas , stack .data [stack .len ()- 1 ])
399
+ // Replace the stack item with the new gas calculation. This means that
400
+ // either the original item is left on the stack or the item is replaced by:
401
+ // (availableGas - gas) * 63 / 64
402
+ // We replace the stack item so that it's available when the opCall instruction is
403
+ // called. This information is otherwise lost due to the dependency on *current*
404
+ // available gas.
405
+ stack .data [stack .len ()- 1 ] = cg
406
+ gas .Add (gas , cg )
407
+
365
408
case DELEGATECALL :
366
- gas .Add ( gas , stack . data [ stack . len () - 1 ] )
409
+ gas .Set ( gasTable . Calls )
367
410
368
411
x := calcMemSize (stack .data [stack .len ()- 5 ], stack .data [stack .len ()- 6 ])
369
412
y := calcMemSize (stack .data [stack .len ()- 3 ], stack .data [stack .len ()- 4 ])
370
413
371
414
newMemSize = common .BigMax (x , y )
415
+
416
+ quadMemGas (mem , newMemSize , gas )
417
+
418
+ cg := callGas (gasTable , contract .Gas , gas , stack .data [stack .len ()- 1 ])
419
+ // Replace the stack item with the new gas calculation. This means that
420
+ // either the original item is left on the stack or the item is replaced by:
421
+ // (availableGas - gas) * 63 / 64
422
+ // We replace the stack item so that it's available when the opCall instruction is
423
+ // called.
424
+ stack .data [stack .len ()- 1 ] = cg
425
+ gas .Add (gas , cg )
426
+
372
427
}
373
- quadMemGas (mem , newMemSize , gas )
374
428
375
429
return newMemSize , gas , nil
376
430
}
0 commit comments