aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJeffrey Wilcke <jeffrey@ethereum.org>2017-02-08 20:39:26 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2017-02-13 22:15:12 +0800
commit57f4e9025757254536a738bb4771712038f1e763 (patch)
tree5d2f140139f3763a7da3c20a88acff96b58ec8ad /core
parentf8f428cc18c5f70814d7b3937128781bac14bffd (diff)
downloaddexon-57f4e9025757254536a738bb4771712038f1e763.tar.gz
dexon-57f4e9025757254536a738bb4771712038f1e763.tar.zst
dexon-57f4e9025757254536a738bb4771712038f1e763.zip
Revert "params: core, core/vm, miner: 64bit gas instructions (#3514)"
This reverts commit 8b57c494908637a5c0e74f8f7a13b3218e026757.
Diffstat (limited to 'core')
-rw-r--r--core/bench_test.go7
-rw-r--r--core/block_validator.go2
-rw-r--r--core/blockchain_test.go16
-rw-r--r--core/chain_makers_test.go6
-rw-r--r--core/state_transition.go88
-rw-r--r--core/vm/common.go78
-rw-r--r--core/vm/contract.go33
-rw-r--r--core/vm/contracts.go39
-rw-r--r--core/vm/environment.go (renamed from core/vm/evm.go)83
-rw-r--r--core/vm/gas.go153
-rw-r--r--core/vm/gas_table.go418
-rw-r--r--core/vm/gas_table_test.go24
-rw-r--r--core/vm/instructions.go338
-rw-r--r--core/vm/int_pool_verifier.go15
-rw-r--r--core/vm/int_pool_verifier_empty.go7
-rw-r--r--core/vm/jump_table.go567
-rw-r--r--core/vm/logger_test.go4
-rw-r--r--core/vm/memory.go5
-rw-r--r--core/vm/opcodes.go6
-rw-r--r--core/vm/runtime/env.go2
-rw-r--r--core/vm/runtime/runtime.go14
-rw-r--r--core/vm/runtime/runtime_test.go4
-rw-r--r--core/vm/stack_table.go12
-rw-r--r--core/vm/virtual_machine.go (renamed from core/vm/intpool.go)35
-rw-r--r--core/vm/vm.go (renamed from core/vm/interpreter.go)42
25 files changed, 922 insertions, 1076 deletions
diff --git a/core/bench_test.go b/core/bench_test.go
index 59b5ad758..353d217fd 100644
--- a/core/bench_test.go
+++ b/core/bench_test.go
@@ -92,7 +92,6 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
var (
ringKeys = make([]*ecdsa.PrivateKey, 1000)
ringAddrs = make([]common.Address, len(ringKeys))
- bigTxGas = new(big.Int).SetUint64(params.TxGas)
)
func init() {
@@ -112,8 +111,8 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) {
gas := CalcGasLimit(gen.PrevBlock(i - 1))
for {
- gas.Sub(gas, bigTxGas)
- if gas.Cmp(bigTxGas) < 0 {
+ gas.Sub(gas, params.TxGas)
+ if gas.Cmp(params.TxGas) < 0 {
break
}
to := (from + 1) % naccounts
@@ -121,7 +120,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
gen.TxNonce(ringAddrs[from]),
ringAddrs[to],
benchRootFunds,
- bigTxGas,
+ params.TxGas,
nil,
nil,
)
diff --git a/core/block_validator.go b/core/block_validator.go
index ee524b61f..65f975345 100644
--- a/core/block_validator.go
+++ b/core/block_validator.go
@@ -204,7 +204,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
//
// See YP section 4.3.4. "Block Header Validity"
func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
- if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
+ if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
}
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index cdf9b5cc6..8f1383acd 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -719,7 +719,7 @@ func TestFastVsFullChains(t *testing.T) {
// If the block number is multiple of 3, send a few bonus transactions to the miner
if i%3 == 2 {
for j := 0; j < i%4+1; j++ {
- tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), bigTxGas, nil, nil), signer, key)
+ tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key)
if err != nil {
panic(err)
}
@@ -883,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
// Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number in the forked chain
- postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
- swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
+ postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
+ swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
// Create two transactions that will be dropped by the forked chain:
// - pastDrop: transaction dropped retroactively from a past block
@@ -900,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
switch i {
case 0:
- pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
+ pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
case 2:
- freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
+ freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
gen.AddTx(swapped) // This transaction will be swapped out at the exact height
@@ -925,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
switch i {
case 0:
- pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
+ pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
case 2:
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
- freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
+ freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
case 3:
- futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
+ futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(futureAdd) // This transaction will be added after a full reorg
}
})
diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go
index 5c563de46..2796817c0 100644
--- a/core/chain_makers_test.go
+++ b/core/chain_makers_test.go
@@ -56,13 +56,13 @@ func ExampleGenerateChain() {
switch i {
case 0:
// In block 1, addr1 sends addr2 some ether.
- tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), bigTxGas, nil, nil), signer, key1)
+ tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
gen.AddTx(tx)
case 1:
// In block 2, addr1 sends some more ether to addr2.
// addr2 passes it on to addr3.
- tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
- tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
+ tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
+ tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(tx1)
gen.AddTx(tx2)
case 2:
diff --git a/core/state_transition.go b/core/state_transition.go
index 98dc8d995..3cb7e500c 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -49,16 +49,15 @@ The state transitioning model does all all the necessary work to work out a vali
6) Derive new state root
*/
type StateTransition struct {
- gp *GasPool
- msg Message
- gas uint64
- gasPrice *big.Int
- initialGas *big.Int
- value *big.Int
- data []byte
- state vm.StateDB
-
- evm *vm.EVM
+ gp *GasPool
+ msg Message
+ gas, gasPrice *big.Int
+ initialGas *big.Int
+ value *big.Int
+ data []byte
+ state vm.StateDB
+
+ env *vm.EVM
}
// Message represents a message sent to a contract.
@@ -82,14 +81,12 @@ func MessageCreatesContract(msg Message) bool {
// IntrinsicGas computes the 'intrinsic gas' for a message
// with the given data.
-//
-// TODO convert to uint64
func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
igas := new(big.Int)
if contractCreation && homestead {
- igas.SetUint64(params.TxGasContractCreation)
+ igas.Set(params.TxGasContractCreation)
} else {
- igas.SetUint64(params.TxGas)
+ igas.Set(params.TxGas)
}
if len(data) > 0 {
var nz int64
@@ -99,26 +96,27 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
}
}
m := big.NewInt(nz)
- m.Mul(m, new(big.Int).SetUint64(params.TxDataNonZeroGas))
+ m.Mul(m, params.TxDataNonZeroGas)
igas.Add(igas, m)
m.SetInt64(int64(len(data)) - nz)
- m.Mul(m, new(big.Int).SetUint64(params.TxDataZeroGas))
+ m.Mul(m, params.TxDataZeroGas)
igas.Add(igas, m)
}
return igas
}
// NewStateTransition initialises and returns a new state transition object.
-func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
+func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition {
return &StateTransition{
gp: gp,
- evm: evm,
+ env: env,
msg: msg,
+ gas: new(big.Int),
gasPrice: msg.GasPrice(),
initialGas: new(big.Int),
value: msg.Value(),
data: msg.Data(),
- state: evm.StateDB,
+ state: env.StateDB,
}
}
@@ -129,8 +127,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
// the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
-func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
- st := NewStateTransition(evm, msg, gp)
+func ApplyMessage(env *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
+ st := NewStateTransition(env, msg, gp)
ret, _, gasUsed, err := st.TransitionDb()
return ret, gasUsed, err
@@ -159,21 +157,21 @@ func (self *StateTransition) to() vm.Account {
return self.state.GetAccount(*to)
}
-func (self *StateTransition) useGas(amount uint64) error {
- if self.gas < amount {
+func (self *StateTransition) useGas(amount *big.Int) error {
+ if self.gas.Cmp(amount) < 0 {
return vm.ErrOutOfGas
}
- self.gas -= amount
+ self.gas.Sub(self.gas, amount)
return nil
}
+func (self *StateTransition) addGas(amount *big.Int) {
+ self.gas.Add(self.gas, amount)
+}
+
func (self *StateTransition) buyGas() error {
mgas := self.msg.Gas()
- if mgas.BitLen() > 64 {
- return vm.ErrOutOfGas
- }
-
mgval := new(big.Int).Mul(mgas, self.gasPrice)
sender := self.from()
@@ -183,8 +181,7 @@ func (self *StateTransition) buyGas() error {
if err := self.gp.SubGas(mgas); err != nil {
return err
}
- self.gas += mgas.Uint64()
-
+ self.addGas(mgas)
self.initialGas.Set(mgas)
sender.SubBalance(mgval)
return nil
@@ -212,9 +209,7 @@ func (self *StateTransition) preCheck() (err error) {
return nil
}
-// TransitionDb will transition the state by applying the current message and returning the result
-// including the required gas for the operation as well as the used gas. It returns an error if it
-// failed. An error indicates a consensus issue.
+// TransitionDb will move the state by applying the message against the given environment.
func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) {
if err = self.preCheck(); err != nil {
return
@@ -222,32 +217,26 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
msg := self.msg
sender := self.from() // err checked in preCheck
- homestead := self.evm.ChainConfig().IsHomestead(self.evm.BlockNumber)
+ homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber)
contractCreation := MessageCreatesContract(msg)
// Pay intrinsic gas
- // TODO convert to uint64
- intrinsicGas := IntrinsicGas(self.data, contractCreation, homestead)
- if intrinsicGas.BitLen() > 64 {
- return nil, nil, nil, InvalidTxError(vm.ErrOutOfGas)
- }
-
- if err = self.useGas(intrinsicGas.Uint64()); err != nil {
+ if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
return nil, nil, nil, InvalidTxError(err)
}
var (
- evm = self.evm
+ vmenv = self.env
// vm errors do not effect consensus and are therefor
// not assigned to err, except for insufficient balance
// error.
vmerr error
)
if contractCreation {
- ret, _, self.gas, vmerr = evm.Create(sender, self.data, self.gas, self.value)
+ ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value)
} else {
// Increment the nonce for the next transaction
self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1)
- ret, self.gas, vmerr = evm.Call(sender, self.to().Address(), self.data, self.gas, self.value)
+ ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.value)
}
if vmerr != nil {
glog.V(logger.Core).Infoln("vm returned with error:", err)
@@ -262,7 +251,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
requiredGas = new(big.Int).Set(self.gasUsed())
self.refundGas()
- self.state.AddBalance(self.evm.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
+ self.state.AddBalance(self.env.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
return ret, requiredGas, self.gasUsed(), err
}
@@ -271,21 +260,20 @@ func (self *StateTransition) refundGas() {
// Return eth for remaining gas to the sender account,
// exchanged at the original rate.
sender := self.from() // err already checked
- remaining := new(big.Int).Mul(new(big.Int).SetUint64(self.gas), self.gasPrice)
+ remaining := new(big.Int).Mul(self.gas, self.gasPrice)
sender.AddBalance(remaining)
// Apply refund counter, capped to half of the used gas.
uhalf := remaining.Div(self.gasUsed(), common.Big2)
refund := common.BigMin(uhalf, self.state.GetRefund())
- self.gas += refund.Uint64()
-
+ self.gas.Add(self.gas, refund)
self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
- self.gp.AddGas(new(big.Int).SetUint64(self.gas))
+ self.gp.AddGas(self.gas)
}
func (self *StateTransition) gasUsed() *big.Int {
- return new(big.Int).Sub(self.initialGas, new(big.Int).SetUint64(self.gas))
+ return new(big.Int).Sub(self.initialGas, self.gas)
}
diff --git a/core/vm/common.go b/core/vm/common.go
index b7b9a6a9c..2878b92d2 100644
--- a/core/vm/common.go
+++ b/core/vm/common.go
@@ -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
}
diff --git a/core/vm/contract.go b/core/vm/contract.go
index 091106d84..dfa93ab18 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -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
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 593b6ca55..9645d268f 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -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
diff --git a/core/vm/evm.go b/core/vm/environment.go
index 0c5d998c2..c19ef464b 100644
--- a/core/vm/evm.go
+++ b/core/vm/environment.go
@@ -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
diff --git a/core/vm/gas.go b/core/vm/gas.go
index dd64d5f17..cb225b6ca 100644
--- a/core/vm/gas.go
+++ b/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
-
- GasReturn uint64 = 0
- GasStop uint64 = 0
- GasContractByte uint64 = 200
+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 = 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
+ }
+
+ 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
+}
- return callCost.Uint64(), nil
+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},
}
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index fba1eb066..4d2c4e94a 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -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
- }
-
- 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
+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)
+ }
}
- 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
- }
-
- var overflow bool
- if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
- return 0, errGasUintOverflow
- }
+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))
- 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
- }
-
- var overflow bool
- if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
- return 0, errGasUintOverflow
- }
+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))
- 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
- }
-
- 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
- }
+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))
- 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)
-
- 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 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, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+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 = 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
}
diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go
deleted file mode 100644
index cceb89285..000000000
--- a/core/vm/gas_table_test.go
+++ /dev/null
@@ -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")
- }
-}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 39e5c0587..3b1b06cca 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -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)
-
+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 opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
+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, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+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
}
diff --git a/core/vm/int_pool_verifier.go b/core/vm/int_pool_verifier.go
deleted file mode 100644
index 61c83ba7e..000000000
--- a/core/vm/int_pool_verifier.go
+++ /dev/null
@@ -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))
- }
- }
-}
diff --git a/core/vm/int_pool_verifier_empty.go b/core/vm/int_pool_verifier_empty.go
deleted file mode 100644
index 982f8c6dd..000000000
--- a/core/vm/int_pool_verifier_empty.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// +build !VERIFY_EVM_INTEGER_POOL
-
-package vm
-
-const verifyPool = false
-
-func verifyIntegerPool(ip *intPool) {}
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 80e12c10b..073798274 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -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{
- ADD: {
- execute: opAdd,
- gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ STOP: {
+ execute: opStop,
+ gasCost: constGasFunc(new(big.Int)),
+ validateStack: makeStackFunc(0, 0),
+ halts: true,
valid: true,
},
- SUB: {
- execute: opSub,
+ ADD: {
+ execute: opAdd,
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),
+ validateStack: makeStackFunc(2, -1),
+ valid: true,
+ },
+ ADDMOD: {
+ execute: opAddmod,
+ gasCost: constGasFunc(GasMidStep),
+ validateStack: makeStackFunc(3, -2),
+ valid: true,
+ },
+ MULMOD: {
+ execute: opMulmod,
+ gasCost: constGasFunc(GasMidStep),
+ validateStack: makeStackFunc(3, -2),
valid: true,
},
EXP: {
execute: opExp,
gasCost: gasExp,
- validateStack: makeStackFunc(2, 1),
+ 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),
+ validateStack: makeStackFunc(2, -1),
valid: true,
},
LT: {
execute: opLt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ validateStack: makeStackFunc(2, -1),
valid: true,
},
GT: {
execute: opGt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ validateStack: makeStackFunc(2, -1),
valid: true,
},
SLT: {
execute: opSlt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ validateStack: makeStackFunc(2, -1),
valid: true,
},
SGT: {
execute: opSgt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ validateStack: makeStackFunc(2, -1),
valid: true,
},
EQ: {
execute: opEq,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ validateStack: makeStackFunc(2, -1),
valid: true,
},
ISZERO: {
execute: opIszero,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(1, 1),
+ validateStack: makeStackFunc(1, 0),
valid: true,
},
AND: {
execute: opAnd,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ 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),
+ validateStack: makeStackFunc(2, -1),
valid: true,
},
- XOR: {
- execute: opXor,
+ NOT: {
+ execute: opNot,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
+ validateStack: makeStackFunc(1, 0),
valid: true,
},
BYTE: {
execute: opByte,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, 1),
- valid: true,
- },
- ADDMOD: {
- execute: opAddmod,
- gasCost: constGasFunc(GasMidStep),
- validateStack: makeStackFunc(3, 1),
- valid: true,
- },
- MULMOD: {
- execute: opMulmod,
- gasCost: constGasFunc(GasMidStep),
- validateStack: makeStackFunc(3, 1),
+ 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,
},
}
diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go
index ca60cba43..1d0bd96fa 100644
--- a/core/vm/logger_test.go
+++ b/core/vm/logger_test.go
@@ -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()
diff --git a/core/vm/memory.go b/core/vm/memory.go
index 99a84d227..d01188417 100644
--- a/core/vm/memory.go
+++ b/core/vm/memory.go
@@ -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
diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go
index 9d2b037a5..d4ba7f156 100644
--- a/core/vm/opcodes.go
+++ b/core/vm/opcodes.go
@@ -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 {
diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go
index 9aa88e669..a25c6d71c 100644
--- a/core/vm/runtime/env.go
+++ b/core/vm/runtime/env.go
@@ -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),
}
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index cf46603db..b5adb982c 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -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,
diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go
index 8ad74a89a..1e618b688 100644
--- a/core/vm/runtime/runtime_test.go
+++ b/core/vm/runtime/runtime_test.go
@@ -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")
diff --git a/core/vm/stack_table.go b/core/vm/stack_table.go
index 0936ef06f..eed8805f2 100644
--- a/core/vm/stack_table.go
+++ b/core/vm/stack_table.go
@@ -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)
+}
diff --git a/core/vm/intpool.go b/core/vm/virtual_machine.go
index 4f1228e14..629108884 100644
--- a/core/vm/intpool.go
+++ b/core/vm/virtual_machine.go
@@ -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)
}
diff --git a/core/vm/interpreter.go b/core/vm/vm.go
index ad41e3602..05886a863 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/vm.go
@@ -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