From 57f4e9025757254536a738bb4771712038f1e763 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Wed, 8 Feb 2017 13:39:26 +0100 Subject: [PATCH] Revert "params: core, core/vm, miner: 64bit gas instructions (#3514)" This reverts commit 8b57c494908637a5c0e74f8f7a13b3218e026757. --- cmd/evm/main.go | 4 +- cmd/geth/main.go | 2 +- common/math/integer.go | 25 - common/math/integer_test.go | 50 -- core/bench_test.go | 7 +- core/block_validator.go | 2 +- core/blockchain_test.go | 16 +- core/chain_makers_test.go | 6 +- core/state_transition.go | 88 ++-- core/vm/common.go | 78 ++- core/vm/contract.go | 33 +- core/vm/contracts.go | 39 +- core/vm/{evm.go => environment.go} | 83 ++- core/vm/gas.go | 153 +++++- core/vm/gas_table.go | 418 +++++---------- core/vm/gas_table_test.go | 24 - core/vm/instructions.go | 338 +++++------- core/vm/int_pool_verifier.go | 15 - core/vm/int_pool_verifier_empty.go | 7 - core/vm/jump_table.go | 567 ++++++++++----------- core/vm/logger_test.go | 4 +- core/vm/memory.go | 5 +- core/vm/opcodes.go | 6 +- core/vm/runtime/env.go | 2 +- core/vm/runtime/runtime.go | 14 +- core/vm/runtime/runtime_test.go | 4 +- core/vm/stack_table.go | 12 +- core/vm/{intpool.go => virtual_machine.go} | 35 +- core/vm/{interpreter.go => vm.go} | 42 +- eth/api_backend.go | 4 +- eth/bind.go | 4 +- eth/downloader/downloader.go | 12 +- eth/downloader/downloader_test.go | 2 +- eth/fetcher/fetcher_test.go | 2 +- eth/handler_test.go | 14 +- internal/ethapi/api.go | 61 +-- internal/ethapi/backend.go | 2 +- internal/ethapi/tracer_test.go | 4 +- les/api_backend.go | 4 +- les/helper_test.go | 8 +- light/odr_test.go | 8 +- light/txpool_test.go | 2 +- miner/miner.go | 2 +- params/gas_table.go | 68 +-- params/protocol_params.go | 100 ++-- tests/block_test_util.go | 2 +- tests/state_test.go | 2 +- tests/state_test_util.go | 2 +- tests/vm_test_util.go | 6 +- 49 files changed, 1068 insertions(+), 1320 deletions(-) delete mode 100644 common/math/integer.go delete mode 100644 common/math/integer_test.go rename core/vm/{evm.go => environment.go} (85%) delete mode 100644 core/vm/gas_table_test.go delete mode 100644 core/vm/int_pool_verifier.go delete mode 100644 core/vm/int_pool_verifier_empty.go rename core/vm/{intpool.go => virtual_machine.go} (53%) rename core/vm/{interpreter.go => vm.go} (78%) diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 8af0cebbb5..9f67e66286 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -156,7 +156,7 @@ func run(ctx *cli.Context) error { ret, _, err = runtime.Create(input, &runtime.Config{ Origin: sender.Address(), State: statedb, - GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(), + GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)), GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), Value: common.Big(ctx.GlobalString(ValueFlag.Name)), EVMConfig: vm.Config{ @@ -172,7 +172,7 @@ func run(ctx *cli.Context) error { ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ Origin: sender.Address(), State: statedb, - GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(), + GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)), GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), Value: common.Big(ctx.GlobalString(ValueFlag.Name)), EVMConfig: vm.Config{ diff --git a/cmd/geth/main.go b/cmd/geth/main.go index c19770bfaa..1680a32e02 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -205,7 +205,7 @@ func makeFullNode(ctx *cli.Context) *node.Node { if err != nil { glog.V(logger.Warn).Infoln("error setting canonical miner information:", err) } - if uint64(len(extra)) > params.MaximumExtraDataSize { + if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() { glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize) glog.V(logger.Debug).Infof("extra: %x\n", extra) extra = nil diff --git a/common/math/integer.go b/common/math/integer.go deleted file mode 100644 index 8162b19854..0000000000 --- a/common/math/integer.go +++ /dev/null @@ -1,25 +0,0 @@ -package math - -import gmath "math" - -/* - * NOTE: The following methods need to be optimised using either bit checking or asm - */ - -// SafeSub returns subtraction result and whether overflow occurred. -func SafeSub(x, y uint64) (uint64, bool) { - return x - y, x < y -} - -// SafeAdd returns the result and whether overflow occurred. -func SafeAdd(x, y uint64) (uint64, bool) { - return x + y, y > gmath.MaxUint64-x -} - -// SafeMul returns multiplication result and whether overflow occurred. -func SafeMul(x, y uint64) (uint64, bool) { - if x == 0 { - return 0, false - } - return x * y, x != 0 && y != 0 && y > gmath.MaxUint64/x -} diff --git a/common/math/integer_test.go b/common/math/integer_test.go deleted file mode 100644 index 198114e5e1..0000000000 --- a/common/math/integer_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package math - -import ( - gmath "math" - "testing" -) - -type operation byte - -const ( - sub operation = iota - add - mul -) - -func TestOverflow(t *testing.T) { - for i, test := range []struct { - x uint64 - y uint64 - overflow bool - op operation - }{ - // add operations - {gmath.MaxUint64, 1, true, add}, - {gmath.MaxUint64 - 1, 1, false, add}, - - // sub operations - {0, 1, true, sub}, - {0, 0, false, sub}, - - // mul operations - {10, 10, false, mul}, - {gmath.MaxUint64, 2, true, mul}, - {gmath.MaxUint64, 1, false, mul}, - } { - var overflows bool - switch test.op { - case sub: - _, overflows = SafeSub(test.x, test.y) - case add: - _, overflows = SafeAdd(test.x, test.y) - case mul: - _, overflows = SafeMul(test.x, test.y) - } - - if test.overflow != overflows { - t.Errorf("%d failed. Expected test to be %v, got %v", i, test.overflow, overflows) - } - } -} diff --git a/core/bench_test.go b/core/bench_test.go index 59b5ad7589..353d217fd4 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 ee524b61f8..65f975345c 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 cdf9b5cc64..8f1383acdb 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 5c563de469..2796817c01 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 98dc8d9958..3cb7e500c5 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 b7b9a6a9c7..2878b92d2a 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 091106d84d..dfa93ab18b 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 593b6ca55c..9645d268fe 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 similarity index 85% rename from core/vm/evm.go rename to core/vm/environment.go index 0c5d998c29..c19ef464ba 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 dd64d5f178..cb225b6cac 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 fba1eb066e..4d2c4e94ae 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 cceb892859..0000000000 --- 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 39e5c05870..3b1b06cca1 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 61c83ba7e9..0000000000 --- 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 982f8c6dd5..0000000000 --- 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 80e12c10b5..0737982745 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 ca60cba43e..1d0bd96fad 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 99a84d2271..d011884173 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 9d2b037a56..d4ba7f1563 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 9aa88e6690..a25c6d71c6 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 cf46603dbd..b5adb982c3 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 8ad74a89ab..1e618b688a 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 0936ef06fc..eed8805f23 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 similarity index 53% rename from core/vm/intpool.go rename to core/vm/virtual_machine.go index 4f1228e149..6291088846 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 similarity index 78% rename from core/vm/interpreter.go rename to core/vm/vm.go index ad41e36022..05886a8639 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 diff --git a/eth/api_backend.go b/eth/api_backend.go index 72ed76cc4a..1174588ea7 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -106,14 +106,14 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { return b.eth.blockchain.GetTdByHash(blockHash) } -func (b *EthApiBackend) GetEVM(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { +func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) { statedb := state.(EthApiState).state from := statedb.GetOrNewStateObject(msg.From()) from.SetBalance(common.MaxBig) vmError := func() error { return nil } context := core.NewEVMContext(msg, header, b.eth.BlockChain()) - return vm.NewEVM(context, statedb, b.eth.chainConfig, vmCfg), vmError, nil + return vm.NewEVM(context, statedb, b.eth.chainConfig, vm.Config{}), vmError, nil } func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { diff --git a/eth/bind.go b/eth/bind.go index 2ee9f2bf7b..a9864b3677 100644 --- a/eth/bind.go +++ b/eth/bind.go @@ -69,7 +69,7 @@ func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Add // against the pending block, not the stable head of the chain. func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) { out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum)) - return out, err + return common.FromHex(out), err } // ContractCall implements bind.ContractCaller executing an Ethereum contract @@ -77,7 +77,7 @@ func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg // against the pending block, not the stable head of the chain. func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { out, err := b.bcapi.Call(ctx, toCallArgs(msg), rpc.PendingBlockNumber) - return out, err + return common.FromHex(out), err } func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs { diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 7e2952439a..9be4bd87d0 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -49,12 +49,12 @@ var ( MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request MaxStateFetch = 384 // Amount of node state values to allow fetching per request - MaxForkAncestry = 3 * params.EpochDuration // Maximum chain reorganisation - rttMinEstimate = 2 * time.Second // Minimum round-trip time to target for download requests - rttMaxEstimate = 20 * time.Second // Maximum rount-trip time to target for download requests - rttMinConfidence = 0.1 // Worse confidence factor in our estimated RTT value - ttlScaling = 3 // Constant scaling factor for RTT -> TTL conversion - ttlLimit = time.Minute // Maximum TTL allowance to prevent reaching crazy timeouts + MaxForkAncestry = 3 * params.EpochDuration.Uint64() // Maximum chain reorganisation + rttMinEstimate = 2 * time.Second // Minimum round-trip time to target for download requests + rttMaxEstimate = 20 * time.Second // Maximum rount-trip time to target for download requests + rttMinConfidence = 0.1 // Worse confidence factor in our estimated RTT value + ttlScaling = 3 // Constant scaling factor for RTT -> TTL conversion + ttlLimit = time.Minute // Maximum TTL allowance to prevent reaching crazy timeouts qosTuningPeers = 5 // Number of peers to tune based on (best peers) qosConfidenceCap = 10 // Number of peers above which not to modify RTT confidence diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index a9ea797eac..b156c471df 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -119,7 +119,7 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren // If the block number is multiple of 3, send a bonus transaction to the miner if parent == dl.genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) if err != nil { panic(err) } diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 7a94241c66..2e28541ab3 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -51,7 +51,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) if err != nil { panic(err) } diff --git a/eth/handler_test.go b/eth/handler_test.go index 03d5404a4d..8a5d7173b3 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -36,8 +36,6 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var bigTxGas = new(big.Int).SetUint64(params.TxGas) - // Tests that protocol versions and modes of operations are matched up properly. func TestProtocolCompatibility(t *testing.T) { // Define the compatibility chart @@ -314,13 +312,13 @@ func testGetNodeData(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: @@ -406,13 +404,13 @@ func testGetReceipt(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f49434e173..cf82cc8665 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -48,8 +48,6 @@ import ( const defaultGas = 90000 -var emptyHex = "0x" - // PublicEthereumAPI provides an API to access Ethereum related information. // It offers only methods that operate on public data that is freely available to anyone. type PublicEthereumAPI struct { @@ -576,12 +574,12 @@ type CallArgs struct { Data hexutil.Bytes `json:"data"` } -func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, error) { +func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { defer func(start time.Time) { glog.V(logger.Debug).Infof("call took %v", time.Since(start)) }(time.Now()) state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { - return nil, common.Big0, err + return "0x", common.Big0, err } // Set sender address or use a default if none specified addr := args.From @@ -591,59 +589,40 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr addr = accounts[0].Address } } + } else { + addr = args.From } // Set default gas & gas price if none were set gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt() - if gas.BitLen() == 0 { + if gas.Cmp(common.Big0) == 0 { gas = big.NewInt(50000000) } - if gasPrice.BitLen() == 0 { + if gasPrice.Cmp(common.Big0) == 0 { gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } - // Create new call message msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false) - // Setup context so it may be cancelled the call has completed - // or, in case of unmetered gas, setup a context with a timeout. - var cancel context.CancelFunc - if vmCfg.DisableGasMetering { - ctx, cancel = context.WithTimeout(ctx, time.Second*5) - } else { - ctx, cancel = context.WithCancel(ctx) - } - // Make sure the context is cancelled when the call has completed - // this makes sure resources are cleaned up. - defer func() { cancel() }() - - // Get a new instance of the EVM. - evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) + // Execute the call and return + vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header) if err != nil { - return nil, common.Big0, err - } - // Wait for the context to be done and cancel the evm. Even if the - // EVM has finished, cancelling may be done (repeatedly) - go func() { - select { - case <-ctx.Done(): - evm.Cancel() - } - }() - - // Setup the gas pool (also for unmetered requests) - // and apply the message. + return "0x", common.Big0, err + } gp := new(core.GasPool).AddGas(common.MaxBig) - res, gas, err := core.ApplyMessage(evm, msg, gp) + res, gas, err := core.ApplyMessage(vmenv, msg, gp) if err := vmError(); err != nil { - return nil, common.Big0, err + return "0x", common.Big0, err + } + if len(res) == 0 { // backwards compatibility + return "0x", gas, err } - return res, gas, err + return common.ToHex(res), gas, err } // Call executes the given transaction on the state for the given block number. // It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values. -func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { - result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true}) - return (hexutil.Bytes)(result), err +func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, error) { + result, _, err := s.doCall(ctx, args, blockNr) + return result, err } // EstimateGas returns an estimate of the amount of gas needed to execute the given transaction. @@ -665,7 +644,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* mid := (hi + lo) / 2 (*big.Int)(&args.Gas).SetUint64(mid) - _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}) + _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber) // If the transaction became invalid or used all the gas (failed), raise the gas limit if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 { diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 214214f511..ebb14a5b5c 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -51,7 +51,7 @@ type Backend interface { GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetTd(blockHash common.Hash) *big.Int - GetEVM(ctx context.Context, msg core.Message, state State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) + GetVMEnv(ctx context.Context, msg core.Message, state State, header *types.Header) (*vm.EVM, func() error, error) // TxPool API SendTx(ctx context.Context, signedTx *types.Transaction) error RemoveTx(txHash common.Hash) diff --git a/internal/ethapi/tracer_test.go b/internal/ethapi/tracer_test.go index 693afe802f..65a23f55e7 100644 --- a/internal/ethapi/tracer_test.go +++ b/internal/ethapi/tracer_test.go @@ -45,7 +45,7 @@ func (account) ForEachStorage(cb func(key, value common.Hash) bool) {} func runTrace(tracer *JavascriptTracer) (interface{}, error) { env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) - contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000) + contract := vm.NewContract(account{}, account{}, big.NewInt(0), big.NewInt(10000)) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} _, err := env.Interpreter().Run(contract, []byte{}) @@ -134,7 +134,7 @@ func TestHaltBetweenSteps(t *testing.T) { } env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) - contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0) + contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), big.NewInt(0)) tracer.CaptureState(env, 0, 0, big.NewInt(0), big.NewInt(0), nil, nil, contract, 0, nil) timeout := errors.New("stahp") diff --git a/les/api_backend.go b/les/api_backend.go index ed2a7cd13e..3a71ac4e02 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -88,7 +88,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int { return b.eth.blockchain.GetTdByHash(blockHash) } -func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { +func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) { stateDb := state.(*light.LightState).Copy() addr := msg.From() from, err := stateDb.GetOrNewStateObject(ctx, addr) @@ -99,7 +99,7 @@ func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state etha vmstate := light.NewVMState(ctx, stateDb) context := core.NewEVMContext(msg, header, b.eth.blockchain) - return vm.NewEVM(context, vmstate, b.eth.chainConfig, vmCfg), vmstate.Error, nil + return vm.NewEVM(context, vmstate, b.eth.chainConfig, vm.Config{}), vmstate.Error, nil } func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { diff --git a/les/helper_test.go b/les/helper_test.go index 2c6f34a92e..e0b7558eeb 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -57,8 +57,6 @@ var ( testContractDeployed = uint64(2) testBufLimit = uint64(100) - - bigTxGas = new(big.Int).SetUint64(params.TxGas) ) /* @@ -82,15 +80,15 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) nonce++ tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) diff --git a/light/odr_test.go b/light/odr_test.go index a76050a299..a2f969acb3 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -49,8 +49,6 @@ var ( testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") testContractAddr common.Address - - bigTxGas = new(big.Int).SetUint64(params.TxGas) ) type testOdr struct { @@ -207,15 +205,15 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) nonce++ tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) diff --git a/light/txpool_test.go b/light/txpool_test.go index af2dcbbef1..d8f04e6173 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -77,7 +77,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) { func TestTxPool(t *testing.T) { for i := range testTx { - testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), types.HomesteadSigner{}, testBankKey) + testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) } var ( diff --git a/miner/miner.go b/miner/miner.go index 83059f4b1d..61cd3e0499 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -171,7 +171,7 @@ func (self *Miner) HashRate() (tot int64) { } func (self *Miner) SetExtra(extra []byte) error { - if uint64(len(extra)) > params.MaximumExtraDataSize { + if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() { return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize) } self.worker.setExtra(extra) diff --git a/params/gas_table.go b/params/gas_table.go index a060539041..093dacc8b3 100644 --- a/params/gas_table.go +++ b/params/gas_table.go @@ -16,35 +16,41 @@ package params +import "math/big" + type GasTable struct { - ExtcodeSize uint64 - ExtcodeCopy uint64 - Balance uint64 - SLoad uint64 - Calls uint64 - Suicide uint64 + ExtcodeSize *big.Int + ExtcodeCopy *big.Int + Balance *big.Int + SLoad *big.Int + Calls *big.Int + Suicide *big.Int - ExpByte uint64 + ExpByte *big.Int // CreateBySuicide occurs when the // refunded account is one that does // not exist. This logic is similar // to call. May be left nil. Nil means // not charged. - CreateBySuicide uint64 + CreateBySuicide *big.Int } var ( // GasTableHomestead contain the gas prices for // the homestead phase. GasTableHomestead = GasTable{ - ExtcodeSize: 20, - ExtcodeCopy: 20, - Balance: 20, - SLoad: 50, - Calls: 40, - Suicide: 0, - ExpByte: 10, + ExtcodeSize: big.NewInt(20), + ExtcodeCopy: big.NewInt(20), + Balance: big.NewInt(20), + SLoad: big.NewInt(50), + Calls: big.NewInt(40), + Suicide: big.NewInt(0), + ExpByte: big.NewInt(10), + + // explicitly set to nil to indicate + // this rule does not apply to homestead. + CreateBySuicide: nil, } // GasTableHomestead contain the gas re-prices for @@ -52,26 +58,26 @@ var ( // // TODO rename to GasTableEIP150 GasTableHomesteadGasRepriceFork = GasTable{ - ExtcodeSize: 700, - ExtcodeCopy: 700, - Balance: 400, - SLoad: 200, - Calls: 700, - Suicide: 5000, - ExpByte: 10, + ExtcodeSize: big.NewInt(700), + ExtcodeCopy: big.NewInt(700), + Balance: big.NewInt(400), + SLoad: big.NewInt(200), + Calls: big.NewInt(700), + Suicide: big.NewInt(5000), + ExpByte: big.NewInt(10), - CreateBySuicide: 25000, + CreateBySuicide: big.NewInt(25000), } GasTableEIP158 = GasTable{ - ExtcodeSize: 700, - ExtcodeCopy: 700, - Balance: 400, - SLoad: 200, - Calls: 700, - Suicide: 5000, - ExpByte: 50, + ExtcodeSize: big.NewInt(700), + ExtcodeCopy: big.NewInt(700), + Balance: big.NewInt(400), + SLoad: big.NewInt(200), + Calls: big.NewInt(700), + Suicide: big.NewInt(5000), + ExpByte: big.NewInt(50), - CreateBySuicide: 25000, + CreateBySuicide: big.NewInt(25000), } ) diff --git a/params/protocol_params.go b/params/protocol_params.go index f48bf4992d..f5b6bedeb7 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -18,58 +18,56 @@ package params import "math/big" -const ( - MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. - ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. - SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. - CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero. - CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior. - TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions. - TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. - TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. - QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation. - SstoreSetGas uint64 = 20000 // Once per SLOAD operation. - LogDataGas uint64 = 8 // Per byte in a LOG* operation's data. - CallStipend uint64 = 2300 // Free gas given at beginning of call. - EcrecoverGas uint64 = 3000 // - Sha256WordGas uint64 = 12 // +var ( + MaximumExtraDataSize = big.NewInt(32) // Maximum size extra data may be after Genesis. + ExpByteGas = big.NewInt(10) // Times ceil(log256(exponent)) for the EXP instruction. + SloadGas = big.NewInt(50) // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. + CallValueTransferGas = big.NewInt(9000) // Paid for CALL when the value transfer is non-zero. + CallNewAccountGas = big.NewInt(25000) // Paid for CALL when the destination address didn't exist prior. + TxGas = big.NewInt(21000) // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions. + TxGasContractCreation = big.NewInt(53000) // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. + TxDataZeroGas = big.NewInt(4) // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. + DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations. + QuadCoeffDiv = big.NewInt(512) // Divisor for the quadratic particle of the memory cost equation. + GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block. + DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. + SstoreSetGas = big.NewInt(20000) // Once per SLOAD operation. + LogDataGas = big.NewInt(8) // Per byte in a LOG* operation's data. + CallStipend = big.NewInt(2300) // Free gas given at beginning of call. + EcrecoverGas = big.NewInt(3000) // + Sha256WordGas = big.NewInt(12) // - Sha3Gas uint64 = 30 // Once per SHA3 operation. - Sha256Gas uint64 = 60 // - IdentityWordGas uint64 = 3 // - Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data. - SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero. - SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change. - SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero. - JumpdestGas uint64 = 1 // Refunded gas, once per SSTORE operation if the zeroness changes to zero. - IdentityGas uint64 = 15 // - EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. - CallGas uint64 = 40 // Once per CALL operation & message call transaction. - CreateDataGas uint64 = 200 // - Ripemd160Gas uint64 = 600 // - Ripemd160WordGas uint64 = 120 // - CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack. - ExpGas uint64 = 10 // Once per EXP instruction - LogGas uint64 = 375 // Per LOG* operation. - CopyGas uint64 = 3 // - StackLimit uint64 = 1024 // Maximum size of VM stack allowed. - TierStepGas uint64 = 0 // Once per operation, for a selection of them. - LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. - CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. - SuicideRefundGas uint64 = 24000 // Refunded following a suicide operation. - MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. - TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. + MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be. + GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block. + TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target - MaxCodeSize = 24576 -) + Sha3Gas = big.NewInt(30) // Once per SHA3 operation. + Sha256Gas = big.NewInt(60) // + IdentityWordGas = big.NewInt(3) // + Sha3WordGas = big.NewInt(6) // Once per word of the SHA3 operation's data. + SstoreResetGas = big.NewInt(5000) // Once per SSTORE operation if the zeroness changes from zero. + SstoreClearGas = big.NewInt(5000) // Once per SSTORE operation if the zeroness doesn't change. + SstoreRefundGas = big.NewInt(15000) // Once per SSTORE operation if the zeroness changes to zero. + JumpdestGas = big.NewInt(1) // Refunded gas, once per SSTORE operation if the zeroness changes to zero. + IdentityGas = big.NewInt(15) // + GasLimitBoundDivisor = big.NewInt(1024) // The bound divisor of the gas limit, used in update calculations. + EpochDuration = big.NewInt(30000) // Duration between proof-of-work epochs. + CallGas = big.NewInt(40) // Once per CALL operation & message call transaction. + CreateDataGas = big.NewInt(200) // + Ripemd160Gas = big.NewInt(600) // + Ripemd160WordGas = big.NewInt(120) // + MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. + CallCreateDepth = big.NewInt(1024) // Maximum depth of call/create stack. + ExpGas = big.NewInt(10) // Once per EXP instruction. + LogGas = big.NewInt(375) // Per LOG* operation. + CopyGas = big.NewInt(3) // + StackLimit = big.NewInt(1024) // Maximum size of VM stack allowed. + TierStepGas = big.NewInt(0) // Once per operation, for a selection of them. + LogTopicGas = big.NewInt(375) // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. + CreateGas = big.NewInt(32000) // Once per CREATE operation & contract-creation transaction. + SuicideRefundGas = big.NewInt(24000) // Refunded following a suicide operation. + MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. + TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. -var ( - GasLimitBoundDivisor = big.NewInt(1024) // The bound divisor of the gas limit, used in update calculations. - MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be. - GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block. - TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target - DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations. - GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block. - MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. - DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. + MaxCodeSize = 24576 ) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 01539de03e..470eb7cb7f 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -146,7 +146,7 @@ func runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, bt map[s } for name, test := range bt { - if skipTest[name] /*|| name != "CallingCanonicalContractFromFork_CALLCODE"*/ { + if skipTest[name] { glog.Infoln("Skipping block test", name) continue } diff --git a/tests/state_test.go b/tests/state_test.go index 0b77f72761..97c4e5eebf 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -237,13 +237,13 @@ func TestWallet(t *testing.T) { } func TestStateTestsRandom(t *testing.T) { - t.Skip() chainConfig := ¶ms.ChainConfig{ HomesteadBlock: big.NewInt(1150000), } fns, _ := filepath.Glob("./files/StateTests/RandomTests/*") for _, fn := range fns { + t.Log("running:", fn) if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil { t.Error(fn, err) } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index e8ab29d143..5469a4c71b 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -108,7 +108,7 @@ func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, ski } for name, test := range tests { - if skipTest[name] /*|| name != "JUMPDEST_Attack"*/ { + if skipTest[name] { glog.Infoln("Skipping state test", name) continue } diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 1edf0e425a..25e55886f4 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -129,7 +129,7 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error { } for name, test := range tests { - if skipTest[name] /*|| name != "exp0"*/ { + if skipTest[name] /*|| name != "loop_stacklimit_1021"*/ { glog.Infoln("Skipping VM test", name) continue } @@ -229,6 +229,6 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract) environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec) - ret, g, err := environment.Call(caller, to, data, gas.Uint64(), value) - return ret, statedb.Logs(), new(big.Int).SetUint64(g), err + ret, err := environment.Call(caller, to, data, gas, value) + return ret, statedb.Logs(), gas, err }