Merge pull request #1758 from fjl/coinbase
core, core/state: move gas tracking out of core/state
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 { | ||||||
|   | |||||||
| @@ -63,7 +63,6 @@ type uint64RingBuffer struct { | |||||||
| // 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 | ||||||
| @@ -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