github.com/codingfuture/orig-energi3@v0.8.4/core/state_transition.go (about) 1 // Copyright 2018 The Energi Core Authors 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of the Energi Core library. 4 // 5 // The Energi Core library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The Energi Core library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>. 17 18 package core 19 20 import ( 21 "errors" 22 "math" 23 "math/big" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/core/vm" 27 "github.com/ethereum/go-ethereum/log" 28 "github.com/ethereum/go-ethereum/params" 29 ) 30 31 var ( 32 errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") 33 genesisNumber = big.NewInt(0) 34 ) 35 36 /* 37 The State Transitioning Model 38 39 A state transition is a change made when a transaction is applied to the current world state 40 The state transitioning model does all the necessary work to work out a valid new state root. 41 42 1) Nonce handling 43 2) Pre pay gas 44 3) Create a new state object if the recipient is \0*32 45 4) Value transfer 46 == If contract creation == 47 4a) Attempt to run transaction data 48 4b) If valid, use result as code for the new state object 49 == end == 50 5) Run Script section 51 6) Derive new state root 52 */ 53 type StateTransition struct { 54 gp *GasPool 55 msg Message 56 gas uint64 57 gasPrice *big.Int 58 initialGas uint64 59 value *big.Int 60 data []byte 61 state vm.StateDB 62 evm *vm.EVM 63 inSetup bool 64 } 65 66 // Message represents a message sent to a contract. 67 type Message interface { 68 From() common.Address 69 //FromFrontier() (common.Address, error) 70 To() *common.Address 71 72 GasPrice() *big.Int 73 Gas() uint64 74 Value() *big.Int 75 76 Nonce() uint64 77 CheckNonce() bool 78 Data() []byte 79 } 80 81 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. 82 func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) { 83 // Set the starting gas for the raw transaction 84 var gas uint64 85 if contractCreation && homestead { 86 gas = params.TxGasContractCreation 87 } else { 88 gas = params.TxGas 89 } 90 // Bump the required gas by the amount of transactional data 91 if len(data) > 0 { 92 // Zero and non-zero bytes are priced differently 93 var nz uint64 94 for _, byt := range data { 95 if byt != 0 { 96 nz++ 97 } 98 } 99 // Make sure we don't exceed uint64 for all data combinations 100 if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz { 101 return 0, vm.ErrOutOfGas 102 } 103 gas += nz * params.TxDataNonZeroGas 104 105 z := uint64(len(data)) - nz 106 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 107 return 0, vm.ErrOutOfGas 108 } 109 gas += z * params.TxDataZeroGas 110 } 111 return gas, nil 112 } 113 114 // NewStateTransition initialises and returns a new state transition object. 115 func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { 116 return &StateTransition{ 117 gp: gp, 118 evm: evm, 119 msg: msg, 120 gasPrice: msg.GasPrice(), 121 value: msg.Value(), 122 data: msg.Data(), 123 state: evm.StateDB, 124 inSetup: false, 125 } 126 } 127 128 // ApplyMessage computes the new state by applying the given message 129 // against the old state within the environment. 130 // 131 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 132 // the gas used (which includes gas refunds) and an error if it failed. An error always 133 // indicates a core error meaning that the message would always fail for that particular 134 // state and would never be accepted within a block. 135 func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { 136 return NewStateTransition(evm, msg, gp).TransitionDb() 137 } 138 139 // to returns the recipient of the message. 140 func (st *StateTransition) to() common.Address { 141 if st.msg == nil || st.msg.To() == nil /* contract creation */ { 142 return common.Address{} 143 } 144 return *st.msg.To() 145 } 146 147 func (st *StateTransition) useGas(amount uint64) error { 148 if st.gas < amount { 149 return vm.ErrOutOfGas 150 } 151 st.gas -= amount 152 153 return nil 154 } 155 156 func (st *StateTransition) buyGas() error { 157 mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) 158 if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { 159 return errInsufficientBalanceForGas 160 } 161 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 162 return err 163 } 164 st.gas += st.msg.Gas() 165 166 st.initialGas = st.msg.Gas() 167 st.state.SubBalance(st.msg.From(), mgval) 168 return nil 169 } 170 171 func (st *StateTransition) preCheck() error { 172 // Make sure this transaction's nonce is correct. 173 if st.msg.CheckNonce() { 174 nonce := st.state.GetNonce(st.msg.From()) 175 if nonce < st.msg.Nonce() { 176 return ErrNonceTooHigh 177 } else if nonce > st.msg.Nonce() { 178 return ErrNonceTooLow 179 } 180 } 181 return st.buyGas() 182 } 183 184 // TransitionDb will transition the state by applying the current message and 185 // returning the result including the used gas. It returns an error if failed. 186 // An error indicates a consensus issue. 187 func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) { 188 if err = st.preCheck(); err != nil { 189 return 190 } 191 msg := st.msg 192 sender := vm.AccountRef(msg.From()) 193 homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 194 contractCreation := msg.To() == nil 195 196 // Pay intrinsic gas 197 gas, err := IntrinsicGas(st.data, contractCreation, homestead) 198 if err != nil { 199 return nil, 0, false, err 200 } 201 if err = st.useGas(gas); err != nil { 202 return nil, 0, false, err 203 } 204 205 var ( 206 evm = st.evm 207 // vm errors do not effect consensus and are therefor 208 // not assigned to err, except for insufficient balance 209 // error. 210 vmerr error 211 ) 212 if contractCreation { 213 ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) 214 } else if st.inSetup { 215 ret, _, st.gas, vmerr = evm.CreateGenesis(sender, *msg.To(), st.data, st.gas, st.value) 216 } else { 217 // Increment the nonce for the next transaction 218 st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) 219 ret, st.gas, vmerr = evm.Call(sender, st.to(), st.data, st.gas, st.value) 220 } 221 if vmerr != nil { 222 log.Debug("VM returned with error", "err", vmerr) 223 // The only possible consensus-error would be if there wasn't 224 // sufficient balance to make the transfer happen. The first 225 // balance transfer may never fail. 226 if vmerr == vm.ErrInsufficientBalance { 227 return nil, 0, false, vmerr 228 } 229 } 230 st.refundGas() 231 st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 232 233 return ret, st.gasUsed(), vmerr != nil, err 234 } 235 236 func (st *StateTransition) refundGas() { 237 // Apply refund counter, capped to half of the used gas. 238 refund := st.gasUsed() / 2 239 if refund > st.state.GetRefund() { 240 refund = st.state.GetRefund() 241 } 242 st.gas += refund 243 244 // Return ETH for remaining gas, exchanged at the original rate. 245 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 246 st.state.AddBalance(st.msg.From(), remaining) 247 248 // Also return remaining gas to the block gas counter so it is 249 // available for the next transaction. 250 st.gp.AddGas(st.gas) 251 } 252 253 // gasUsed returns the amount of gas used up by the state transition. 254 func (st *StateTransition) gasUsed() uint64 { 255 return st.initialGas - st.gas 256 }