Revert "params: core, core/vm, miner: 64bit gas instructions (#3514)"
This reverts commit 8b57c49490
.
This commit is contained in:
@ -21,11 +21,28 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// Type is the VM type accepted by **NewVm**
|
||||
type Type byte
|
||||
|
||||
const (
|
||||
StdVmTy Type = iota // Default standard VM
|
||||
JitVmTy // LLVM JIT VM
|
||||
MaxVmTy
|
||||
)
|
||||
|
||||
var (
|
||||
Pow256 = common.BigPow(2, 256) // Pow256 is 2**256
|
||||
|
||||
U256 = common.U256 // Shortcut to common.U256
|
||||
S256 = common.S256 // Shortcut to common.S256
|
||||
|
||||
Zero = common.Big0 // Shortcut to common.Big0
|
||||
One = common.Big1 // Shortcut to common.Big1
|
||||
|
||||
max = big.NewInt(math.MaxInt64) // Maximum 64 bit integer
|
||||
)
|
||||
|
||||
// calculates the memory size required for a step
|
||||
@ -37,6 +54,48 @@ func calcMemSize(off, l *big.Int) *big.Int {
|
||||
return new(big.Int).Add(off, l)
|
||||
}
|
||||
|
||||
// calculates the quadratic gas
|
||||
func quadMemGas(mem *Memory, newMemSize, gas *big.Int) {
|
||||
if newMemSize.Cmp(common.Big0) > 0 {
|
||||
newMemSizeWords := toWordSize(newMemSize)
|
||||
newMemSize.Mul(newMemSizeWords, u256(32))
|
||||
|
||||
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
|
||||
// be careful reusing variables here when changing.
|
||||
// The order has been optimised to reduce allocation
|
||||
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
|
||||
pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
|
||||
linCoef := oldSize.Mul(oldSize, params.MemoryGas)
|
||||
quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
|
||||
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
|
||||
|
||||
pow.Exp(newMemSizeWords, common.Big2, Zero)
|
||||
linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
|
||||
quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
|
||||
newTotalFee := linCoef.Add(linCoef, quadCoef)
|
||||
|
||||
fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
|
||||
gas.Add(gas, fee)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple helper
|
||||
func u256(n int64) *big.Int {
|
||||
return big.NewInt(n)
|
||||
}
|
||||
|
||||
// Mainly used for print variables and passing to Print*
|
||||
func toValue(val *big.Int) interface{} {
|
||||
// Let's assume a string on right padded zero's
|
||||
b := val.Bytes()
|
||||
if b[0] != 0 && b[len(b)-1] == 0x0 && b[len(b)-2] == 0x0 {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// getData 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 getData(data []byte, start, size *big.Int) []byte {
|
||||
@ -47,17 +106,14 @@ func getData(data []byte, start, size *big.Int) []byte {
|
||||
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.BitLen() > 64
|
||||
}
|
||||
|
||||
// toWordSize returns the ceiled word size required for memory expansion.
|
||||
func toWordSize(size uint64) uint64 {
|
||||
if size > math.MaxUint64-31 {
|
||||
return math.MaxUint64/32 + 1
|
||||
// useGas attempts to subtract the amount of gas and returns whether it was
|
||||
// successful
|
||||
func useGas(gas, amount *big.Int) bool {
|
||||
if gas.Cmp(amount) < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return (size + 31) / 32
|
||||
// Sub the amount of gas from the remaining
|
||||
gas.Sub(gas, amount)
|
||||
return true
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
|
||||
// ContractRef is a reference to the contract's backing object
|
||||
type ContractRef interface {
|
||||
ReturnGas(*big.Int)
|
||||
Address() common.Address
|
||||
Value() *big.Int
|
||||
SetCode(common.Hash, []byte)
|
||||
@ -47,8 +48,7 @@ type Contract struct {
|
||||
CodeAddr *common.Address
|
||||
Input []byte
|
||||
|
||||
Gas uint64
|
||||
value *big.Int
|
||||
value, Gas, UsedGas *big.Int
|
||||
|
||||
Args []byte
|
||||
|
||||
@ -56,7 +56,7 @@ type Contract struct {
|
||||
}
|
||||
|
||||
// NewContract returns a new contract environment for the execution of EVM.
|
||||
func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
|
||||
func NewContract(caller ContractRef, object ContractRef, value, gas *big.Int) *Contract {
|
||||
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
|
||||
|
||||
if parent, ok := caller.(*Contract); ok {
|
||||
@ -68,8 +68,9 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
|
||||
|
||||
// Gas should be a pointer so it can safely be reduced through the run
|
||||
// This pointer will be off the state transition
|
||||
c.Gas = gas
|
||||
c.Gas = gas //new(big.Int).Set(gas)
|
||||
c.value = new(big.Int).Set(value)
|
||||
c.UsedGas = new(big.Int)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -106,13 +107,27 @@ func (c *Contract) Caller() common.Address {
|
||||
return c.CallerAddress
|
||||
}
|
||||
|
||||
// Finalise finalises the contract and returning any remaining gas to the original
|
||||
// caller.
|
||||
func (c *Contract) Finalise() {
|
||||
// Return the remaining gas to the caller
|
||||
c.caller.ReturnGas(c.Gas)
|
||||
}
|
||||
|
||||
// UseGas attempts the use gas and subtracts it and returns true on success
|
||||
func (c *Contract) UseGas(gas uint64) (ok bool) {
|
||||
if c.Gas < gas {
|
||||
return false
|
||||
func (c *Contract) UseGas(gas *big.Int) (ok bool) {
|
||||
ok = useGas(c.Gas, gas)
|
||||
if ok {
|
||||
c.UsedGas.Add(c.UsedGas, gas)
|
||||
}
|
||||
c.Gas -= gas
|
||||
return true
|
||||
return
|
||||
}
|
||||
|
||||
// ReturnGas adds the given gas back to itself.
|
||||
func (c *Contract) ReturnGas(gas *big.Int) {
|
||||
// Return the gas to the context
|
||||
c.Gas.Add(c.Gas, gas)
|
||||
c.UsedGas.Sub(c.UsedGas, gas)
|
||||
}
|
||||
|
||||
// Address returns the contracts address
|
||||
|
@ -17,6 +17,8 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
@ -28,8 +30,8 @@ import (
|
||||
// requires a deterministic gas count based on the input size of the Run method of the
|
||||
// contract.
|
||||
type PrecompiledContract interface {
|
||||
RequiredGas(inputSize int) uint64 // RequiredPrice calculates the contract gas use
|
||||
Run(input []byte) []byte // Run runs the precompiled contract
|
||||
RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
|
||||
Run(input []byte) []byte // Run runs the precompiled contract
|
||||
}
|
||||
|
||||
// Precompiled contains the default set of ethereum contracts
|
||||
@ -55,7 +57,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr
|
||||
// ECRECOVER implemented as a native contract
|
||||
type ecrecover struct{}
|
||||
|
||||
func (c *ecrecover) RequiredGas(inputSize int) uint64 {
|
||||
func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
|
||||
return params.EcrecoverGas
|
||||
}
|
||||
|
||||
@ -90,12 +92,10 @@ func (c *ecrecover) Run(in []byte) []byte {
|
||||
// SHA256 implemented as a native contract
|
||||
type sha256 struct{}
|
||||
|
||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||
//
|
||||
// This method does not require any overflow checking as the input size gas costs
|
||||
// required for anything significant is so high it's impossible to pay for.
|
||||
func (c *sha256) RequiredGas(inputSize int) uint64 {
|
||||
return uint64(inputSize+31)/32*params.Sha256WordGas + params.Sha256Gas
|
||||
func (c *sha256) RequiredGas(inputSize int) *big.Int {
|
||||
n := big.NewInt(int64(inputSize+31) / 32)
|
||||
n.Mul(n, params.Sha256WordGas)
|
||||
return n.Add(n, params.Sha256Gas)
|
||||
}
|
||||
func (c *sha256) Run(in []byte) []byte {
|
||||
return crypto.Sha256(in)
|
||||
@ -104,12 +104,10 @@ func (c *sha256) Run(in []byte) []byte {
|
||||
// RIPMED160 implemented as a native contract
|
||||
type ripemd160 struct{}
|
||||
|
||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||
//
|
||||
// This method does not require any overflow checking as the input size gas costs
|
||||
// required for anything significant is so high it's impossible to pay for.
|
||||
func (c *ripemd160) RequiredGas(inputSize int) uint64 {
|
||||
return uint64(inputSize+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas
|
||||
func (c *ripemd160) RequiredGas(inputSize int) *big.Int {
|
||||
n := big.NewInt(int64(inputSize+31) / 32)
|
||||
n.Mul(n, params.Ripemd160WordGas)
|
||||
return n.Add(n, params.Ripemd160Gas)
|
||||
}
|
||||
func (c *ripemd160) Run(in []byte) []byte {
|
||||
return common.LeftPadBytes(crypto.Ripemd160(in), 32)
|
||||
@ -118,12 +116,11 @@ func (c *ripemd160) Run(in []byte) []byte {
|
||||
// data copy implemented as a native contract
|
||||
type dataCopy struct{}
|
||||
|
||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||
//
|
||||
// This method does not require any overflow checking as the input size gas costs
|
||||
// required for anything significant is so high it's impossible to pay for.
|
||||
func (c *dataCopy) RequiredGas(inputSize int) uint64 {
|
||||
return uint64(inputSize+31)/32*params.IdentityWordGas + params.IdentityGas
|
||||
func (c *dataCopy) RequiredGas(inputSize int) *big.Int {
|
||||
n := big.NewInt(int64(inputSize+31) / 32)
|
||||
n.Mul(n, params.IdentityWordGas)
|
||||
|
||||
return n.Add(n, params.IdentityGas)
|
||||
}
|
||||
func (c *dataCopy) Run(in []byte) []byte {
|
||||
return in
|
||||
|
@ -17,6 +17,7 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
|
||||
@ -101,18 +102,24 @@ func (evm *EVM) Cancel() {
|
||||
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
|
||||
// necessary value transfer required and takes 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) {
|
||||
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
|
||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||
return nil, gas, nil
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, ErrDepth
|
||||
}
|
||||
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
return nil, gas, ErrInsufficientBalance
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, ErrInsufficientBalance
|
||||
}
|
||||
|
||||
var (
|
||||
@ -121,7 +128,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
)
|
||||
if !evm.StateDB.Exist(addr) {
|
||||
if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.BitLen() == 0 {
|
||||
return nil, gas, nil
|
||||
caller.ReturnGas(gas)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
to = evm.StateDB.CreateAccount(addr)
|
||||
@ -135,6 +143,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
// only.
|
||||
contract := NewContract(caller, to, value, gas)
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
defer contract.Finalise()
|
||||
|
||||
ret, err = evm.interpreter.Run(contract, input)
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
@ -145,7 +154,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
}
|
||||
return ret, contract.Gas, err
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
|
||||
@ -153,18 +162,24 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
// case of an execution error or failed value transfer.
|
||||
//
|
||||
// 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) {
|
||||
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
|
||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||
return nil, gas, nil
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, ErrDepth
|
||||
}
|
||||
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
return nil, gas, ErrInsufficientBalance
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", value, evm.StateDB.GetBalance(caller.Address()))
|
||||
}
|
||||
|
||||
var (
|
||||
@ -176,6 +191,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||
// only.
|
||||
contract := NewContract(caller, to, value, gas)
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
defer contract.Finalise()
|
||||
|
||||
ret, err = evm.interpreter.Run(contract, input)
|
||||
if err != nil {
|
||||
@ -184,7 +200,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
}
|
||||
|
||||
return ret, contract.Gas, err
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// DelegateCall executes the contract associated with the addr with the given input as parameters.
|
||||
@ -192,15 +208,18 @@ 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) {
|
||||
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas *big.Int) (ret []byte, err error) {
|
||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||
return nil, gas, nil
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||
caller.ReturnGas(gas)
|
||||
return nil, ErrDepth
|
||||
}
|
||||
|
||||
var (
|
||||
@ -211,6 +230,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||
// Iinitialise a new contract and make initialise the delegate values
|
||||
contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
defer contract.Finalise()
|
||||
|
||||
ret, err = evm.interpreter.Run(contract, input)
|
||||
if err != nil {
|
||||
@ -219,22 +239,28 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
}
|
||||
|
||||
return ret, contract.Gas, err
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (ret []byte, contractAddr common.Address, err error) {
|
||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||
return nil, common.Address{}, gas, nil
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, common.Address{}, nil
|
||||
}
|
||||
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, common.Address{}, gas, ErrDepth
|
||||
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, common.Address{}, ErrDepth
|
||||
}
|
||||
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
return nil, common.Address{}, gas, ErrInsufficientBalance
|
||||
caller.ReturnGas(gas)
|
||||
|
||||
return nil, common.Address{}, ErrInsufficientBalance
|
||||
}
|
||||
|
||||
// Create a new account on the state
|
||||
@ -254,6 +280,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
// only.
|
||||
contract := NewContract(caller, to, value, gas)
|
||||
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
||||
defer contract.Finalise()
|
||||
|
||||
ret, err = evm.interpreter.Run(contract, nil)
|
||||
|
||||
@ -264,8 +291,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
// 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 {
|
||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||
if contract.UseGas(createDataGas) {
|
||||
dataGas := big.NewInt(int64(len(ret)))
|
||||
dataGas.Mul(dataGas, params.CreateDataGas)
|
||||
if contract.UseGas(dataGas) {
|
||||
evm.StateDB.SetCode(contractAddr, ret)
|
||||
} else {
|
||||
err = ErrCodeStoreOutOfGas
|
||||
@ -277,10 +305,11 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
// when we're in homestead this also counts for code storage gas errors.
|
||||
if maxCodeSizeExceeded ||
|
||||
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
|
||||
contract.UseGas(contract.Gas)
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
|
||||
// Nothing should be returned when an error is thrown.
|
||||
return nil, contractAddr, 0, err
|
||||
return nil, contractAddr, err
|
||||
}
|
||||
// If the vm returned with an error the return value should be set to nil.
|
||||
// This isn't consensus critical but merely to for behaviour reasons such as
|
||||
@ -289,7 +318,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
ret = nil
|
||||
}
|
||||
|
||||
return ret, contractAddr, contract.Gas, err
|
||||
return ret, contractAddr, err
|
||||
}
|
||||
|
||||
// ChainConfig returns the evmironment's chain configuration
|
151
core/vm/gas.go
151
core/vm/gas.go
@ -17,42 +17,149 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
const (
|
||||
GasQuickStep uint64 = 2
|
||||
GasFastestStep uint64 = 3
|
||||
GasFastStep uint64 = 5
|
||||
GasMidStep uint64 = 8
|
||||
GasSlowStep uint64 = 10
|
||||
GasExtStep uint64 = 20
|
||||
var (
|
||||
GasQuickStep = big.NewInt(2)
|
||||
GasFastestStep = big.NewInt(3)
|
||||
GasFastStep = big.NewInt(5)
|
||||
GasMidStep = big.NewInt(8)
|
||||
GasSlowStep = big.NewInt(10)
|
||||
GasExtStep = big.NewInt(20)
|
||||
|
||||
GasReturn uint64 = 0
|
||||
GasStop uint64 = 0
|
||||
GasContractByte uint64 = 200
|
||||
GasReturn = big.NewInt(0)
|
||||
GasStop = big.NewInt(0)
|
||||
|
||||
GasContractByte = big.NewInt(200)
|
||||
|
||||
n64 = big.NewInt(64)
|
||||
)
|
||||
|
||||
// calcGas returns the actual gas cost of the call.
|
||||
//
|
||||
// The cost of gas was changed during the homestead price change HF. To allow for EIP150
|
||||
// to be implemented. The returned gas is gas - base * 63 / 64.
|
||||
func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) {
|
||||
if gasTable.CreateBySuicide > 0 {
|
||||
availableGas = availableGas - base
|
||||
gas := availableGas - availableGas/64
|
||||
// If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150
|
||||
// is smaller than the requested amount. Therefor we return the new gas instead
|
||||
// of returning an error.
|
||||
if callCost.BitLen() > 64 || gas < callCost.Uint64() {
|
||||
return gas, nil
|
||||
func callGas(gasTable params.GasTable, availableGas, base, callCost *big.Int) *big.Int {
|
||||
if gasTable.CreateBySuicide != nil {
|
||||
availableGas = new(big.Int).Sub(availableGas, base)
|
||||
g := new(big.Int).Div(availableGas, n64)
|
||||
g.Sub(availableGas, g)
|
||||
|
||||
if g.Cmp(callCost) < 0 {
|
||||
return g
|
||||
}
|
||||
}
|
||||
if callCost.BitLen() > 64 {
|
||||
return 0, errGasUintOverflow
|
||||
return callCost
|
||||
}
|
||||
|
||||
// baseCheck checks for any stack error underflows
|
||||
func baseCheck(op OpCode, stack *Stack, gas *big.Int) error {
|
||||
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
|
||||
// PUSH is also allowed to calculate the same price for all PUSHes
|
||||
// DUP requirements are handled elsewhere (except for the stack limit check)
|
||||
if op >= PUSH1 && op <= PUSH32 {
|
||||
op = PUSH1
|
||||
}
|
||||
if op >= DUP1 && op <= DUP16 {
|
||||
op = DUP1
|
||||
}
|
||||
|
||||
return callCost.Uint64(), nil
|
||||
if r, ok := _baseCheck[op]; ok {
|
||||
err := stack.require(r.stackPop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.stackPush > 0 && stack.len()-r.stackPop+r.stackPush > int(params.StackLimit.Int64()) {
|
||||
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
|
||||
}
|
||||
|
||||
gas.Add(gas, r.gas)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// casts a arbitrary number to the amount of words (sets of 32 bytes)
|
||||
func toWordSize(size *big.Int) *big.Int {
|
||||
tmp := new(big.Int)
|
||||
tmp.Add(size, u256(31))
|
||||
tmp.Div(tmp, u256(32))
|
||||
return tmp
|
||||
}
|
||||
|
||||
type req struct {
|
||||
stackPop int
|
||||
gas *big.Int
|
||||
stackPush int
|
||||
}
|
||||
|
||||
var _baseCheck = map[OpCode]req{
|
||||
// opcode | stack pop | gas price | stack push
|
||||
ADD: {2, GasFastestStep, 1},
|
||||
LT: {2, GasFastestStep, 1},
|
||||
GT: {2, GasFastestStep, 1},
|
||||
SLT: {2, GasFastestStep, 1},
|
||||
SGT: {2, GasFastestStep, 1},
|
||||
EQ: {2, GasFastestStep, 1},
|
||||
ISZERO: {1, GasFastestStep, 1},
|
||||
SUB: {2, GasFastestStep, 1},
|
||||
AND: {2, GasFastestStep, 1},
|
||||
OR: {2, GasFastestStep, 1},
|
||||
XOR: {2, GasFastestStep, 1},
|
||||
NOT: {1, GasFastestStep, 1},
|
||||
BYTE: {2, GasFastestStep, 1},
|
||||
CALLDATALOAD: {1, GasFastestStep, 1},
|
||||
CALLDATACOPY: {3, GasFastestStep, 1},
|
||||
MLOAD: {1, GasFastestStep, 1},
|
||||
MSTORE: {2, GasFastestStep, 0},
|
||||
MSTORE8: {2, GasFastestStep, 0},
|
||||
CODECOPY: {3, GasFastestStep, 0},
|
||||
MUL: {2, GasFastStep, 1},
|
||||
DIV: {2, GasFastStep, 1},
|
||||
SDIV: {2, GasFastStep, 1},
|
||||
MOD: {2, GasFastStep, 1},
|
||||
SMOD: {2, GasFastStep, 1},
|
||||
SIGNEXTEND: {2, GasFastStep, 1},
|
||||
ADDMOD: {3, GasMidStep, 1},
|
||||
MULMOD: {3, GasMidStep, 1},
|
||||
JUMP: {1, GasMidStep, 0},
|
||||
JUMPI: {2, GasSlowStep, 0},
|
||||
EXP: {2, GasSlowStep, 1},
|
||||
ADDRESS: {0, GasQuickStep, 1},
|
||||
ORIGIN: {0, GasQuickStep, 1},
|
||||
CALLER: {0, GasQuickStep, 1},
|
||||
CALLVALUE: {0, GasQuickStep, 1},
|
||||
CODESIZE: {0, GasQuickStep, 1},
|
||||
GASPRICE: {0, GasQuickStep, 1},
|
||||
COINBASE: {0, GasQuickStep, 1},
|
||||
TIMESTAMP: {0, GasQuickStep, 1},
|
||||
NUMBER: {0, GasQuickStep, 1},
|
||||
CALLDATASIZE: {0, GasQuickStep, 1},
|
||||
DIFFICULTY: {0, GasQuickStep, 1},
|
||||
GASLIMIT: {0, GasQuickStep, 1},
|
||||
POP: {1, GasQuickStep, 0},
|
||||
PC: {0, GasQuickStep, 1},
|
||||
MSIZE: {0, GasQuickStep, 1},
|
||||
GAS: {0, GasQuickStep, 1},
|
||||
BLOCKHASH: {1, GasExtStep, 1},
|
||||
BALANCE: {1, Zero, 1},
|
||||
EXTCODESIZE: {1, Zero, 1},
|
||||
EXTCODECOPY: {4, Zero, 0},
|
||||
SLOAD: {1, params.SloadGas, 1},
|
||||
SSTORE: {2, Zero, 0},
|
||||
SHA3: {2, params.Sha3Gas, 1},
|
||||
CREATE: {3, params.CreateGas, 1},
|
||||
// Zero is calculated in the gasSwitch
|
||||
CALL: {7, Zero, 1},
|
||||
CALLCODE: {7, Zero, 1},
|
||||
DELEGATECALL: {6, Zero, 1},
|
||||
SELFDESTRUCT: {1, Zero, 0},
|
||||
JUMPDEST: {0, params.JumpdestGas, 0},
|
||||
RETURN: {2, Zero, 0},
|
||||
PUSH1: {0, GasFastestStep, 1},
|
||||
DUP1: {0, Zero, 1},
|
||||
}
|
||||
|
@ -1,80 +1,56 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
gmath "math"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// memoryGasCosts calculates the quadratic gas for memory expansion. It does so
|
||||
// only for the memory region that is expanded, not the total memory.
|
||||
func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
||||
// The maximum that will fit in a uint64 is max_word_count - 1
|
||||
// anything above that will result in an overflow.
|
||||
if newMemSize > gmath.MaxUint64-32 {
|
||||
return 0, errGasUintOverflow
|
||||
func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int {
|
||||
gas := new(big.Int)
|
||||
if newMemSize.Cmp(common.Big0) > 0 {
|
||||
newMemSizeWords := toWordSize(newMemSize)
|
||||
|
||||
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
|
||||
// be careful reusing variables here when changing.
|
||||
// The order has been optimised to reduce allocation
|
||||
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
|
||||
pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
|
||||
linCoef := oldSize.Mul(oldSize, params.MemoryGas)
|
||||
quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
|
||||
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
|
||||
|
||||
pow.Exp(newMemSizeWords, common.Big2, Zero)
|
||||
linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
|
||||
quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
|
||||
newTotalFee := linCoef.Add(linCoef, quadCoef)
|
||||
|
||||
fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
|
||||
gas.Add(gas, fee)
|
||||
}
|
||||
}
|
||||
|
||||
if newMemSize == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
newMemSizeWords := toWordSize(newMemSize)
|
||||
newMemSize = newMemSizeWords * 32
|
||||
|
||||
if newMemSize > uint64(mem.Len()) {
|
||||
square := newMemSizeWords * newMemSizeWords
|
||||
linCoef := newMemSizeWords * params.MemoryGas
|
||||
quadCoef := square / params.QuadCoeffDiv
|
||||
newTotalFee := linCoef + quadCoef
|
||||
|
||||
fee := newTotalFee - mem.lastGasCost
|
||||
mem.lastGasCost = newTotalFee
|
||||
|
||||
return fee, nil
|
||||
}
|
||||
return 0, nil
|
||||
return gas
|
||||
}
|
||||
|
||||
func constGasFunc(gas uint64) gasFunc {
|
||||
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return gas, nil
|
||||
func constGasFunc(gas *big.Int) gasFunc {
|
||||
return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return gas
|
||||
}
|
||||
}
|
||||
|
||||
func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := memoryGasCost(mem, memorySize)
|
||||
gas.Add(gas, GasFastestStep)
|
||||
words := toWordSize(stack.Back(2))
|
||||
|
||||
var overflow bool
|
||||
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
words, overflow := bigUint64(stack.Back(2))
|
||||
if overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
if gas, overflow = math.SafeAdd(gas, words); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
return gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||
}
|
||||
|
||||
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
var (
|
||||
y, x = stack.Back(1), stack.Back(0)
|
||||
val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
||||
val = env.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
||||
)
|
||||
// This checks for 3 scenario's and calculates gas accordingly
|
||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||
@ -82,335 +58,189 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
|
||||
// 3. From a non-zero to a non-zero (CHANGE)
|
||||
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
|
||||
// 0 => non 0
|
||||
return params.SstoreSetGas, nil
|
||||
return new(big.Int).Set(params.SstoreSetGas)
|
||||
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
|
||||
evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas))
|
||||
env.StateDB.AddRefund(params.SstoreRefundGas)
|
||||
|
||||
return params.SstoreClearGas, nil
|
||||
return new(big.Int).Set(params.SstoreClearGas)
|
||||
} else {
|
||||
// non 0 => non 0 (or 0 => 0)
|
||||
return params.SstoreResetGas, nil
|
||||
return new(big.Int).Set(params.SstoreResetGas)
|
||||
}
|
||||
}
|
||||
|
||||
func makeGasLog(n uint64) gasFunc {
|
||||
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
requestedSize, overflow := bigUint64(stack.Back(1))
|
||||
if overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
func makeGasLog(n uint) gasFunc {
|
||||
return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
mSize := stack.Back(1)
|
||||
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
var memorySizeGas uint64
|
||||
if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas)
|
||||
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
|
||||
gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
|
||||
return gas
|
||||
}
|
||||
}
|
||||
|
||||
func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var overflow bool
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
wordGas, overflow := bigUint64(stack.Back(1))
|
||||
if overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := memoryGasCost(mem, memorySize)
|
||||
gas.Add(gas, params.Sha3Gas)
|
||||
words := toWordSize(stack.Back(1))
|
||||
return gas.Add(gas, words.Mul(words, params.Sha3WordGas))
|
||||
}
|
||||
|
||||
func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := memoryGasCost(mem, memorySize)
|
||||
gas.Add(gas, GasFastestStep)
|
||||
words := toWordSize(stack.Back(2))
|
||||
|
||||
var overflow bool
|
||||
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
wordGas, overflow := bigUint64(stack.Back(2))
|
||||
if overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
return gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||
}
|
||||
|
||||
func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := memoryGasCost(mem, memorySize)
|
||||
gas.Add(gas, gt.ExtcodeCopy)
|
||||
words := toWordSize(stack.Back(3))
|
||||
|
||||
var overflow bool
|
||||
if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
wordGas, overflow := bigUint64(stack.Back(3))
|
||||
if overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
|
||||
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
return gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||
}
|
||||
|
||||
func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var overflow bool
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
|
||||
}
|
||||
|
||||
func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var overflow bool
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
|
||||
}
|
||||
|
||||
func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var overflow bool
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
|
||||
}
|
||||
|
||||
func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var overflow bool
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize))
|
||||
}
|
||||
|
||||
func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return gt.Balance, nil
|
||||
func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return gt.Balance
|
||||
}
|
||||
|
||||
func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return gt.ExtcodeSize, nil
|
||||
func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return gt.ExtcodeSize
|
||||
}
|
||||
|
||||
func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return gt.SLoad, nil
|
||||
func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return gt.SLoad
|
||||
}
|
||||
|
||||
func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
||||
func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
||||
gas := big.NewInt(expByteLen)
|
||||
gas.Mul(gas, gt.ExpByte)
|
||||
return gas.Add(gas, GasSlowStep)
|
||||
}
|
||||
|
||||
func gasCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := new(big.Int).Set(gt.Calls)
|
||||
|
||||
transfersValue := stack.Back(2).BitLen() > 0
|
||||
var (
|
||||
gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
|
||||
overflow bool
|
||||
)
|
||||
if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
|
||||
func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var (
|
||||
gas = gt.Calls
|
||||
transfersValue = stack.Back(2).BitLen() > 0
|
||||
address = common.BigToAddress(stack.Back(1))
|
||||
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
|
||||
address = common.BigToAddress(stack.Back(1))
|
||||
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
|
||||
)
|
||||
if eip158 {
|
||||
if evm.StateDB.Empty(address) && transfersValue {
|
||||
gas += params.CallNewAccountGas
|
||||
if env.StateDB.Empty(address) && transfersValue {
|
||||
gas.Add(gas, params.CallNewAccountGas)
|
||||
}
|
||||
} else if !evm.StateDB.Exist(address) {
|
||||
gas += params.CallNewAccountGas
|
||||
} else if !env.StateDB.Exist(address) {
|
||||
gas.Add(gas, params.CallNewAccountGas)
|
||||
}
|
||||
if transfersValue {
|
||||
gas += params.CallValueTransferGas
|
||||
}
|
||||
memoryGas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var overflow bool
|
||||
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
gas.Add(gas, params.CallValueTransferGas)
|
||||
}
|
||||
gas.Add(gas, memoryGasCost(mem, memorySize))
|
||||
|
||||
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
|
||||
// Replace the stack item with the new gas calculation. This means that
|
||||
// either the original item is left on the stack or the item is replaced by:
|
||||
// (availableGas - gas) * 63 / 64
|
||||
// We replace the stack item so that it's available when the opCall instruction is
|
||||
// called. This information is otherwise lost due to the dependency on *current*
|
||||
// available gas.
|
||||
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
|
||||
stack.data[stack.len()-1] = cg
|
||||
|
||||
if gas, overflow = math.SafeAdd(gas, cg); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
return gas.Add(gas, cg)
|
||||
}
|
||||
|
||||
func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
gas := gt.Calls
|
||||
func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := new(big.Int).Set(gt.Calls)
|
||||
if stack.Back(2).BitLen() > 0 {
|
||||
gas += params.CallValueTransferGas
|
||||
}
|
||||
memoryGas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var overflow bool
|
||||
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
gas.Add(gas, params.CallValueTransferGas)
|
||||
}
|
||||
gas.Add(gas, memoryGasCost(mem, memorySize))
|
||||
|
||||
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
|
||||
// Replace the stack item with the new gas calculation. This means that
|
||||
// either the original item is left on the stack or the item is replaced by:
|
||||
// (availableGas - gas) * 63 / 64
|
||||
// We replace the stack item so that it's available when the opCall instruction is
|
||||
// called. This information is otherwise lost due to the dependency on *current*
|
||||
// available gas.
|
||||
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
|
||||
stack.data[stack.len()-1] = cg
|
||||
|
||||
if gas, overflow = math.SafeAdd(gas, cg); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
return gas.Add(gas, cg)
|
||||
}
|
||||
|
||||
func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
func gasReturn(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return memoryGasCost(mem, memorySize)
|
||||
}
|
||||
|
||||
func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var gas uint64
|
||||
func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := new(big.Int)
|
||||
// EIP150 homestead gas reprice fork:
|
||||
if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
|
||||
gas = gt.Suicide
|
||||
if env.ChainConfig().IsEIP150(env.BlockNumber) {
|
||||
gas.Set(gt.Suicide)
|
||||
var (
|
||||
address = common.BigToAddress(stack.Back(0))
|
||||
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
|
||||
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
|
||||
)
|
||||
|
||||
if eip158 {
|
||||
// if empty and transfers value
|
||||
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).BitLen() > 0 {
|
||||
gas += gt.CreateBySuicide
|
||||
if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 {
|
||||
gas.Add(gas, gt.CreateBySuicide)
|
||||
}
|
||||
} else if !evm.StateDB.Exist(address) {
|
||||
gas += gt.CreateBySuicide
|
||||
} else if !env.StateDB.Exist(address) {
|
||||
gas.Add(gas, gt.CreateBySuicide)
|
||||
}
|
||||
}
|
||||
|
||||
if !evm.StateDB.HasSuicided(contract.Address()) {
|
||||
evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas))
|
||||
if !env.StateDB.HasSuicided(contract.Address()) {
|
||||
env.StateDB.AddRefund(params.SuicideRefundGas)
|
||||
}
|
||||
return gas, nil
|
||||
return gas
|
||||
}
|
||||
|
||||
func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var overflow bool
|
||||
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize))
|
||||
|
||||
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
|
||||
// Replace the stack item with the new gas calculation. This means that
|
||||
// either the original item is left on the stack or the item is replaced by:
|
||||
// (availableGas - gas) * 63 / 64
|
||||
// We replace the stack item so that it's available when the opCall instruction is
|
||||
// called.
|
||||
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
|
||||
stack.data[stack.len()-1] = cg
|
||||
|
||||
if gas, overflow = math.SafeAdd(gas, cg); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
return gas.Add(gas, cg)
|
||||
}
|
||||
|
||||
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return GasFastestStep, nil
|
||||
func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return GasFastestStep
|
||||
}
|
||||
|
||||
func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return GasFastestStep, nil
|
||||
func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return GasFastestStep
|
||||
}
|
||||
|
||||
func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return GasFastestStep, nil
|
||||
func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||
return GasFastestStep
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMemoryGasCost(t *testing.T) {
|
||||
size := uint64(math.MaxUint64 - 64)
|
||||
_, err := memoryGasCost(&Memory{}, size)
|
||||
if err != nil {
|
||||
t.Error("didn't expect error:", err)
|
||||
}
|
||||
|
||||
_, err = memoryGasCost(&Memory{}, size+32)
|
||||
if err != nil {
|
||||
t.Error("didn't expect error:", err)
|
||||
}
|
||||
|
||||
_, err = memoryGasCost(&Memory{}, size+33)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
}
|
@ -27,56 +27,42 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var bigZero = new(big.Int)
|
||||
|
||||
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAdd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(U256(x.Add(x, y)))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSub(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(U256(x.Sub(x, y)))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMul(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(U256(x.Mul(x, y)))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opDiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
if y.Cmp(common.Big0) != 0 {
|
||||
stack.push(U256(x.Div(x, y)))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := S256(stack.pop()), S256(stack.pop())
|
||||
if y.Cmp(common.Big0) == 0 {
|
||||
stack.push(new(big.Int))
|
||||
return nil, nil
|
||||
} else {
|
||||
n := new(big.Int)
|
||||
if evm.interpreter.intPool.get().Mul(x, y).Cmp(common.Big0) < 0 {
|
||||
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
|
||||
n.SetInt64(-1)
|
||||
} else {
|
||||
n.SetInt64(1)
|
||||
@ -87,22 +73,20 @@ func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||
|
||||
stack.push(U256(res))
|
||||
}
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
if y.Cmp(common.Big0) == 0 {
|
||||
stack.push(new(big.Int))
|
||||
} else {
|
||||
stack.push(U256(x.Mod(x, y)))
|
||||
}
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := S256(stack.pop()), S256(stack.pop())
|
||||
|
||||
if y.Cmp(common.Big0) == 0 {
|
||||
@ -120,20 +104,16 @@ func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||
|
||||
stack.push(U256(res))
|
||||
}
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opExp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opExp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
base, exponent := stack.pop(), stack.pop()
|
||||
stack.push(math.Exp(base, exponent))
|
||||
|
||||
evm.interpreter.intPool.put(base, exponent)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
back := stack.pop()
|
||||
if back.Cmp(big.NewInt(31)) < 0 {
|
||||
bit := uint(back.Uint64()*8 + 7)
|
||||
@ -148,231 +128,198 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
|
||||
|
||||
stack.push(U256(num))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(back)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opNot(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x := stack.pop()
|
||||
stack.push(U256(x.Not(x)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opLt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
if x.Cmp(y) < 0 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(big.NewInt(1))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opGt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
if x.Cmp(y) > 0 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(big.NewInt(1))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSlt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := S256(stack.pop()), S256(stack.pop())
|
||||
if x.Cmp(S256(y)) < 0 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(big.NewInt(1))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSgt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := S256(stack.pop()), S256(stack.pop())
|
||||
if x.Cmp(y) > 0 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(big.NewInt(1))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opEq(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
if x.Cmp(y) == 0 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(big.NewInt(1))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opIszero(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x := stack.pop()
|
||||
if x.Cmp(common.Big0) > 0 {
|
||||
stack.push(new(big.Int))
|
||||
} else {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(big.NewInt(1))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAnd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(x.And(x, y))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opOr(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(x.Or(x, y))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opXor(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(x.Xor(x, y))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opByte(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
th, val := stack.pop(), stack.pop()
|
||||
if th.Cmp(big.NewInt(32)) < 0 {
|
||||
byte := evm.interpreter.intPool.get().SetInt64(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
||||
byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
||||
stack.push(byte)
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(th, val)
|
||||
return nil, nil
|
||||
}
|
||||
func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAddmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||
if z.Cmp(bigZero) > 0 {
|
||||
if z.Cmp(Zero) > 0 {
|
||||
add := x.Add(x, y)
|
||||
add.Mod(add, z)
|
||||
stack.push(U256(add))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(y, z)
|
||||
return nil, nil
|
||||
}
|
||||
func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMulmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||
if z.Cmp(bigZero) > 0 {
|
||||
if z.Cmp(Zero) > 0 {
|
||||
mul := x.Mul(x, y)
|
||||
mul.Mod(mul, z)
|
||||
stack.push(U256(mul))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(y, z)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSha3(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
offset, size := stack.pop(), stack.pop()
|
||||
data := memory.Get(offset.Int64(), size.Int64())
|
||||
hash := crypto.Keccak256(data)
|
||||
|
||||
if evm.vmConfig.EnablePreimageRecording {
|
||||
evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
|
||||
if env.vmConfig.EnablePreimageRecording {
|
||||
env.StateDB.AddPreimage(common.BytesToHash(hash), data)
|
||||
}
|
||||
|
||||
stack.push(common.BytesToBig(hash))
|
||||
|
||||
evm.interpreter.intPool.put(offset, size)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAddress(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(common.Bytes2Big(contract.Address().Bytes()))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opBalance(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
addr := common.BigToAddress(stack.pop())
|
||||
balance := evm.StateDB.GetBalance(addr)
|
||||
balance := env.StateDB.GetBalance(addr)
|
||||
|
||||
stack.push(new(big.Int).Set(balance))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.Origin.Big())
|
||||
func opOrigin(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(env.Origin.Big())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCaller(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(contract.Caller().Big())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().Set(contract.value))
|
||||
func opCallValue(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(new(big.Int).Set(contract.value))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCalldataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCalldataLoad(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(common.Bytes2Big(getData(contract.Input, stack.pop(), common.Big32)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCalldataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
|
||||
func opCalldataSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(big.NewInt(int64(len(contract.Input))))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCalldataCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
mOff = stack.pop()
|
||||
cOff = stack.pop()
|
||||
l = stack.pop()
|
||||
)
|
||||
memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l))
|
||||
|
||||
evm.interpreter.intPool.put(mOff, cOff, l)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
a := stack.pop()
|
||||
|
||||
addr := common.BigToAddress(a)
|
||||
a.SetInt64(int64(evm.StateDB.GetCodeSize(addr)))
|
||||
stack.push(a)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
|
||||
func opExtCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
addr := common.BigToAddress(stack.pop())
|
||||
l := big.NewInt(int64(env.StateDB.GetCodeSize(addr)))
|
||||
stack.push(l)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
l := big.NewInt(int64(len(contract.Code)))
|
||||
stack.push(l)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
mOff = stack.pop()
|
||||
cOff = stack.pop()
|
||||
@ -381,129 +328,113 @@ func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||
codeCopy := getData(contract.Code, cOff, l)
|
||||
|
||||
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||||
|
||||
evm.interpreter.intPool.put(mOff, cOff, l)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opExtCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
addr = common.BigToAddress(stack.pop())
|
||||
mOff = stack.pop()
|
||||
cOff = stack.pop()
|
||||
l = stack.pop()
|
||||
)
|
||||
codeCopy := getData(evm.StateDB.GetCode(addr), cOff, l)
|
||||
codeCopy := getData(env.StateDB.GetCode(addr), cOff, l)
|
||||
|
||||
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||||
|
||||
evm.interpreter.intPool.put(mOff, cOff, l)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice))
|
||||
func opGasprice(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(new(big.Int).Set(env.GasPrice))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opBlockhash(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
num := stack.pop()
|
||||
|
||||
n := evm.interpreter.intPool.get().Sub(evm.BlockNumber, common.Big257)
|
||||
if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
|
||||
stack.push(evm.GetHash(num.Uint64()).Big())
|
||||
n := new(big.Int).Sub(env.BlockNumber, common.Big257)
|
||||
if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber) < 0 {
|
||||
stack.push(env.GetHash(num.Uint64()).Big())
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(num, n)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.Coinbase.Big())
|
||||
func opCoinbase(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(env.Coinbase.Big())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(evm.Time)))
|
||||
func opTimestamp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(env.Time)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(evm.BlockNumber)))
|
||||
func opNumber(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(env.BlockNumber)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(evm.Difficulty)))
|
||||
func opDifficulty(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(env.Difficulty)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(evm.GasLimit)))
|
||||
func opGasLimit(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(U256(new(big.Int).Set(env.GasLimit)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
evm.interpreter.intPool.put(stack.pop())
|
||||
func opPop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.pop()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
offset := stack.pop()
|
||||
val := common.BigD(memory.Get(offset.Int64(), 32))
|
||||
stack.push(val)
|
||||
|
||||
evm.interpreter.intPool.put(offset)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// pop value of the stack
|
||||
mStart, val := stack.pop(), stack.pop()
|
||||
memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
|
||||
|
||||
evm.interpreter.intPool.put(mStart, val)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMstore8(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
off, val := stack.pop().Int64(), stack.pop().Int64()
|
||||
memory.store[off] = byte(val & 0xff)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
loc := common.BigToHash(stack.pop())
|
||||
val := evm.StateDB.GetState(contract.Address(), loc).Big()
|
||||
val := env.StateDB.GetState(contract.Address(), loc).Big()
|
||||
stack.push(val)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
loc := common.BigToHash(stack.pop())
|
||||
val := stack.pop()
|
||||
evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
|
||||
|
||||
evm.interpreter.intPool.put(val)
|
||||
env.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opJump(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
pos := stack.pop()
|
||||
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
|
||||
nop := contract.GetOp(pos.Uint64())
|
||||
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
|
||||
}
|
||||
*pc = pos.Uint64()
|
||||
|
||||
evm.interpreter.intPool.put(pos)
|
||||
return nil, nil
|
||||
}
|
||||
func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
pos, cond := stack.pop(), stack.pop()
|
||||
if cond.Cmp(common.BigTrue) >= 0 {
|
||||
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
|
||||
@ -514,62 +445,57 @@ func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St
|
||||
} else {
|
||||
*pc++
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(pos, cond)
|
||||
return nil, nil
|
||||
}
|
||||
func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opJumpdest(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(*pc))
|
||||
func opPc(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(new(big.Int).SetUint64(*pc))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len())))
|
||||
func opMsize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(big.NewInt(int64(memory.Len())))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(contract.Gas))
|
||||
func opGas(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(new(big.Int).Set(contract.Gas))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCreate(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
value = stack.pop()
|
||||
offset, size = stack.pop(), stack.pop()
|
||||
input = memory.Get(offset.Int64(), size.Int64())
|
||||
gas = contract.Gas
|
||||
gas = new(big.Int).Set(contract.Gas)
|
||||
)
|
||||
if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
|
||||
gas -= gas / 64
|
||||
if env.ChainConfig().IsEIP150(env.BlockNumber) {
|
||||
gas.Div(gas, n64)
|
||||
gas = gas.Sub(contract.Gas, gas)
|
||||
}
|
||||
|
||||
contract.UseGas(gas)
|
||||
_, addr, returnGas, suberr := evm.Create(contract, input, gas, value)
|
||||
_, addr, suberr := env.Create(contract, input, gas, value)
|
||||
// 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 evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||
if env.ChainConfig().IsHomestead(env.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||
stack.push(new(big.Int))
|
||||
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||
stack.push(new(big.Int))
|
||||
} else {
|
||||
stack.push(addr.Big())
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(value, offset, size)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
gas := stack.pop().Uint64()
|
||||
func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
gas := stack.pop()
|
||||
// pop gas and value of the stack.
|
||||
addr, value := stack.pop(), stack.pop()
|
||||
value = U256(value)
|
||||
@ -583,26 +509,25 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||
// Get the arguments from the memory
|
||||
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
||||
|
||||
if value.BitLen() > 0 {
|
||||
gas += params.CallStipend
|
||||
if len(value.Bytes()) > 0 {
|
||||
gas.Add(gas, params.CallStipend)
|
||||
}
|
||||
|
||||
ret, returnGas, err := evm.Call(contract, address, args, gas, value)
|
||||
ret, err := env.Call(contract, address, args, gas, value)
|
||||
|
||||
if err != nil {
|
||||
stack.push(new(big.Int))
|
||||
|
||||
} else {
|
||||
stack.push(big.NewInt(1))
|
||||
|
||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
gas := stack.pop().Uint64()
|
||||
func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
gas := stack.pop()
|
||||
// pop gas and value of the stack.
|
||||
addr, value := stack.pop(), stack.pop()
|
||||
value = U256(value)
|
||||
@ -616,11 +541,12 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||
// Get the arguments from the memory
|
||||
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
||||
|
||||
if value.BitLen() > 0 {
|
||||
gas += params.CallStipend
|
||||
if len(value.Bytes()) > 0 {
|
||||
gas.Add(gas, params.CallStipend)
|
||||
}
|
||||
|
||||
ret, returnGas, err := evm.CallCode(contract, address, args, gas, value)
|
||||
ret, err := env.CallCode(contract, address, args, gas, value)
|
||||
|
||||
if err != nil {
|
||||
stack.push(new(big.Int))
|
||||
|
||||
@ -629,54 +555,46 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||
|
||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opDelegateCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// if not homestead return an error. DELEGATECALL is not supported
|
||||
// during pre-homestead.
|
||||
if !evm.ChainConfig().IsHomestead(evm.BlockNumber) {
|
||||
if !env.ChainConfig().IsHomestead(env.BlockNumber) {
|
||||
return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL)
|
||||
}
|
||||
|
||||
gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||
gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||
|
||||
toAddr := common.BigToAddress(to)
|
||||
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
||||
|
||||
ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
|
||||
ret, err := env.DelegateCall(contract, toAddr, args, gas)
|
||||
if err != nil {
|
||||
stack.push(new(big.Int))
|
||||
} else {
|
||||
stack.push(big.NewInt(1))
|
||||
memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opReturn(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
offset, size := stack.pop(), stack.pop()
|
||||
ret := memory.GetPtr(offset.Int64(), size.Int64())
|
||||
|
||||
evm.interpreter.intPool.put(offset, size)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opStop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
balance := evm.StateDB.GetBalance(contract.Address())
|
||||
evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
|
||||
func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
balance := env.StateDB.GetBalance(contract.Address())
|
||||
env.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
|
||||
|
||||
evm.StateDB.Suicide(contract.Address())
|
||||
env.StateDB.Suicide(contract.Address())
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
@ -685,7 +603,7 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
|
||||
|
||||
// make log instruction function
|
||||
func makeLog(size int) executionFunc {
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
topics := make([]common.Hash, size)
|
||||
mStart, mSize := stack.pop(), stack.pop()
|
||||
for i := 0; i < size; i++ {
|
||||
@ -693,24 +611,22 @@ func makeLog(size int) executionFunc {
|
||||
}
|
||||
|
||||
d := memory.Get(mStart.Int64(), mSize.Int64())
|
||||
evm.StateDB.AddLog(&types.Log{
|
||||
env.StateDB.AddLog(&types.Log{
|
||||
Address: contract.Address(),
|
||||
Topics: topics,
|
||||
Data: d,
|
||||
// This is a non-consensus field, but assigned here because
|
||||
// core/state doesn't know the current block number.
|
||||
BlockNumber: evm.BlockNumber.Uint64(),
|
||||
BlockNumber: env.BlockNumber.Uint64(),
|
||||
})
|
||||
|
||||
evm.interpreter.intPool.put(mStart, mSize)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// make push instruction function
|
||||
func makePush(size uint64, bsize *big.Int) executionFunc {
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
byts := getData(contract.Code, evm.interpreter.intPool.get().SetUint64(*pc+1), bsize)
|
||||
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
byts := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize)
|
||||
stack.push(common.Bytes2Big(byts))
|
||||
*pc += size
|
||||
return nil, nil
|
||||
@ -719,7 +635,7 @@ func makePush(size uint64, bsize *big.Int) executionFunc {
|
||||
|
||||
// make push instruction function
|
||||
func makeDup(size int64) executionFunc {
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.dup(int(size))
|
||||
return nil, nil
|
||||
}
|
||||
@ -729,7 +645,7 @@ func makeDup(size int64) executionFunc {
|
||||
func makeSwap(size int64) executionFunc {
|
||||
// switch n + 1 otherwise n would be swapped with n
|
||||
size += 1
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.swap(int(size))
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
// +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))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
// +build !VERIFY_EVM_INTEGER_POOL
|
||||
|
||||
package vm
|
||||
|
||||
const verifyPool = false
|
||||
|
||||
func verifyIntegerPool(ip *intPool) {}
|
@ -17,7 +17,6 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
@ -25,13 +24,11 @@ import (
|
||||
|
||||
type (
|
||||
executionFunc func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
|
||||
gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
|
||||
gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, *big.Int) *big.Int
|
||||
stackValidationFunc func(*Stack) error
|
||||
memorySizeFunc func(*Stack) *big.Int
|
||||
)
|
||||
|
||||
var errGasUintOverflow = errors.New("gas uint64 overflow")
|
||||
|
||||
type operation struct {
|
||||
// op is the operation function
|
||||
execute executionFunc
|
||||
@ -55,142 +52,149 @@ var defaultJumpTable = NewJumpTable()
|
||||
|
||||
func NewJumpTable() [256]operation {
|
||||
return [256]operation{
|
||||
STOP: {
|
||||
execute: opStop,
|
||||
gasCost: constGasFunc(new(big.Int)),
|
||||
validateStack: makeStackFunc(0, 0),
|
||||
halts: true,
|
||||
valid: true,
|
||||
},
|
||||
ADD: {
|
||||
execute: opAdd,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
SUB: {
|
||||
execute: opSub,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
MUL: {
|
||||
execute: opMul,
|
||||
gasCost: constGasFunc(GasFastStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
SUB: {
|
||||
execute: opSub,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
DIV: {
|
||||
execute: opDiv,
|
||||
gasCost: constGasFunc(GasFastStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
SDIV: {
|
||||
execute: opSdiv,
|
||||
gasCost: constGasFunc(GasFastStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
MOD: {
|
||||
execute: opMod,
|
||||
gasCost: constGasFunc(GasFastStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
SMOD: {
|
||||
execute: opSmod,
|
||||
gasCost: constGasFunc(GasFastStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
EXP: {
|
||||
execute: opExp,
|
||||
gasCost: gasExp,
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
SIGNEXTEND: {
|
||||
execute: opSignExtend,
|
||||
gasCost: constGasFunc(GasFastStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
NOT: {
|
||||
execute: opNot,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
valid: true,
|
||||
},
|
||||
LT: {
|
||||
execute: opLt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
GT: {
|
||||
execute: opGt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
SLT: {
|
||||
execute: opSlt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
SGT: {
|
||||
execute: opSgt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
EQ: {
|
||||
execute: opEq,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
ISZERO: {
|
||||
execute: opIszero,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
valid: true,
|
||||
},
|
||||
AND: {
|
||||
execute: opAnd,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
OR: {
|
||||
execute: opOr,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
XOR: {
|
||||
execute: opXor,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
BYTE: {
|
||||
execute: opByte,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
ADDMOD: {
|
||||
execute: opAddmod,
|
||||
gasCost: constGasFunc(GasMidStep),
|
||||
validateStack: makeStackFunc(3, 1),
|
||||
validateStack: makeStackFunc(3, -2),
|
||||
valid: true,
|
||||
},
|
||||
MULMOD: {
|
||||
execute: opMulmod,
|
||||
gasCost: constGasFunc(GasMidStep),
|
||||
validateStack: makeStackFunc(3, 1),
|
||||
validateStack: makeStackFunc(3, -2),
|
||||
valid: true,
|
||||
},
|
||||
EXP: {
|
||||
execute: opExp,
|
||||
gasCost: gasExp,
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
SIGNEXTEND: {
|
||||
execute: opSignExtend,
|
||||
gasCost: constGasFunc(GasFastStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
LT: {
|
||||
execute: opLt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
GT: {
|
||||
execute: opGt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
SLT: {
|
||||
execute: opSlt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
SGT: {
|
||||
execute: opSgt,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
EQ: {
|
||||
execute: opEq,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
ISZERO: {
|
||||
execute: opIszero,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
valid: true,
|
||||
},
|
||||
AND: {
|
||||
execute: opAnd,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
XOR: {
|
||||
execute: opXor,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
OR: {
|
||||
execute: opOr,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
NOT: {
|
||||
execute: opNot,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
valid: true,
|
||||
},
|
||||
BYTE: {
|
||||
execute: opByte,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
valid: true,
|
||||
},
|
||||
SHA3: {
|
||||
execute: opSha3,
|
||||
gasCost: gasSha3,
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeStackFunc(2, -1),
|
||||
memorySize: memorySha3,
|
||||
valid: true,
|
||||
},
|
||||
@ -203,7 +207,7 @@ func NewJumpTable() [256]operation {
|
||||
BALANCE: {
|
||||
execute: opBalance,
|
||||
gasCost: gasBalance,
|
||||
validateStack: makeStackFunc(0, 1),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
valid: true,
|
||||
},
|
||||
ORIGIN: {
|
||||
@ -227,7 +231,7 @@ func NewJumpTable() [256]operation {
|
||||
CALLDATALOAD: {
|
||||
execute: opCalldataLoad,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
valid: true,
|
||||
},
|
||||
CALLDATASIZE: {
|
||||
@ -239,7 +243,7 @@ func NewJumpTable() [256]operation {
|
||||
CALLDATACOPY: {
|
||||
execute: opCalldataCopy,
|
||||
gasCost: gasCalldataCopy,
|
||||
validateStack: makeStackFunc(3, 1),
|
||||
validateStack: makeStackFunc(3, -3),
|
||||
memorySize: memoryCalldataCopy,
|
||||
valid: true,
|
||||
},
|
||||
@ -249,36 +253,36 @@ func NewJumpTable() [256]operation {
|
||||
validateStack: makeStackFunc(0, 1),
|
||||
valid: true,
|
||||
},
|
||||
EXTCODESIZE: {
|
||||
execute: opExtCodeSize,
|
||||
gasCost: gasExtCodeSize,
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
valid: true,
|
||||
},
|
||||
CODECOPY: {
|
||||
execute: opCodeCopy,
|
||||
gasCost: gasCodeCopy,
|
||||
validateStack: makeStackFunc(3, 0),
|
||||
validateStack: makeStackFunc(3, -3),
|
||||
memorySize: memoryCodeCopy,
|
||||
valid: true,
|
||||
},
|
||||
EXTCODECOPY: {
|
||||
execute: opExtCodeCopy,
|
||||
gasCost: gasExtCodeCopy,
|
||||
validateStack: makeStackFunc(4, 0),
|
||||
memorySize: memoryExtCodeCopy,
|
||||
valid: true,
|
||||
},
|
||||
GASPRICE: {
|
||||
execute: opGasprice,
|
||||
gasCost: constGasFunc(GasQuickStep),
|
||||
validateStack: makeStackFunc(0, 1),
|
||||
valid: true,
|
||||
},
|
||||
EXTCODESIZE: {
|
||||
execute: opExtCodeSize,
|
||||
gasCost: gasExtCodeSize,
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
valid: true,
|
||||
},
|
||||
EXTCODECOPY: {
|
||||
execute: opExtCodeCopy,
|
||||
gasCost: gasExtCodeCopy,
|
||||
validateStack: makeStackFunc(4, -4),
|
||||
memorySize: memoryExtCodeCopy,
|
||||
valid: true,
|
||||
},
|
||||
BLOCKHASH: {
|
||||
execute: opBlockhash,
|
||||
gasCost: constGasFunc(GasExtStep),
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
valid: true,
|
||||
},
|
||||
COINBASE: {
|
||||
@ -314,20 +318,20 @@ func NewJumpTable() [256]operation {
|
||||
POP: {
|
||||
execute: opPop,
|
||||
gasCost: constGasFunc(GasQuickStep),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
validateStack: makeStackFunc(1, -1),
|
||||
valid: true,
|
||||
},
|
||||
MLOAD: {
|
||||
execute: opMload,
|
||||
gasCost: gasMLoad,
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
memorySize: memoryMLoad,
|
||||
valid: true,
|
||||
},
|
||||
MSTORE: {
|
||||
execute: opMstore,
|
||||
gasCost: gasMStore,
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
validateStack: makeStackFunc(2, -2),
|
||||
memorySize: memoryMStore,
|
||||
valid: true,
|
||||
},
|
||||
@ -335,26 +339,34 @@ func NewJumpTable() [256]operation {
|
||||
execute: opMstore8,
|
||||
gasCost: gasMStore8,
|
||||
memorySize: memoryMStore8,
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
validateStack: makeStackFunc(2, -2),
|
||||
|
||||
valid: true,
|
||||
},
|
||||
SLOAD: {
|
||||
execute: opSload,
|
||||
gasCost: gasSLoad,
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
valid: true,
|
||||
},
|
||||
SSTORE: {
|
||||
execute: opSstore,
|
||||
gasCost: gasSStore,
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
validateStack: makeStackFunc(2, -2),
|
||||
valid: true,
|
||||
},
|
||||
JUMPDEST: {
|
||||
execute: opJumpdest,
|
||||
gasCost: constGasFunc(params.JumpdestGas),
|
||||
validateStack: makeStackFunc(0, 0),
|
||||
JUMP: {
|
||||
execute: opJump,
|
||||
gasCost: constGasFunc(GasMidStep),
|
||||
validateStack: makeStackFunc(1, -1),
|
||||
jumps: true,
|
||||
valid: true,
|
||||
},
|
||||
JUMPI: {
|
||||
execute: opJumpi,
|
||||
gasCost: constGasFunc(GasSlowStep),
|
||||
validateStack: makeStackFunc(2, -2),
|
||||
jumps: true,
|
||||
valid: true,
|
||||
},
|
||||
PC: {
|
||||
@ -375,199 +387,10 @@ func NewJumpTable() [256]operation {
|
||||
validateStack: makeStackFunc(0, 1),
|
||||
valid: true,
|
||||
},
|
||||
CREATE: {
|
||||
execute: opCreate,
|
||||
gasCost: gasCreate,
|
||||
validateStack: makeStackFunc(3, 1),
|
||||
memorySize: memoryCreate,
|
||||
valid: true,
|
||||
},
|
||||
CALL: {
|
||||
execute: opCall,
|
||||
gasCost: gasCall,
|
||||
validateStack: makeStackFunc(7, 1),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
},
|
||||
CALLCODE: {
|
||||
execute: opCallCode,
|
||||
gasCost: gasCallCode,
|
||||
validateStack: makeStackFunc(7, 1),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
},
|
||||
DELEGATECALL: {
|
||||
execute: opDelegateCall,
|
||||
gasCost: gasDelegateCall,
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
memorySize: memoryDelegateCall,
|
||||
valid: true,
|
||||
},
|
||||
RETURN: {
|
||||
execute: opReturn,
|
||||
gasCost: gasReturn,
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
memorySize: memoryReturn,
|
||||
halts: true,
|
||||
valid: true,
|
||||
},
|
||||
SUICIDE: {
|
||||
execute: opSuicide,
|
||||
gasCost: gasSuicide,
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
halts: true,
|
||||
valid: true,
|
||||
},
|
||||
JUMP: {
|
||||
execute: opJump,
|
||||
gasCost: constGasFunc(GasMidStep),
|
||||
validateStack: makeStackFunc(1, 0),
|
||||
jumps: true,
|
||||
valid: true,
|
||||
},
|
||||
JUMPI: {
|
||||
execute: opJumpi,
|
||||
gasCost: constGasFunc(GasSlowStep),
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
jumps: true,
|
||||
valid: true,
|
||||
},
|
||||
STOP: {
|
||||
execute: opStop,
|
||||
gasCost: constGasFunc(0),
|
||||
JUMPDEST: {
|
||||
execute: opJumpdest,
|
||||
gasCost: constGasFunc(params.JumpdestGas),
|
||||
validateStack: makeStackFunc(0, 0),
|
||||
halts: true,
|
||||
valid: true,
|
||||
},
|
||||
LOG0: {
|
||||
execute: makeLog(0),
|
||||
gasCost: makeGasLog(0),
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG1: {
|
||||
execute: makeLog(1),
|
||||
gasCost: makeGasLog(1),
|
||||
validateStack: makeStackFunc(3, 0),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG2: {
|
||||
execute: makeLog(2),
|
||||
gasCost: makeGasLog(2),
|
||||
validateStack: makeStackFunc(4, 0),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG3: {
|
||||
execute: makeLog(3),
|
||||
gasCost: makeGasLog(3),
|
||||
validateStack: makeStackFunc(5, 0),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG4: {
|
||||
execute: makeLog(4),
|
||||
gasCost: makeGasLog(4),
|
||||
validateStack: makeStackFunc(6, 0),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
SWAP1: {
|
||||
execute: makeSwap(1),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP2: {
|
||||
execute: makeSwap(2),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(3, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP3: {
|
||||
execute: makeSwap(3),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(4, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP4: {
|
||||
execute: makeSwap(4),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(5, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP5: {
|
||||
execute: makeSwap(5),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(6, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP6: {
|
||||
execute: makeSwap(6),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(7, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP7: {
|
||||
execute: makeSwap(7),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(8, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP8: {
|
||||
execute: makeSwap(8),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(9, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP9: {
|
||||
execute: makeSwap(9),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(10, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP10: {
|
||||
execute: makeSwap(10),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(11, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP11: {
|
||||
execute: makeSwap(11),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(12, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP12: {
|
||||
execute: makeSwap(12),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(13, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP13: {
|
||||
execute: makeSwap(13),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(14, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP14: {
|
||||
execute: makeSwap(14),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(15, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP15: {
|
||||
execute: makeSwap(15),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(16, 0),
|
||||
valid: true,
|
||||
},
|
||||
SWAP16: {
|
||||
execute: makeSwap(16),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeStackFunc(17, 0),
|
||||
valid: true,
|
||||
},
|
||||
PUSH1: {
|
||||
@ -765,97 +588,271 @@ func NewJumpTable() [256]operation {
|
||||
DUP1: {
|
||||
execute: makeDup(1),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
validateStack: makeDupStackFunc(1),
|
||||
valid: true,
|
||||
},
|
||||
DUP2: {
|
||||
execute: makeDup(2),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
validateStack: makeDupStackFunc(2),
|
||||
valid: true,
|
||||
},
|
||||
DUP3: {
|
||||
execute: makeDup(3),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(3, 1),
|
||||
validateStack: makeDupStackFunc(3),
|
||||
valid: true,
|
||||
},
|
||||
DUP4: {
|
||||
execute: makeDup(4),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(4, 1),
|
||||
validateStack: makeDupStackFunc(4),
|
||||
valid: true,
|
||||
},
|
||||
DUP5: {
|
||||
execute: makeDup(5),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(5, 1),
|
||||
validateStack: makeDupStackFunc(5),
|
||||
valid: true,
|
||||
},
|
||||
DUP6: {
|
||||
execute: makeDup(6),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
validateStack: makeDupStackFunc(6),
|
||||
valid: true,
|
||||
},
|
||||
DUP7: {
|
||||
execute: makeDup(7),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(7, 1),
|
||||
validateStack: makeDupStackFunc(7),
|
||||
valid: true,
|
||||
},
|
||||
DUP8: {
|
||||
execute: makeDup(8),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(8, 1),
|
||||
validateStack: makeDupStackFunc(8),
|
||||
valid: true,
|
||||
},
|
||||
DUP9: {
|
||||
execute: makeDup(9),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(9, 1),
|
||||
validateStack: makeDupStackFunc(9),
|
||||
valid: true,
|
||||
},
|
||||
DUP10: {
|
||||
execute: makeDup(10),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(10, 1),
|
||||
validateStack: makeDupStackFunc(10),
|
||||
valid: true,
|
||||
},
|
||||
DUP11: {
|
||||
execute: makeDup(11),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(11, 1),
|
||||
validateStack: makeDupStackFunc(11),
|
||||
valid: true,
|
||||
},
|
||||
DUP12: {
|
||||
execute: makeDup(12),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(12, 1),
|
||||
validateStack: makeDupStackFunc(12),
|
||||
valid: true,
|
||||
},
|
||||
DUP13: {
|
||||
execute: makeDup(13),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(13, 1),
|
||||
validateStack: makeDupStackFunc(13),
|
||||
valid: true,
|
||||
},
|
||||
DUP14: {
|
||||
execute: makeDup(14),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(14, 1),
|
||||
validateStack: makeDupStackFunc(14),
|
||||
valid: true,
|
||||
},
|
||||
DUP15: {
|
||||
execute: makeDup(15),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(15, 1),
|
||||
validateStack: makeDupStackFunc(15),
|
||||
valid: true,
|
||||
},
|
||||
DUP16: {
|
||||
execute: makeDup(16),
|
||||
gasCost: gasDup,
|
||||
validateStack: makeStackFunc(16, 1),
|
||||
validateStack: makeDupStackFunc(16),
|
||||
valid: true,
|
||||
},
|
||||
SWAP1: {
|
||||
execute: makeSwap(1),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(2),
|
||||
valid: true,
|
||||
},
|
||||
SWAP2: {
|
||||
execute: makeSwap(2),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(3),
|
||||
valid: true,
|
||||
},
|
||||
SWAP3: {
|
||||
execute: makeSwap(3),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(4),
|
||||
valid: true,
|
||||
},
|
||||
SWAP4: {
|
||||
execute: makeSwap(4),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(5),
|
||||
valid: true,
|
||||
},
|
||||
SWAP5: {
|
||||
execute: makeSwap(5),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(6),
|
||||
valid: true,
|
||||
},
|
||||
SWAP6: {
|
||||
execute: makeSwap(6),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(7),
|
||||
valid: true,
|
||||
},
|
||||
SWAP7: {
|
||||
execute: makeSwap(7),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(8),
|
||||
valid: true,
|
||||
},
|
||||
SWAP8: {
|
||||
execute: makeSwap(8),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(9),
|
||||
valid: true,
|
||||
},
|
||||
SWAP9: {
|
||||
execute: makeSwap(9),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(10),
|
||||
valid: true,
|
||||
},
|
||||
SWAP10: {
|
||||
execute: makeSwap(10),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(11),
|
||||
valid: true,
|
||||
},
|
||||
SWAP11: {
|
||||
execute: makeSwap(11),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(12),
|
||||
valid: true,
|
||||
},
|
||||
SWAP12: {
|
||||
execute: makeSwap(12),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(13),
|
||||
valid: true,
|
||||
},
|
||||
SWAP13: {
|
||||
execute: makeSwap(13),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(14),
|
||||
valid: true,
|
||||
},
|
||||
SWAP14: {
|
||||
execute: makeSwap(14),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(15),
|
||||
valid: true,
|
||||
},
|
||||
SWAP15: {
|
||||
execute: makeSwap(15),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(16),
|
||||
valid: true,
|
||||
},
|
||||
SWAP16: {
|
||||
execute: makeSwap(16),
|
||||
gasCost: gasSwap,
|
||||
validateStack: makeSwapStackFunc(17),
|
||||
valid: true,
|
||||
},
|
||||
LOG0: {
|
||||
execute: makeLog(0),
|
||||
gasCost: makeGasLog(0),
|
||||
validateStack: makeStackFunc(2, -2),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG1: {
|
||||
execute: makeLog(1),
|
||||
gasCost: makeGasLog(1),
|
||||
validateStack: makeStackFunc(3, -3),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG2: {
|
||||
execute: makeLog(2),
|
||||
gasCost: makeGasLog(2),
|
||||
validateStack: makeStackFunc(4, -4),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG3: {
|
||||
execute: makeLog(3),
|
||||
gasCost: makeGasLog(3),
|
||||
validateStack: makeStackFunc(5, -5),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
LOG4: {
|
||||
execute: makeLog(4),
|
||||
gasCost: makeGasLog(4),
|
||||
validateStack: makeStackFunc(6, -6),
|
||||
memorySize: memoryLog,
|
||||
valid: true,
|
||||
},
|
||||
CREATE: {
|
||||
execute: opCreate,
|
||||
gasCost: gasCreate,
|
||||
validateStack: makeStackFunc(3, -2),
|
||||
memorySize: memoryCreate,
|
||||
valid: true,
|
||||
},
|
||||
CALL: {
|
||||
execute: opCall,
|
||||
gasCost: gasCall,
|
||||
validateStack: makeStackFunc(7, -6),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
},
|
||||
CALLCODE: {
|
||||
execute: opCallCode,
|
||||
gasCost: gasCallCode,
|
||||
validateStack: makeStackFunc(7, -6),
|
||||
memorySize: memoryCall,
|
||||
valid: true,
|
||||
},
|
||||
RETURN: {
|
||||
execute: opReturn,
|
||||
gasCost: gasReturn,
|
||||
validateStack: makeStackFunc(2, -2),
|
||||
memorySize: memoryReturn,
|
||||
halts: true,
|
||||
valid: true,
|
||||
},
|
||||
DELEGATECALL: {
|
||||
execute: opDelegateCall,
|
||||
gasCost: gasDelegateCall,
|
||||
validateStack: makeStackFunc(6, -5),
|
||||
memorySize: memoryDelegateCall,
|
||||
valid: true,
|
||||
},
|
||||
SELFDESTRUCT: {
|
||||
execute: opSuicide,
|
||||
gasCost: gasSuicide,
|
||||
validateStack: makeStackFunc(1, -1),
|
||||
halts: true,
|
||||
valid: true,
|
||||
},
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func TestStoreCapture(t *testing.T) {
|
||||
logger = NewStructLogger(nil)
|
||||
mem = NewMemory()
|
||||
stack = newstack()
|
||||
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
||||
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), new(big.Int))
|
||||
)
|
||||
stack.push(big.NewInt(1))
|
||||
stack.push(big.NewInt(0))
|
||||
@ -78,7 +78,7 @@ func TestStorageCapture(t *testing.T) {
|
||||
t.Skip("implementing this function is difficult. it requires all sort of interfaces to be implemented which isn't trivial. The value (the actual test) isn't worth it")
|
||||
var (
|
||||
ref = &dummyContractRef{}
|
||||
contract = NewContract(ref, ref, new(big.Int), 0)
|
||||
contract = NewContract(ref, ref, new(big.Int), new(big.Int))
|
||||
env = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
||||
logger = NewStructLogger(nil)
|
||||
mem = NewMemory()
|
||||
|
@ -20,12 +20,11 @@ import "fmt"
|
||||
|
||||
// Memory implements a simple memory model for the ethereum virtual machine.
|
||||
type Memory struct {
|
||||
store []byte
|
||||
lastGasCost uint64
|
||||
store []byte
|
||||
}
|
||||
|
||||
func NewMemory() *Memory {
|
||||
return &Memory{}
|
||||
return &Memory{nil}
|
||||
}
|
||||
|
||||
// Set sets offset + size to value
|
||||
|
@ -202,7 +202,7 @@ const (
|
||||
RETURN
|
||||
DELEGATECALL
|
||||
|
||||
SUICIDE = 0xff
|
||||
SELFDESTRUCT = 0xff
|
||||
)
|
||||
|
||||
// Since the opcodes aren't all in order we can't use a regular slice
|
||||
@ -355,7 +355,7 @@ var opCodeToString = map[OpCode]string{
|
||||
RETURN: "RETURN",
|
||||
CALLCODE: "CALLCODE",
|
||||
DELEGATECALL: "DELEGATECALL",
|
||||
SUICIDE: "SUICIDE",
|
||||
SELFDESTRUCT: "SELFDESTRUCT",
|
||||
|
||||
PUSH: "PUSH",
|
||||
DUP: "DUP",
|
||||
@ -501,7 +501,7 @@ var stringToOp = map[string]OpCode{
|
||||
"CALL": CALL,
|
||||
"RETURN": RETURN,
|
||||
"CALLCODE": CALLCODE,
|
||||
"SUICIDE": SUICIDE,
|
||||
"SELFDESTRUCT": SELFDESTRUCT,
|
||||
}
|
||||
|
||||
func StringToOp(str string) OpCode {
|
||||
|
@ -36,7 +36,7 @@ func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM {
|
||||
BlockNumber: cfg.BlockNumber,
|
||||
Time: cfg.Time,
|
||||
Difficulty: cfg.Difficulty,
|
||||
GasLimit: new(big.Int).SetUint64(cfg.GasLimit),
|
||||
GasLimit: cfg.GasLimit,
|
||||
GasPrice: new(big.Int),
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
@ -38,7 +37,7 @@ type Config struct {
|
||||
Coinbase common.Address
|
||||
BlockNumber *big.Int
|
||||
Time *big.Int
|
||||
GasLimit uint64
|
||||
GasLimit *big.Int
|
||||
GasPrice *big.Int
|
||||
Value *big.Int
|
||||
DisableJit bool // "disable" so it's enabled by default
|
||||
@ -69,8 +68,8 @@ func setDefaults(cfg *Config) {
|
||||
if cfg.Time == nil {
|
||||
cfg.Time = big.NewInt(time.Now().Unix())
|
||||
}
|
||||
if cfg.GasLimit == 0 {
|
||||
cfg.GasLimit = math.MaxUint64
|
||||
if cfg.GasLimit == nil {
|
||||
cfg.GasLimit = new(big.Int).Set(common.MaxBig)
|
||||
}
|
||||
if cfg.GasPrice == nil {
|
||||
cfg.GasPrice = new(big.Int)
|
||||
@ -113,7 +112,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||
receiver.SetCode(crypto.Keccak256Hash(code), code)
|
||||
|
||||
// Call the code with the given configuration.
|
||||
ret, _, err := vmenv.Call(
|
||||
ret, err := vmenv.Call(
|
||||
sender,
|
||||
receiver.Address(),
|
||||
input,
|
||||
@ -141,13 +140,12 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) {
|
||||
)
|
||||
|
||||
// Call the code with the given configuration.
|
||||
code, address, _, err := vmenv.Create(
|
||||
return vmenv.Create(
|
||||
sender,
|
||||
input,
|
||||
cfg.GasLimit,
|
||||
cfg.Value,
|
||||
)
|
||||
return code, address, err
|
||||
}
|
||||
|
||||
// Call executes the code given by the contract's address. It will return the
|
||||
@ -162,7 +160,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) {
|
||||
|
||||
sender := cfg.State.GetOrNewStateObject(cfg.Origin)
|
||||
// Call the code with the given configuration.
|
||||
ret, _, err := vmenv.Call(
|
||||
ret, err := vmenv.Call(
|
||||
sender,
|
||||
address,
|
||||
input,
|
||||
|
@ -39,8 +39,8 @@ func TestDefaults(t *testing.T) {
|
||||
if cfg.Time == nil {
|
||||
t.Error("expected time to be non nil")
|
||||
}
|
||||
if cfg.GasLimit == 0 {
|
||||
t.Error("didn't expect gaslimit to be zero")
|
||||
if cfg.GasLimit == nil {
|
||||
t.Error("expected time to be non nil")
|
||||
}
|
||||
if cfg.GasPrice == nil {
|
||||
t.Error("expected time to be non nil")
|
||||
|
@ -6,15 +6,23 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
func makeStackFunc(pop, push int) stackValidationFunc {
|
||||
func makeStackFunc(pop, diff int) stackValidationFunc {
|
||||
return func(stack *Stack) error {
|
||||
if err := stack.require(pop); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if push > 0 && stack.len()-pop+push > int(params.StackLimit) {
|
||||
if int64(stack.len()+diff) > params.StackLimit.Int64() {
|
||||
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeDupStackFunc(n int) stackValidationFunc {
|
||||
return makeStackFunc(n, 1)
|
||||
}
|
||||
|
||||
func makeSwapStackFunc(n int) stackValidationFunc {
|
||||
return makeStackFunc(n, 0)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 The go-ethereum Authors
|
||||
// Copyright 2014 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
|
||||
@ -16,34 +16,7 @@
|
||||
|
||||
package vm
|
||||
|
||||
import "math/big"
|
||||
|
||||
var checkVal = big.NewInt(-42)
|
||||
|
||||
// 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()}
|
||||
}
|
||||
|
||||
func (p *intPool) get() *big.Int {
|
||||
if p.pool.len() > 0 {
|
||||
return p.pool.pop()
|
||||
}
|
||||
return new(big.Int)
|
||||
}
|
||||
func (p *intPool) put(is ...*big.Int) {
|
||||
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)
|
||||
}
|
||||
// VirtualMachine is an EVM interface
|
||||
type VirtualMachine interface {
|
||||
Run(*Contract, []byte) ([]byte, error)
|
||||
}
|
@ -23,7 +23,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
@ -61,7 +60,6 @@ type Interpreter struct {
|
||||
env *EVM
|
||||
cfg Config
|
||||
gasTable params.GasTable
|
||||
intPool *intPool
|
||||
}
|
||||
|
||||
// NewInterpreter returns a new instance of the Interpreter.
|
||||
@ -77,7 +75,6 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter {
|
||||
env: env,
|
||||
cfg: cfg,
|
||||
gasTable: env.ChainConfig().GasTable(env.BlockNumber),
|
||||
intPool: newIntPool(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,18 +106,14 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
|
||||
// For optimisation reason we're using uint64 as the program counter.
|
||||
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible.
|
||||
pc = uint64(0) // program counter
|
||||
cost uint64
|
||||
cost *big.Int
|
||||
)
|
||||
contract.Input = input
|
||||
|
||||
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
|
||||
defer func() {
|
||||
if err != nil && evm.cfg.Debug {
|
||||
// XXX For debugging
|
||||
//fmt.Printf("%04d: %8v cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err)
|
||||
// TODO update the tracer
|
||||
g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost)
|
||||
evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err)
|
||||
evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
|
||||
}
|
||||
}()
|
||||
|
||||
@ -133,7 +126,7 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
|
||||
}
|
||||
|
||||
// The Interpreter main run loop (contextual). This loop runs until either an
|
||||
// explicit STOP, RETURN or SUICIDE is executed, an error occurred during
|
||||
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
|
||||
// the execution of one of the operations or until the evm.done is set by
|
||||
// the parent context.Context.
|
||||
for atomic.LoadInt32(&evm.env.abort) == 0 {
|
||||
@ -154,47 +147,34 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var memorySize uint64
|
||||
var memorySize *big.Int
|
||||
// calculate the new memory size and expand the memory to fit
|
||||
// the operation
|
||||
if operation.memorySize != nil {
|
||||
memSize, overflow := bigUint64(operation.memorySize(stack))
|
||||
if overflow {
|
||||
return nil, errGasUintOverflow
|
||||
}
|
||||
memorySize = operation.memorySize(stack)
|
||||
// memory is expanded in words of 32 bytes. Gas
|
||||
// is also calculated in words.
|
||||
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
|
||||
return nil, errGasUintOverflow
|
||||
}
|
||||
memorySize.Mul(toWordSize(memorySize), big.NewInt(32))
|
||||
}
|
||||
|
||||
if !evm.cfg.DisableGasMetering {
|
||||
// consume the gas and return an error if not enough gas is available.
|
||||
// cost is explicitly set so that the capture state defer method cas get the proper cost
|
||||
cost, err = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize)
|
||||
if err != nil || !contract.UseGas(cost) {
|
||||
cost = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize)
|
||||
if !contract.UseGas(cost) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
if memorySize != nil {
|
||||
mem.Resize(memorySize.Uint64())
|
||||
}
|
||||
|
||||
if evm.cfg.Debug {
|
||||
g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost)
|
||||
evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err)
|
||||
evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
|
||||
}
|
||||
// XXX For debugging
|
||||
//fmt.Printf("%04d: %8v cost = %-8d stack = %-8d\n", pc, op, cost, stack.len())
|
||||
|
||||
// execute the operation
|
||||
res, err := operation.execute(&pc, evm.env, contract, mem, stack)
|
||||
// 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(evm.intPool)
|
||||
}
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
Reference in New Issue
Block a user