Commit 1f3596c2 authored by Jeffrey Wilcke's avatar Jeffrey Wilcke

core: transition db now also returns the required gas amount

Exposes some core methods to transition and compute new state
information and adds an additional return value to the transition db
method to fetch required gas for that particular message (excluding gas
refunds from any SSTORE[X] = 0 and SUICIDE.

Fixes #2395
parent 9055c16e
...@@ -104,8 +104,9 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { ...@@ -104,8 +104,9 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
return igas return igas
} }
func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, error) { // NewStateTransition initialises and returns a new state transition object.
var st = StateTransition{ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTransition {
return &StateTransition{
gp: gp, gp: gp,
env: env, env: env,
msg: msg, msg: msg,
...@@ -116,7 +117,20 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In ...@@ -116,7 +117,20 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In
data: msg.Data(), data: msg.Data(),
state: env.Db(), state: env.Db(),
} }
return st.transitionDb() }
// ApplyMessage computes the new state by applying the given message
// against the old state within the environment.
//
// ApplyMessage returns the bytes returned by any EVM execution (if it took place),
// the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
st := NewStateTransition(env, msg, gp)
ret, _, gasUsed, err := st.TransitionDb()
return ret, gasUsed, err
} }
func (self *StateTransition) from() (vm.Account, error) { func (self *StateTransition) from() (vm.Account, error) {
...@@ -209,7 +223,8 @@ func (self *StateTransition) preCheck() (err error) { ...@@ -209,7 +223,8 @@ func (self *StateTransition) preCheck() (err error) {
return nil return nil
} }
func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err error) { // TransitionDb will move the state by applying the message against the given environment.
func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) {
if err = self.preCheck(); err != nil { if err = self.preCheck(); err != nil {
return return
} }
...@@ -220,7 +235,7 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e ...@@ -220,7 +235,7 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e
contractCreation := MessageCreatesContract(msg) contractCreation := MessageCreatesContract(msg)
// Pay intrinsic gas // Pay intrinsic gas
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil { if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
return nil, nil, InvalidTxError(err) return nil, nil, nil, InvalidTxError(err)
} }
vmenv := self.env vmenv := self.env
...@@ -245,7 +260,7 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e ...@@ -245,7 +260,7 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e
} }
if err != nil && IsValueTransferErr(err) { if err != nil && IsValueTransferErr(err) {
return nil, nil, InvalidTxError(err) return nil, nil, nil, InvalidTxError(err)
} }
// We aren't interested in errors here. Errors returned by the VM are non-consensus errors and therefor shouldn't bubble up // We aren't interested in errors here. Errors returned by the VM are non-consensus errors and therefor shouldn't bubble up
...@@ -253,10 +268,12 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e ...@@ -253,10 +268,12 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e
err = nil err = nil
} }
requiredGas = new(big.Int).Set(self.gasUsed())
self.refundGas() self.refundGas()
self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice)) self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice))
return ret, self.gasUsed(), err return ret, requiredGas, self.gasUsed(), err
} }
func (self *StateTransition) refundGas() { func (self *StateTransition) refundGas() {
......
...@@ -674,11 +674,11 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st ...@@ -674,11 +674,11 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st
vmenv := core.NewEnv(stateDb, s.config, s.bc, msg, block.Header(), s.config.VmConfig) vmenv := core.NewEnv(stateDb, s.config, s.bc, msg, block.Header(), s.config.VmConfig)
gp := new(core.GasPool).AddGas(common.MaxBig) gp := new(core.GasPool).AddGas(common.MaxBig)
res, gas, err := core.ApplyMessage(vmenv, msg, gp) res, requiredGas, _, err := core.NewStateTransition(vmenv, msg, gp).TransitionDb()
if len(res) == 0 { // backwards compatibility if len(res) == 0 { // backwards compatibility
return "0x", gas, err return "0x", requiredGas, err
} }
return common.ToHex(res), gas, err return common.ToHex(res), requiredGas, err
} }
// Call executes the given transaction on the state for the given block number. // Call executes the given transaction on the state for the given block number.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment