提交 0850f68f 编写于 作者: P Péter Szilágyi 提交者: GitHub

Merge pull request #3668 from obscuren/revert-gas64

Revert "params: core, core/vm, miner: 64bit gas instructions (#3514)"
...@@ -156,7 +156,7 @@ func run(ctx *cli.Context) error { ...@@ -156,7 +156,7 @@ func run(ctx *cli.Context) error {
ret, _, err = runtime.Create(input, &runtime.Config{ ret, _, err = runtime.Create(input, &runtime.Config{
Origin: sender.Address(), Origin: sender.Address(),
State: statedb, State: statedb,
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(), GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
Value: common.Big(ctx.GlobalString(ValueFlag.Name)), Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
EVMConfig: vm.Config{ EVMConfig: vm.Config{
...@@ -172,7 +172,7 @@ func run(ctx *cli.Context) error { ...@@ -172,7 +172,7 @@ func run(ctx *cli.Context) error {
ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
Origin: sender.Address(), Origin: sender.Address(),
State: statedb, State: statedb,
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(), GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
Value: common.Big(ctx.GlobalString(ValueFlag.Name)), Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
EVMConfig: vm.Config{ EVMConfig: vm.Config{
......
...@@ -205,7 +205,7 @@ func makeFullNode(ctx *cli.Context) *node.Node { ...@@ -205,7 +205,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
if err != nil { if err != nil {
glog.V(logger.Warn).Infoln("error setting canonical miner information:", err) 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.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
glog.V(logger.Debug).Infof("extra: %x\n", extra) glog.V(logger.Debug).Infof("extra: %x\n", extra)
extra = nil extra = nil
......
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
}
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)
}
}
}
...@@ -92,7 +92,6 @@ func genValueTx(nbytes int) func(int, *BlockGen) { ...@@ -92,7 +92,6 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
var ( var (
ringKeys = make([]*ecdsa.PrivateKey, 1000) ringKeys = make([]*ecdsa.PrivateKey, 1000)
ringAddrs = make([]common.Address, len(ringKeys)) ringAddrs = make([]common.Address, len(ringKeys))
bigTxGas = new(big.Int).SetUint64(params.TxGas)
) )
func init() { func init() {
...@@ -112,8 +111,8 @@ func genTxRing(naccounts int) func(int, *BlockGen) { ...@@ -112,8 +111,8 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) { return func(i int, gen *BlockGen) {
gas := CalcGasLimit(gen.PrevBlock(i - 1)) gas := CalcGasLimit(gen.PrevBlock(i - 1))
for { for {
gas.Sub(gas, bigTxGas) gas.Sub(gas, params.TxGas)
if gas.Cmp(bigTxGas) < 0 { if gas.Cmp(params.TxGas) < 0 {
break break
} }
to := (from + 1) % naccounts to := (from + 1) % naccounts
...@@ -121,7 +120,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { ...@@ -121,7 +120,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
gen.TxNonce(ringAddrs[from]), gen.TxNonce(ringAddrs[from]),
ringAddrs[to], ringAddrs[to],
benchRootFunds, benchRootFunds,
bigTxGas, params.TxGas,
nil, nil,
nil, nil,
) )
......
...@@ -204,7 +204,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b ...@@ -204,7 +204,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
// //
// See YP section 4.3.4. "Block Header Validity" // 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 { 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)) return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
} }
......
...@@ -719,7 +719,7 @@ func TestFastVsFullChains(t *testing.T) { ...@@ -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 the block number is multiple of 3, send a few bonus transactions to the miner
if i%3 == 2 { if i%3 == 2 {
for j := 0; j < i%4+1; j++ { 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 { if err != nil {
panic(err) panic(err)
} }
...@@ -883,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) { ...@@ -883,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
// Create two transactions shared between the chains: // Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain // - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number 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) 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), bigTxGas, 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: // Create two transactions that will be dropped by the forked chain:
// - pastDrop: transaction dropped retroactively from a past block // - pastDrop: transaction dropped retroactively from a past block
...@@ -900,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) { ...@@ -900,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: 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(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 gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
case 2: 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(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 gen.AddTx(swapped) // This transaction will be swapped out at the exact height
...@@ -925,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) { ...@@ -925,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) { chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: 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 gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
case 2: case 2:
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain 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 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 gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
case 3: 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 gen.AddTx(futureAdd) // This transaction will be added after a full reorg
} }
}) })
......
...@@ -56,13 +56,13 @@ func ExampleGenerateChain() { ...@@ -56,13 +56,13 @@ func ExampleGenerateChain() {
switch i { switch i {
case 0: case 0:
// In block 1, addr1 sends addr2 some ether. // 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) gen.AddTx(tx)
case 1: case 1:
// In block 2, addr1 sends some more ether to addr2. // In block 2, addr1 sends some more ether to addr2.
// addr2 passes it on to addr3. // addr2 passes it on to addr3.
tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key1) 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), bigTxGas, nil, nil), signer, key2) tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(tx1) gen.AddTx(tx1)
gen.AddTx(tx2) gen.AddTx(tx2)
case 2: case 2:
......
...@@ -49,16 +49,15 @@ The state transitioning model does all all the necessary work to work out a vali ...@@ -49,16 +49,15 @@ The state transitioning model does all all the necessary work to work out a vali
6) Derive new state root 6) Derive new state root
*/ */
type StateTransition struct { type StateTransition struct {
gp *GasPool gp *GasPool
msg Message msg Message
gas uint64 gas, gasPrice *big.Int
gasPrice *big.Int initialGas *big.Int
initialGas *big.Int value *big.Int
value *big.Int data []byte
data []byte state vm.StateDB
state vm.StateDB
env *vm.EVM
evm *vm.EVM
} }
// Message represents a message sent to a contract. // Message represents a message sent to a contract.
...@@ -82,14 +81,12 @@ func MessageCreatesContract(msg Message) bool { ...@@ -82,14 +81,12 @@ func MessageCreatesContract(msg Message) bool {
// IntrinsicGas computes the 'intrinsic gas' for a message // IntrinsicGas computes the 'intrinsic gas' for a message
// with the given data. // with the given data.
//
// TODO convert to uint64
func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
igas := new(big.Int) igas := new(big.Int)
if contractCreation && homestead { if contractCreation && homestead {
igas.SetUint64(params.TxGasContractCreation) igas.Set(params.TxGasContractCreation)
} else { } else {
igas.SetUint64(params.TxGas) igas.Set(params.TxGas)
} }
if len(data) > 0 { if len(data) > 0 {
var nz int64 var nz int64
...@@ -99,26 +96,27 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { ...@@ -99,26 +96,27 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
} }
} }
m := big.NewInt(nz) m := big.NewInt(nz)
m.Mul(m, new(big.Int).SetUint64(params.TxDataNonZeroGas)) m.Mul(m, params.TxDataNonZeroGas)
igas.Add(igas, m) igas.Add(igas, m)
m.SetInt64(int64(len(data)) - nz) m.SetInt64(int64(len(data)) - nz)
m.Mul(m, new(big.Int).SetUint64(params.TxDataZeroGas)) m.Mul(m, params.TxDataZeroGas)
igas.Add(igas, m) igas.Add(igas, m)
} }
return igas return igas
} }
// NewStateTransition initialises and returns a new state transition object. // 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{ return &StateTransition{
gp: gp, gp: gp,
evm: evm, env: env,
msg: msg, msg: msg,
gas: new(big.Int),
gasPrice: msg.GasPrice(), gasPrice: msg.GasPrice(),
initialGas: new(big.Int), initialGas: new(big.Int),
value: msg.Value(), value: msg.Value(),
data: msg.Data(), data: msg.Data(),
state: evm.StateDB, state: env.StateDB,
} }
} }
...@@ -129,8 +127,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition ...@@ -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 // 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 // indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block. // state and would never be accepted within a block.
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) { func ApplyMessage(env *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
st := NewStateTransition(evm, msg, gp) st := NewStateTransition(env, msg, gp)
ret, _, gasUsed, err := st.TransitionDb() ret, _, gasUsed, err := st.TransitionDb()
return ret, gasUsed, err return ret, gasUsed, err
...@@ -159,21 +157,21 @@ func (self *StateTransition) to() vm.Account { ...@@ -159,21 +157,21 @@ func (self *StateTransition) to() vm.Account {
return self.state.GetAccount(*to) return self.state.GetAccount(*to)
} }
func (self *StateTransition) useGas(amount uint64) error { func (self *StateTransition) useGas(amount *big.Int) error {
if self.gas < amount { if self.gas.Cmp(amount) < 0 {
return vm.ErrOutOfGas return vm.ErrOutOfGas
} }
self.gas -= amount self.gas.Sub(self.gas, amount)
return nil return nil
} }
func (self *StateTransition) addGas(amount *big.Int) {
self.gas.Add(self.gas, amount)
}
func (self *StateTransition) buyGas() error { func (self *StateTransition) buyGas() error {
mgas := self.msg.Gas() mgas := self.msg.Gas()
if mgas.BitLen() > 64 {
return vm.ErrOutOfGas
}
mgval := new(big.Int).Mul(mgas, self.gasPrice) mgval := new(big.Int).Mul(mgas, self.gasPrice)
sender := self.from() sender := self.from()
...@@ -183,8 +181,7 @@ func (self *StateTransition) buyGas() error { ...@@ -183,8 +181,7 @@ func (self *StateTransition) buyGas() error {
if err := self.gp.SubGas(mgas); err != nil { if err := self.gp.SubGas(mgas); err != nil {
return err return err
} }
self.gas += mgas.Uint64() self.addGas(mgas)
self.initialGas.Set(mgas) self.initialGas.Set(mgas)
sender.SubBalance(mgval) sender.SubBalance(mgval)
return nil return nil
...@@ -212,9 +209,7 @@ func (self *StateTransition) preCheck() (err error) { ...@@ -212,9 +209,7 @@ func (self *StateTransition) preCheck() (err error) {
return nil return nil
} }
// TransitionDb will transition the state by applying the current message and returning the result // TransitionDb will move the state by applying the message against the given environment.
// 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.
func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) { func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) {
if err = self.preCheck(); err != nil { if err = self.preCheck(); err != nil {
return return
...@@ -222,32 +217,26 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b ...@@ -222,32 +217,26 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
msg := self.msg msg := self.msg
sender := self.from() // err checked in preCheck 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) contractCreation := MessageCreatesContract(msg)
// Pay intrinsic gas // Pay intrinsic gas
// TODO convert to uint64 if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
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 {
return nil, nil, nil, InvalidTxError(err) return nil, nil, nil, InvalidTxError(err)
} }
var ( var (
evm = self.evm vmenv = self.env
// vm errors do not effect consensus and are therefor // vm errors do not effect consensus and are therefor
// not assigned to err, except for insufficient balance // not assigned to err, except for insufficient balance
// error. // error.
vmerr error vmerr error
) )
if contractCreation { 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 { } else {
// Increment the nonce for the next transaction // Increment the nonce for the next transaction
self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1) 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 { if vmerr != nil {
glog.V(logger.Core).Infoln("vm returned with error:", err) glog.V(logger.Core).Infoln("vm returned with error:", err)
...@@ -262,7 +251,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b ...@@ -262,7 +251,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
requiredGas = new(big.Int).Set(self.gasUsed()) requiredGas = new(big.Int).Set(self.gasUsed())
self.refundGas() 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 return ret, requiredGas, self.gasUsed(), err
} }
...@@ -271,21 +260,20 @@ func (self *StateTransition) refundGas() { ...@@ -271,21 +260,20 @@ func (self *StateTransition) refundGas() {
// Return eth for remaining gas to the sender account, // Return eth for remaining gas to the sender account,
// exchanged at the original rate. // exchanged at the original rate.
sender := self.from() // err already checked 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) sender.AddBalance(remaining)
// Apply refund counter, capped to half of the used gas. // Apply refund counter, capped to half of the used gas.
uhalf := remaining.Div(self.gasUsed(), common.Big2) uhalf := remaining.Div(self.gasUsed(), common.Big2)
refund := common.BigMin(uhalf, self.state.GetRefund()) 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)) self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
// Also return remaining gas to the block gas counter so it is // Also return remaining gas to the block gas counter so it is
// available for the next transaction. // 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 { 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)
} }
...@@ -21,11 +21,28 @@ import ( ...@@ -21,11 +21,28 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "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 ( var (
Pow256 = common.BigPow(2, 256) // Pow256 is 2**256
U256 = common.U256 // Shortcut to common.U256 U256 = common.U256 // Shortcut to common.U256
S256 = common.S256 // Shortcut to common.S256 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 // calculates the memory size required for a step
...@@ -37,6 +54,48 @@ func calcMemSize(off, l *big.Int) *big.Int { ...@@ -37,6 +54,48 @@ func calcMemSize(off, l *big.Int) *big.Int {
return new(big.Int).Add(off, l) 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 // 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. // up to size with zero's. This function is overflow safe.
func getData(data []byte, start, size *big.Int) []byte { func getData(data []byte, start, size *big.Int) []byte {
...@@ -47,17 +106,14 @@ 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())) return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
} }
// bigUint64 returns the integer casted to a uint64 and returns whether it // useGas attempts to subtract the amount of gas and returns whether it was
// overflowed in the process. // successful
func bigUint64(v *big.Int) (uint64, bool) { func useGas(gas, amount *big.Int) bool {
return v.Uint64(), v.BitLen() > 64 if gas.Cmp(amount) < 0 {
} return false
// 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
} }
return (size + 31) / 32 // Sub the amount of gas from the remaining
gas.Sub(gas, amount)
return true
} }
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
// ContractRef is a reference to the contract's backing object // ContractRef is a reference to the contract's backing object
type ContractRef interface { type ContractRef interface {
ReturnGas(*big.Int)
Address() common.Address Address() common.Address
Value() *big.Int Value() *big.Int
SetCode(common.Hash, []byte) SetCode(common.Hash, []byte)
...@@ -47,8 +48,7 @@ type Contract struct { ...@@ -47,8 +48,7 @@ type Contract struct {
CodeAddr *common.Address CodeAddr *common.Address
Input []byte Input []byte
Gas uint64 value, Gas, UsedGas *big.Int
value *big.Int
Args []byte Args []byte
...@@ -56,7 +56,7 @@ type Contract struct { ...@@ -56,7 +56,7 @@ type Contract struct {
} }
// NewContract returns a new contract environment for the execution of EVM. // 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} c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
if parent, ok := caller.(*Contract); ok { if parent, ok := caller.(*Contract); ok {
...@@ -68,8 +68,9 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin ...@@ -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 // Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition // 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.value = new(big.Int).Set(value)
c.UsedGas = new(big.Int)
return c return c
} }
...@@ -106,13 +107,27 @@ func (c *Contract) Caller() common.Address { ...@@ -106,13 +107,27 @@ func (c *Contract) Caller() common.Address {
return c.CallerAddress 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 // UseGas attempts the use gas and subtracts it and returns true on success
func (c *Contract) UseGas(gas uint64) (ok bool) { func (c *Contract) UseGas(gas *big.Int) (ok bool) {
if c.Gas < gas { ok = useGas(c.Gas, gas)
return false if ok {
c.UsedGas.Add(c.UsedGas, gas)
} }
c.Gas -= gas return
return true }
// 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 // Address returns the contracts address
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
package vm package vm
import ( import (
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
...@@ -28,8 +30,8 @@ import ( ...@@ -28,8 +30,8 @@ import (
// requires a deterministic gas count based on the input size of the Run method of the // requires a deterministic gas count based on the input size of the Run method of the
// contract. // contract.
type PrecompiledContract interface { type PrecompiledContract interface {
RequiredGas(inputSize int) uint64 // RequiredPrice calculates the contract gas use RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
Run(input []byte) []byte // Run runs the precompiled contract Run(input []byte) []byte // Run runs the precompiled contract
} }
// Precompiled contains the default set of ethereum contracts // Precompiled contains the default set of ethereum contracts
...@@ -55,7 +57,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr ...@@ -55,7 +57,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr
// ECRECOVER implemented as a native contract // ECRECOVER implemented as a native contract
type ecrecover struct{} type ecrecover struct{}
func (c *ecrecover) RequiredGas(inputSize int) uint64 { func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
return params.EcrecoverGas return params.EcrecoverGas
} }
...@@ -90,12 +92,10 @@ func (c *ecrecover) Run(in []byte) []byte { ...@@ -90,12 +92,10 @@ func (c *ecrecover) Run(in []byte) []byte {
// SHA256 implemented as a native contract // SHA256 implemented as a native contract
type sha256 struct{} type sha256 struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. func (c *sha256) RequiredGas(inputSize int) *big.Int {
// n := big.NewInt(int64(inputSize+31) / 32)
// This method does not require any overflow checking as the input size gas costs n.Mul(n, params.Sha256WordGas)
// required for anything significant is so high it's impossible to pay for. return n.Add(n, params.Sha256Gas)
func (c *sha256) RequiredGas(inputSize int) uint64 {
return uint64(inputSize+31)/32*params.Sha256WordGas + params.Sha256Gas
} }
func (c *sha256) Run(in []byte) []byte { func (c *sha256) Run(in []byte) []byte {
return crypto.Sha256(in) return crypto.Sha256(in)
...@@ -104,12 +104,10 @@ func (c *sha256) Run(in []byte) []byte { ...@@ -104,12 +104,10 @@ func (c *sha256) Run(in []byte) []byte {
// RIPMED160 implemented as a native contract // RIPMED160 implemented as a native contract
type ripemd160 struct{} type ripemd160 struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. func (c *ripemd160) RequiredGas(inputSize int) *big.Int {
// n := big.NewInt(int64(inputSize+31) / 32)
// This method does not require any overflow checking as the input size gas costs n.Mul(n, params.Ripemd160WordGas)
// required for anything significant is so high it's impossible to pay for. return n.Add(n, params.Ripemd160Gas)
func (c *ripemd160) RequiredGas(inputSize int) uint64 {
return uint64(inputSize+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas
} }
func (c *ripemd160) Run(in []byte) []byte { func (c *ripemd160) Run(in []byte) []byte {
return common.LeftPadBytes(crypto.Ripemd160(in), 32) return common.LeftPadBytes(crypto.Ripemd160(in), 32)
...@@ -118,12 +116,11 @@ func (c *ripemd160) Run(in []byte) []byte { ...@@ -118,12 +116,11 @@ func (c *ripemd160) Run(in []byte) []byte {
// data copy implemented as a native contract // data copy implemented as a native contract
type dataCopy struct{} type dataCopy struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. func (c *dataCopy) RequiredGas(inputSize int) *big.Int {
// n := big.NewInt(int64(inputSize+31) / 32)
// This method does not require any overflow checking as the input size gas costs n.Mul(n, params.IdentityWordGas)
// required for anything significant is so high it's impossible to pay for.
func (c *dataCopy) RequiredGas(inputSize int) uint64 { return n.Add(n, params.IdentityGas)
return uint64(inputSize+31)/32*params.IdentityWordGas + params.IdentityGas
} }
func (c *dataCopy) Run(in []byte) []byte { func (c *dataCopy) Run(in []byte) []byte {
return in return in
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package vm package vm
import ( import (
"fmt"
"math/big" "math/big"
"sync/atomic" "sync/atomic"
...@@ -101,18 +102,24 @@ func (evm *EVM) Cancel() { ...@@ -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 // 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 // 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. // 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 { 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 // Depth check execution. Fail if we're trying to execute above the
// limit. // limit.
if evm.depth > int(params.CallCreateDepth) { if evm.depth > int(params.CallCreateDepth.Int64()) {
return nil, gas, ErrDepth caller.ReturnGas(gas)
return nil, ErrDepth
} }
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
return nil, gas, ErrInsufficientBalance caller.ReturnGas(gas)
return nil, ErrInsufficientBalance
} }
var ( var (
...@@ -121,7 +128,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas ...@@ -121,7 +128,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
) )
if !evm.StateDB.Exist(addr) { if !evm.StateDB.Exist(addr) {
if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.BitLen() == 0 { 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) to = evm.StateDB.CreateAccount(addr)
...@@ -135,6 +143,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas ...@@ -135,6 +143,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// only. // only.
contract := NewContract(caller, to, value, gas) contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input) ret, err = evm.interpreter.Run(contract, input)
// When an error was returned by the EVM or when setting the creation code // 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 ...@@ -145,7 +154,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.StateDB.RevertToSnapshot(snapshot) 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 // 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 ...@@ -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. // 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. // 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 { 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 // Depth check execution. Fail if we're trying to execute above the
// limit. // limit.
if evm.depth > int(params.CallCreateDepth) { if evm.depth > int(params.CallCreateDepth.Int64()) {
return nil, gas, ErrDepth caller.ReturnGas(gas)
return nil, ErrDepth
} }
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 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 ( var (
...@@ -176,6 +191,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, ...@@ -176,6 +191,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// only. // only.
contract := NewContract(caller, to, value, gas) contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input) ret, err = evm.interpreter.Run(contract, input)
if err != nil { if err != nil {
...@@ -184,7 +200,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, ...@@ -184,7 +200,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
evm.StateDB.RevertToSnapshot(snapshot) 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. // 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, ...@@ -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 // 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. // 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 { 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 // Depth check execution. Fail if we're trying to execute above the
// limit. // limit.
if evm.depth > int(params.CallCreateDepth) { if evm.depth > int(params.CallCreateDepth.Int64()) {
return nil, gas, ErrDepth caller.ReturnGas(gas)
return nil, ErrDepth
} }
var ( var (
...@@ -211,6 +230,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by ...@@ -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 // Iinitialise a new contract and make initialise the delegate values
contract := NewContract(caller, to, caller.Value(), gas).AsDelegate() contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input) ret, err = evm.interpreter.Run(contract, input)
if err != nil { if err != nil {
...@@ -219,22 +239,28 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by ...@@ -219,22 +239,28 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
} }
return ret, contract.Gas, err return ret, err
} }
// Create creates a new contract using code as deployment code. // 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 { 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 // Depth check execution. Fail if we're trying to execute above the
// limit. // limit.
if evm.depth > int(params.CallCreateDepth) { if evm.depth > int(params.CallCreateDepth.Int64()) {
return nil, common.Address{}, gas, ErrDepth caller.ReturnGas(gas)
return nil, common.Address{}, ErrDepth
} }
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 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 // Create a new account on the state
...@@ -254,6 +280,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I ...@@ -254,6 +280,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
// only. // only.
contract := NewContract(caller, to, value, gas) contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, nil) ret, err = evm.interpreter.Run(contract, nil)
...@@ -264,8 +291,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I ...@@ -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 // be stored due to not enough gas set an error and let it be handled
// by the error checking condition below. // by the error checking condition below.
if err == nil && !maxCodeSizeExceeded { if err == nil && !maxCodeSizeExceeded {
createDataGas := uint64(len(ret)) * params.CreateDataGas dataGas := big.NewInt(int64(len(ret)))
if contract.UseGas(createDataGas) { dataGas.Mul(dataGas, params.CreateDataGas)
if contract.UseGas(dataGas) {
evm.StateDB.SetCode(contractAddr, ret) evm.StateDB.SetCode(contractAddr, ret)
} else { } else {
err = ErrCodeStoreOutOfGas err = ErrCodeStoreOutOfGas
...@@ -277,10 +305,11 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I ...@@ -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. // when we're in homestead this also counts for code storage gas errors.
if maxCodeSizeExceeded || if maxCodeSizeExceeded ||
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
contract.UseGas(contract.Gas)
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
// Nothing should be returned when an error is thrown. // 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. // 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 // 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 ...@@ -289,7 +318,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
ret = nil ret = nil
} }
return ret, contractAddr, contract.Gas, err return ret, contractAddr, err
} }
// ChainConfig returns the evmironment's chain configuration // ChainConfig returns the evmironment's chain configuration
......
...@@ -17,42 +17,149 @@ ...@@ -17,42 +17,149 @@
package vm package vm
import ( import (
"fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
const ( var (
GasQuickStep uint64 = 2 GasQuickStep = big.NewInt(2)
GasFastestStep uint64 = 3 GasFastestStep = big.NewInt(3)
GasFastStep uint64 = 5 GasFastStep = big.NewInt(5)
GasMidStep uint64 = 8 GasMidStep = big.NewInt(8)
GasSlowStep uint64 = 10 GasSlowStep = big.NewInt(10)
GasExtStep uint64 = 20 GasExtStep = big.NewInt(20)
GasReturn uint64 = 0 GasReturn = big.NewInt(0)
GasStop uint64 = 0 GasStop = big.NewInt(0)
GasContractByte uint64 = 200
GasContractByte = big.NewInt(200)
n64 = big.NewInt(64)
) )
// calcGas returns the actual gas cost of the call. // 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 // 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. // to be implemented. The returned gas is gas - base * 63 / 64.
func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) { func callGas(gasTable params.GasTable, availableGas, base, callCost *big.Int) *big.Int {
if gasTable.CreateBySuicide > 0 { if gasTable.CreateBySuicide != nil {
availableGas = availableGas - base availableGas = new(big.Int).Sub(availableGas, base)
gas := availableGas - availableGas/64 g := new(big.Int).Div(availableGas, n64)
// If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150 g.Sub(availableGas, g)
// is smaller than the requested amount. Therefor we return the new gas instead
// of returning an error. if g.Cmp(callCost) < 0 {
if callCost.BitLen() > 64 || gas < callCost.Uint64() { return g
return gas, nil
} }
} }
if callCost.BitLen() > 64 { return callCost
return 0, errGasUintOverflow }
// 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},
} }
package vm package vm
import ( import (
gmath "math"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
// memoryGasCosts calculates the quadratic gas for memory expansion. It does so func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int {
// only for the memory region that is expanded, not the total memory. gas := new(big.Int)
func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { if newMemSize.Cmp(common.Big0) > 0 {
// The maximum that will fit in a uint64 is max_word_count - 1 newMemSizeWords := toWordSize(newMemSize)
// anything above that will result in an overflow.
if newMemSize > gmath.MaxUint64-32 { if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
return 0, errGasUintOverflow // be careful reusing variables here when changing.
} // The order has been optimised to reduce allocation
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
if newMemSize == 0 { pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
return 0, nil linCoef := oldSize.Mul(oldSize, params.MemoryGas)
} quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
newMemSizeWords := toWordSize(newMemSize)
newMemSize = newMemSizeWords * 32 pow.Exp(newMemSizeWords, common.Big2, Zero)
linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
if newMemSize > uint64(mem.Len()) { quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
square := newMemSizeWords * newMemSizeWords newTotalFee := linCoef.Add(linCoef, quadCoef)
linCoef := newMemSizeWords * params.MemoryGas
quadCoef := square / params.QuadCoeffDiv fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
newTotalFee := linCoef + quadCoef gas.Add(gas, fee)
}
fee := newTotalFee - mem.lastGasCost
mem.lastGasCost = newTotalFee
return fee, nil
} }
return 0, nil return gas
} }
func constGasFunc(gas uint64) gasFunc { func constGasFunc(gas *big.Int) gasFunc {
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
return gas, nil return gas
} }
} }
func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
gas, err := memoryGasCost(mem, memorySize) gas := memoryGasCost(mem, memorySize)
if err != nil { gas.Add(gas, GasFastestStep)
return 0, err words := toWordSize(stack.Back(2))
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
words, overflow := bigUint64(stack.Back(2)) return gas.Add(gas, words.Mul(words, params.CopyGas))
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
} }
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 ( var (
y, x = stack.Back(1), stack.Back(0) 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 // This checks for 3 scenario's and calculates gas accordingly
// 1. From a zero-value address to a non-zero value (NEW VALUE) // 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 ...@@ -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) // 3. From a non-zero to a non-zero (CHANGE)
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
// 0 => non 0 // 0 => non 0
return params.SstoreSetGas, nil return new(big.Int).Set(params.SstoreSetGas)
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { } 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 { } else {
// non 0 => non 0 (or 0 => 0) // non 0 => non 0 (or 0 => 0)
return params.SstoreResetGas, nil return new(big.Int).Set(params.SstoreResetGas)
} }
} }
func makeGasLog(n uint64) gasFunc { func makeGasLog(n uint) gasFunc {
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
requestedSize, overflow := bigUint64(stack.Back(1)) mSize := stack.Back(1)
if overflow {
return 0, errGasUintOverflow
}
gas, err := memoryGasCost(mem, memorySize) gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas)
if err != nil { gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
return 0, err gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
} return gas
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
} }
} }
func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
var overflow bool gas := memoryGasCost(mem, memorySize)
gas, err := memoryGasCost(mem, memorySize) gas.Add(gas, params.Sha3Gas)
if err != nil { words := toWordSize(stack.Back(1))
return 0, err return gas.Add(gas, words.Mul(words, params.Sha3WordGas))
}
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 gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
gas, err := memoryGasCost(mem, memorySize) gas := memoryGasCost(mem, memorySize)
if err != nil { gas.Add(gas, GasFastestStep)
return 0, err words := toWordSize(stack.Back(2))
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
wordGas, overflow := bigUint64(stack.Back(2)) return gas.Add(gas, words.Mul(words, params.CopyGas))
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
} }
func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
gas, err := memoryGasCost(mem, memorySize) gas := memoryGasCost(mem, memorySize)
if err != nil { gas.Add(gas, gt.ExtcodeCopy)
return 0, err words := toWordSize(stack.Back(3))
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
return 0, errGasUintOverflow
}
wordGas, overflow := bigUint64(stack.Back(3))
if overflow {
return 0, errGasUintOverflow
}
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, wordGas); overflow { return gas.Add(gas, words.Mul(words, params.CopyGas))
return 0, errGasUintOverflow
}
return gas, nil
} }
func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
var overflow bool return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
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, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
var overflow bool return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
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, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
var overflow bool return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
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 gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
var overflow bool return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize))
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 gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
return gt.Balance, nil return gt.Balance
} }
func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
return gt.ExtcodeSize, nil return gt.ExtcodeSize
} }
func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
return gt.SLoad, nil return gt.SLoad
} }
func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8)
gas := big.NewInt(expByteLen)
var ( gas.Mul(gas, gt.ExpByte)
gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas return gas.Add(gas, GasSlowStep)
overflow bool
)
if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
return 0, errGasUintOverflow
}
return gas, nil
} }
func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 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 ( var (
gas = gt.Calls address = common.BigToAddress(stack.Back(1))
transfersValue = stack.Back(2).BitLen() > 0 eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
address = common.BigToAddress(stack.Back(1))
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
) )
if eip158 { if eip158 {
if evm.StateDB.Empty(address) && transfersValue { if env.StateDB.Empty(address) && transfersValue {
gas += params.CallNewAccountGas gas.Add(gas, params.CallNewAccountGas)
} }
} else if !evm.StateDB.Exist(address) { } else if !env.StateDB.Exist(address) {
gas += params.CallNewAccountGas gas.Add(gas, params.CallNewAccountGas)
} }
if transfersValue { if transfersValue {
gas += params.CallValueTransferGas gas.Add(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, memoryGasCost(mem, memorySize))
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
if err != nil {
return 0, err
}
// Replace the stack item with the new gas calculation. This means that // 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: // either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64 // (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is // 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* // called. This information is otherwise lost due to the dependency on *current*
// available gas. // 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 gas.Add(gas, cg)
return 0, errGasUintOverflow
}
return gas, nil
} }
func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
gas := gt.Calls gas := new(big.Int).Set(gt.Calls)
if stack.Back(2).BitLen() > 0 { if stack.Back(2).BitLen() > 0 {
gas += params.CallValueTransferGas gas.Add(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, memoryGasCost(mem, memorySize))
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
if err != nil {
return 0, err
}
// Replace the stack item with the new gas calculation. This means that // 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: // either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64 // (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is // 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* // called. This information is otherwise lost due to the dependency on *current*
// available gas. // 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 gas.Add(gas, cg)
return 0, errGasUintOverflow
}
return gas, nil
} }
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) return memoryGasCost(mem, memorySize)
} }
func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
var gas uint64 gas := new(big.Int)
// EIP150 homestead gas reprice fork: // EIP150 homestead gas reprice fork:
if evm.ChainConfig().IsEIP150(evm.BlockNumber) { if env.ChainConfig().IsEIP150(env.BlockNumber) {
gas = gt.Suicide gas.Set(gt.Suicide)
var ( var (
address = common.BigToAddress(stack.Back(0)) address = common.BigToAddress(stack.Back(0))
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
) )
if eip158 { if eip158 {
// if empty and transfers value // if empty and transfers value
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).BitLen() > 0 { if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 {
gas += gt.CreateBySuicide gas.Add(gas, gt.CreateBySuicide)
} }
} else if !evm.StateDB.Exist(address) { } else if !env.StateDB.Exist(address) {
gas += gt.CreateBySuicide gas.Add(gas, gt.CreateBySuicide)
} }
} }
if !evm.StateDB.HasSuicided(contract.Address()) { if !env.StateDB.HasSuicided(contract.Address()) {
evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas)) 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) { func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
gas, err := memoryGasCost(mem, memorySize) gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize))
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
return 0, errGasUintOverflow
}
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
if err != nil {
return 0, err
}
// Replace the stack item with the new gas calculation. This means that // 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: // either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64 // (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is // We replace the stack item so that it's available when the opCall instruction is
// called. // 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 gas.Add(gas, cg)
return 0, errGasUintOverflow
}
return gas, nil
} }
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
return GasFastestStep, nil return GasFastestStep
} }
func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
return GasFastestStep, nil return GasFastestStep
} }
func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
return GasFastestStep, nil return GasFastestStep
} }
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")
}
}
此差异已折叠。
// +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))
}
}
}
// +build !VERIFY_EVM_INTEGER_POOL
package vm
const verifyPool = false
func verifyIntegerPool(ip *intPool) {}
此差异已折叠。
...@@ -56,7 +56,7 @@ func TestStoreCapture(t *testing.T) { ...@@ -56,7 +56,7 @@ func TestStoreCapture(t *testing.T) {
logger = NewStructLogger(nil) logger = NewStructLogger(nil)
mem = NewMemory() mem = NewMemory()
stack = newstack() 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(1))
stack.push(big.NewInt(0)) stack.push(big.NewInt(0))
...@@ -78,7 +78,7 @@ func TestStorageCapture(t *testing.T) { ...@@ -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") 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 ( var (
ref = &dummyContractRef{} 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}) env = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
logger = NewStructLogger(nil) logger = NewStructLogger(nil)
mem = NewMemory() mem = NewMemory()
......
...@@ -20,12 +20,11 @@ import "fmt" ...@@ -20,12 +20,11 @@ import "fmt"
// Memory implements a simple memory model for the ethereum virtual machine. // Memory implements a simple memory model for the ethereum virtual machine.
type Memory struct { type Memory struct {
store []byte store []byte
lastGasCost uint64
} }
func NewMemory() *Memory { func NewMemory() *Memory {
return &Memory{} return &Memory{nil}
} }
// Set sets offset + size to value // Set sets offset + size to value
......
...@@ -202,7 +202,7 @@ const ( ...@@ -202,7 +202,7 @@ const (
RETURN RETURN
DELEGATECALL DELEGATECALL
SUICIDE = 0xff SELFDESTRUCT = 0xff
) )
// Since the opcodes aren't all in order we can't use a regular slice // Since the opcodes aren't all in order we can't use a regular slice
...@@ -355,7 +355,7 @@ var opCodeToString = map[OpCode]string{ ...@@ -355,7 +355,7 @@ var opCodeToString = map[OpCode]string{
RETURN: "RETURN", RETURN: "RETURN",
CALLCODE: "CALLCODE", CALLCODE: "CALLCODE",
DELEGATECALL: "DELEGATECALL", DELEGATECALL: "DELEGATECALL",
SUICIDE: "SUICIDE", SELFDESTRUCT: "SELFDESTRUCT",
PUSH: "PUSH", PUSH: "PUSH",
DUP: "DUP", DUP: "DUP",
...@@ -501,7 +501,7 @@ var stringToOp = map[string]OpCode{ ...@@ -501,7 +501,7 @@ var stringToOp = map[string]OpCode{
"CALL": CALL, "CALL": CALL,
"RETURN": RETURN, "RETURN": RETURN,
"CALLCODE": CALLCODE, "CALLCODE": CALLCODE,
"SUICIDE": SUICIDE, "SELFDESTRUCT": SELFDESTRUCT,
} }
func StringToOp(str string) OpCode { func StringToOp(str string) OpCode {
......
...@@ -36,7 +36,7 @@ func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM { ...@@ -36,7 +36,7 @@ func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM {
BlockNumber: cfg.BlockNumber, BlockNumber: cfg.BlockNumber,
Time: cfg.Time, Time: cfg.Time,
Difficulty: cfg.Difficulty, Difficulty: cfg.Difficulty,
GasLimit: new(big.Int).SetUint64(cfg.GasLimit), GasLimit: cfg.GasLimit,
GasPrice: new(big.Int), GasPrice: new(big.Int),
} }
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
package runtime package runtime
import ( import (
"math"
"math/big" "math/big"
"time" "time"
...@@ -38,7 +37,7 @@ type Config struct { ...@@ -38,7 +37,7 @@ type Config struct {
Coinbase common.Address Coinbase common.Address
BlockNumber *big.Int BlockNumber *big.Int
Time *big.Int Time *big.Int
GasLimit uint64 GasLimit *big.Int
GasPrice *big.Int GasPrice *big.Int
Value *big.Int Value *big.Int
DisableJit bool // "disable" so it's enabled by default DisableJit bool // "disable" so it's enabled by default
...@@ -69,8 +68,8 @@ func setDefaults(cfg *Config) { ...@@ -69,8 +68,8 @@ func setDefaults(cfg *Config) {
if cfg.Time == nil { if cfg.Time == nil {
cfg.Time = big.NewInt(time.Now().Unix()) cfg.Time = big.NewInt(time.Now().Unix())
} }
if cfg.GasLimit == 0 { if cfg.GasLimit == nil {
cfg.GasLimit = math.MaxUint64 cfg.GasLimit = new(big.Int).Set(common.MaxBig)
} }
if cfg.GasPrice == nil { if cfg.GasPrice == nil {
cfg.GasPrice = new(big.Int) cfg.GasPrice = new(big.Int)
...@@ -113,7 +112,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { ...@@ -113,7 +112,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
receiver.SetCode(crypto.Keccak256Hash(code), code) receiver.SetCode(crypto.Keccak256Hash(code), code)
// Call the code with the given configuration. // Call the code with the given configuration.
ret, _, err := vmenv.Call( ret, err := vmenv.Call(
sender, sender,
receiver.Address(), receiver.Address(),
input, input,
...@@ -141,13 +140,12 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) { ...@@ -141,13 +140,12 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) {
) )
// Call the code with the given configuration. // Call the code with the given configuration.
code, address, _, err := vmenv.Create( return vmenv.Create(
sender, sender,
input, input,
cfg.GasLimit, cfg.GasLimit,
cfg.Value, cfg.Value,
) )
return code, address, err
} }
// Call executes the code given by the contract's address. It will return the // 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) { ...@@ -162,7 +160,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) {
sender := cfg.State.GetOrNewStateObject(cfg.Origin) sender := cfg.State.GetOrNewStateObject(cfg.Origin)
// Call the code with the given configuration. // Call the code with the given configuration.
ret, _, err := vmenv.Call( ret, err := vmenv.Call(
sender, sender,
address, address,
input, input,
......
...@@ -39,8 +39,8 @@ func TestDefaults(t *testing.T) { ...@@ -39,8 +39,8 @@ func TestDefaults(t *testing.T) {
if cfg.Time == nil { if cfg.Time == nil {
t.Error("expected time to be non nil") t.Error("expected time to be non nil")
} }
if cfg.GasLimit == 0 { if cfg.GasLimit == nil {
t.Error("didn't expect gaslimit to be zero") t.Error("expected time to be non nil")
} }
if cfg.GasPrice == nil { if cfg.GasPrice == nil {
t.Error("expected time to be non nil") t.Error("expected time to be non nil")
......
...@@ -6,15 +6,23 @@ import ( ...@@ -6,15 +6,23 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
func makeStackFunc(pop, push int) stackValidationFunc { func makeStackFunc(pop, diff int) stackValidationFunc {
return func(stack *Stack) error { return func(stack *Stack) error {
if err := stack.require(pop); err != nil { if err := stack.require(pop); err != nil {
return err 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 fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
} }
return nil return nil
} }
} }
func makeDupStackFunc(n int) stackValidationFunc {
return makeStackFunc(n, 1)
}
func makeSwapStackFunc(n int) stackValidationFunc {
return makeStackFunc(n, 0)
}
// Copyright 2017 The go-ethereum Authors // Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
...@@ -16,34 +16,7 @@ ...@@ -16,34 +16,7 @@
package vm package vm
import "math/big" // VirtualMachine is an EVM interface
type VirtualMachine interface {
var checkVal = big.NewInt(-42) Run(*Contract, []byte) ([]byte, error)
// 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)
}
} }
...@@ -23,7 +23,6 @@ import ( ...@@ -23,7 +23,6 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
...@@ -61,7 +60,6 @@ type Interpreter struct { ...@@ -61,7 +60,6 @@ type Interpreter struct {
env *EVM env *EVM
cfg Config cfg Config
gasTable params.GasTable gasTable params.GasTable
intPool *intPool
} }
// NewInterpreter returns a new instance of the Interpreter. // NewInterpreter returns a new instance of the Interpreter.
...@@ -77,7 +75,6 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter { ...@@ -77,7 +75,6 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter {
env: env, env: env,
cfg: cfg, cfg: cfg,
gasTable: env.ChainConfig().GasTable(env.BlockNumber), gasTable: env.ChainConfig().GasTable(env.BlockNumber),
intPool: newIntPool(),
} }
} }
...@@ -109,18 +106,14 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e ...@@ -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. // 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. // 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 pc = uint64(0) // program counter
cost uint64 cost *big.Int
) )
contract.Input = input 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. // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
defer func() { defer func() {
if err != nil && evm.cfg.Debug { if err != nil && evm.cfg.Debug {
// XXX For debugging evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
//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)
} }
}() }()
...@@ -133,7 +126,7 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e ...@@ -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 // 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 execution of one of the operations or until the evm.done is set by
// the parent context.Context. // the parent context.Context.
for atomic.LoadInt32(&evm.env.abort) == 0 { for atomic.LoadInt32(&evm.env.abort) == 0 {
...@@ -154,47 +147,34 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e ...@@ -154,47 +147,34 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
return nil, err return nil, err
} }
var memorySize uint64 var memorySize *big.Int
// calculate the new memory size and expand the memory to fit // calculate the new memory size and expand the memory to fit
// the operation // the operation
if operation.memorySize != nil { if operation.memorySize != nil {
memSize, overflow := bigUint64(operation.memorySize(stack)) memorySize = operation.memorySize(stack)
if overflow {
return nil, errGasUintOverflow
}
// memory is expanded in words of 32 bytes. Gas // memory is expanded in words of 32 bytes. Gas
// is also calculated in words. // is also calculated in words.
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { memorySize.Mul(toWordSize(memorySize), big.NewInt(32))
return nil, errGasUintOverflow
}
} }
if !evm.cfg.DisableGasMetering { if !evm.cfg.DisableGasMetering {
// consume the gas and return an error if not enough gas is available. // 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 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) cost = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize)
if err != nil || !contract.UseGas(cost) { if !contract.UseGas(cost) {
return nil, ErrOutOfGas return nil, ErrOutOfGas
} }
} }
if memorySize > 0 { if memorySize != nil {
mem.Resize(memorySize) mem.Resize(memorySize.Uint64())
} }
if evm.cfg.Debug { 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, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, 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 // execute the operation
res, err := operation.execute(&pc, evm.env, contract, mem, stack) 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 { switch {
case err != nil: case err != nil:
return nil, err return nil, err
......
...@@ -106,14 +106,14 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { ...@@ -106,14 +106,14 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash) 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 statedb := state.(EthApiState).state
from := statedb.GetOrNewStateObject(msg.From()) from := statedb.GetOrNewStateObject(msg.From())
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
vmError := func() error { return nil } vmError := func() error { return nil }
context := core.NewEVMContext(msg, header, b.eth.BlockChain()) 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 { func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
......
...@@ -69,7 +69,7 @@ func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Add ...@@ -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. // 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) { 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)) 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 // ContractCall implements bind.ContractCaller executing an Ethereum contract
...@@ -77,7 +77,7 @@ func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg ...@@ -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. // against the pending block, not the stable head of the chain.
func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) {
out, err := b.bcapi.Call(ctx, toCallArgs(msg), rpc.PendingBlockNumber) 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 { func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs {
......
...@@ -49,12 +49,12 @@ var ( ...@@ -49,12 +49,12 @@ var (
MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request
MaxStateFetch = 384 // Amount of node state values to allow fetching per request MaxStateFetch = 384 // Amount of node state values to allow fetching per request
MaxForkAncestry = 3 * params.EpochDuration // Maximum chain reorganisation MaxForkAncestry = 3 * params.EpochDuration.Uint64() // Maximum chain reorganisation
rttMinEstimate = 2 * time.Second // Minimum round-trip time to target for download requests 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 rttMaxEstimate = 20 * time.Second // Maximum rount-trip time to target for download requests
rttMinConfidence = 0.1 // Worse confidence factor in our estimated RTT value rttMinConfidence = 0.1 // Worse confidence factor in our estimated RTT value
ttlScaling = 3 // Constant scaling factor for RTT -> TTL conversion ttlScaling = 3 // Constant scaling factor for RTT -> TTL conversion
ttlLimit = time.Minute // Maximum TTL allowance to prevent reaching crazy timeouts ttlLimit = time.Minute // Maximum TTL allowance to prevent reaching crazy timeouts
qosTuningPeers = 5 // Number of peers to tune based on (best peers) qosTuningPeers = 5 // Number of peers to tune based on (best peers)
qosConfidenceCap = 10 // Number of peers above which not to modify RTT confidence qosConfidenceCap = 10 // Number of peers above which not to modify RTT confidence
......
...@@ -119,7 +119,7 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren ...@@ -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 the block number is multiple of 3, send a bonus transaction to the miner
if parent == dl.genesis && i%3 == 0 { if parent == dl.genesis && i%3 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) 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 { if err != nil {
panic(err) panic(err)
} }
......
...@@ -51,7 +51,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common ...@@ -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 the block number is multiple of 3, send a bonus transaction to the miner
if parent == genesis && i%3 == 0 { if parent == genesis && i%3 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) 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 { if err != nil {
panic(err) panic(err)
} }
......
...@@ -36,8 +36,6 @@ import ( ...@@ -36,8 +36,6 @@ import (
"github.com/ethereum/go-ethereum/params" "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. // Tests that protocol versions and modes of operations are matched up properly.
func TestProtocolCompatibility(t *testing.T) { func TestProtocolCompatibility(t *testing.T) {
// Define the compatibility chart // Define the compatibility chart
...@@ -314,13 +312,13 @@ func testGetNodeData(t *testing.T, protocol int) { ...@@ -314,13 +312,13 @@ func testGetNodeData(t *testing.T, protocol int) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // 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) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // 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) 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), bigTxGas, nil, nil), signer, acc1Key) tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
case 2: case 2:
...@@ -406,13 +404,13 @@ func testGetReceipt(t *testing.T, protocol int) { ...@@ -406,13 +404,13 @@ func testGetReceipt(t *testing.T, protocol int) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // 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) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // 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) 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), bigTxGas, nil, nil), signer, acc1Key) tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
case 2: case 2:
......
...@@ -48,8 +48,6 @@ import ( ...@@ -48,8 +48,6 @@ import (
const defaultGas = 90000 const defaultGas = 90000
var emptyHex = "0x"
// PublicEthereumAPI provides an API to access Ethereum related information. // PublicEthereumAPI provides an API to access Ethereum related information.
// It offers only methods that operate on public data that is freely available to anyone. // It offers only methods that operate on public data that is freely available to anyone.
type PublicEthereumAPI struct { type PublicEthereumAPI struct {
...@@ -576,12 +574,12 @@ type CallArgs struct { ...@@ -576,12 +574,12 @@ type CallArgs struct {
Data hexutil.Bytes `json:"data"` 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()) 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) state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil { 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 // Set sender address or use a default if none specified
addr := args.From addr := args.From
...@@ -591,59 +589,40 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr ...@@ -591,59 +589,40 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
addr = accounts[0].Address addr = accounts[0].Address
} }
} }
} else {
addr = args.From
} }
// Set default gas & gas price if none were set // Set default gas & gas price if none were set
gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt() gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt()
if gas.BitLen() == 0 { if gas.Cmp(common.Big0) == 0 {
gas = big.NewInt(50000000) gas = big.NewInt(50000000)
} }
if gasPrice.BitLen() == 0 { if gasPrice.Cmp(common.Big0) == 0 {
gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) 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) 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 // Execute the call and return
// or, in case of unmetered gas, setup a context with a timeout. vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
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)
if err != nil { if err != nil {
return nil, common.Big0, err return "0x", 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.
gp := new(core.GasPool).AddGas(common.MaxBig) 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 { 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. // 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. // 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) { func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, error) {
result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true}) result, _, err := s.doCall(ctx, args, blockNr)
return (hexutil.Bytes)(result), err return result, err
} }
// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction. // 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) (* ...@@ -665,7 +644,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*
mid := (hi + lo) / 2 mid := (hi + lo) / 2
(*big.Int)(&args.Gas).SetUint64(mid) (*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 the transaction became invalid or used all the gas (failed), raise the gas limit
if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 { if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 {
......
...@@ -51,7 +51,7 @@ type Backend interface { ...@@ -51,7 +51,7 @@ type Backend interface {
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetTd(blockHash common.Hash) *big.Int 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 // TxPool API
SendTx(ctx context.Context, signedTx *types.Transaction) error SendTx(ctx context.Context, signedTx *types.Transaction) error
RemoveTx(txHash common.Hash) RemoveTx(txHash common.Hash)
......
...@@ -45,7 +45,7 @@ func (account) ForEachStorage(cb func(key, value common.Hash) bool) {} ...@@ -45,7 +45,7 @@ func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
func runTrace(tracer *JavascriptTracer) (interface{}, error) { func runTrace(tracer *JavascriptTracer) (interface{}, error) {
env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) 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} contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
_, err := env.Interpreter().Run(contract, []byte{}) _, err := env.Interpreter().Run(contract, []byte{})
...@@ -134,7 +134,7 @@ func TestHaltBetweenSteps(t *testing.T) { ...@@ -134,7 +134,7 @@ func TestHaltBetweenSteps(t *testing.T) {
} }
env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) 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) tracer.CaptureState(env, 0, 0, big.NewInt(0), big.NewInt(0), nil, nil, contract, 0, nil)
timeout := errors.New("stahp") timeout := errors.New("stahp")
......
...@@ -88,7 +88,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int { ...@@ -88,7 +88,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash) 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() stateDb := state.(*light.LightState).Copy()
addr := msg.From() addr := msg.From()
from, err := stateDb.GetOrNewStateObject(ctx, addr) from, err := stateDb.GetOrNewStateObject(ctx, addr)
...@@ -99,7 +99,7 @@ func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state etha ...@@ -99,7 +99,7 @@ func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state etha
vmstate := light.NewVMState(ctx, stateDb) vmstate := light.NewVMState(ctx, stateDb)
context := core.NewEVMContext(msg, header, b.eth.blockchain) 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 { func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
......
...@@ -57,8 +57,6 @@ var ( ...@@ -57,8 +57,6 @@ var (
testContractDeployed = uint64(2) testContractDeployed = uint64(2)
testBufLimit = uint64(100) testBufLimit = uint64(100)
bigTxGas = new(big.Int).SetUint64(params.TxGas)
) )
/* /*
...@@ -82,15 +80,15 @@ func testChainGen(i int, block *core.BlockGen) { ...@@ -82,15 +80,15 @@ func testChainGen(i int, block *core.BlockGen) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // 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) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
// acc1Addr creates a test contract. // 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) 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++ nonce++
tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode), signer, acc1Key) tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode), signer, acc1Key)
testContractAddr = crypto.CreateAddress(acc1Addr, nonce) testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
......
...@@ -49,8 +49,6 @@ var ( ...@@ -49,8 +49,6 @@ var (
testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056")
testContractAddr common.Address testContractAddr common.Address
bigTxGas = new(big.Int).SetUint64(params.TxGas)
) )
type testOdr struct { type testOdr struct {
...@@ -207,15 +205,15 @@ func testChainGen(i int, block *core.BlockGen) { ...@@ -207,15 +205,15 @@ func testChainGen(i int, block *core.BlockGen) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // 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) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
// acc1Addr creates a test contract. // 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) 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++ nonce++
tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode), signer, acc1Key) tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode), signer, acc1Key)
testContractAddr = crypto.CreateAddress(acc1Addr, nonce) testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
......
...@@ -77,7 +77,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) { ...@@ -77,7 +77,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) {
func TestTxPool(t *testing.T) { func TestTxPool(t *testing.T) {
for i := range testTx { 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 ( var (
......
...@@ -171,7 +171,7 @@ func (self *Miner) HashRate() (tot int64) { ...@@ -171,7 +171,7 @@ func (self *Miner) HashRate() (tot int64) {
} }
func (self *Miner) SetExtra(extra []byte) error { 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) return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
} }
self.worker.setExtra(extra) self.worker.setExtra(extra)
......
...@@ -16,35 +16,41 @@ ...@@ -16,35 +16,41 @@
package params package params
import "math/big"
type GasTable struct { type GasTable struct {
ExtcodeSize uint64 ExtcodeSize *big.Int
ExtcodeCopy uint64 ExtcodeCopy *big.Int
Balance uint64 Balance *big.Int
SLoad uint64 SLoad *big.Int
Calls uint64 Calls *big.Int
Suicide uint64 Suicide *big.Int
ExpByte uint64 ExpByte *big.Int
// CreateBySuicide occurs when the // CreateBySuicide occurs when the
// refunded account is one that does // refunded account is one that does
// not exist. This logic is similar // not exist. This logic is similar
// to call. May be left nil. Nil means // to call. May be left nil. Nil means
// not charged. // not charged.
CreateBySuicide uint64 CreateBySuicide *big.Int
} }
var ( var (
// GasTableHomestead contain the gas prices for // GasTableHomestead contain the gas prices for
// the homestead phase. // the homestead phase.
GasTableHomestead = GasTable{ GasTableHomestead = GasTable{
ExtcodeSize: 20, ExtcodeSize: big.NewInt(20),
ExtcodeCopy: 20, ExtcodeCopy: big.NewInt(20),
Balance: 20, Balance: big.NewInt(20),
SLoad: 50, SLoad: big.NewInt(50),
Calls: 40, Calls: big.NewInt(40),
Suicide: 0, Suicide: big.NewInt(0),
ExpByte: 10, 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 // GasTableHomestead contain the gas re-prices for
...@@ -52,26 +58,26 @@ var ( ...@@ -52,26 +58,26 @@ var (
// //
// TODO rename to GasTableEIP150 // TODO rename to GasTableEIP150
GasTableHomesteadGasRepriceFork = GasTable{ GasTableHomesteadGasRepriceFork = GasTable{
ExtcodeSize: 700, ExtcodeSize: big.NewInt(700),
ExtcodeCopy: 700, ExtcodeCopy: big.NewInt(700),
Balance: 400, Balance: big.NewInt(400),
SLoad: 200, SLoad: big.NewInt(200),
Calls: 700, Calls: big.NewInt(700),
Suicide: 5000, Suicide: big.NewInt(5000),
ExpByte: 10, ExpByte: big.NewInt(10),
CreateBySuicide: 25000, CreateBySuicide: big.NewInt(25000),
} }
GasTableEIP158 = GasTable{ GasTableEIP158 = GasTable{
ExtcodeSize: 700, ExtcodeSize: big.NewInt(700),
ExtcodeCopy: 700, ExtcodeCopy: big.NewInt(700),
Balance: 400, Balance: big.NewInt(400),
SLoad: 200, SLoad: big.NewInt(200),
Calls: 700, Calls: big.NewInt(700),
Suicide: 5000, Suicide: big.NewInt(5000),
ExpByte: 50, ExpByte: big.NewInt(50),
CreateBySuicide: 25000, CreateBySuicide: big.NewInt(25000),
} }
) )
...@@ -18,58 +18,56 @@ package params ...@@ -18,58 +18,56 @@ package params
import "math/big" import "math/big"
const ( var (
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. MaximumExtraDataSize = big.NewInt(32) // Maximum size extra data may be after Genesis.
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. ExpByteGas = big.NewInt(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. SloadGas = big.NewInt(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. CallValueTransferGas = big.NewInt(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. CallNewAccountGas = big.NewInt(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. TxGas = big.NewInt(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. TxGasContractCreation = big.NewInt(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. TxDataZeroGas = big.NewInt(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. DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
SstoreSetGas uint64 = 20000 // Once per SLOAD operation. QuadCoeffDiv = big.NewInt(512) // Divisor for the quadratic particle of the memory cost equation.
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data. GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
CallStipend uint64 = 2300 // Free gas given at beginning of call. DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
EcrecoverGas uint64 = 3000 // SstoreSetGas = big.NewInt(20000) // Once per SLOAD operation.
Sha256WordGas uint64 = 12 // 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. MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be.
Sha256Gas uint64 = 60 // GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block.
IdentityWordGas uint64 = 3 // TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target
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.
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 ( MaxCodeSize = 24576
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.
) )
...@@ -146,7 +146,7 @@ func runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, bt map[s ...@@ -146,7 +146,7 @@ func runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, bt map[s
} }
for name, test := range bt { for name, test := range bt {
if skipTest[name] /*|| name != "CallingCanonicalContractFromFork_CALLCODE"*/ { if skipTest[name] {
glog.Infoln("Skipping block test", name) glog.Infoln("Skipping block test", name)
continue continue
} }
......
...@@ -237,13 +237,13 @@ func TestWallet(t *testing.T) { ...@@ -237,13 +237,13 @@ func TestWallet(t *testing.T) {
} }
func TestStateTestsRandom(t *testing.T) { func TestStateTestsRandom(t *testing.T) {
t.Skip()
chainConfig := &params.ChainConfig{ chainConfig := &params.ChainConfig{
HomesteadBlock: big.NewInt(1150000), HomesteadBlock: big.NewInt(1150000),
} }
fns, _ := filepath.Glob("./files/StateTests/RandomTests/*") fns, _ := filepath.Glob("./files/StateTests/RandomTests/*")
for _, fn := range fns { for _, fn := range fns {
t.Log("running:", fn)
if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil { if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
t.Error(fn, err) t.Error(fn, err)
} }
......
...@@ -108,7 +108,7 @@ func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, ski ...@@ -108,7 +108,7 @@ func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, ski
} }
for name, test := range tests { for name, test := range tests {
if skipTest[name] /*|| name != "JUMPDEST_Attack"*/ { if skipTest[name] {
glog.Infoln("Skipping state test", name) glog.Infoln("Skipping state test", name)
continue continue
} }
......
...@@ -129,7 +129,7 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error { ...@@ -129,7 +129,7 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error {
} }
for name, test := range tests { for name, test := range tests {
if skipTest[name] /*|| name != "exp0"*/ { if skipTest[name] /*|| name != "loop_stacklimit_1021"*/ {
glog.Infoln("Skipping VM test", name) glog.Infoln("Skipping VM test", name)
continue continue
} }
...@@ -229,6 +229,6 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type ...@@ -229,6 +229,6 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract) vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec) environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
ret, g, err := environment.Call(caller, to, data, gas.Uint64(), value) ret, err := environment.Call(caller, to, data, gas, value)
return ret, statedb.Logs(), new(big.Int).SetUint64(g), err return ret, statedb.Logs(), gas, err
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册