github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/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/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core/state" 25 "github.com/ethereum/go-ethereum/core/vm" 26 "github.com/ethereum/go-ethereum/logger" 27 "github.com/ethereum/go-ethereum/logger/glog" 28 "github.com/ethereum/go-ethereum/params" 29 ) 30 31 /* 32 * The State transitioning model 33 * 34 * A state transition is a change made when a transaction is applied to the current world state 35 * The state transitioning model does all all the necessary work to work out a valid new state root. 36 * 1) Nonce handling 37 * 2) Pre pay / buy gas of the coinbase (miner) 38 * 3) Create a new state object if the recipient is \0*32 39 * 4) Value transfer 40 * == If contract creation == 41 * 4a) Attempt to run transaction data 42 * 4b) If valid, use result as code for the new state object 43 * == end == 44 * 5) Run Script section 45 * 6) Derive new state root 46 */ 47 type StateTransition struct { 48 gp GasPool 49 msg Message 50 gas, gasPrice *big.Int 51 initialGas *big.Int 52 value *big.Int 53 data []byte 54 state *state.StateDB 55 56 env vm.Environment 57 } 58 59 // Message represents a message sent to a contract. 60 type Message interface { 61 From() (common.Address, error) 62 To() *common.Address 63 64 GasPrice() *big.Int 65 Gas() *big.Int 66 Value() *big.Int 67 68 Nonce() uint64 69 Data() []byte 70 } 71 72 func MessageCreatesContract(msg Message) bool { 73 return msg.To() == nil 74 } 75 76 // IntrinsicGas computes the 'intrisic gas' for a message 77 // with the given data. 78 func IntrinsicGas(data []byte) *big.Int { 79 igas := new(big.Int).Set(params.TxGas) 80 if len(data) > 0 { 81 var nz int64 82 for _, byt := range data { 83 if byt != 0 { 84 nz++ 85 } 86 } 87 m := big.NewInt(nz) 88 m.Mul(m, params.TxDataNonZeroGas) 89 igas.Add(igas, m) 90 m.SetInt64(int64(len(data)) - nz) 91 m.Mul(m, params.TxDataZeroGas) 92 igas.Add(igas, m) 93 } 94 return igas 95 } 96 97 func ApplyMessage(env vm.Environment, msg Message, gp GasPool) ([]byte, *big.Int, error) { 98 return NewStateTransition(env, msg, gp).transitionState() 99 } 100 101 func NewStateTransition(env vm.Environment, msg Message, gp GasPool) *StateTransition { 102 return &StateTransition{ 103 gp: gp, 104 env: env, 105 msg: msg, 106 gas: new(big.Int), 107 gasPrice: msg.GasPrice(), 108 initialGas: new(big.Int), 109 value: msg.Value(), 110 data: msg.Data(), 111 state: env.State(), 112 } 113 } 114 115 func (self *StateTransition) From() (*state.StateObject, error) { 116 f, err := self.msg.From() 117 if err != nil { 118 return nil, err 119 } 120 return self.state.GetOrNewStateObject(f), nil 121 } 122 func (self *StateTransition) To() *state.StateObject { 123 if self.msg == nil { 124 return nil 125 } 126 to := self.msg.To() 127 if to == nil { 128 return nil // contract creation 129 } 130 return self.state.GetOrNewStateObject(*to) 131 } 132 133 func (self *StateTransition) UseGas(amount *big.Int) error { 134 if self.gas.Cmp(amount) < 0 { 135 return vm.OutOfGasError 136 } 137 self.gas.Sub(self.gas, amount) 138 139 return nil 140 } 141 142 func (self *StateTransition) AddGas(amount *big.Int) { 143 self.gas.Add(self.gas, amount) 144 } 145 146 func (self *StateTransition) BuyGas() error { 147 mgas := self.msg.Gas() 148 mgval := new(big.Int).Mul(mgas, self.gasPrice) 149 150 sender, err := self.From() 151 if err != nil { 152 return err 153 } 154 if sender.Balance().Cmp(mgval) < 0 { 155 return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance()) 156 } 157 if err = self.gp.SubGas(mgas, self.gasPrice); err != nil { 158 return err 159 } 160 self.AddGas(mgas) 161 self.initialGas.Set(mgas) 162 sender.SubBalance(mgval) 163 return nil 164 } 165 166 func (self *StateTransition) preCheck() (err error) { 167 msg := self.msg 168 sender, err := self.From() 169 if err != nil { 170 return err 171 } 172 173 // Make sure this transaction's nonce is correct 174 if sender.Nonce() != msg.Nonce() { 175 return NonceError(msg.Nonce(), sender.Nonce()) 176 } 177 178 // Pre-pay gas / Buy gas of the coinbase account 179 if err = self.BuyGas(); err != nil { 180 if state.IsGasLimitErr(err) { 181 return err 182 } 183 return InvalidTxError(err) 184 } 185 186 return nil 187 } 188 189 func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, err error) { 190 if err = self.preCheck(); err != nil { 191 return 192 } 193 194 msg := self.msg 195 sender, _ := self.From() // err checked in preCheck 196 197 // Pay intrinsic gas 198 if err = self.UseGas(IntrinsicGas(self.data)); err != nil { 199 return nil, nil, InvalidTxError(err) 200 } 201 202 vmenv := self.env 203 var ref vm.ContextRef 204 if MessageCreatesContract(msg) { 205 ret, err, ref = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value) 206 if err == nil { 207 dataGas := big.NewInt(int64(len(ret))) 208 dataGas.Mul(dataGas, params.CreateDataGas) 209 if err := self.UseGas(dataGas); err == nil { 210 ref.SetCode(ret) 211 } else { 212 ret = nil // does not affect consensus but useful for StateTests validations 213 glog.V(logger.Core).Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas) 214 } 215 } 216 glog.V(logger.Core).Infoln("VM create err:", err) 217 } else { 218 // Increment the nonce for the next transaction 219 self.state.SetNonce(sender.Address(), sender.Nonce()+1) 220 ret, err = vmenv.Call(sender, self.To().Address(), self.data, self.gas, self.gasPrice, self.value) 221 glog.V(logger.Core).Infoln("VM call err:", err) 222 } 223 224 if err != nil && IsValueTransferErr(err) { 225 return nil, nil, InvalidTxError(err) 226 } 227 228 // We aren't interested in errors here. Errors returned by the VM are non-consensus errors and therefor shouldn't bubble up 229 if err != nil { 230 err = nil 231 } 232 233 if vm.Debug { 234 vm.StdErrFormat(vmenv.StructLogs()) 235 } 236 237 self.refundGas() 238 self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice)) 239 240 return ret, self.gasUsed(), err 241 } 242 243 func (self *StateTransition) refundGas() { 244 sender, _ := self.From() // err already checked 245 // Return remaining gas 246 remaining := new(big.Int).Mul(self.gas, self.gasPrice) 247 sender.AddBalance(remaining) 248 249 uhalf := remaining.Div(self.gasUsed(), common.Big2) 250 refund := common.BigMin(uhalf, self.state.Refunds()) 251 self.gas.Add(self.gas, refund) 252 self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice)) 253 254 self.gp.AddGas(self.gas, self.gasPrice) 255 } 256 257 func (self *StateTransition) gasUsed() *big.Int { 258 return new(big.Int).Sub(self.initialGas, self.gas) 259 }