diff --git a/cmd/evm/json_logger.go b/cmd/evm/json_logger.go
index 458d56494b30..90e44f9c4ae5 100644
--- a/cmd/evm/json_logger.go
+++ b/cmd/evm/json_logger.go
@@ -56,7 +56,12 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos
log.Memory = memory.Data()
}
if !l.cfg.DisableStack {
- log.Stack = stack.Data()
+ //TODO(@holiman) improve this
+ logstack := make([]*big.Int, len(stack.Data()))
+ for i, item := range stack.Data() {
+ logstack[i] = item.ToBig()
+ }
+ log.Stack = logstack
}
return l.encoder.Encode(log)
}
diff --git a/core/state/state_object.go b/core/state/state_object.go
index 53ea774d6194..6d50461f1587 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -306,9 +306,6 @@ func (self *stateObject) setBalance(amount *big.Int) {
}
}
-// Return the gas back to the origin. Used by the Virtual machine or Closures
-func (c *stateObject) ReturnGas(gas *big.Int) {}
-
func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject {
stateObject := newObject(db, self.address, self.data, onDirty)
if self.trie != nil {
diff --git a/core/vm/analysis.go b/core/vm/analysis.go
index 449cded2a896..3733bab6a7c0 100644
--- a/core/vm/analysis.go
+++ b/core/vm/analysis.go
@@ -17,12 +17,12 @@
package vm
const (
- set2BitsMask = uint16(0b1100_0000_0000_0000)
- set3BitsMask = uint16(0b1110_0000_0000_0000)
- set4BitsMask = uint16(0b1111_0000_0000_0000)
- set5BitsMask = uint16(0b1111_1000_0000_0000)
- set6BitsMask = uint16(0b1111_1100_0000_0000)
- set7BitsMask = uint16(0b1111_1110_0000_0000)
+ set2BitsMask = uint16(0b11)
+ set3BitsMask = uint16(0b111)
+ set4BitsMask = uint16(0b1111)
+ set5BitsMask = uint16(0b1_1111)
+ set6BitsMask = uint16(0b11_1111)
+ set7BitsMask = uint16(0b111_1111)
)
// bitvec is a bit vector which maps bytes in a program.
@@ -30,32 +30,26 @@ const (
// it's data (i.e. argument of PUSHxx).
type bitvec []byte
-var lookup = [8]byte{
- 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1,
-}
-
func (bits bitvec) set1(pos uint64) {
- bits[pos/8] |= lookup[pos%8]
+ bits[pos/8] |= 1 << (pos % 8)
}
func (bits bitvec) setN(flag uint16, pos uint64) {
- a := flag >> (pos % 8)
- bits[pos/8] |= byte(a >> 8)
- if b := byte(a); b != 0 {
- // If the bit-setting affects the neighbouring byte, we can assign - no need to OR it,
- // since it's the first write to that byte
+ a := flag << (pos % 8)
+ bits[pos/8] |= byte(a)
+ if b := byte(a >> 8); b != 0 {
bits[pos/8+1] = b
}
}
func (bits bitvec) set8(pos uint64) {
- a := byte(0xFF >> (pos % 8))
+ a := byte(0xFF << (pos % 8))
bits[pos/8] |= a
bits[pos/8+1] = ^a
}
func (bits bitvec) set16(pos uint64) {
- a := byte(0xFF >> (pos % 8))
+ a := byte(0xFF << (pos % 8))
bits[pos/8] |= a
bits[pos/8+1] = 0xFF
bits[pos/8+2] = ^a
@@ -63,7 +57,7 @@ func (bits bitvec) set16(pos uint64) {
// codeSegment checks if the position is in a code segment.
func (bits *bitvec) codeSegment(pos uint64) bool {
- return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0
+ return (((*bits)[pos/8] >> (pos % 8)) & 1) == 0
}
// codeBitmap collects data locations in code.
diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go
index 99e4e386b404..20674bf919d3 100644
--- a/core/vm/analysis_test.go
+++ b/core/vm/analysis_test.go
@@ -17,6 +17,7 @@
package vm
import (
+ "math/bits"
"testing"
"github.com/XinFinOrg/XDPoSChain/crypto"
@@ -28,24 +29,27 @@ func TestJumpDestAnalysis(t *testing.T) {
exp byte
which int
}{
- {[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0x40, 0},
- {[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0x50, 0},
- {[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, 0x7F, 0},
- {[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x80, 1},
- {[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0x03, 0},
- {[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0x00, 1},
- {[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x74, 0},
- {[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x00, 1},
- {[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x3F, 0},
- {[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0xC0, 1},
- {[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x7F, 0},
- {[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0xFF, 1},
- {[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x80, 2},
- {[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0x7f, 0},
- {[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0xA0, 1},
- {[]byte{byte(PUSH32)}, 0x7F, 0},
- {[]byte{byte(PUSH32)}, 0xFF, 1},
- {[]byte{byte(PUSH32)}, 0xFF, 2},
+ {[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0b0000_0010, 0},
+ {[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0b0000_1010, 0},
+ {[]byte{0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1)}, 0b0101_0100, 0},
+ {[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, bits.Reverse8(0x7F), 0},
+ {[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 1},
+ {[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0b1100_0000, 0},
+ {[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
+ {[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0010_1110, 0},
+ {[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
+ {[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1100, 0},
+ {[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0011, 1},
+ {[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1110, 0},
+ {[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1111, 1},
+ {[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 2},
+ {[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b1111_1110, 0},
+ {[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b0000_0101, 1},
+ {[]byte{byte(PUSH32)}, 0b1111_1110, 0},
+ {[]byte{byte(PUSH32)}, 0b1111_1111, 1},
+ {[]byte{byte(PUSH32)}, 0b1111_1111, 2},
+ {[]byte{byte(PUSH32)}, 0b1111_1111, 3},
+ {[]byte{byte(PUSH32)}, 0b0000_0001, 4},
}
for i, test := range tests {
ret := codeBitmap(test.code)
@@ -55,9 +59,12 @@ func TestJumpDestAnalysis(t *testing.T) {
}
}
+const analysisCodeSize = 1200 * 1024
+
func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
// 1.4 ms
- code := make([]byte, 1200000)
+ code := make([]byte, analysisCodeSize)
+ bench.SetBytes(analysisCodeSize)
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
codeBitmap(code)
@@ -66,7 +73,8 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
}
func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
// 4 ms
- code := make([]byte, 1200000)
+ code := make([]byte, analysisCodeSize)
+ bench.SetBytes(analysisCodeSize)
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
crypto.Keccak256Hash(code)
@@ -77,13 +85,19 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
var op OpCode
bencher := func(b *testing.B) {
- code := make([]byte, 32*b.N)
+ code := make([]byte, analysisCodeSize)
+ b.SetBytes(analysisCodeSize)
for i := range code {
code[i] = byte(op)
}
bits := make(bitvec, len(code)/8+1+4)
b.ResetTimer()
- codeBitmapInternal(code, bits)
+ for i := 0; i < b.N; i++ {
+ for j := range bits {
+ bits[j] = 0
+ }
+ codeBitmapInternal(code, bits)
+ }
}
for op = PUSH1; op <= PUSH32; op++ {
bench.Run(op.String(), bencher)
diff --git a/core/vm/common.go b/core/vm/common.go
index 194e3897f8c3..bb11f4a393e5 100644
--- a/core/vm/common.go
+++ b/core/vm/common.go
@@ -17,15 +17,14 @@
package vm
import (
- "math/big"
-
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
+ "github.com/holiman/uint256"
)
// calcMemSize64 calculates the required memory size, and returns
// the size and whether the result overflowed uint64
-func calcMemSize64(off, l *big.Int) (uint64, bool) {
+func calcMemSize64(off, l *uint256.Int) (uint64, bool) {
if !l.IsUint64() {
return 0, true
}
@@ -35,16 +34,16 @@ func calcMemSize64(off, l *big.Int) (uint64, bool) {
// calcMemSize64WithUint calculates the required memory size, and returns
// the size and whether the result overflowed uint64
// Identical to calcMemSize64, but length is a uint64
-func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) {
+func calcMemSize64WithUint(off *uint256.Int, length64 uint64) (uint64, bool) {
// if length is zero, memsize is always zero, regardless of offset
if length64 == 0 {
return 0, false
}
// Check that offset doesn't overflow
- if !off.IsUint64() {
+ offset64, overflow := off.Uint64WithOverflow()
+ if overflow {
return 0, true
}
- offset64 := off.Uint64()
val := offset64 + length64
// if value < either of it's parts, then it overflowed
return val, val < offset64
@@ -64,22 +63,6 @@ func getData(data []byte, start uint64, size uint64) []byte {
return common.RightPadBytes(data[start:end], int(size))
}
-// getDataBig returns a slice from the data based on the start and size and pads
-// up to size with zero's. This function is overflow safe.
-func getDataBig(data []byte, start *big.Int, size *big.Int) []byte {
- dlen := big.NewInt(int64(len(data)))
-
- s := math.BigMin(start, dlen)
- e := math.BigMin(new(big.Int).Add(s, size), dlen)
- return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
-}
-
-// bigUint64 returns the integer casted to a uint64 and returns whether it
-// overflowed in the process.
-func bigUint64(v *big.Int) (uint64, bool) {
- return v.Uint64(), !v.IsUint64()
-}
-
// toWordSize returns the ceiled word size required for memory expansion.
func toWordSize(size uint64) uint64 {
if size > math.MaxUint64-31 {
diff --git a/core/vm/contract.go b/core/vm/contract.go
index cc9d59cf2deb..2be61b51d0ce 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -20,6 +20,7 @@ import (
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
+ "github.com/holiman/uint256"
)
// ContractRef is a reference to the contract's backing object
@@ -81,11 +82,11 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
return c
}
-func (c *Contract) validJumpdest(dest *big.Int) bool {
- udest := dest.Uint64()
+func (c *Contract) validJumpdest(dest *uint256.Int) bool {
+ udest, overflow := dest.Uint64WithOverflow()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
- if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) {
+ if overflow || udest >= uint64(len(c.Code)) {
return false
}
// Only JUMPDESTs allowed for destinations
@@ -131,16 +132,11 @@ func (c *Contract) AsDelegate() *Contract {
// GetOp returns the n'th element in the contract's byte array
func (c *Contract) GetOp(n uint64) OpCode {
- return OpCode(c.GetByte(n))
-}
-
-// GetByte returns the n'th byte in the contract's byte array
-func (c *Contract) GetByte(n uint64) byte {
if n < uint64(len(c.Code)) {
- return c.Code[n]
+ return OpCode(c.Code[n])
}
- return 0
+ return STOP
}
// Caller returns the caller of the contract.
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 28394d4dd23c..b07cce9fc29b 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -521,7 +521,7 @@ func (c *blake2F) Run(input []byte) ([]byte, error) {
// Parse the input into the Blake2b call parameters
var (
rounds = binary.BigEndian.Uint32(input[0:4])
- final = (input[212] == blake2FFinalBlockBytes)
+ final = input[212] == blake2FFinalBlockBytes
h [8]uint64
m [16]uint64
diff --git a/core/vm/eips.go b/core/vm/eips.go
index 40da1f88fafa..6ba7bbd6ec7a 100644
--- a/core/vm/eips.go
+++ b/core/vm/eips.go
@@ -20,6 +20,7 @@ import (
"fmt"
"github.com/XinFinOrg/XDPoSChain/params"
+ "github.com/holiman/uint256"
)
// EnableEIP enables the given EIP on the config.
@@ -51,17 +52,16 @@ func enable1884(jt *JumpTable) {
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884
// New opcode
- jt[SELFBALANCE] = operation{
+ jt[SELFBALANCE] = &operation{
execute: opSelfBalance,
constantGas: GasFastStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
}
}
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
+ balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
callContext.stack.push(balance)
return nil, nil
}
@@ -70,18 +70,17 @@ func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
// - Adds an opcode that returns the current chain’s EIP-155 unique identifier
func enable1344(jt *JumpTable) {
// New opcode
- jt[CHAINID] = operation{
+ jt[CHAINID] = &operation{
execute: opChainID,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
}
}
// opChainID implements CHAINID opcode
func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainId)
+ chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainId)
callContext.stack.push(chainId)
return nil, nil
}
diff --git a/core/vm/errors.go b/core/vm/errors.go
index c813aa36af36..236e22568b58 100644
--- a/core/vm/errors.go
+++ b/core/vm/errors.go
@@ -34,6 +34,10 @@ var (
ErrWriteProtection = errors.New("write protection")
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
ErrGasUintOverflow = errors.New("gas uint64 overflow")
+
+ // errStopToken is an internal token indicating interpreter loop termination,
+ // never returned to outside callers.
+ errStopToken = errors.New("stop token")
)
// ErrStackUnderflow wraps an evm error when the items on the stack less
diff --git a/core/vm/evm.go b/core/vm/evm.go
index f6f6a29a87d0..284ea6768c96 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -189,9 +189,6 @@ func (evm *EVM) Interpreter() Interpreter {
// the necessary steps to create accounts and reverses the state in case of an
// execution error or failed value transfer.
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
- return nil, gas, nil
- }
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
@@ -263,9 +260,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// CallCode differs from Call in the sense that it executes the given address'
// code with the caller as context.
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
- return nil, gas, nil
- }
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
@@ -302,9 +296,6 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// DelegateCall differs from CallCode in the sense that it executes the given address'
// code with the caller as context and the caller is set to the caller of the caller.
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
- return nil, gas, nil
- }
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
@@ -332,9 +323,6 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
// Opcodes that attempt to perform such modifications will result in exceptions
// instead of performing the modifications.
func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
- return nil, gas, nil
- }
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
@@ -353,7 +341,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
// but is the correct thing to do and matters on other networks, in tests, and potential
// future scenarios
- evm.StateDB.AddBalance(addr, bigZero)
+ evm.StateDB.AddBalance(addr, big.NewInt(0))
}
// When an error was returned by the EVM or when setting the creation code
@@ -412,10 +400,6 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
contract := NewContract(caller, AccountRef(address), value, gas)
contract.SetCodeOptionalHash(&address, codeAndHash)
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
- return nil, address, gas, nil
- }
-
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
}
@@ -423,13 +407,16 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
ret, err := run(evm, contract, nil, false)
- // check whether the max code size has been exceeded
- maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize
+ // Check whether the max code size has been exceeded, assign err if the case.
+ if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
+ err = ErrMaxCodeSizeExceeded
+ }
+
// if the contract creation ran successfully and no errors were returned
// calculate the gas required to store the code. If the code could not
// be stored due to not enough gas set an error and let it be handled
// by the error checking condition below.
- if err == nil && !maxCodeSizeExceeded {
+ if err == nil {
createDataGas := uint64(len(ret)) * params.CreateDataGas
if contract.UseGas(createDataGas) {
evm.StateDB.SetCode(address, ret)
@@ -441,21 +428,17 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
- if maxCodeSizeExceeded || (err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas)) {
+ if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
contract.UseGas(contract.Gas)
}
}
- // Assign err if contract code size exceeds the max while the err is still empty.
- if maxCodeSizeExceeded && err == nil {
- err = ErrMaxCodeSizeExceeded
- }
+
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
}
return ret, address, contract.Gas, err
-
}
// Create creates a new contract using code as deployment code.
@@ -466,7 +449,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
// Create2 creates a new contract using code as deployment code.
//
-// The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:]
+// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
codeAndHash := &codeAndHash{code: code}
diff --git a/core/vm/gas.go b/core/vm/gas.go
index bda326cdc7ab..5cf1d852d24a 100644
--- a/core/vm/gas.go
+++ b/core/vm/gas.go
@@ -17,7 +17,7 @@
package vm
import (
- "math/big"
+ "github.com/holiman/uint256"
)
// Gas costs
@@ -34,7 +34,7 @@ const (
//
// The cost of gas was changed during the homestead price change HF.
// As part of EIP 150 (TangerineWhistle), the returned gas is gas - base * 63 / 64.
-func callGas(isEip150 bool, availableGas, base uint64, callCost *big.Int) (uint64, error) {
+func callGas(isEip150 bool, availableGas, base uint64, callCost *uint256.Int) (uint64, error) {
if isEip150 {
availableGas = availableGas - base
gas := availableGas - availableGas/64
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index 987dca32384d..45589157bb00 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -61,7 +61,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
// as argument:
// CALLDATACOPY (stack position 2)
// CODECOPY (stack position 2)
-// EXTCODECOPY (stack poition 3)
+// EXTCODECOPY (stack position 3)
// RETURNDATACOPY (stack position 2)
func memoryCopierGas(stackpos int) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
@@ -71,7 +71,7 @@ func memoryCopierGas(stackpos int) gasFunc {
return 0, err
}
// And gas for copying data, charged per word at param.CopyGas
- words, overflow := bigUint64(stack.Back(stackpos))
+ words, overflow := stack.Back(stackpos).Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
@@ -97,7 +97,7 @@ var (
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
y, x = stack.Back(1), stack.Back(0)
- current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
+ current = evm.StateDB.GetState(contract.Address(), common.Hash(x.Bytes32()))
)
// The legacy gas metering only takes into consideration the current state
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
@@ -132,11 +132,11 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
// 2.2.2. If original value equals new value (this storage slot is reset)
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
- value := common.BigToHash(y)
+ value := common.Hash(y.Bytes32())
if current == value { // noop (1)
return params.NetSstoreNoopGas, nil
}
- original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
+ original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(x.Bytes32()))
if original == current {
if original == (common.Hash{}) { // create slot (2.1.1)
return params.NetSstoreInitGas, nil
@@ -164,18 +164,18 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
}
// 0. If *gasleft* is less than or equal to 2300, fail the current call.
-// 1. If current value equals new value (this is a no-op), SSTORE_NOOP_GAS gas is deducted.
+// 1. If current value equals new value (this is a no-op), SLOAD_GAS is deducted.
// 2. If current value does not equal new value:
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context):
-// 2.1.1. If original value is 0, SSTORE_INIT_GAS gas is deducted.
-// 2.1.2. Otherwise, SSTORE_CLEAN_GAS gas is deducted. If new value is 0, add SSTORE_CLEAR_REFUND to refund counter.
-// 2.2. If original value does not equal current value (this storage slot is dirty), SSTORE_DIRTY_GAS gas is deducted. Apply both of the following clauses:
+// 2.1.1. If original value is 0, SSTORE_SET_GAS (20K) gas is deducted.
+// 2.1.2. Otherwise, SSTORE_RESET_GAS gas is deducted. If new value is 0, add SSTORE_CLEARS_SCHEDULE to refund counter.
+// 2.2. If original value does not equal current value (this storage slot is dirty), SLOAD_GAS gas is deducted. Apply both of the following clauses:
// 2.2.1. If original value is not 0:
-// 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEAR_REFUND gas from refund counter. We can prove that refund counter will never go below 0.
-// 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEAR_REFUND gas to refund counter.
+// 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEARS_SCHEDULE gas from refund counter.
+// 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEARS_SCHEDULE gas to refund counter.
// 2.2.2. If original value equals new value (this storage slot is reset):
-// 2.2.2.1. If original value is 0, add SSTORE_INIT_REFUND to refund counter.
-// 2.2.2.2. Otherwise, add SSTORE_CLEAN_REFUND gas to refund counter.
+// 2.2.2.1. If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter.
+// 2.2.2.2. Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter.
func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
// If we fail the minimum gas availability invariant, fail (0)
if contract.Gas <= params.SstoreSentryGasEIP2200 {
@@ -184,43 +184,43 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
// Gas sentry honoured, do the actual gas calculation based on the stored value
var (
y, x = stack.Back(1), stack.Back(0)
- current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
+ current = evm.StateDB.GetState(contract.Address(), common.Hash(x.Bytes32()))
)
- value := common.BigToHash(y)
+ value := common.Hash(y.Bytes32())
if current == value { // noop (1)
- return params.SstoreNoopGasEIP2200, nil
+ return params.SloadGasEIP2200, nil
}
- original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
+ original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(x.Bytes32()))
if original == current {
if original == (common.Hash{}) { // create slot (2.1.1)
- return params.SstoreInitGasEIP2200, nil
+ return params.SstoreSetGasEIP2200, nil
}
if value == (common.Hash{}) { // delete slot (2.1.2b)
- evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
+ evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200)
}
- return params.SstoreCleanGasEIP2200, nil // write existing slot (2.1.2)
+ return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
}
if original != (common.Hash{}) {
if current == (common.Hash{}) { // recreate slot (2.2.1.1)
- evm.StateDB.SubRefund(params.SstoreClearRefundEIP2200)
+ evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP2200)
} else if value == (common.Hash{}) { // delete slot (2.2.1.2)
- evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
+ evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200)
}
}
if original == value {
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
- evm.StateDB.AddRefund(params.SstoreInitRefundEIP2200)
+ evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
} else { // reset to original existing slot (2.2.2.2)
- evm.StateDB.AddRefund(params.SstoreCleanRefundEIP2200)
+ evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
}
}
- return params.SstoreDirtyGasEIP2200, nil // dirty update (2.2)
+ return params.SloadGasEIP2200, nil // dirty update (2.2)
}
func makeGasLog(n uint64) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- requestedSize, overflow := bigUint64(stack.Back(1))
+ requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
@@ -248,16 +248,16 @@ func makeGasLog(n uint64) gasFunc {
}
}
-func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
- wordGas, overflow := bigUint64(stack.Back(1))
+ wordGas, overflow := stack.Back(1).Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
- if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
+ if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); overflow {
return 0, ErrGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
@@ -287,11 +287,11 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
if err != nil {
return 0, err
}
- wordGas, overflow := bigUint64(stack.Back(2))
+ wordGas, overflow := stack.Back(2).Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
- if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
+ if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); overflow {
return 0, ErrGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
@@ -329,8 +329,8 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
gas uint64
- transfersValue = stack.Back(2).Sign() != 0
- address = common.BigToAddress(stack.Back(1))
+ transfersValue = !stack.Back(2).IsZero()
+ address = common.Address(stack.Back(1).Bytes20())
)
if evm.chainRules.IsEIP158 {
if transfersValue && evm.StateDB.Empty(address) {
@@ -423,7 +423,7 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
// EIP150 homestead gas reprice fork:
if evm.chainRules.IsEIP150 {
gas = params.SelfdestructGasEIP150
- var address = common.BigToAddress(stack.Back(0))
+ var address = common.Address(stack.Back(0).Bytes20())
if evm.chainRules.IsEIP158 {
// if empty and transfers value
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 4f1d12291132..73173b903981 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -17,303 +17,172 @@
package vm
import (
- "math/big"
-
- "github.com/XinFinOrg/XDPoSChain/params"
+ "sync/atomic"
"github.com/XinFinOrg/XDPoSChain/common"
- "github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core/types"
+ "github.com/XinFinOrg/XDPoSChain/params"
+ "github.com/holiman/uint256"
"golang.org/x/crypto/sha3"
)
-var (
- bigZero = new(big.Int)
- tt255 = math.BigPow(2, 255)
-)
-
func opAdd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- math.U256(y.Add(x, y))
-
- interpreter.intPool.putOne(x)
+ y.Add(&x, y)
return nil, nil
}
func opSub(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- math.U256(y.Sub(x, y))
-
- interpreter.intPool.putOne(x)
+ y.Sub(&x, y)
return nil, nil
}
func opMul(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- x, y := callContext.stack.pop(), callContext.stack.pop()
- callContext.stack.push(math.U256(x.Mul(x, y)))
-
- interpreter.intPool.putOne(y)
-
+ x, y := callContext.stack.pop(), callContext.stack.peek()
+ y.Mul(&x, y)
return nil, nil
}
func opDiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- if y.Sign() != 0 {
- math.U256(y.Div(x, y))
- } else {
- y.SetUint64(0)
- }
- interpreter.intPool.putOne(x)
+ y.Div(&x, y)
return nil, nil
}
func opSdiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop())
- res := interpreter.intPool.getZero()
-
- if y.Sign() == 0 || x.Sign() == 0 {
- callContext.stack.push(res)
- } else {
- if x.Sign() != y.Sign() {
- res.Div(x.Abs(x), y.Abs(y))
- res.Neg(res)
- } else {
- res.Div(x.Abs(x), y.Abs(y))
- }
- callContext.stack.push(math.U256(res))
- }
- interpreter.intPool.put(x, y)
+ x, y := callContext.stack.pop(), callContext.stack.peek()
+ y.SDiv(&x, y)
return nil, nil
}
func opMod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- x, y := callContext.stack.pop(), callContext.stack.pop()
- if y.Sign() == 0 {
- callContext.stack.push(x.SetUint64(0))
- } else {
- callContext.stack.push(math.U256(x.Mod(x, y)))
- }
- interpreter.intPool.putOne(y)
+ x, y := callContext.stack.pop(), callContext.stack.peek()
+ y.Mod(&x, y)
return nil, nil
}
func opSmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop())
- res := interpreter.intPool.getZero()
-
- if y.Sign() == 0 {
- callContext.stack.push(res)
- } else {
- if x.Sign() < 0 {
- res.Mod(x.Abs(x), y.Abs(y))
- res.Neg(res)
- } else {
- res.Mod(x.Abs(x), y.Abs(y))
- }
- callContext.stack.push(math.U256(res))
- }
- interpreter.intPool.put(x, y)
+ x, y := callContext.stack.pop(), callContext.stack.peek()
+ y.SMod(&x, y)
return nil, nil
}
func opExp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- base, exponent := callContext.stack.pop(), callContext.stack.pop()
- // some shortcuts
- cmpToOne := exponent.Cmp(big1)
- if cmpToOne < 0 { // Exponent is zero
- // x ^ 0 == 1
- callContext.stack.push(base.SetUint64(1))
- } else if base.Sign() == 0 {
- // 0 ^ y, if y != 0, == 0
- callContext.stack.push(base.SetUint64(0))
- } else if cmpToOne == 0 { // Exponent is one
- // x ^ 1 == x
- callContext.stack.push(base)
- } else {
- callContext.stack.push(math.Exp(base, exponent))
- interpreter.intPool.putOne(base)
- }
- interpreter.intPool.putOne(exponent)
+ base, exponent := callContext.stack.pop(), callContext.stack.peek()
+ exponent.Exp(&base, exponent)
return nil, nil
}
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- back := callContext.stack.pop()
- if back.Cmp(big.NewInt(31)) < 0 {
- bit := uint(back.Uint64()*8 + 7)
- num := callContext.stack.pop()
- mask := back.Lsh(common.Big1, bit)
- mask.Sub(mask, common.Big1)
- if num.Bit(int(bit)) > 0 {
- num.Or(num, mask.Not(mask))
- } else {
- num.And(num, mask)
- }
-
- callContext.stack.push(math.U256(num))
- }
-
- interpreter.intPool.putOne(back)
+ back, num := callContext.stack.pop(), callContext.stack.peek()
+ num.ExtendSign(num, &back)
return nil, nil
}
func opNot(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x := callContext.stack.peek()
- math.U256(x.Not(x))
+ x.Not(x)
return nil, nil
}
func opLt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- if x.Cmp(y) < 0 {
- y.SetUint64(1)
+ if x.Lt(y) {
+ y.SetOne()
} else {
- y.SetUint64(0)
+ y.Clear()
}
- interpreter.intPool.putOne(x)
return nil, nil
}
func opGt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- if x.Cmp(y) > 0 {
- y.SetUint64(1)
+ if x.Gt(y) {
+ y.SetOne()
} else {
- y.SetUint64(0)
+ y.Clear()
}
- interpreter.intPool.putOne(x)
return nil, nil
}
func opSlt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
-
- xSign := x.Cmp(tt255)
- ySign := y.Cmp(tt255)
-
- switch {
- case xSign >= 0 && ySign < 0:
- y.SetUint64(1)
-
- case xSign < 0 && ySign >= 0:
- y.SetUint64(0)
-
- default:
- if x.Cmp(y) < 0 {
- y.SetUint64(1)
- } else {
- y.SetUint64(0)
- }
+ if x.Slt(y) {
+ y.SetOne()
+ } else {
+ y.Clear()
}
- interpreter.intPool.putOne(x)
return nil, nil
}
func opSgt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
-
- xSign := x.Cmp(tt255)
- ySign := y.Cmp(tt255)
-
- switch {
- case xSign >= 0 && ySign < 0:
- y.SetUint64(0)
-
- case xSign < 0 && ySign >= 0:
- y.SetUint64(1)
-
- default:
- if x.Cmp(y) > 0 {
- y.SetUint64(1)
- } else {
- y.SetUint64(0)
- }
+ if x.Sgt(y) {
+ y.SetOne()
+ } else {
+ y.Clear()
}
- interpreter.intPool.putOne(x)
return nil, nil
}
func opEq(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- if x.Cmp(y) == 0 {
- y.SetUint64(1)
+ if x.Eq(y) {
+ y.SetOne()
} else {
- y.SetUint64(0)
+ y.Clear()
}
- interpreter.intPool.putOne(x)
return nil, nil
}
func opIszero(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x := callContext.stack.peek()
- if x.Sign() > 0 {
- x.SetUint64(0)
+ if x.IsZero() {
+ x.SetOne()
} else {
- x.SetUint64(1)
+ x.Clear()
}
return nil, nil
}
func opAnd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- x, y := callContext.stack.pop(), callContext.stack.pop()
- callContext.stack.push(x.And(x, y))
-
- interpreter.intPool.putOne(y)
+ x, y := callContext.stack.pop(), callContext.stack.peek()
+ y.And(&x, y)
return nil, nil
}
func opOr(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- y.Or(x, y)
-
- interpreter.intPool.putOne(x)
+ y.Or(&x, y)
return nil, nil
}
func opXor(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
- y.Xor(x, y)
-
- interpreter.intPool.putOne(x)
+ y.Xor(&x, y)
return nil, nil
}
func opByte(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
th, val := callContext.stack.pop(), callContext.stack.peek()
- if th.Cmp(common.Big32) < 0 {
- b := math.Byte(val, 32, int(th.Int64()))
- val.SetUint64(uint64(b))
- } else {
- val.SetUint64(0)
- }
- interpreter.intPool.putOne(th)
+ val.Byte(&th)
return nil, nil
}
func opAddmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
- if z.Cmp(bigZero) > 0 {
- x.Add(x, y)
- x.Mod(x, z)
- callContext.stack.push(math.U256(x))
+ x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.peek()
+ if z.IsZero() {
+ z.Clear()
} else {
- callContext.stack.push(x.SetUint64(0))
+ z.AddMod(&x, &y, z)
}
- interpreter.intPool.put(y, z)
return nil, nil
}
func opMulmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
- if z.Cmp(bigZero) > 0 {
- x.Mul(x, y)
- x.Mod(x, z)
- callContext.stack.push(math.U256(x))
- } else {
- callContext.stack.push(x.SetUint64(0))
- }
- interpreter.intPool.put(y, z)
+ x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.peek()
+ z.MulMod(&x, &y, z)
return nil, nil
}
@@ -322,16 +191,12 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
func opSHL(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
- shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek())
- defer interpreter.intPool.putOne(shift) // First operand back into the pool
-
- if shift.Cmp(common.Big256) >= 0 {
- value.SetUint64(0)
- return nil, nil
+ shift, value := callContext.stack.pop(), callContext.stack.peek()
+ if shift.LtUint64(256) {
+ value.Lsh(value, uint(shift.Uint64()))
+ } else {
+ value.Clear()
}
- n := uint(shift.Uint64())
- math.U256(value.Lsh(value, n))
-
return nil, nil
}
@@ -340,16 +205,12 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
func opSHR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
- shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek())
- defer interpreter.intPool.putOne(shift) // First operand back into the pool
-
- if shift.Cmp(common.Big256) >= 0 {
- value.SetUint64(0)
- return nil, nil
+ shift, value := callContext.stack.pop(), callContext.stack.peek()
+ if shift.LtUint64(256) {
+ value.Rsh(value, uint(shift.Uint64()))
+ } else {
+ value.Clear()
}
- n := uint(shift.Uint64())
- math.U256(value.Rsh(value, n))
-
return nil, nil
}
@@ -357,29 +218,24 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
func opSAR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one
- shift, value := math.U256(callContext.stack.pop()), math.S256(callContext.stack.pop())
- defer interpreter.intPool.putOne(shift) // First operand back into the pool
-
- if shift.Cmp(common.Big256) >= 0 {
+ shift, value := callContext.stack.pop(), callContext.stack.peek()
+ if shift.GtUint64(256) {
if value.Sign() >= 0 {
- value.SetUint64(0)
+ value.Clear()
} else {
- value.SetInt64(-1)
+ // Max negative shift: all bits set
+ value.SetAllOne()
}
- callContext.stack.push(math.U256(value))
return nil, nil
}
n := uint(shift.Uint64())
- value.Rsh(value, n)
- callContext.stack.push(math.U256(value))
-
+ value.SRsh(value, n)
return nil, nil
}
-func opSha3(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- offset, size := callContext.stack.pop(), callContext.stack.pop()
- data := callContext.memory.GetPtr(offset.Int64(), size.Int64())
+func opKeccak256(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ offset, size := callContext.stack.pop(), callContext.stack.peek()
+ data := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
if interpreter.hasher == nil {
interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
@@ -393,45 +249,50 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by
if evm.vmConfig.EnablePreimageRecording {
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
}
- callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:]))
- interpreter.intPool.put(offset, size)
+ size.SetBytes(interpreter.hasherBuf[:])
return nil, nil
}
-
func opAddress(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Address().Bytes()))
+ callContext.stack.push(new(uint256.Int).SetBytes(callContext.contract.Address().Bytes()))
return nil, nil
}
func opBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := callContext.stack.peek()
- slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot)))
+ address := common.Address(slot.Bytes20())
+ slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
return nil, nil
}
func opOrigin(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes()))
+ callContext.stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
return nil, nil
}
-
func opCaller(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Caller().Bytes()))
+ callContext.stack.push(new(uint256.Int).SetBytes(callContext.contract.Caller().Bytes()))
return nil, nil
}
func opCallValue(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().Set(callContext.contract.value))
+ v, _ := uint256.FromBig(callContext.contract.value)
+ callContext.stack.push(v)
return nil, nil
}
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetBytes(getDataBig(callContext.contract.Input, callContext.stack.pop(), big32)))
+ x := callContext.stack.peek()
+ if offset, overflow := x.Uint64WithOverflow(); !overflow {
+ data := getData(callContext.contract.Input, offset, 32)
+ x.SetBytes(data)
+ } else {
+ x.Clear()
+ }
return nil, nil
}
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Input))))
+ callContext.stack.push(new(uint256.Int).SetUint64(uint64(len(callContext.contract.Input))))
return nil, nil
}
@@ -441,14 +302,20 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCt
dataOffset = callContext.stack.pop()
length = callContext.stack.pop()
)
- callContext.memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(callContext.contract.Input, dataOffset, length))
+ dataOffset64, overflow := dataOffset.Uint64WithOverflow()
+ if overflow {
+ dataOffset64 = 0xffffffffffffffff
+ }
+ // These values are checked for overflow during gas cost calculation
+ memOffset64 := memOffset.Uint64()
+ length64 := length.Uint64()
+ callContext.memory.Set(memOffset64, length64, getData(callContext.contract.Input, dataOffset64, length64))
- interpreter.intPool.put(memOffset, dataOffset, length)
return nil, nil
}
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData))))
+ callContext.stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
return nil, nil
}
@@ -457,30 +324,33 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *call
memOffset = callContext.stack.pop()
dataOffset = callContext.stack.pop()
length = callContext.stack.pop()
-
- end = interpreter.intPool.get().Add(dataOffset, length)
)
- defer interpreter.intPool.put(memOffset, dataOffset, length, end)
- if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() {
+ offset64, overflow := dataOffset.Uint64WithOverflow()
+ if overflow {
return nil, ErrReturnDataOutOfBounds
}
- callContext.memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()])
-
+ // we can reuse dataOffset now (aliasing it for clarity)
+ var end = dataOffset
+ end.Add(&dataOffset, &length)
+ end64, overflow := end.Uint64WithOverflow()
+ if overflow || uint64(len(interpreter.returnData)) < end64 {
+ return nil, ErrReturnDataOutOfBounds
+ }
+ callContext.memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64])
return nil, nil
}
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := callContext.stack.peek()
- slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
-
+ slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.Address(slot.Bytes20()))))
return nil, nil
}
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- l := interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Code)))
+ l := new(uint256.Int)
+ l.SetUint64(uint64(len(callContext.contract.Code)))
callContext.stack.push(l)
-
return nil, nil
}
@@ -490,24 +360,32 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) (
codeOffset = callContext.stack.pop()
length = callContext.stack.pop()
)
- codeCopy := getDataBig(callContext.contract.Code, codeOffset, length)
+ uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
+ if overflow {
+ uint64CodeOffset = 0xffffffffffffffff
+ }
+ codeCopy := getData(callContext.contract.Code, uint64CodeOffset, length.Uint64())
callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
- interpreter.intPool.put(memOffset, codeOffset, length)
return nil, nil
}
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var (
- addr = common.BigToAddress(callContext.stack.pop())
- memOffset = callContext.stack.pop()
- codeOffset = callContext.stack.pop()
- length = callContext.stack.pop()
+ stack = callContext.stack
+ a = stack.pop()
+ memOffset = stack.pop()
+ codeOffset = stack.pop()
+ length = stack.pop()
)
- codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length)
+ uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
+ if overflow {
+ uint64CodeOffset = 0xffffffffffffffff
+ }
+ addr := common.Address(a.Bytes20())
+ codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
- interpreter.intPool.put(memOffset, codeOffset, length)
return nil, nil
}
@@ -539,9 +417,9 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
// this account should be regarded as a non-existent account and zero should be returned.
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := callContext.stack.peek()
- address := common.BigToAddress(slot)
+ address := common.Address(slot.Bytes20())
if interpreter.evm.StateDB.Empty(address) {
- slot.SetUint64(0)
+ slot.Clear()
} else {
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
}
@@ -549,56 +427,69 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
}
func opGasprice(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice))
+ v, _ := uint256.FromBig(interpreter.evm.GasPrice)
+ callContext.stack.push(v)
return nil, nil
}
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- num := callContext.stack.pop()
-
- n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257)
- if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 {
- callContext.stack.push(interpreter.evm.GetHash(num.Uint64()).Big())
+ num := callContext.stack.peek()
+ num64, overflow := num.Uint64WithOverflow()
+ if overflow {
+ num.Clear()
+ return nil, nil
+ }
+ var upper, lower uint64
+ upper = interpreter.evm.BlockNumber.Uint64()
+ if upper < 257 {
+ lower = 0
+ } else {
+ lower = upper - 256
+ }
+ if num64 >= lower && num64 < upper {
+ num.SetBytes(interpreter.evm.GetHash(num64).Bytes())
} else {
- callContext.stack.push(interpreter.intPool.getZero())
+ num.Clear()
}
- interpreter.intPool.put(num, n)
return nil, nil
}
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes()))
+ callContext.stack.push(new(uint256.Int).SetBytes(interpreter.evm.Coinbase.Bytes()))
return nil, nil
}
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time)))
+ v, _ := uint256.FromBig(interpreter.evm.Time)
+ callContext.stack.push(v)
return nil, nil
}
func opNumber(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber)))
+ v, _ := uint256.FromBig(interpreter.evm.BlockNumber)
+ callContext.stack.push(v)
return nil, nil
}
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty)))
+ v, _ := uint256.FromBig(interpreter.evm.Difficulty)
+ callContext.stack.push(v)
return nil, nil
}
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit)))
+ callContext.stack.push(new(uint256.Int).SetUint64(interpreter.evm.GasLimit))
return nil, nil
}
func opPop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- interpreter.intPool.putOne(callContext.stack.pop())
+ callContext.stack.pop()
return nil, nil
}
func opMload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
v := callContext.stack.peek()
- offset := v.Int64()
+ offset := int64(v.Uint64())
v.SetBytes(callContext.memory.GetPtr(offset, 32))
return nil, nil
}
@@ -606,58 +497,58 @@ func opMload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]b
func opMstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// pop value of the stack
mStart, val := callContext.stack.pop(), callContext.stack.pop()
- callContext.memory.Set32(mStart.Uint64(), val)
-
- interpreter.intPool.put(mStart, val)
+ callContext.memory.Set32(mStart.Uint64(), &val)
return nil, nil
}
func opMstore8(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- off, val := callContext.stack.pop().Int64(), callContext.stack.pop().Int64()
- callContext.memory.store[off] = byte(val & 0xff)
-
+ off, val := callContext.stack.pop(), callContext.stack.pop()
+ callContext.memory.store[off.Uint64()] = byte(val.Uint64())
return nil, nil
}
func opSload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
loc := callContext.stack.peek()
- val := interpreter.evm.StateDB.GetState(callContext.contract.Address(), common.BigToHash(loc))
+ hash := common.Hash(loc.Bytes32())
+ val := interpreter.evm.StateDB.GetState(callContext.contract.Address(), hash)
loc.SetBytes(val.Bytes())
return nil, nil
}
func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- loc := common.BigToHash(callContext.stack.pop())
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
+ loc := callContext.stack.pop()
val := callContext.stack.pop()
- interpreter.evm.StateDB.SetState(callContext.contract.Address(), loc, common.BigToHash(val))
-
- interpreter.intPool.putOne(val)
+ interpreter.evm.StateDB.SetState(callContext.contract.Address(),
+ common.Hash(loc.Bytes32()), common.Hash(val.Bytes32()))
return nil, nil
}
func opJump(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ if atomic.LoadInt32(&interpreter.evm.abort) != 0 {
+ return nil, errStopToken
+ }
pos := callContext.stack.pop()
- if !callContext.contract.validJumpdest(pos) {
+ if !callContext.contract.validJumpdest(&pos) {
return nil, ErrInvalidJump
}
- *pc = pos.Uint64()
-
- interpreter.intPool.putOne(pos)
+ *pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
return nil, nil
}
func opJumpi(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ if atomic.LoadInt32(&interpreter.evm.abort) != 0 {
+ return nil, errStopToken
+ }
pos, cond := callContext.stack.pop(), callContext.stack.pop()
- if cond.Sign() != 0 {
- if !callContext.contract.validJumpdest(pos) {
+ if !cond.IsZero() {
+ if !callContext.contract.validJumpdest(&pos) {
return nil, ErrInvalidJump
}
- *pc = pos.Uint64()
- } else {
- *pc++
+ *pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
}
-
- interpreter.intPool.put(pos, cond)
return nil, nil
}
@@ -666,219 +557,253 @@ func opJumpdest(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) (
}
func opPc(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetUint64(*pc))
+ callContext.stack.push(new(uint256.Int).SetUint64(*pc))
return nil, nil
}
func opMsize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetInt64(int64(callContext.memory.Len())))
+ callContext.stack.push(new(uint256.Int).SetUint64(uint64(callContext.memory.Len())))
return nil, nil
}
func opGas(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.push(interpreter.intPool.get().SetUint64(callContext.contract.Gas))
+ callContext.stack.push(new(uint256.Int).SetUint64(callContext.contract.Gas))
return nil, nil
}
func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
var (
value = callContext.stack.pop()
offset, size = callContext.stack.pop(), callContext.stack.pop()
- input = callContext.memory.GetCopy(offset.Int64(), size.Int64())
+ input = callContext.memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
gas = callContext.contract.Gas
)
if interpreter.evm.chainRules.IsEIP150 {
gas -= gas / 64
}
+ // reuse size int for stackvalue
+ stackvalue := size
callContext.contract.UseGas(gas)
- res, addr, returnGas, suberr := interpreter.evm.Create(callContext.contract, input, gas, value)
+ res, addr, returnGas, suberr := interpreter.evm.Create(callContext.contract, input, gas, value.ToBig())
// Push item on the stack based on the returned error. If the ruleset is
// homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful.
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
- callContext.stack.push(interpreter.intPool.getZero())
+ stackvalue.Clear()
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
- callContext.stack.push(interpreter.intPool.getZero())
+ stackvalue.Clear()
} else {
- callContext.stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
+ stackvalue.SetBytes(addr.Bytes())
}
+ callContext.stack.push(&stackvalue)
callContext.contract.Gas += returnGas
- interpreter.intPool.put(value, offset, size)
if suberr == ErrExecutionReverted {
+ interpreter.returnData = res // set REVERT data to return data buffer
return res, nil
}
+ interpreter.returnData = nil // clear dirty return data buffer
return nil, nil
}
func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
var (
endowment = callContext.stack.pop()
offset, size = callContext.stack.pop(), callContext.stack.pop()
salt = callContext.stack.pop()
- input = callContext.memory.GetCopy(offset.Int64(), size.Int64())
+ input = callContext.memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
gas = callContext.contract.Gas
)
// Apply EIP150
gas -= gas / 64
callContext.contract.UseGas(gas)
- res, addr, returnGas, suberr := interpreter.evm.Create2(callContext.contract, input, gas, endowment, salt)
+ // reuse size int for stackvalue
+ stackvalue := size
+ res, addr, returnGas, suberr := interpreter.evm.Create2(callContext.contract, input, gas,
+ endowment.ToBig(), salt.ToBig())
// Push item on the stack based on the returned error.
if suberr != nil {
- callContext.stack.push(interpreter.intPool.getZero())
+ stackvalue.Clear()
} else {
- callContext.stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
+ stackvalue.SetBytes(addr.Bytes())
}
+ callContext.stack.push(&stackvalue)
callContext.contract.Gas += returnGas
- interpreter.intPool.put(endowment, offset, size, salt)
if suberr == ErrExecutionReverted {
+ interpreter.returnData = res // set REVERT data to return data buffer
return res, nil
}
+ interpreter.returnData = nil // clear dirty return data buffer
return nil, nil
}
func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ stack := callContext.stack
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
- interpreter.intPool.putOne(callContext.stack.pop())
+ // We can use this as a temporary value
+ temp := stack.pop()
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
- addr, value, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
- toAddr := common.BigToAddress(addr)
- value = math.U256(value)
+ addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
// Get the arguments from the memory.
- args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
+ args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
- if value.Sign() != 0 {
+ if interpreter.readOnly && !value.IsZero() {
+ return nil, ErrWriteProtection
+ }
+ if !value.IsZero() {
gas += params.CallStipend
}
- ret, returnGas, err := interpreter.evm.Call(callContext.contract, toAddr, args, gas, value)
+ ret, returnGas, err := interpreter.evm.Call(callContext.contract, toAddr, args, gas, value.ToBig())
if err != nil {
- callContext.stack.push(interpreter.intPool.getZero())
+ temp.Clear()
} else {
- callContext.stack.push(interpreter.intPool.get().SetUint64(1))
+ temp.SetOne()
}
+ stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
callContext.contract.Gas += returnGas
- interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
+ interpreter.returnData = ret
return ret, nil
}
func opCallCode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
- interpreter.intPool.putOne(callContext.stack.pop())
+ stack := callContext.stack
+ // We use it as a temporary value
+ temp := stack.pop()
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
- addr, value, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
- toAddr := common.BigToAddress(addr)
- value = math.U256(value)
+ addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
- args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
+ args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
- if value.Sign() != 0 {
+ if !value.IsZero() {
gas += params.CallStipend
}
- ret, returnGas, err := interpreter.evm.CallCode(callContext.contract, toAddr, args, gas, value)
+ ret, returnGas, err := interpreter.evm.CallCode(callContext.contract, toAddr, args, gas, value.ToBig())
if err != nil {
- callContext.stack.push(interpreter.intPool.getZero())
+ temp.Clear()
} else {
- callContext.stack.push(interpreter.intPool.get().SetUint64(1))
+ temp.SetOne()
}
+ stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
callContext.contract.Gas += returnGas
- interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
+ interpreter.returnData = ret
return ret, nil
}
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ stack := callContext.stack
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
- interpreter.intPool.putOne(callContext.stack.pop())
+ // We use it as a temporary value
+ temp := stack.pop()
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
- addr, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
- toAddr := common.BigToAddress(addr)
+ addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
- args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
+ args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
ret, returnGas, err := interpreter.evm.DelegateCall(callContext.contract, toAddr, args, gas)
if err != nil {
- callContext.stack.push(interpreter.intPool.getZero())
+ temp.Clear()
} else {
- callContext.stack.push(interpreter.intPool.get().SetUint64(1))
+ temp.SetOne()
}
+ stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
callContext.contract.Gas += returnGas
- interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
+ interpreter.returnData = ret
return ret, nil
}
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
- interpreter.intPool.putOne(callContext.stack.pop())
+ stack := callContext.stack
+ // We use it as a temporary value
+ temp := stack.pop()
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
- addr, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
- toAddr := common.BigToAddress(addr)
+ addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
- args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
+ args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
ret, returnGas, err := interpreter.evm.StaticCall(callContext.contract, toAddr, args, gas)
if err != nil {
- callContext.stack.push(interpreter.intPool.getZero())
+ temp.Clear()
} else {
- callContext.stack.push(interpreter.intPool.get().SetUint64(1))
+ temp.SetOne()
}
+ stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
callContext.contract.Gas += returnGas
- interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
+ interpreter.returnData = ret
return ret, nil
}
func opReturn(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := callContext.stack.pop(), callContext.stack.pop()
- ret := callContext.memory.GetPtr(offset.Int64(), size.Int64())
+ ret := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
- interpreter.intPool.put(offset, size)
- return ret, nil
+ return ret, errStopToken
}
func opRevert(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := callContext.stack.pop(), callContext.stack.pop()
- ret := callContext.memory.GetPtr(offset.Int64(), size.Int64())
+ ret := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
- interpreter.intPool.put(offset, size)
- return ret, nil
+ interpreter.returnData = ret
+ return ret, ErrExecutionReverted
+}
+
+func opUndefined(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ return nil, &ErrInvalidOpCode{opcode: OpCode(callContext.contract.Code[*pc])}
}
func opStop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- return nil, nil
+ return nil, errStopToken
}
-func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
+ beneficiary := callContext.stack.pop()
balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address())
- interpreter.evm.StateDB.AddBalance(common.BigToAddress(callContext.stack.pop()), balance)
-
+ interpreter.evm.StateDB.AddBalance(common.Address(beneficiary.Bytes20()), balance)
interpreter.evm.StateDB.Suicide(callContext.contract.Address())
- return nil, nil
+ return nil, errStopToken
}
// following functions are used by the instruction jump table
@@ -886,13 +811,18 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([
// make log instruction function
func makeLog(size int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ if interpreter.readOnly {
+ return nil, ErrWriteProtection
+ }
topics := make([]common.Hash, size)
- mStart, mSize := callContext.stack.pop(), callContext.stack.pop()
+ stack := callContext.stack
+ mStart, mSize := stack.pop(), stack.pop()
for i := 0; i < size; i++ {
- topics[i] = common.BigToHash(callContext.stack.pop())
+ addr := stack.pop()
+ topics[i] = common.Hash(addr.Bytes32())
}
- d := callContext.memory.GetCopy(mStart.Int64(), mSize.Int64())
+ d := callContext.memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
interpreter.evm.StateDB.AddLog(&types.Log{
Address: callContext.contract.Address(),
Topics: topics,
@@ -902,7 +832,6 @@ func makeLog(size int) executionFunc {
BlockNumber: interpreter.evm.BlockNumber.Uint64(),
})
- interpreter.intPool.put(mStart, mSize)
return nil, nil
}
}
@@ -911,13 +840,13 @@ func makeLog(size int) executionFunc {
func opPush1(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var (
codeLen = uint64(len(callContext.contract.Code))
- integer = interpreter.intPool.get()
+ integer = new(uint256.Int)
)
*pc += 1
if *pc < codeLen {
callContext.stack.push(integer.SetUint64(uint64(callContext.contract.Code[*pc])))
} else {
- callContext.stack.push(integer.SetUint64(0))
+ callContext.stack.push(integer.Clear())
}
return nil, nil
}
@@ -937,8 +866,9 @@ func makePush(size uint64, pushByteSize int) executionFunc {
endMin = startMin + pushByteSize
}
- integer := interpreter.intPool.get()
- callContext.stack.push(integer.SetBytes(common.RightPadBytes(callContext.contract.Code[startMin:endMin], pushByteSize)))
+ integer := new(uint256.Int)
+ callContext.stack.push(integer.SetBytes(common.RightPadBytes(
+ callContext.contract.Code[startMin:endMin], pushByteSize)))
*pc += size
return nil, nil
@@ -948,7 +878,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
// make dup instruction function
func makeDup(size int64) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
- callContext.stack.dup(interpreter.intPool, int(size))
+ callContext.stack.dup(int(size))
return nil, nil
}
}
diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go
index f439b643a5dd..1f63d2b040a1 100644
--- a/core/vm/instructions_test.go
+++ b/core/vm/instructions_test.go
@@ -21,14 +21,13 @@ import (
"encoding/json"
"fmt"
"log"
- "math/big"
"os"
"testing"
- "github.com/XinFinOrg/XDPoSChain/params"
-
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/crypto"
+ "github.com/XinFinOrg/XDPoSChain/params"
+ "github.com/holiman/uint256"
)
type TwoOperandTestcase struct {
@@ -42,6 +41,7 @@ type twoOperandParams struct {
y string
}
+var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
var commonParams []*twoOperandParams
var twoOpMethods map[string]executionFunc
@@ -91,31 +91,6 @@ func init() {
}
}
-// getResult is a convenience function to generate the expected values
-func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
- var (
- env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
- stack = newstack()
- pc = uint64(0)
- interpreter = env.interpreter.(*EVMInterpreter)
- )
- interpreter.intPool = poolOfIntPools.get()
- result := make([]TwoOperandTestcase, len(args))
- for i, param := range args {
- x := new(big.Int).SetBytes(common.Hex2Bytes(param.x))
- y := new(big.Int).SetBytes(common.Hex2Bytes(param.y))
- stack.push(x)
- stack.push(y)
- _, err := opFn(&pc, interpreter, &callCtx{nil, stack, nil})
- if err != nil {
- log.Fatalln(err)
- }
- actual := stack.pop()
- result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
- }
- return result
-}
-
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
var (
@@ -124,42 +99,23 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
pc = uint64(0)
evmInterpreter = env.interpreter.(*EVMInterpreter)
)
- // Stuff a couple of nonzero bigints into pool, to ensure that ops do not rely on pooled integers to be zero
- evmInterpreter.intPool = poolOfIntPools.get()
- evmInterpreter.intPool.put(big.NewInt(-1337))
- evmInterpreter.intPool.put(big.NewInt(-1337))
- evmInterpreter.intPool.put(big.NewInt(-1337))
for i, test := range tests {
- x := new(big.Int).SetBytes(common.Hex2Bytes(test.X))
- y := new(big.Int).SetBytes(common.Hex2Bytes(test.Y))
- expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
+ x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.X))
+ y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Y))
+ expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
stack.push(x)
stack.push(y)
opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil})
+ if len(stack.data) != 1 {
+ t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
+ }
actual := stack.pop()
if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %v %d, %v(%x, %x): expected %x, got %x", name, i, name, x, y, expected, actual)
}
- // Check pool usage
- // 1.pool is not allowed to contain anything on the stack
- // 2.pool is not allowed to contain the same pointers twice
- if evmInterpreter.intPool.pool.len() > 0 {
-
- poolvals := make(map[*big.Int]struct{})
- poolvals[actual] = struct{}{}
-
- for evmInterpreter.intPool.pool.len() > 0 {
- key := evmInterpreter.intPool.get()
- if _, exist := poolvals[key]; exist {
- t.Errorf("Testcase %v %d, pool contains double-entry", name, i)
- }
- poolvals[key] = struct{}{}
- }
- }
}
- poolOfIntPools.put(evmInterpreter.intPool)
}
func TestByteOp(t *testing.T) {
@@ -235,6 +191,68 @@ func TestSAR(t *testing.T) {
testTwoOperandOp(t, tests, opSAR, "sar")
}
+func TestAddMod(t *testing.T) {
+ var (
+ env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
+ stack = newstack()
+ evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
+ pc = uint64(0)
+ )
+ tests := []struct {
+ x string
+ y string
+ z string
+ expected string
+ }{
+ {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
+ },
+ }
+ // x + y = 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd
+ // in 256 bit repr, fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd
+
+ for i, test := range tests {
+ x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.x))
+ y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.y))
+ z := new(uint256.Int).SetBytes(common.Hex2Bytes(test.z))
+ expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.expected))
+ stack.push(z)
+ stack.push(y)
+ stack.push(x)
+ opAddmod(&pc, evmInterpreter, &callCtx{nil, stack, nil})
+ actual := stack.pop()
+ if actual.Cmp(expected) != 0 {
+ t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
+ }
+ }
+}
+
+// getResult is a convenience function to generate the expected values
+func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
+ var (
+ env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
+ stack = newstack()
+ pc = uint64(0)
+ interpreter = env.interpreter.(*EVMInterpreter)
+ )
+ result := make([]TwoOperandTestcase, len(args))
+ for i, param := range args {
+ x := new(uint256.Int).SetBytes(common.Hex2Bytes(param.x))
+ y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
+ stack.push(x)
+ stack.push(y)
+ _, err := opFn(&pc, interpreter, &callCtx{nil, stack, nil})
+ if err != nil {
+ log.Fatalln(err)
+ }
+ actual := stack.pop()
+ result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
+ }
+ return result
+}
+
// utility function to fill the json-file with testcases
// Enable this test to generate the 'testcases_xx.json' files
func TestWriteExpectedValues(t *testing.T) {
@@ -276,7 +294,6 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
)
env.interpreter = evmInterpreter
- evmInterpreter.intPool = poolOfIntPools.get()
// convert args
byteArgs := make([][]byte, len(args))
for i, arg := range args {
@@ -286,13 +303,13 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
for _, arg := range byteArgs {
- a := new(big.Int).SetBytes(arg)
+ a := new(uint256.Int)
+ a.SetBytes(arg)
stack.push(a)
}
op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
stack.pop()
}
- poolOfIntPools.put(evmInterpreter.intPool)
}
func BenchmarkOpAdd64(b *testing.B) {
@@ -338,8 +355,8 @@ func BenchmarkOpSub256(b *testing.B) {
}
func BenchmarkOpMul(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opMul, x, y)
}
@@ -370,64 +387,64 @@ func BenchmarkOpSdiv(b *testing.B) {
}
func BenchmarkOpMod(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opMod, x, y)
}
func BenchmarkOpSmod(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opSmod, x, y)
}
func BenchmarkOpExp(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opExp, x, y)
}
func BenchmarkOpSignExtend(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opSignExtend, x, y)
}
func BenchmarkOpLt(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opLt, x, y)
}
func BenchmarkOpGt(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opGt, x, y)
}
func BenchmarkOpSlt(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opSlt, x, y)
}
func BenchmarkOpSgt(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opSgt, x, y)
}
func BenchmarkOpEq(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opEq, x, y)
}
@@ -437,45 +454,45 @@ func BenchmarkOpEq2(b *testing.B) {
opBenchmark(b, opEq, x, y)
}
func BenchmarkOpAnd(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opAnd, x, y)
}
func BenchmarkOpOr(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opOr, x, y)
}
func BenchmarkOpXor(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opXor, x, y)
}
func BenchmarkOpByte(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
opBenchmark(b, opByte, x, y)
}
func BenchmarkOpAddmod(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
+ z := alphabetSoup
opBenchmark(b, opAddmod, x, y, z)
}
func BenchmarkOpMulmod(b *testing.B) {
- x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
- z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
+ x := alphabetSoup
+ y := alphabetSoup
+ z := alphabetSoup
opBenchmark(b, opMulmod, x, y, z)
}
@@ -512,21 +529,21 @@ func TestOpMstore(t *testing.T) {
)
env.interpreter = evmInterpreter
- evmInterpreter.intPool = poolOfIntPools.get()
mem.Resize(64)
pc := uint64(0)
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
- stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
+ stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v)))
+ stack.push(new(uint256.Int))
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
}
- stack.pushN(big.NewInt(0x1), big.NewInt(0))
+ stack.push(new(uint256.Int).SetUint64(0x1))
+ stack.push(new(uint256.Int))
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
t.Fatalf("Mstore failed to overwrite previous value")
}
- poolOfIntPools.put(evmInterpreter.intPool)
}
func BenchmarkOpMstore(bench *testing.B) {
@@ -538,21 +555,20 @@ func BenchmarkOpMstore(bench *testing.B) {
)
env.interpreter = evmInterpreter
- evmInterpreter.intPool = poolOfIntPools.get()
mem.Resize(64)
pc := uint64(0)
- memStart := big.NewInt(0)
- value := big.NewInt(0x1337)
+ memStart := new(uint256.Int)
+ value := new(uint256.Int).SetUint64(0x1337)
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
- stack.pushN(value, memStart)
+ stack.push(value)
+ stack.push(memStart)
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
}
- poolOfIntPools.put(evmInterpreter.intPool)
}
-func BenchmarkOpSHA3(bench *testing.B) {
+func BenchmarkOpKeccak256(bench *testing.B) {
var (
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
@@ -560,17 +576,16 @@ func BenchmarkOpSHA3(bench *testing.B) {
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
)
env.interpreter = evmInterpreter
- evmInterpreter.intPool = poolOfIntPools.get()
mem.Resize(32)
pc := uint64(0)
- start := big.NewInt(0)
+ start := new(uint256.Int)
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
- stack.pushN(big.NewInt(32), start)
- opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil})
+ stack.push(uint256.NewInt(32))
+ stack.push(start)
+ opKeccak256(&pc, evmInterpreter, &callCtx{mem, stack, nil})
}
- poolOfIntPools.put(evmInterpreter.intPool)
}
func TestCreate2Addreses(t *testing.T) {
@@ -644,6 +659,5 @@ func TestCreate2Addreses(t *testing.T) {
if !bytes.Equal(expected.Bytes(), address.Bytes()) {
t.Errorf("test %d: expected %s, got %s", i, expected.String(), address.String())
}
-
}
}
diff --git a/core/vm/int_pool_verifier.go b/core/vm/int_pool_verifier.go
deleted file mode 100644
index 82fbfed699de..000000000000
--- a/core/vm/int_pool_verifier.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build VERIFY_EVM_INTEGER_POOL
-
-package vm
-
-import "fmt"
-
-const verifyPool = true
-
-func verifyIntegerPool(ip *intPool) {
- for i, item := range ip.pool.data {
- if item.Cmp(checkVal) != 0 {
- panic(fmt.Sprintf("%d'th item failed aggressive pool check. Value was modified", i))
- }
- }
-}
diff --git a/core/vm/int_pool_verifier_empty.go b/core/vm/int_pool_verifier_empty.go
deleted file mode 100644
index a5f1dc02b7fe..000000000000
--- a/core/vm/int_pool_verifier_empty.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build !VERIFY_EVM_INTEGER_POOL
-
-package vm
-
-const verifyPool = false
-
-func verifyIntegerPool(ip *intPool) {}
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index 2662a1922ec8..59fbf21f7c5a 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -18,7 +18,6 @@ package vm
import (
"hash"
- "sync/atomic"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
@@ -29,10 +28,9 @@ import (
type Config struct {
Debug bool // Enables debugging
Tracer Tracer // Opcode logger
- NoRecursion bool // Disables call, callcode, delegate call and create
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
- JumpTable [256]operation // EVM instruction table, automatically populated if unset
+ JumpTable *JumpTable // EVM instruction table, automatically populated if unset
EWASMInterpreter string // External EWASM interpreter options
EVMInterpreter string // External EVM interpreter options
@@ -83,8 +81,6 @@ type EVMInterpreter struct {
evm *EVM
cfg Config
- intPool *intPool
-
hasher keccakState // Keccak256 hasher instance shared across opcodes
hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes
@@ -94,35 +90,36 @@ type EVMInterpreter struct {
// NewEVMInterpreter returns a new instance of the Interpreter.
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
- // We use the STOP instruction whether to see
- // the jump table was initialised. If it was not
- // we'll set the default jump table.
- if !cfg.JumpTable[STOP].valid {
- var jt JumpTable
+ // If jump table was not initialised we set the default one.
+ if cfg.JumpTable == nil {
switch {
case evm.chainRules.IsIstanbul:
- jt = istanbulInstructionSet
+ cfg.JumpTable = &istanbulInstructionSet
case evm.chainRules.IsConstantinople:
- jt = constantinopleInstructionSet
+ cfg.JumpTable = &constantinopleInstructionSet
case evm.chainRules.IsByzantium:
- jt = byzantiumInstructionSet
+ cfg.JumpTable = &byzantiumInstructionSet
case evm.chainRules.IsEIP158:
- jt = spuriousDragonInstructionSet
+ cfg.JumpTable = &spuriousDragonInstructionSet
case evm.chainRules.IsEIP150:
- jt = tangerineWhistleInstructionSet
+ cfg.JumpTable = &tangerineWhistleInstructionSet
case evm.chainRules.IsHomestead:
- jt = homesteadInstructionSet
+ cfg.JumpTable = &homesteadInstructionSet
default:
- jt = frontierInstructionSet
+ cfg.JumpTable = &frontierInstructionSet
}
- for i, eip := range cfg.ExtraEips {
- if err := EnableEIP(eip, &jt); err != nil {
+ var extraEips []int
+ for _, eip := range cfg.ExtraEips {
+ copy := *cfg.JumpTable
+ if err := EnableEIP(eip, ©); err != nil {
// Disable it, so caller can check if it's activated or not
- cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...)
log.Error("EIP activation failed", "eip", eip, "error", err)
+ } else {
+ extraEips = append(extraEips, eip)
}
+ cfg.JumpTable = ©
}
- cfg.JumpTable = jt
+ cfg.ExtraEips = extraEips
}
return &EVMInterpreter{
@@ -138,20 +135,13 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// considered a revert-and-consume-all-gas operation except for
// ErrExecutionReverted which means revert-and-keep-gas-left.
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
- if in.intPool == nil {
- in.intPool = poolOfIntPools.get()
- defer func() {
- poolOfIntPools.put(in.intPool)
- in.intPool = nil
- }()
- }
// Increment the call depth which is restricted to 1024
in.evm.depth++
defer func() { in.evm.depth-- }()
// Make sure the readOnly is only set if we aren't in readOnly yet.
- // This makes also sure that the readOnly flag isn't removed for child calls.
+ // This also makes sure that the readOnly flag isn't removed for child calls.
if readOnly && !in.readOnly {
in.readOnly = true
defer func() { in.readOnly = false }()
@@ -188,9 +178,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
)
contract.Input = input
- // Reclaim the stack as an int pool when the execution stops
- defer func() { in.intPool.put(stack.data...) }()
-
if in.cfg.Debug {
defer func() {
if err != nil {
@@ -206,12 +193,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
// the execution of one of the operations or until the done flag is set by the
// parent context.
- steps := 0
for {
- steps++
- if steps%1000 == 0 && atomic.LoadInt32(&in.evm.abort) != 0 {
- break
- }
if in.cfg.Debug {
// Capture pre-execution values for tracing.
logged, pcCopy, gasCopy = false, pc, contract.Gas
@@ -221,26 +203,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// enough stack items available to perform the operation.
op = contract.GetOp(pc)
operation := in.cfg.JumpTable[op]
- if !operation.valid {
- return nil, &ErrInvalidOpCode{opcode: op}
- }
// Validate stack
if sLen := stack.len(); sLen < operation.minStack {
return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
} else if sLen > operation.maxStack {
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
}
- // If the operation is valid, enforce and write restrictions
- if in.readOnly && in.evm.chainRules.IsByzantium {
- // If the interpreter is operating in readonly mode, make sure no
- // state-modifying operation is performed. The 3rd stack item
- // for a call operation is the value. Transferring value from one
- // account to the others means the state is modified and should also
- // return with an error.
- if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) {
- return nil, ErrWriteProtection
- }
- }
// Static portion of gas
cost = operation.constantGas // For tracing
if !contract.UseGas(operation.constantGas) {
@@ -285,29 +253,17 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// execute the operation
res, err = operation.execute(&pc, in, callContext)
- // verifyPool is a build flag. Pool verification makes sure the integrity
- // of the integer pool by comparing values to a default value.
- if verifyPool {
- verifyIntegerPool(in.intPool)
- }
- // if the operation clears the return data (e.g. it has returning data)
- // set the last return to the result of the operation.
- if operation.returns {
- in.returnData = res
- }
- switch {
- case err != nil:
- return nil, err
- case operation.reverts:
- log.Debug("ErrExecutionReverted", "pc", pc, "reverts", operation.reverts, "err", err)
- return res, ErrExecutionReverted
- case operation.halts:
- return res, nil
- case !operation.jumps:
- pc++
+ if err != nil {
+ break
}
+ pc++
}
- return nil, nil
+
+ if err == errStopToken {
+ err = nil // clear stop token error
+ }
+
+ return res, err
}
// CanRun tells if the contract, passed as an argument, can be
diff --git a/core/vm/intpool.go b/core/vm/intpool.go
deleted file mode 100644
index eed074b07338..000000000000
--- a/core/vm/intpool.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2017 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package vm
-
-import (
- "math/big"
- "sync"
-)
-
-var checkVal = big.NewInt(-42)
-
-const poolLimit = 256
-
-// intPool is a pool of big integers that
-// can be reused for all big.Int operations.
-type intPool struct {
- pool *Stack
-}
-
-func newIntPool() *intPool {
- return &intPool{pool: newstack()}
-}
-
-// get retrieves a big int from the pool, allocating one if the pool is empty.
-// Note, the returned int's value is arbitrary and will not be zeroed!
-func (p *intPool) get() *big.Int {
- if p.pool.len() > 0 {
- return p.pool.pop()
- }
- return new(big.Int)
-}
-
-// getZero retrieves a big int from the pool, setting it to zero or allocating
-// a new one if the pool is empty.
-func (p *intPool) getZero() *big.Int {
- if p.pool.len() > 0 {
- return p.pool.pop().SetUint64(0)
- }
- return new(big.Int)
-}
-
-// putOne returns an allocated big int to the pool to be later reused by get calls.
-// Note, the values as saved as is; neither put nor get zeroes the ints out!
-// As opposed to 'put' with variadic args, this method becomes inlined by the
-// go compiler
-func (p *intPool) putOne(i *big.Int) {
- if len(p.pool.data) > poolLimit {
- return
- }
- p.pool.push(i)
-}
-
-// put returns an allocated big int to the pool to be later reused by get calls.
-// Note, the values as saved as is; neither put nor get zeroes the ints out!
-func (p *intPool) put(is ...*big.Int) {
- if len(p.pool.data) > poolLimit {
- return
- }
- for _, i := range is {
- // verifyPool is a build flag. Pool verification makes sure the integrity
- // of the integer pool by comparing values to a default value.
- if verifyPool {
- i.Set(checkVal)
- }
- p.pool.push(i)
- }
-}
-
-// The intPool pool's default capacity
-const poolDefaultCap = 25
-
-// intPoolPool manages a pool of intPools.
-type intPoolPool struct {
- pools []*intPool
- lock sync.Mutex
-}
-
-var poolOfIntPools = &intPoolPool{
- pools: make([]*intPool, 0, poolDefaultCap),
-}
-
-// get is looking for an available pool to return.
-func (ipp *intPoolPool) get() *intPool {
- ipp.lock.Lock()
- defer ipp.lock.Unlock()
-
- if len(poolOfIntPools.pools) > 0 {
- ip := ipp.pools[len(ipp.pools)-1]
- ipp.pools = ipp.pools[:len(ipp.pools)-1]
- return ip
- }
- return newIntPool()
-}
-
-// put a pool that has been allocated with get.
-func (ipp *intPoolPool) put(ip *intPool) {
- ipp.lock.Lock()
- defer ipp.lock.Unlock()
-
- if len(ipp.pools) < cap(ipp.pools) {
- ipp.pools = append(ipp.pools, ip)
- }
-}
diff --git a/core/vm/intpool_test.go b/core/vm/intpool_test.go
deleted file mode 100644
index 6c0d00f3ce5c..000000000000
--- a/core/vm/intpool_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package vm
-
-import (
- "testing"
-)
-
-func TestIntPoolPoolGet(t *testing.T) {
- poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
-
- nip := poolOfIntPools.get()
- if nip == nil {
- t.Fatalf("Invalid pool allocation")
- }
-}
-
-func TestIntPoolPoolPut(t *testing.T) {
- poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
-
- nip := poolOfIntPools.get()
- if len(poolOfIntPools.pools) != 0 {
- t.Fatalf("Pool got added to list when none should have been")
- }
-
- poolOfIntPools.put(nip)
- if len(poolOfIntPools.pools) == 0 {
- t.Fatalf("Pool did not get added to list when one should have been")
- }
-}
-
-func TestIntPoolPoolReUse(t *testing.T) {
- poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
- nip := poolOfIntPools.get()
- poolOfIntPools.put(nip)
- poolOfIntPools.get()
-
- if len(poolOfIntPools.pools) != 0 {
- t.Fatalf("Invalid number of pools. Got %d, expected %d", len(poolOfIntPools.pools), 0)
- }
-}
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index b3a0f7ff7ce9..55ad78adc53f 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -40,13 +40,6 @@ type operation struct {
// memorySize returns the memory size required for the operation
memorySize memorySizeFunc
-
- halts bool // indicates whether the operation should halt further execution
- jumps bool // indicates whether the program counter should not increment
- writes bool // determines whether this a state modifying operation
- valid bool // indication whether the retrieved operation is valid and known
- reverts bool // determines whether the operation reverts state (implicitly halts)
- returns bool // determines whether the operations sets the return data content
}
var (
@@ -60,7 +53,7 @@ var (
)
// JumpTable contains the EVM opcodes supported at a given fork.
-type JumpTable [256]operation
+type JumpTable [256]*operation
// newIstanbulInstructionSet returns the frontier, homestead
// byzantium, contantinople and petersburg instructions.
@@ -78,44 +71,37 @@ func newIstanbulInstructionSet() JumpTable {
// byzantium and contantinople instructions.
func newConstantinopleInstructionSet() JumpTable {
instructionSet := newByzantiumInstructionSet()
- instructionSet[SHL] = operation{
+ instructionSet[SHL] = &operation{
execute: opSHL,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
}
- instructionSet[SHR] = operation{
+ instructionSet[SHR] = &operation{
execute: opSHR,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
}
- instructionSet[SAR] = operation{
+ instructionSet[SAR] = &operation{
execute: opSAR,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
}
- instructionSet[EXTCODEHASH] = operation{
+ instructionSet[EXTCODEHASH] = &operation{
execute: opExtCodeHash,
constantGas: params.ExtcodeHashGasConstantinople,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
}
- instructionSet[CREATE2] = operation{
+ instructionSet[CREATE2] = &operation{
execute: opCreate2,
constantGas: params.Create2Gas,
dynamicGas: gasCreate2,
minStack: minStack(4, 1),
maxStack: maxStack(4, 1),
memorySize: memoryCreate2,
- valid: true,
- writes: true,
- returns: true,
}
return instructionSet
}
@@ -124,41 +110,34 @@ func newConstantinopleInstructionSet() JumpTable {
// byzantium instructions.
func newByzantiumInstructionSet() JumpTable {
instructionSet := newSpuriousDragonInstructionSet()
- instructionSet[STATICCALL] = operation{
+ instructionSet[STATICCALL] = &operation{
execute: opStaticCall,
constantGas: params.CallGasEIP150,
dynamicGas: gasStaticCall,
minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryStaticCall,
- valid: true,
- returns: true,
}
- instructionSet[RETURNDATASIZE] = operation{
+ instructionSet[RETURNDATASIZE] = &operation{
execute: opReturnDataSize,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
}
- instructionSet[RETURNDATACOPY] = operation{
+ instructionSet[RETURNDATACOPY] = &operation{
execute: opReturnDataCopy,
constantGas: GasFastestStep,
dynamicGas: gasReturnDataCopy,
minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryReturnDataCopy,
- valid: true,
}
- instructionSet[REVERT] = operation{
+ instructionSet[REVERT] = &operation{
execute: opRevert,
dynamicGas: gasRevert,
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryRevert,
- valid: true,
- reverts: true,
- returns: true,
}
return instructionSet
}
@@ -188,15 +167,13 @@ func newTangerineWhistleInstructionSet() JumpTable {
// instructions that can be executed during the homestead phase.
func newHomesteadInstructionSet() JumpTable {
instructionSet := newFrontierInstructionSet()
- instructionSet[DELEGATECALL] = operation{
+ instructionSet[DELEGATECALL] = &operation{
execute: opDelegateCall,
dynamicGas: gasDelegateCall,
constantGas: params.CallGasFrontier,
minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryDelegateCall,
- valid: true,
- returns: true,
}
return instructionSet
}
@@ -204,226 +181,194 @@ func newHomesteadInstructionSet() JumpTable {
// newFrontierInstructionSet returns the frontier instructions
// that can be executed during the frontier phase.
func newFrontierInstructionSet() JumpTable {
- return JumpTable{
+ tbl := JumpTable{
STOP: {
execute: opStop,
constantGas: 0,
minStack: minStack(0, 0),
maxStack: maxStack(0, 0),
- halts: true,
- valid: true,
},
ADD: {
execute: opAdd,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
MUL: {
execute: opMul,
constantGas: GasFastStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
SUB: {
execute: opSub,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
DIV: {
execute: opDiv,
constantGas: GasFastStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
SDIV: {
execute: opSdiv,
constantGas: GasFastStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
MOD: {
execute: opMod,
constantGas: GasFastStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
SMOD: {
execute: opSmod,
constantGas: GasFastStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
ADDMOD: {
execute: opAddmod,
constantGas: GasMidStep,
minStack: minStack(3, 1),
maxStack: maxStack(3, 1),
- valid: true,
},
MULMOD: {
execute: opMulmod,
constantGas: GasMidStep,
minStack: minStack(3, 1),
maxStack: maxStack(3, 1),
- valid: true,
},
EXP: {
execute: opExp,
dynamicGas: gasExpFrontier,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
SIGNEXTEND: {
execute: opSignExtend,
constantGas: GasFastStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
LT: {
execute: opLt,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
GT: {
execute: opGt,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
SLT: {
execute: opSlt,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
SGT: {
execute: opSgt,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
EQ: {
execute: opEq,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
ISZERO: {
execute: opIszero,
constantGas: GasFastestStep,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
},
AND: {
execute: opAnd,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
XOR: {
execute: opXor,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
OR: {
execute: opOr,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
NOT: {
execute: opNot,
constantGas: GasFastestStep,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
},
BYTE: {
execute: opByte,
constantGas: GasFastestStep,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- valid: true,
},
- SHA3: {
- execute: opSha3,
- constantGas: params.Sha3Gas,
- dynamicGas: gasSha3,
+ KECCAK256: {
+ execute: opKeccak256,
+ constantGas: params.Keccak256Gas,
+ dynamicGas: gasKeccak256,
minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
- memorySize: memorySha3,
- valid: true,
+ memorySize: memoryKeccak256,
},
ADDRESS: {
execute: opAddress,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
BALANCE: {
execute: opBalance,
constantGas: params.BalanceGasFrontier,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
},
ORIGIN: {
execute: opOrigin,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
CALLER: {
execute: opCaller,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
CALLVALUE: {
execute: opCallValue,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
CALLDATALOAD: {
execute: opCallDataLoad,
constantGas: GasFastestStep,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
},
CALLDATASIZE: {
execute: opCallDataSize,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
CALLDATACOPY: {
execute: opCallDataCopy,
@@ -432,14 +377,12 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryCallDataCopy,
- valid: true,
},
CODESIZE: {
execute: opCodeSize,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
CODECOPY: {
execute: opCodeCopy,
@@ -448,21 +391,18 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryCodeCopy,
- valid: true,
},
GASPRICE: {
execute: opGasprice,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
EXTCODESIZE: {
execute: opExtCodeSize,
constantGas: params.ExtcodeSizeGasFrontier,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
},
EXTCODECOPY: {
execute: opExtCodeCopy,
@@ -471,56 +411,48 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(4, 0),
maxStack: maxStack(4, 0),
memorySize: memoryExtCodeCopy,
- valid: true,
},
BLOCKHASH: {
execute: opBlockhash,
constantGas: GasExtStep,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
},
COINBASE: {
execute: opCoinbase,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
TIMESTAMP: {
execute: opTimestamp,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
NUMBER: {
execute: opNumber,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
DIFFICULTY: {
execute: opDifficulty,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
GASLIMIT: {
execute: opGasLimit,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
POP: {
execute: opPop,
constantGas: GasQuickStep,
minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
- valid: true,
},
MLOAD: {
execute: opMload,
@@ -529,7 +461,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
memorySize: memoryMLoad,
- valid: true,
},
MSTORE: {
execute: opMstore,
@@ -538,7 +469,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryMStore,
- valid: true,
},
MSTORE8: {
execute: opMstore8,
@@ -547,515 +477,438 @@ func newFrontierInstructionSet() JumpTable {
memorySize: memoryMStore8,
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
-
- valid: true,
},
SLOAD: {
execute: opSload,
constantGas: params.SloadGasFrontier,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
- valid: true,
},
SSTORE: {
execute: opSstore,
dynamicGas: gasSStore,
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
- valid: true,
- writes: true,
},
JUMP: {
execute: opJump,
constantGas: GasMidStep,
minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
- jumps: true,
- valid: true,
},
JUMPI: {
execute: opJumpi,
constantGas: GasSlowStep,
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
- jumps: true,
- valid: true,
},
PC: {
execute: opPc,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
MSIZE: {
execute: opMsize,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
GAS: {
execute: opGas,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
JUMPDEST: {
execute: opJumpdest,
constantGas: params.JumpdestGas,
minStack: minStack(0, 0),
maxStack: maxStack(0, 0),
- valid: true,
},
PUSH1: {
execute: opPush1,
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH2: {
execute: makePush(2, 2),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH3: {
execute: makePush(3, 3),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH4: {
execute: makePush(4, 4),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH5: {
execute: makePush(5, 5),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH6: {
execute: makePush(6, 6),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH7: {
execute: makePush(7, 7),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH8: {
execute: makePush(8, 8),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH9: {
execute: makePush(9, 9),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH10: {
execute: makePush(10, 10),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH11: {
execute: makePush(11, 11),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH12: {
execute: makePush(12, 12),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH13: {
execute: makePush(13, 13),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH14: {
execute: makePush(14, 14),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH15: {
execute: makePush(15, 15),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH16: {
execute: makePush(16, 16),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH17: {
execute: makePush(17, 17),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH18: {
execute: makePush(18, 18),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH19: {
execute: makePush(19, 19),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH20: {
execute: makePush(20, 20),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH21: {
execute: makePush(21, 21),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH22: {
execute: makePush(22, 22),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH23: {
execute: makePush(23, 23),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH24: {
execute: makePush(24, 24),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH25: {
execute: makePush(25, 25),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH26: {
execute: makePush(26, 26),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH27: {
execute: makePush(27, 27),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH28: {
execute: makePush(28, 28),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH29: {
execute: makePush(29, 29),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH30: {
execute: makePush(30, 30),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH31: {
execute: makePush(31, 31),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
PUSH32: {
execute: makePush(32, 32),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
},
DUP1: {
execute: makeDup(1),
constantGas: GasFastestStep,
minStack: minDupStack(1),
maxStack: maxDupStack(1),
- valid: true,
},
DUP2: {
execute: makeDup(2),
constantGas: GasFastestStep,
minStack: minDupStack(2),
maxStack: maxDupStack(2),
- valid: true,
},
DUP3: {
execute: makeDup(3),
constantGas: GasFastestStep,
minStack: minDupStack(3),
maxStack: maxDupStack(3),
- valid: true,
},
DUP4: {
execute: makeDup(4),
constantGas: GasFastestStep,
minStack: minDupStack(4),
maxStack: maxDupStack(4),
- valid: true,
},
DUP5: {
execute: makeDup(5),
constantGas: GasFastestStep,
minStack: minDupStack(5),
maxStack: maxDupStack(5),
- valid: true,
},
DUP6: {
execute: makeDup(6),
constantGas: GasFastestStep,
minStack: minDupStack(6),
maxStack: maxDupStack(6),
- valid: true,
},
DUP7: {
execute: makeDup(7),
constantGas: GasFastestStep,
minStack: minDupStack(7),
maxStack: maxDupStack(7),
- valid: true,
},
DUP8: {
execute: makeDup(8),
constantGas: GasFastestStep,
minStack: minDupStack(8),
maxStack: maxDupStack(8),
- valid: true,
},
DUP9: {
execute: makeDup(9),
constantGas: GasFastestStep,
minStack: minDupStack(9),
maxStack: maxDupStack(9),
- valid: true,
},
DUP10: {
execute: makeDup(10),
constantGas: GasFastestStep,
minStack: minDupStack(10),
maxStack: maxDupStack(10),
- valid: true,
},
DUP11: {
execute: makeDup(11),
constantGas: GasFastestStep,
minStack: minDupStack(11),
maxStack: maxDupStack(11),
- valid: true,
},
DUP12: {
execute: makeDup(12),
constantGas: GasFastestStep,
minStack: minDupStack(12),
maxStack: maxDupStack(12),
- valid: true,
},
DUP13: {
execute: makeDup(13),
constantGas: GasFastestStep,
minStack: minDupStack(13),
maxStack: maxDupStack(13),
- valid: true,
},
DUP14: {
execute: makeDup(14),
constantGas: GasFastestStep,
minStack: minDupStack(14),
maxStack: maxDupStack(14),
- valid: true,
},
DUP15: {
execute: makeDup(15),
constantGas: GasFastestStep,
minStack: minDupStack(15),
maxStack: maxDupStack(15),
- valid: true,
},
DUP16: {
execute: makeDup(16),
constantGas: GasFastestStep,
minStack: minDupStack(16),
maxStack: maxDupStack(16),
- valid: true,
},
SWAP1: {
execute: makeSwap(1),
constantGas: GasFastestStep,
minStack: minSwapStack(2),
maxStack: maxSwapStack(2),
- valid: true,
},
SWAP2: {
execute: makeSwap(2),
constantGas: GasFastestStep,
minStack: minSwapStack(3),
maxStack: maxSwapStack(3),
- valid: true,
},
SWAP3: {
execute: makeSwap(3),
constantGas: GasFastestStep,
minStack: minSwapStack(4),
maxStack: maxSwapStack(4),
- valid: true,
},
SWAP4: {
execute: makeSwap(4),
constantGas: GasFastestStep,
minStack: minSwapStack(5),
maxStack: maxSwapStack(5),
- valid: true,
},
SWAP5: {
execute: makeSwap(5),
constantGas: GasFastestStep,
minStack: minSwapStack(6),
maxStack: maxSwapStack(6),
- valid: true,
},
SWAP6: {
execute: makeSwap(6),
constantGas: GasFastestStep,
minStack: minSwapStack(7),
maxStack: maxSwapStack(7),
- valid: true,
},
SWAP7: {
execute: makeSwap(7),
constantGas: GasFastestStep,
minStack: minSwapStack(8),
maxStack: maxSwapStack(8),
- valid: true,
},
SWAP8: {
execute: makeSwap(8),
constantGas: GasFastestStep,
minStack: minSwapStack(9),
maxStack: maxSwapStack(9),
- valid: true,
},
SWAP9: {
execute: makeSwap(9),
constantGas: GasFastestStep,
minStack: minSwapStack(10),
maxStack: maxSwapStack(10),
- valid: true,
},
SWAP10: {
execute: makeSwap(10),
constantGas: GasFastestStep,
minStack: minSwapStack(11),
maxStack: maxSwapStack(11),
- valid: true,
},
SWAP11: {
execute: makeSwap(11),
constantGas: GasFastestStep,
minStack: minSwapStack(12),
maxStack: maxSwapStack(12),
- valid: true,
},
SWAP12: {
execute: makeSwap(12),
constantGas: GasFastestStep,
minStack: minSwapStack(13),
maxStack: maxSwapStack(13),
- valid: true,
},
SWAP13: {
execute: makeSwap(13),
constantGas: GasFastestStep,
minStack: minSwapStack(14),
maxStack: maxSwapStack(14),
- valid: true,
},
SWAP14: {
execute: makeSwap(14),
constantGas: GasFastestStep,
minStack: minSwapStack(15),
maxStack: maxSwapStack(15),
- valid: true,
},
SWAP15: {
execute: makeSwap(15),
constantGas: GasFastestStep,
minStack: minSwapStack(16),
maxStack: maxSwapStack(16),
- valid: true,
},
SWAP16: {
execute: makeSwap(16),
constantGas: GasFastestStep,
minStack: minSwapStack(17),
maxStack: maxSwapStack(17),
- valid: true,
},
LOG0: {
execute: makeLog(0),
@@ -1063,8 +916,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryLog,
- valid: true,
- writes: true,
},
LOG1: {
execute: makeLog(1),
@@ -1072,8 +923,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryLog,
- valid: true,
- writes: true,
},
LOG2: {
execute: makeLog(2),
@@ -1081,8 +930,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(4, 0),
maxStack: maxStack(4, 0),
memorySize: memoryLog,
- valid: true,
- writes: true,
},
LOG3: {
execute: makeLog(3),
@@ -1090,8 +937,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(5, 0),
maxStack: maxStack(5, 0),
memorySize: memoryLog,
- valid: true,
- writes: true,
},
LOG4: {
execute: makeLog(4),
@@ -1099,8 +944,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(6, 0),
maxStack: maxStack(6, 0),
memorySize: memoryLog,
- valid: true,
- writes: true,
},
CREATE: {
execute: opCreate,
@@ -1109,9 +952,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(3, 1),
maxStack: maxStack(3, 1),
memorySize: memoryCreate,
- valid: true,
- writes: true,
- returns: true,
},
CALL: {
execute: opCall,
@@ -1120,8 +960,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall,
- valid: true,
- returns: true,
},
CALLCODE: {
execute: opCallCode,
@@ -1130,8 +968,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall,
- valid: true,
- returns: true,
},
RETURN: {
execute: opReturn,
@@ -1139,17 +975,21 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryReturn,
- halts: true,
- valid: true,
},
SELFDESTRUCT: {
- execute: opSuicide,
+ execute: opSelfdestruct,
dynamicGas: gasSelfdestruct,
minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
- halts: true,
- valid: true,
- writes: true,
},
}
+
+ // Fill all unassigned slots with opUndefined.
+ for i, entry := range tbl {
+ if entry == nil {
+ tbl[i] = &operation{execute: opUndefined, maxStack: maxStack(0, 0)}
+ }
+ }
+
+ return tbl
}
diff --git a/core/vm/logger.go b/core/vm/logger.go
index 970ff90fb36e..6cdb7a7c5bed 100644
--- a/core/vm/logger.go
+++ b/core/vm/logger.go
@@ -156,8 +156,8 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
// it in the local storage container.
if op == SSTORE && stack.len() >= 2 {
var (
- value = common.BigToHash(stack.data[stack.len()-2])
- address = common.BigToHash(stack.data[stack.len()-1])
+ value = common.Hash(stack.data[stack.len()-2].Bytes32())
+ address = common.Hash(stack.data[stack.len()-1].Bytes32())
)
l.changedValues[contract.Address()][address] = value
}
@@ -172,7 +172,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
if !l.cfg.DisableStack {
stck = make([]*big.Int, len(stack.Data()))
for i, item := range stack.Data() {
- stck[i] = new(big.Int).Set(item)
+ stck[i] = new(big.Int).Set(item.ToBig())
}
}
// Copy a snapshot of the current storage to a new container
diff --git a/core/vm/logger_json.go b/core/vm/logger_json.go
index 2eeba8dfacc3..4a63120a3df4 100644
--- a/core/vm/logger_json.go
+++ b/core/vm/logger_json.go
@@ -62,14 +62,19 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
log.Memory = memory.Data()
}
if !l.cfg.DisableStack {
- log.Stack = stack.Data()
+ //TODO(@holiman) improve this
+ logstack := make([]*big.Int, len(stack.Data()))
+ for i, item := range stack.Data() {
+ logstack[i] = item.ToBig()
+ }
+ log.Stack = logstack
}
return l.encoder.Encode(log)
}
// CaptureFault outputs state information on the logger.
func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
- return nil
+ return l.CaptureState(env, pc, op, gas, cost, memory, stack, contract, depth, err)
}
// CaptureEnd is triggered at end of execution.
@@ -80,8 +85,9 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration,
Time time.Duration `json:"time"`
Err string `json:"error,omitempty"`
}
+ var errMsg string
if err != nil {
- return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()})
+ errMsg = err.Error()
}
- return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""})
+ return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, errMsg})
}
diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go
index e3e0a085b998..f6c15d9cbb0f 100644
--- a/core/vm/logger_test.go
+++ b/core/vm/logger_test.go
@@ -20,17 +20,16 @@ import (
"math/big"
"testing"
- "github.com/XinFinOrg/XDPoSChain/params"
-
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/state"
+ "github.com/XinFinOrg/XDPoSChain/params"
+ "github.com/holiman/uint256"
)
type dummyContractRef struct {
calledForEach bool
}
-func (dummyContractRef) ReturnGas(*big.Int) {}
func (dummyContractRef) Address() common.Address { return common.Address{} }
func (dummyContractRef) Value() *big.Int { return new(big.Int) }
func (dummyContractRef) SetCode(common.Hash, []byte) {}
@@ -57,8 +56,8 @@ func TestStoreCapture(t *testing.T) {
stack = newstack()
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
)
- stack.push(big.NewInt(1))
- stack.push(big.NewInt(0))
+ stack.push(uint256.NewInt(1))
+ stack.push(new(uint256.Int))
var index common.Hash
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil)
if len(logger.changedValues[contract.Address()]) == 0 {
diff --git a/core/vm/memory.go b/core/vm/memory.go
index 7fc44a096188..35b729996075 100644
--- a/core/vm/memory.go
+++ b/core/vm/memory.go
@@ -17,10 +17,7 @@
package vm
import (
- "fmt"
- "math/big"
-
- "github.com/XinFinOrg/XDPoSChain/common/math"
+ "github.com/holiman/uint256"
)
// Memory implements a simple memory model for the ethereum virtual machine.
@@ -50,16 +47,15 @@ func (m *Memory) Set(offset, size uint64, value []byte) {
// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to
// 32 bytes.
-func (m *Memory) Set32(offset uint64, val *big.Int) {
+func (m *Memory) Set32(offset uint64, val *uint256.Int) {
// length of store may never be less than offset + size.
// The store should be resized PRIOR to setting the memory
if offset+32 > uint64(len(m.store)) {
panic("invalid memory: store empty")
}
- // Zero the memory area
- copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
// Fill in relevant bits
- math.ReadBits(val, m.store[offset:offset+32])
+ b32 := val.Bytes32()
+ copy(m.store[offset:], b32[:])
}
// Resize resizes the memory to size
@@ -69,7 +65,7 @@ func (m *Memory) Resize(size uint64) {
}
}
-// Get returns offset + size as a new slice
+// GetCopy returns offset + size as a new slice
func (m *Memory) GetCopy(offset, size int64) (cpy []byte) {
if size == 0 {
return nil
@@ -107,18 +103,3 @@ func (m *Memory) Len() int {
func (m *Memory) Data() []byte {
return m.store
}
-
-// Print dumps the content of the memory.
-func (m *Memory) Print() {
- fmt.Printf("### mem %d bytes ###\n", len(m.store))
- if len(m.store) > 0 {
- addr := 0
- for i := 0; i+32 <= len(m.store); i += 32 {
- fmt.Printf("%03d: % x\n", addr, m.store[i:i+32])
- addr++
- }
- } else {
- fmt.Println("-- empty --")
- }
- fmt.Println("####################")
-}
diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go
index 4fcb41442c4e..e35ca84e0efa 100644
--- a/core/vm/memory_table.go
+++ b/core/vm/memory_table.go
@@ -16,7 +16,7 @@
package vm
-func memorySha3(stack *Stack) (uint64, bool) {
+func memoryKeccak256(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(1))
}
diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go
index 322e01d17c99..b9001138b05a 100644
--- a/core/vm/opcodes.go
+++ b/core/vm/opcodes.go
@@ -32,75 +32,73 @@ func (op OpCode) IsPush() bool {
return false
}
-// IsStaticJump specifies if an opcode is JUMP.
-func (op OpCode) IsStaticJump() bool {
- return op == JUMP
-}
-
// 0x0 range - arithmetic ops.
const (
- STOP OpCode = iota
- ADD
- MUL
- SUB
- DIV
- SDIV
- MOD
- SMOD
- ADDMOD
- MULMOD
- EXP
- SIGNEXTEND
+ STOP OpCode = 0x0
+ ADD OpCode = 0x1
+ MUL OpCode = 0x2
+ SUB OpCode = 0x3
+ DIV OpCode = 0x4
+ SDIV OpCode = 0x5
+ MOD OpCode = 0x6
+ SMOD OpCode = 0x7
+ ADDMOD OpCode = 0x8
+ MULMOD OpCode = 0x9
+ EXP OpCode = 0xa
+ SIGNEXTEND OpCode = 0xb
)
// 0x10 range - comparison ops.
const (
- LT OpCode = iota + 0x10
- GT
- SLT
- SGT
- EQ
- ISZERO
- AND
- OR
- XOR
- NOT
- BYTE
- SHL
- SHR
- SAR
+ LT OpCode = 0x10
+ GT OpCode = 0x11
+ SLT OpCode = 0x12
+ SGT OpCode = 0x13
+ EQ OpCode = 0x14
+ ISZERO OpCode = 0x15
+ AND OpCode = 0x16
+ OR OpCode = 0x17
+ XOR OpCode = 0x18
+ NOT OpCode = 0x19
+ BYTE OpCode = 0x1a
+ SHL OpCode = 0x1b
+ SHR OpCode = 0x1c
+ SAR OpCode = 0x1d
+)
- SHA3 OpCode = 0x20
+// 0x20 range - crypto.
+const (
+ KECCAK256 OpCode = 0x20
)
// 0x30 range - closure state.
const (
- ADDRESS OpCode = 0x30 + iota
- BALANCE
- ORIGIN
- CALLER
- CALLVALUE
- CALLDATALOAD
- CALLDATASIZE
- CALLDATACOPY
- CODESIZE
- CODECOPY
- GASPRICE
- EXTCODESIZE
- EXTCODECOPY
- RETURNDATASIZE
- RETURNDATACOPY
- EXTCODEHASH
+ ADDRESS OpCode = 0x30
+ BALANCE OpCode = 0x31
+ ORIGIN OpCode = 0x32
+ CALLER OpCode = 0x33
+ CALLVALUE OpCode = 0x34
+ CALLDATALOAD OpCode = 0x35
+ CALLDATASIZE OpCode = 0x36
+ CALLDATACOPY OpCode = 0x37
+ CODESIZE OpCode = 0x38
+ CODECOPY OpCode = 0x39
+ GASPRICE OpCode = 0x3a
+ EXTCODESIZE OpCode = 0x3b
+ EXTCODECOPY OpCode = 0x3c
+ RETURNDATASIZE OpCode = 0x3d
+ RETURNDATACOPY OpCode = 0x3e
+ EXTCODEHASH OpCode = 0x3f
)
// 0x40 range - block operations.
const (
- BLOCKHASH OpCode = 0x40 + iota
- COINBASE
- TIMESTAMP
- NUMBER
- DIFFICULTY
- GASLIMIT
+ BLOCKHASH OpCode = 0x40
+ COINBASE OpCode = 0x41
+ TIMESTAMP OpCode = 0x42
+ NUMBER OpCode = 0x43
+ DIFFICULTY OpCode = 0x44
+ GASLIMIT OpCode = 0x45
CHAINID OpCode = 0x46
SELFBALANCE OpCode = 0x47
)
@@ -121,7 +119,7 @@ const (
JUMPDEST
)
-// 0x60 range.
+// 0x60 range - pushes.
const (
PUSH1 OpCode = 0x60 + iota
PUSH2
@@ -155,7 +153,11 @@ const (
PUSH30
PUSH31
PUSH32
- DUP1
+)
+
+// 0x80 range - dups.
+const (
+ DUP1 = 0x80 + iota
DUP2
DUP3
DUP4
@@ -171,7 +173,11 @@ const (
DUP14
DUP15
DUP16
- SWAP1
+)
+
+// 0x90 range - swaps.
+const (
+ SWAP1 = 0x90 + iota
SWAP2
SWAP3
SWAP4
@@ -198,28 +204,22 @@ const (
LOG4
)
-// unofficial opcodes used for parsing.
-const (
- PUSH OpCode = 0xb0 + iota
- DUP
- SWAP
-)
-
// 0xf0 range - closures.
const (
- CREATE OpCode = 0xf0 + iota
- CALL
- CALLCODE
- RETURN
- DELEGATECALL
- CREATE2
+ CREATE OpCode = 0xf0
+ CALL OpCode = 0xf1
+ CALLCODE OpCode = 0xf2
+ RETURN OpCode = 0xf3
+ DELEGATECALL OpCode = 0xf4
+ CREATE2 OpCode = 0xf5
+
STATICCALL OpCode = 0xfa
REVERT OpCode = 0xfd
+ INVALID OpCode = 0xfe
SELFDESTRUCT OpCode = 0xff
)
-// Since the opcodes aren't all in order we can't use a regular slice.
-var opCodeToString = map[OpCode]string{
+var opCodeToString = [256]string{
// 0x0 range - arithmetic ops.
STOP: "STOP",
ADD: "ADD",
@@ -251,7 +251,7 @@ var opCodeToString = map[OpCode]string{
MULMOD: "MULMOD",
// 0x20 range - crypto.
- SHA3: "SHA3",
+ KECCAK256: "KECCAK256",
// 0x30 range - closure state.
ADDRESS: "ADDRESS",
@@ -379,20 +379,16 @@ var opCodeToString = map[OpCode]string{
CREATE2: "CREATE2",
STATICCALL: "STATICCALL",
REVERT: "REVERT",
+ INVALID: "INVALID",
SELFDESTRUCT: "SELFDESTRUCT",
-
- PUSH: "PUSH",
- DUP: "DUP",
- SWAP: "SWAP",
}
func (op OpCode) String() string {
- str := opCodeToString[op]
- if len(str) == 0 {
- return fmt.Sprintf("opcode 0x%x not defined", int(op))
+ if s := opCodeToString[op]; s != "" {
+ return s
}
- return str
+ return fmt.Sprintf("opcode %#x not defined", int(op))
}
var stringToOp = map[string]OpCode{
@@ -422,7 +418,7 @@ var stringToOp = map[string]OpCode{
"SAR": SAR,
"ADDMOD": ADDMOD,
"MULMOD": MULMOD,
- "SHA3": SHA3,
+ "KECCAK256": KECCAK256,
"ADDRESS": ADDRESS,
"BALANCE": BALANCE,
"ORIGIN": ORIGIN,
@@ -536,6 +532,7 @@ var stringToOp = map[string]OpCode{
"RETURN": RETURN,
"CALLCODE": CALLCODE,
"REVERT": REVERT,
+ "INVALID": INVALID,
"SELFDESTRUCT": SELFDESTRUCT,
}
diff --git a/core/vm/stack.go b/core/vm/stack.go
index c9c3d07f4b6f..a389c04b725d 100644
--- a/core/vm/stack.go
+++ b/core/vm/stack.go
@@ -17,37 +17,31 @@
package vm
import (
- "fmt"
- "math/big"
+ "github.com/holiman/uint256"
)
// Stack is an object for basic stack operations. Items popped to the stack are
// expected to be changed and modified. stack does not take care of adding newly
// initialised objects.
type Stack struct {
- data []*big.Int
+ data []uint256.Int
}
func newstack() *Stack {
- return &Stack{data: make([]*big.Int, 0, 1024)}
+ return &Stack{data: make([]uint256.Int, 0, 16)}
}
-// Data returns the underlying big.Int array.
-func (st *Stack) Data() []*big.Int {
+// Data returns the underlying uint256.Int array.
+func (st *Stack) Data() []uint256.Int {
return st.data
}
-func (st *Stack) push(d *big.Int) {
+func (st *Stack) push(d *uint256.Int) {
// NOTE push limit (1024) is checked in baseCheck
- //stackItem := new(big.Int).Set(d)
- //st.data = append(st.data, stackItem)
- st.data = append(st.data, d)
-}
-func (st *Stack) pushN(ds ...*big.Int) {
- st.data = append(st.data, ds...)
+ st.data = append(st.data, *d)
}
-func (st *Stack) pop() (ret *big.Int) {
+func (st *Stack) pop() (ret uint256.Int) {
ret = st.data[len(st.data)-1]
st.data = st.data[:len(st.data)-1]
return
@@ -61,28 +55,15 @@ func (st *Stack) swap(n int) {
st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
}
-func (st *Stack) dup(pool *intPool, n int) {
- st.push(pool.get().Set(st.data[st.len()-n]))
+func (st *Stack) dup(n int) {
+ st.push(&st.data[st.len()-n])
}
-func (st *Stack) peek() *big.Int {
- return st.data[st.len()-1]
+func (st *Stack) peek() *uint256.Int {
+ return &st.data[st.len()-1]
}
// Back returns the n'th item in stack
-func (st *Stack) Back(n int) *big.Int {
- return st.data[st.len()-n-1]
-}
-
-// Print dumps the content of the stack
-func (st *Stack) Print() {
- fmt.Println("### stack ###")
- if len(st.data) > 0 {
- for i, val := range st.data {
- fmt.Printf("%-3d %v\n", i, val)
- }
- } else {
- fmt.Println("-- empty --")
- }
- fmt.Println("#############")
+func (st *Stack) Back(n int) *uint256.Int {
+ return &st.data[st.len()-n-1]
}
diff --git a/eth/tracers/testdata/call_tracer_inner_throw_outer_revert.json b/eth/tracers/testdata/call_tracer_inner_throw_outer_revert.json
index 7627c8c23d68..ec2ceb426fda 100644
--- a/eth/tracers/testdata/call_tracer_inner_throw_outer_revert.json
+++ b/eth/tracers/testdata/call_tracer_inner_throw_outer_revert.json
@@ -59,7 +59,7 @@
"result": {
"calls": [
{
- "error": "invalid opcode: opcode 0xfe not defined",
+ "error": "invalid opcode: INVALID",
"from": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76",
"gas": "0x75fe3",
"gasUsed": "0x75fe3",
diff --git a/eth/tracers/tracer.go b/eth/tracers/tracer.go
index 94c828fc900e..235f752bac0a 100644
--- a/eth/tracers/tracer.go
+++ b/eth/tracers/tracer.go
@@ -162,7 +162,7 @@ func (sw *stackWrapper) peek(idx int) *big.Int {
log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx)
return new(big.Int)
}
- return sw.stack.Data()[len(sw.stack.Data())-idx-1]
+ return sw.stack.Back(idx).ToBig()
}
// pushObject assembles a JSVM object wrapping a swappable stack and pushes it
diff --git a/eth/tracers/tracer_test.go b/eth/tracers/tracer_test.go
index a7266c178880..577fd1e576c3 100644
--- a/eth/tracers/tracer_test.go
+++ b/eth/tracers/tracer_test.go
@@ -40,7 +40,6 @@ func (account) SetBalance(*big.Int) {}
func (account) SetNonce(uint64) {}
func (account) Balance() *big.Int { return nil }
func (account) Address() common.Address { return common.Address{} }
-func (account) ReturnGas(*big.Int) {}
func (account) SetCode(common.Hash, []byte) {}
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
diff --git a/go.mod b/go.mod
index e2065745fde8..8d19bc4956fc 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,7 @@ require (
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/gorilla/websocket v1.4.2
github.com/hashicorp/golang-lru v0.5.3
+ github.com/holiman/uint256 v1.2.4
github.com/huin/goupnp v1.3.0
github.com/influxdata/influxdb v1.7.9
github.com/jackpal/go-nat-pmp v1.0.2
@@ -61,7 +62,6 @@ require (
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/google/uuid v1.3.0 // indirect
- github.com/holiman/uint256 v1.2.3 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/maruel/panicparse v0.0.0-20160720141634-ad661195ed0e // indirect
diff --git a/go.sum b/go.sum
index 70a3ac6c9348..19df00ede131 100644
--- a/go.sum
+++ b/go.sum
@@ -140,6 +140,8 @@ github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
+github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
+github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
diff --git a/params/protocol_params.go b/params/protocol_params.go
index f7ab3cdd1046..f15530649750 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -41,8 +41,8 @@ const (
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
CallStipend uint64 = 2300 // Free gas given at beginning of call.
- Sha3Gas uint64 = 30 // Once per SHA3 operation.
- Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data.
+ Keccak256Gas uint64 = 30 // Once per KECCAK256 operation.
+ Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data.
SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero.
SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change.
SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero.
@@ -98,14 +98,10 @@ const (
NetSstoreResetRefund uint64 = 4800 // Once per SSTORE operation for resetting to the original non-zero value
NetSstoreResetClearRefund uint64 = 19800 // Once per SSTORE operation for resetting to the original zero value
- SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed
- SstoreNoopGasEIP2200 uint64 = 800 // Once per SSTORE operation if the value doesn't change.
- SstoreDirtyGasEIP2200 uint64 = 800 // Once per SSTORE operation if a dirty value is changed.
- SstoreInitGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
- SstoreInitRefundEIP2200 uint64 = 19200 // Once per SSTORE operation for resetting to the original zero value
- SstoreCleanGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
- SstoreCleanRefundEIP2200 uint64 = 4200 // Once per SSTORE operation for resetting to the original non-zero value
- SstoreClearRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
+ SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed
+ SstoreSetGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
+ SstoreResetGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
+ SstoreClearsScheduleRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
Create2Gas uint64 = 32000 // Once per CREATE2 operation
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index 509022bf5149..bd516a182721 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -20,13 +20,13 @@ import (
"bytes"
"encoding/json"
"fmt"
- "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core"
+ "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/crypto"
@@ -143,7 +143,6 @@ func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM {
Difficulty: t.json.Env.Difficulty,
GasPrice: t.json.Exec.GasPrice,
}
- vmconfig.NoRecursion = true
return vm.NewEVM(context, statedb, nil, params.MainnetChainConfig, vmconfig)
}