github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/state_transition.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "fmt" 21 "math/big" 22 23 "github.com/ethereumproject/go-ethereum/common" 24 "github.com/ethereumproject/go-ethereum/core/vm" 25 "github.com/ethereumproject/go-ethereum/logger" 26 "github.com/ethereumproject/go-ethereum/logger/glog" 27 ) 28 29 var ( 30 TxGas = big.NewInt(21000) // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions. 31 TxGasContractCreation = big.NewInt(53000) // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. 32 TxDataZeroGas = big.NewInt(4) // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. 33 TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. 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 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, gasPrice *big.Int 57 initialGas *big.Int 58 value *big.Int 59 data []byte 60 state vm.Database 61 62 env vm.Environment 63 } 64 65 // Message represents a message sent to a contract. 66 type Message interface { 67 From() (common.Address, error) 68 To() *common.Address 69 70 GasPrice() *big.Int 71 Gas() *big.Int 72 Value() *big.Int 73 74 Nonce() uint64 75 Data() []byte 76 } 77 78 func MessageCreatesContract(msg Message) bool { 79 return msg.To() == nil 80 } 81 82 // IntrinsicGas computes the 'intrinsic gas' for a message 83 // with the given data. 84 func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { 85 igas := new(big.Int) 86 if contractCreation && homestead { 87 igas.Set(TxGasContractCreation) 88 } else { 89 igas.Set(TxGas) 90 } 91 if len(data) > 0 { 92 var nz int64 93 for _, byt := range data { 94 if byt != 0 { 95 nz++ 96 } 97 } 98 m := big.NewInt(nz) 99 m.Mul(m, TxDataNonZeroGas) 100 igas.Add(igas, m) 101 m.SetInt64(int64(len(data)) - nz) 102 m.Mul(m, TxDataZeroGas) 103 igas.Add(igas, m) 104 } 105 return igas 106 } 107 108 // NewStateTransition initialises and returns a new state transition object. 109 func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTransition { 110 return &StateTransition{ 111 gp: gp, 112 env: env, 113 msg: msg, 114 gas: new(big.Int), 115 gasPrice: msg.GasPrice(), 116 initialGas: new(big.Int), 117 value: msg.Value(), 118 data: msg.Data(), 119 state: env.Db(), 120 } 121 } 122 123 // ApplyMessage computes the new state by applying the given message 124 // against the old state within the environment. 125 // 126 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 127 // the gas used (which includes gas refunds) and an error if it failed. An error always 128 // indicates a core error meaning that the message would always fail for that particular 129 // state and would never be accepted within a block. 130 func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) { 131 st := NewStateTransition(env, msg, gp) 132 133 ret, gasUsed, failed, err := st.TransitionDb() 134 return ret, gasUsed, failed, err 135 } 136 137 func (self *StateTransition) from() (vm.Account, error) { 138 var ( 139 f common.Address 140 err error 141 ) 142 f, err = self.msg.From() 143 if err != nil { 144 return nil, err 145 } 146 if !self.state.Exist(f) { 147 return self.state.CreateAccount(f), nil 148 } 149 return self.state.GetAccount(f), nil 150 } 151 152 func (self *StateTransition) to() vm.Account { 153 if self.msg == nil { 154 return nil 155 } 156 to := self.msg.To() 157 if to == nil { 158 return nil // contract creation 159 } 160 161 if !self.state.Exist(*to) { 162 return self.state.CreateAccount(*to) 163 } 164 return self.state.GetAccount(*to) 165 } 166 167 func (self *StateTransition) useGas(amount *big.Int) error { 168 if self.gas.Cmp(amount) < 0 { 169 return vm.OutOfGasError 170 } 171 self.gas.Sub(self.gas, amount) 172 173 return nil 174 } 175 176 func (self *StateTransition) addGas(amount *big.Int) { 177 self.gas.Add(self.gas, amount) 178 } 179 180 func (self *StateTransition) buyGas() error { 181 mgas := self.msg.Gas() 182 mgval := new(big.Int).Mul(mgas, self.gasPrice) 183 184 sender, err := self.from() 185 if err != nil { 186 return err 187 } 188 if sender.Balance().Cmp(mgval) < 0 { 189 return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance()) 190 } 191 if err = self.gp.SubGas(mgas); err != nil { 192 return err 193 } 194 self.addGas(mgas) 195 self.initialGas.Set(mgas) 196 sender.SubBalance(mgval) 197 return nil 198 } 199 200 func (self *StateTransition) preCheck() (err error) { 201 msg := self.msg 202 sender, err := self.from() 203 if err != nil { 204 return err 205 } 206 207 // Make sure this transaction's nonce is correct 208 if n := self.state.GetNonce(sender.Address()); n != msg.Nonce() { 209 return NonceError(msg.Nonce(), n) 210 } 211 212 // Pre-pay gas 213 if err = self.buyGas(); err != nil { 214 if IsGasLimitErr(err) { 215 return err 216 } 217 return InvalidTxError(err) 218 } 219 220 return nil 221 } 222 223 // TransitionDb will move the state by applying the message against the given environment. 224 func (self *StateTransition) TransitionDb() (ret []byte, gas *big.Int, failed bool, err error) { 225 if err = self.preCheck(); err != nil { 226 return 227 } 228 msg := self.msg 229 sender, _ := self.from() // err checked in preCheck 230 231 homestead := self.env.RuleSet().IsHomestead(self.env.BlockNumber()) 232 contractCreation := MessageCreatesContract(msg) 233 // Pay intrinsic gas 234 if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil { 235 return nil, nil, false, InvalidTxError(err) 236 } 237 238 vmenv := self.env 239 //var addr common.Address 240 var vmerr error 241 if contractCreation { 242 ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value) 243 if homestead && vmerr == vm.CodeStoreOutOfGasError { 244 self.gas = big.NewInt(0) 245 } 246 247 if vmerr != nil { 248 glog.V(logger.Core).Infoln("VM create err:", vmerr) 249 } 250 } else { 251 // Increment the nonce for the next transaction 252 self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1) 253 ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.gasPrice, self.value) 254 if vmerr != nil { 255 glog.V(logger.Core).Infoln("VM call err:", vmerr) 256 } 257 } 258 259 if vmerr != nil && IsValueTransferErr(vmerr) { 260 // if the vmerr was a value transfer error, return immediately 261 // transaction receipt status will be set to TxSuccess 262 return nil, nil, false, InvalidTxError(vmerr) 263 } 264 265 self.refundGas() 266 self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice)) 267 268 return ret, self.gasUsed(), vmerr != nil, err 269 } 270 271 func (self *StateTransition) refundGas() { 272 // Return eth for remaining gas to the sender account, 273 // exchanged at the original rate. 274 sender, _ := self.from() // err already checked 275 remaining := new(big.Int).Mul(self.gas, self.gasPrice) 276 sender.AddBalance(remaining) 277 278 // Apply refund counter, capped to half of the used gas. 279 uhalf := remaining.Div(self.gasUsed(), common.Big2) 280 refund := common.BigMin(uhalf, self.state.GetRefund()) 281 self.gas.Add(self.gas, refund) 282 self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice)) 283 // Also return remaining gas to the block gas counter so it is 284 // available for the next transaction. 285 self.gp.AddGas(self.gas) 286 } 287 288 func (self *StateTransition) gasUsed() *big.Int { 289 return new(big.Int).Sub(self.initialGas, self.gas) 290 }