core, core/state: move gas tracking out of core/state
The amount of gas available for tx execution was tracked in the StateObject representing the coinbase account. This commit makes the gas counter a separate type in package core, which avoids unintended consequences of intertwining the counter with state logic.
This commit is contained in:
		@@ -58,16 +58,31 @@ type BlockProcessor struct {
 | 
				
			|||||||
	eventMux *event.TypeMux
 | 
						eventMux *event.TypeMux
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: type GasPool big.Int
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// GasPool is implemented by state.StateObject. This is a historical
 | 
					 | 
				
			||||||
// coincidence. Gas tracking should move out of StateObject.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GasPool tracks the amount of gas available during
 | 
					// GasPool tracks the amount of gas available during
 | 
				
			||||||
// execution of the transactions in a block.
 | 
					// execution of the transactions in a block.
 | 
				
			||||||
type GasPool interface {
 | 
					// The zero value is a pool with zero gas available.
 | 
				
			||||||
	AddGas(gas, price *big.Int)
 | 
					type GasPool big.Int
 | 
				
			||||||
	SubGas(gas, price *big.Int) error
 | 
					
 | 
				
			||||||
 | 
					// AddGas makes gas available for execution.
 | 
				
			||||||
 | 
					func (gp *GasPool) AddGas(amount *big.Int) *GasPool {
 | 
				
			||||||
 | 
						i := (*big.Int)(gp)
 | 
				
			||||||
 | 
						i.Add(i, amount)
 | 
				
			||||||
 | 
						return gp
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SubGas deducts the given amount from the pool if enough gas is
 | 
				
			||||||
 | 
					// available and returns an error otherwise.
 | 
				
			||||||
 | 
					func (gp *GasPool) SubGas(amount *big.Int) error {
 | 
				
			||||||
 | 
						i := (*big.Int)(gp)
 | 
				
			||||||
 | 
						if i.Cmp(amount) < 0 {
 | 
				
			||||||
 | 
							return &GasLimitErr{Have: new(big.Int).Set(i), Want: amount}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						i.Sub(i, amount)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (gp *GasPool) String() string {
 | 
				
			||||||
 | 
						return (*big.Int)(gp).String()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewBlockProcessor(db ethdb.Database, pow pow.PoW, blockchain *BlockChain, eventMux *event.TypeMux) *BlockProcessor {
 | 
					func NewBlockProcessor(db ethdb.Database, pow pow.PoW, blockchain *BlockChain, eventMux *event.TypeMux) *BlockProcessor {
 | 
				
			||||||
@@ -82,8 +97,10 @@ func NewBlockProcessor(db ethdb.Database, pow pow.PoW, blockchain *BlockChain, e
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
 | 
					func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
 | 
				
			||||||
	gp := statedb.GetOrNewStateObject(block.Coinbase())
 | 
						gp := new(GasPool).AddGas(block.GasLimit())
 | 
				
			||||||
	gp.SetGasLimit(block.GasLimit())
 | 
						if glog.V(logger.Core) {
 | 
				
			||||||
 | 
							glog.Infof("%x: gas (+ %v)", block.Coinbase(), gp)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Process the transactions on to parent state
 | 
						// Process the transactions on to parent state
 | 
				
			||||||
	receipts, err = sm.ApplyTransactions(gp, statedb, block, block.Transactions(), transientProcess)
 | 
						receipts, err = sm.ApplyTransactions(gp, statedb, block, block.Transactions(), transientProcess)
 | 
				
			||||||
@@ -94,7 +111,7 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block
 | 
				
			|||||||
	return receipts, nil
 | 
						return receipts, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *BlockProcessor) ApplyTransaction(gp GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
 | 
					func (self *BlockProcessor) ApplyTransaction(gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
 | 
				
			||||||
	_, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, gp)
 | 
						_, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, gp)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
@@ -128,7 +145,7 @@ func (self *BlockProcessor) BlockChain() *BlockChain {
 | 
				
			|||||||
	return self.bc
 | 
						return self.bc
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *BlockProcessor) ApplyTransactions(gp GasPool, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) {
 | 
					func (self *BlockProcessor) ApplyTransactions(gp *GasPool, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		receipts      types.Receipts
 | 
							receipts      types.Receipts
 | 
				
			||||||
		totalUsedGas  = big.NewInt(0)
 | 
							totalUsedGas  = big.NewInt(0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ type BlockGen struct {
 | 
				
			|||||||
	header  *types.Header
 | 
						header  *types.Header
 | 
				
			||||||
	statedb *state.StateDB
 | 
						statedb *state.StateDB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	coinbase *state.StateObject
 | 
						gasPool  *GasPool
 | 
				
			||||||
	txs      []*types.Transaction
 | 
						txs      []*types.Transaction
 | 
				
			||||||
	receipts []*types.Receipt
 | 
						receipts []*types.Receipt
 | 
				
			||||||
	uncles   []*types.Header
 | 
						uncles   []*types.Header
 | 
				
			||||||
@@ -63,15 +63,14 @@ type BlockGen struct {
 | 
				
			|||||||
// SetCoinbase sets the coinbase of the generated block.
 | 
					// SetCoinbase sets the coinbase of the generated block.
 | 
				
			||||||
// It can be called at most once.
 | 
					// It can be called at most once.
 | 
				
			||||||
func (b *BlockGen) SetCoinbase(addr common.Address) {
 | 
					func (b *BlockGen) SetCoinbase(addr common.Address) {
 | 
				
			||||||
	if b.coinbase != nil {
 | 
						if b.gasPool != nil {
 | 
				
			||||||
		if len(b.txs) > 0 {
 | 
							if len(b.txs) > 0 {
 | 
				
			||||||
			panic("coinbase must be set before adding transactions")
 | 
								panic("coinbase must be set before adding transactions")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		panic("coinbase can only be set once")
 | 
							panic("coinbase can only be set once")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	b.header.Coinbase = addr
 | 
						b.header.Coinbase = addr
 | 
				
			||||||
	b.coinbase = b.statedb.GetOrNewStateObject(addr)
 | 
						b.gasPool = new(GasPool).AddGas(b.header.GasLimit)
 | 
				
			||||||
	b.coinbase.SetGasLimit(b.header.GasLimit)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetExtra sets the extra data field of the generated block.
 | 
					// SetExtra sets the extra data field of the generated block.
 | 
				
			||||||
@@ -88,10 +87,10 @@ func (b *BlockGen) SetExtra(data []byte) {
 | 
				
			|||||||
// added. Notably, contract code relying on the BLOCKHASH instruction
 | 
					// added. Notably, contract code relying on the BLOCKHASH instruction
 | 
				
			||||||
// will panic during execution.
 | 
					// will panic during execution.
 | 
				
			||||||
func (b *BlockGen) AddTx(tx *types.Transaction) {
 | 
					func (b *BlockGen) AddTx(tx *types.Transaction) {
 | 
				
			||||||
	if b.coinbase == nil {
 | 
						if b.gasPool == nil {
 | 
				
			||||||
		b.SetCoinbase(common.Address{})
 | 
							b.SetCoinbase(common.Address{})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, b.header), tx, b.coinbase)
 | 
						_, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, b.header), tx, b.gasPool)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		panic(err)
 | 
							panic(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -188,3 +188,16 @@ func IsBadHashError(err error) bool {
 | 
				
			|||||||
	_, ok := err.(BadHashError)
 | 
						_, ok := err.(BadHashError)
 | 
				
			||||||
	return ok
 | 
						return ok
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GasLimitErr struct {
 | 
				
			||||||
 | 
						Have, Want *big.Int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsGasLimitErr(err error) bool {
 | 
				
			||||||
 | 
						_, ok := err.(*GasLimitErr)
 | 
				
			||||||
 | 
						return ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (err *GasLimitErr) Error() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("GasLimit reached. Have %d gas, transaction requires %d", err.Have, err.Want)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,39 +0,0 @@
 | 
				
			|||||||
// Copyright 2014 The go-ethereum Authors
 | 
					 | 
				
			||||||
// This file is part of the go-ethereum library.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
// it under the terms of the GNU Lesser General Public License as published by
 | 
					 | 
				
			||||||
// the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
// (at your option) any later version.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// The go-ethereum library is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
					 | 
				
			||||||
// GNU Lesser General Public License for more details.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// You should have received a copy of the GNU Lesser General Public License
 | 
					 | 
				
			||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package state
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"math/big"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type GasLimitErr struct {
 | 
					 | 
				
			||||||
	Message string
 | 
					 | 
				
			||||||
	Is, Max *big.Int
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func IsGasLimitErr(err error) bool {
 | 
					 | 
				
			||||||
	_, ok := err.(*GasLimitErr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ok
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
func (err *GasLimitErr) Error() string {
 | 
					 | 
				
			||||||
	return err.Message
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
func GasLimitError(is, max *big.Int) *GasLimitErr {
 | 
					 | 
				
			||||||
	return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -75,11 +75,6 @@ type StateObject struct {
 | 
				
			|||||||
	// Cached storage (flushed when updated)
 | 
						// Cached storage (flushed when updated)
 | 
				
			||||||
	storage Storage
 | 
						storage Storage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Total gas pool is the total amount of gas currently
 | 
					 | 
				
			||||||
	// left if this object is the coinbase. Gas is directly
 | 
					 | 
				
			||||||
	// purchased of the coinbase.
 | 
					 | 
				
			||||||
	gasPool *big.Int
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Mark for deletion
 | 
						// Mark for deletion
 | 
				
			||||||
	// When an object is marked for deletion it will be delete from the trie
 | 
						// When an object is marked for deletion it will be delete from the trie
 | 
				
			||||||
	// during the "update" phase of the state transition
 | 
						// during the "update" phase of the state transition
 | 
				
			||||||
@@ -89,10 +84,9 @@ type StateObject struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewStateObject(address common.Address, db ethdb.Database) *StateObject {
 | 
					func NewStateObject(address common.Address, db ethdb.Database) *StateObject {
 | 
				
			||||||
	object := &StateObject{db: db, address: address, balance: new(big.Int), gasPool: new(big.Int), dirty: true}
 | 
						object := &StateObject{db: db, address: address, balance: new(big.Int), dirty: true}
 | 
				
			||||||
	object.trie, _ = trie.NewSecure(common.Hash{}, db)
 | 
						object.trie, _ = trie.NewSecure(common.Hash{}, db)
 | 
				
			||||||
	object.storage = make(Storage)
 | 
						object.storage = make(Storage)
 | 
				
			||||||
	object.gasPool = new(big.Int)
 | 
					 | 
				
			||||||
	return object
 | 
						return object
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,7 +115,6 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Datab
 | 
				
			|||||||
	object.codeHash = extobject.CodeHash
 | 
						object.codeHash = extobject.CodeHash
 | 
				
			||||||
	object.trie = trie
 | 
						object.trie = trie
 | 
				
			||||||
	object.storage = make(map[string]common.Hash)
 | 
						object.storage = make(map[string]common.Hash)
 | 
				
			||||||
	object.gasPool = new(big.Int)
 | 
					 | 
				
			||||||
	object.code, _ = db.Get(extobject.CodeHash)
 | 
						object.code, _ = db.Get(extobject.CodeHash)
 | 
				
			||||||
	return object
 | 
						return object
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -209,36 +202,9 @@ func (c *StateObject) St() Storage {
 | 
				
			|||||||
	return c.storage
 | 
						return c.storage
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Gas setters and getters
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
 | 
					// Return the gas back to the origin. Used by the Virtual machine or Closures
 | 
				
			||||||
func (c *StateObject) ReturnGas(gas, price *big.Int) {}
 | 
					func (c *StateObject) ReturnGas(gas, price *big.Int) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *StateObject) SetGasLimit(gasLimit *big.Int) {
 | 
					 | 
				
			||||||
	self.gasPool = new(big.Int).Set(gasLimit)
 | 
					 | 
				
			||||||
	self.dirty = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if glog.V(logger.Core) {
 | 
					 | 
				
			||||||
		glog.Infof("%x: gas (+ %v)", self.Address(), self.gasPool)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (self *StateObject) SubGas(gas, price *big.Int) error {
 | 
					 | 
				
			||||||
	if self.gasPool.Cmp(gas) < 0 {
 | 
					 | 
				
			||||||
		return GasLimitError(self.gasPool, gas)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	self.gasPool.Sub(self.gasPool, gas)
 | 
					 | 
				
			||||||
	self.dirty = true
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (self *StateObject) AddGas(gas, price *big.Int) {
 | 
					 | 
				
			||||||
	self.gasPool.Add(self.gasPool, gas)
 | 
					 | 
				
			||||||
	self.dirty = true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (self *StateObject) Copy() *StateObject {
 | 
					func (self *StateObject) Copy() *StateObject {
 | 
				
			||||||
	stateObject := NewStateObject(self.Address(), self.db)
 | 
						stateObject := NewStateObject(self.Address(), self.db)
 | 
				
			||||||
	stateObject.balance.Set(self.balance)
 | 
						stateObject.balance.Set(self.balance)
 | 
				
			||||||
@@ -248,7 +214,6 @@ func (self *StateObject) Copy() *StateObject {
 | 
				
			|||||||
	stateObject.code = common.CopyBytes(self.code)
 | 
						stateObject.code = common.CopyBytes(self.code)
 | 
				
			||||||
	stateObject.initCode = common.CopyBytes(self.initCode)
 | 
						stateObject.initCode = common.CopyBytes(self.initCode)
 | 
				
			||||||
	stateObject.storage = self.storage.Copy()
 | 
						stateObject.storage = self.storage.Copy()
 | 
				
			||||||
	stateObject.gasPool.Set(self.gasPool)
 | 
					 | 
				
			||||||
	stateObject.remove = self.remove
 | 
						stateObject.remove = self.remove
 | 
				
			||||||
	stateObject.dirty = self.dirty
 | 
						stateObject.dirty = self.dirty
 | 
				
			||||||
	stateObject.deleted = self.deleted
 | 
						stateObject.deleted = self.deleted
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,7 +138,6 @@ func TestSnapshot2(t *testing.T) {
 | 
				
			|||||||
	so0 := state.GetStateObject(stateobjaddr0)
 | 
						so0 := state.GetStateObject(stateobjaddr0)
 | 
				
			||||||
	so0.balance = big.NewInt(42)
 | 
						so0.balance = big.NewInt(42)
 | 
				
			||||||
	so0.nonce = 43
 | 
						so0.nonce = 43
 | 
				
			||||||
	so0.gasPool = big.NewInt(44)
 | 
					 | 
				
			||||||
	so0.code = []byte{'c', 'a', 'f', 'e'}
 | 
						so0.code = []byte{'c', 'a', 'f', 'e'}
 | 
				
			||||||
	so0.codeHash = so0.CodeHash()
 | 
						so0.codeHash = so0.CodeHash()
 | 
				
			||||||
	so0.remove = true
 | 
						so0.remove = true
 | 
				
			||||||
@@ -150,7 +149,6 @@ func TestSnapshot2(t *testing.T) {
 | 
				
			|||||||
	so1 := state.GetStateObject(stateobjaddr1)
 | 
						so1 := state.GetStateObject(stateobjaddr1)
 | 
				
			||||||
	so1.balance = big.NewInt(52)
 | 
						so1.balance = big.NewInt(52)
 | 
				
			||||||
	so1.nonce = 53
 | 
						so1.nonce = 53
 | 
				
			||||||
	so1.gasPool = big.NewInt(54)
 | 
					 | 
				
			||||||
	so1.code = []byte{'c', 'a', 'f', 'e', '2'}
 | 
						so1.code = []byte{'c', 'a', 'f', 'e', '2'}
 | 
				
			||||||
	so1.codeHash = so1.CodeHash()
 | 
						so1.codeHash = so1.CodeHash()
 | 
				
			||||||
	so1.remove = true
 | 
						so1.remove = true
 | 
				
			||||||
@@ -207,9 +205,6 @@ func compareStateObjects(so0, so1 *StateObject, t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if so0.gasPool.Cmp(so1.gasPool) != 0 {
 | 
					 | 
				
			||||||
		t.Fatalf("GasPool mismatch: have %v, want %v", so0.gasPool, so1.gasPool)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if so0.remove != so1.remove {
 | 
						if so0.remove != so1.remove {
 | 
				
			||||||
		t.Fatalf("Remove mismatch: have %v, want %v", so0.remove, so1.remove)
 | 
							t.Fatalf("Remove mismatch: have %v, want %v", so0.remove, so1.remove)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,6 @@ import (
 | 
				
			|||||||
	"math/big"
 | 
						"math/big"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/common"
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/core/state"
 | 
					 | 
				
			||||||
	"github.com/ethereum/go-ethereum/core/vm"
 | 
						"github.com/ethereum/go-ethereum/core/vm"
 | 
				
			||||||
	"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"
 | 
				
			||||||
@@ -29,23 +28,24 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The State transitioning model
 | 
					The State Transitioning Model
 | 
				
			||||||
 *
 | 
					
 | 
				
			||||||
 * A state transition is a change made when a transaction is applied to the current world state
 | 
					A state transition is a change made when a transaction is applied to the current world state
 | 
				
			||||||
 * The state transitioning model does all all the necessary work to work out a valid new state root.
 | 
					The state transitioning model does all all the necessary work to work out a valid new state root.
 | 
				
			||||||
 * 1) Nonce handling
 | 
					
 | 
				
			||||||
 * 2) Pre pay / buy gas of the coinbase (miner)
 | 
					1) Nonce handling
 | 
				
			||||||
 * 3) Create a new state object if the recipient is \0*32
 | 
					2) Pre pay gas
 | 
				
			||||||
 * 4) Value transfer
 | 
					3) Create a new state object if the recipient is \0*32
 | 
				
			||||||
 * == If contract creation ==
 | 
					4) Value transfer
 | 
				
			||||||
 * 4a) Attempt to run transaction data
 | 
					== If contract creation ==
 | 
				
			||||||
 * 4b) If valid, use result as code for the new state object
 | 
					  4a) Attempt to run transaction data
 | 
				
			||||||
 * == end ==
 | 
					  4b) If valid, use result as code for the new state object
 | 
				
			||||||
 * 5) Run Script section
 | 
					== end ==
 | 
				
			||||||
 * 6) Derive new state root
 | 
					5) Run Script section
 | 
				
			||||||
 */
 | 
					6) Derive new state root
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
type StateTransition struct {
 | 
					type StateTransition struct {
 | 
				
			||||||
	gp            GasPool
 | 
						gp            *GasPool
 | 
				
			||||||
	msg           Message
 | 
						msg           Message
 | 
				
			||||||
	gas, gasPrice *big.Int
 | 
						gas, gasPrice *big.Int
 | 
				
			||||||
	initialGas    *big.Int
 | 
						initialGas    *big.Int
 | 
				
			||||||
@@ -94,7 +94,7 @@ func IntrinsicGas(data []byte) *big.Int {
 | 
				
			|||||||
	return igas
 | 
						return igas
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ApplyMessage(env vm.Environment, msg Message, gp GasPool) ([]byte, *big.Int, error) {
 | 
					func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
 | 
				
			||||||
	var st = StateTransition{
 | 
						var st = StateTransition{
 | 
				
			||||||
		gp:         gp,
 | 
							gp:         gp,
 | 
				
			||||||
		env:        env,
 | 
							env:        env,
 | 
				
			||||||
@@ -158,7 +158,7 @@ func (self *StateTransition) buyGas() error {
 | 
				
			|||||||
	if sender.Balance().Cmp(mgval) < 0 {
 | 
						if sender.Balance().Cmp(mgval) < 0 {
 | 
				
			||||||
		return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
 | 
							return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err = self.gp.SubGas(mgas, self.gasPrice); err != nil {
 | 
						if err = self.gp.SubGas(mgas); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	self.addGas(mgas)
 | 
						self.addGas(mgas)
 | 
				
			||||||
@@ -180,9 +180,9 @@ func (self *StateTransition) preCheck() (err error) {
 | 
				
			|||||||
		return NonceError(msg.Nonce(), n)
 | 
							return NonceError(msg.Nonce(), n)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Pre-pay gas / Buy gas of the coinbase account
 | 
						// Pre-pay gas
 | 
				
			||||||
	if err = self.buyGas(); err != nil {
 | 
						if err = self.buyGas(); err != nil {
 | 
				
			||||||
		if state.IsGasLimitErr(err) {
 | 
							if IsGasLimitErr(err) {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return InvalidTxError(err)
 | 
							return InvalidTxError(err)
 | 
				
			||||||
@@ -246,17 +246,21 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *StateTransition) refundGas() {
 | 
					func (self *StateTransition) refundGas() {
 | 
				
			||||||
 | 
						// Return eth for remaining gas to the sender account,
 | 
				
			||||||
 | 
						// exchanged at the original rate.
 | 
				
			||||||
	sender, _ := self.from() // err already checked
 | 
						sender, _ := self.from() // err already checked
 | 
				
			||||||
	// Return remaining gas
 | 
					 | 
				
			||||||
	remaining := new(big.Int).Mul(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.
 | 
				
			||||||
	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.Add(self.gas, refund)
 | 
						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))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self.gp.AddGas(self.gas, self.gasPrice)
 | 
						// Also return remaining gas to the block gas counter so it is
 | 
				
			||||||
 | 
						// available for the next transaction.
 | 
				
			||||||
 | 
						self.gp.AddGas(self.gas)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *StateTransition) gasUsed() *big.Int {
 | 
					func (self *StateTransition) gasUsed() *big.Int {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,13 +62,12 @@ type uint64RingBuffer struct {
 | 
				
			|||||||
// environment is the workers current environment and holds
 | 
					// environment is the workers current environment and holds
 | 
				
			||||||
// all of the current state information
 | 
					// all of the current state information
 | 
				
			||||||
type Work struct {
 | 
					type Work struct {
 | 
				
			||||||
	state              *state.StateDB     // apply state changes here
 | 
						state              *state.StateDB // apply state changes here
 | 
				
			||||||
	coinbase           *state.StateObject // the miner's account
 | 
						ancestors          *set.Set       // ancestor set (used for checking uncle parent validity)
 | 
				
			||||||
	ancestors          *set.Set           // ancestor set (used for checking uncle parent validity)
 | 
						family             *set.Set       // family set (used for checking uncle invalidity)
 | 
				
			||||||
	family             *set.Set           // family set (used for checking uncle invalidity)
 | 
						uncles             *set.Set       // uncle set
 | 
				
			||||||
	uncles             *set.Set           // uncle set
 | 
						remove             *set.Set       // tx which will be removed
 | 
				
			||||||
	remove             *set.Set           // tx which will be removed
 | 
						tcount             int            // tx count in cycle
 | 
				
			||||||
	tcount             int                // tx count in cycle
 | 
					 | 
				
			||||||
	ignoredTransactors *set.Set
 | 
						ignoredTransactors *set.Set
 | 
				
			||||||
	lowGasTransactors  *set.Set
 | 
						lowGasTransactors  *set.Set
 | 
				
			||||||
	ownedAccounts      *set.Set
 | 
						ownedAccounts      *set.Set
 | 
				
			||||||
@@ -366,7 +365,6 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
 | 
				
			|||||||
		family:    set.New(),
 | 
							family:    set.New(),
 | 
				
			||||||
		uncles:    set.New(),
 | 
							uncles:    set.New(),
 | 
				
			||||||
		header:    header,
 | 
							header:    header,
 | 
				
			||||||
		coinbase:  state.GetOrNewStateObject(self.coinbase),
 | 
					 | 
				
			||||||
		createdAt: time.Now(),
 | 
							createdAt: time.Now(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -514,7 +512,6 @@ func (self *worker) commitNewWork() {
 | 
				
			|||||||
	transactions := append(singleTxOwner, multiTxOwner...)
 | 
						transactions := append(singleTxOwner, multiTxOwner...)
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	work.coinbase.SetGasLimit(header.GasLimit)
 | 
					 | 
				
			||||||
	work.commitTransactions(transactions, self.gasPrice, self.proc)
 | 
						work.commitTransactions(transactions, self.gasPrice, self.proc)
 | 
				
			||||||
	self.eth.TxPool().RemoveTransactions(work.lowGasTxs)
 | 
						self.eth.TxPool().RemoveTransactions(work.lowGasTxs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -575,6 +572,8 @@ func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
 | 
					func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
 | 
				
			||||||
 | 
						gp := new(core.GasPool).AddGas(env.header.GasLimit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tx := range transactions {
 | 
						for _, tx := range transactions {
 | 
				
			||||||
		// We can skip err. It has already been validated in the tx pool
 | 
							// We can skip err. It has already been validated in the tx pool
 | 
				
			||||||
		from, _ := tx.From()
 | 
							from, _ := tx.From()
 | 
				
			||||||
@@ -612,9 +611,9 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		env.state.StartRecord(tx.Hash(), common.Hash{}, 0)
 | 
							env.state.StartRecord(tx.Hash(), common.Hash{}, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err := env.commitTransaction(tx, proc)
 | 
							err := env.commitTransaction(tx, proc, gp)
 | 
				
			||||||
		switch {
 | 
							switch {
 | 
				
			||||||
		case state.IsGasLimitErr(err):
 | 
							case core.IsGasLimitErr(err):
 | 
				
			||||||
			// ignore the transactor so no nonce errors will be thrown for this account
 | 
								// ignore the transactor so no nonce errors will be thrown for this account
 | 
				
			||||||
			// next time the worker is run, they'll be picked up again.
 | 
								// next time the worker is run, they'll be picked up again.
 | 
				
			||||||
			env.ignoredTransactors.Add(from)
 | 
								env.ignoredTransactors.Add(from)
 | 
				
			||||||
@@ -632,9 +631,9 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (env *Work) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor) error {
 | 
					func (env *Work) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor, gp *core.GasPool) error {
 | 
				
			||||||
	snap := env.state.Copy()
 | 
						snap := env.state.Copy()
 | 
				
			||||||
	receipt, _, err := proc.ApplyTransaction(env.coinbase, env.state, env.header, tx, env.header.GasUsed, true)
 | 
						receipt, _, err := proc.ApplyTransaction(gp, env.state, env.header, tx, env.header.GasUsed, true)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		env.state.Set(snap)
 | 
							env.state.Set(snap)
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -223,7 +223,6 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Log
 | 
				
			|||||||
		price = common.Big(tx["gasPrice"])
 | 
							price = common.Big(tx["gasPrice"])
 | 
				
			||||||
		value = common.Big(tx["value"])
 | 
							value = common.Big(tx["value"])
 | 
				
			||||||
		nonce = common.Big(tx["nonce"]).Uint64()
 | 
							nonce = common.Big(tx["nonce"]).Uint64()
 | 
				
			||||||
		caddr = common.HexToAddress(env["currentCoinbase"])
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var to *common.Address
 | 
						var to *common.Address
 | 
				
			||||||
@@ -235,16 +234,15 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Log
 | 
				
			|||||||
	vm.Precompiled = vm.PrecompiledContracts()
 | 
						vm.Precompiled = vm.PrecompiledContracts()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snapshot := statedb.Copy()
 | 
						snapshot := statedb.Copy()
 | 
				
			||||||
	coinbase := statedb.GetOrNewStateObject(caddr)
 | 
						gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
 | 
				
			||||||
	coinbase.SetGasLimit(common.Big(env["currentGasLimit"]))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key, _ := hex.DecodeString(tx["secretKey"])
 | 
						key, _ := hex.DecodeString(tx["secretKey"])
 | 
				
			||||||
	addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
 | 
						addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
 | 
				
			||||||
	message := NewMessage(addr, to, data, value, gas, price, nonce)
 | 
						message := NewMessage(addr, to, data, value, gas, price, nonce)
 | 
				
			||||||
	vmenv := NewEnvFromMap(statedb, env, tx)
 | 
						vmenv := NewEnvFromMap(statedb, env, tx)
 | 
				
			||||||
	vmenv.origin = addr
 | 
						vmenv.origin = addr
 | 
				
			||||||
	ret, _, err := core.ApplyMessage(vmenv, message, coinbase)
 | 
						ret, _, err := core.ApplyMessage(vmenv, message, gaspool)
 | 
				
			||||||
	if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || state.IsGasLimitErr(err) {
 | 
						if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) {
 | 
				
			||||||
		statedb.Set(snapshot)
 | 
							statedb.Set(snapshot)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	statedb.Commit()
 | 
						statedb.Commit()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -850,7 +850,6 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	from.SetBalance(common.MaxBig)
 | 
						from.SetBalance(common.MaxBig)
 | 
				
			||||||
	from.SetGasLimit(common.MaxBig)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg := callmsg{
 | 
						msg := callmsg{
 | 
				
			||||||
		from:     from,
 | 
							from:     from,
 | 
				
			||||||
@@ -874,8 +873,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	header := self.CurrentBlock().Header()
 | 
						header := self.CurrentBlock().Header()
 | 
				
			||||||
	vmenv := core.NewEnv(statedb, self.backend.BlockChain(), msg, header)
 | 
						vmenv := core.NewEnv(statedb, self.backend.BlockChain(), msg, header)
 | 
				
			||||||
 | 
						gp := new(core.GasPool).AddGas(common.MaxBig)
 | 
				
			||||||
	res, gas, err := core.ApplyMessage(vmenv, msg, from)
 | 
						res, gas, err := core.ApplyMessage(vmenv, msg, gp)
 | 
				
			||||||
	return common.ToHex(res), gas.String(), err
 | 
						return common.ToHex(res), gas.String(), err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user