forked from cerc-io/plugeth
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:
parent
10ed107ba2
commit
de8d5aaa92
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user