github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/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 "errors" 21 "math" 22 "math/big" 23 24 "github.com/intfoundation/intchain/common" 25 "github.com/intfoundation/intchain/core/vm" 26 "github.com/intfoundation/intchain/params" 27 ) 28 29 var ( 30 errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") 31 ) 32 33 /* 34 The State Transitioning Model 35 36 A state transition is a change made when a transaction is applied to the current world state 37 The state transitioning model does all all the necessary work to work out a valid new state root. 38 39 1) Nonce handling 40 2) Pre pay gas 41 3) Create a new state object if the recipient is \0*32 42 4) Value transfer 43 == If contract creation == 44 4a) Attempt to run transaction data 45 4b) If valid, use result as code for the new state object 46 == end == 47 5) Run Script section 48 6) Derive new state root 49 */ 50 type StateTransition struct { 51 gp *GasPool 52 msg Message 53 gas uint64 54 gasPrice *big.Int 55 initialGas uint64 56 value *big.Int 57 data []byte 58 state vm.StateDB 59 evm *vm.EVM 60 } 61 62 // Message represents a message sent to a contract. 63 type Message interface { 64 From() common.Address 65 //FromFrontier() (common.Address, error) 66 To() *common.Address 67 68 GasPrice() *big.Int 69 Gas() uint64 70 Value() *big.Int 71 72 Nonce() uint64 73 CheckNonce() bool 74 Data() []byte 75 } 76 77 // ExecutionResult includes all output after executing given evm 78 // message no matter the execution itself is successful or not. 79 type ExecutionResult struct { 80 UsedGas uint64 // Total used gas but include the refunded gas 81 Err error // Any error encountered during the execution(listed in core/vm/errors.go) 82 ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) 83 } 84 85 // Unwrap returns the internal evm error which allows us for further 86 // analysis outside. 87 func (result *ExecutionResult) Unwrap() error { 88 return result.Err 89 } 90 91 // Failed returns the indicator whether the execution is successful or not 92 func (result *ExecutionResult) Failed() bool { return result.Err != nil } 93 94 // Return is a helper function to help caller distinguish between revert reason 95 // and function return. Return returns the data after execution if no error occurs. 96 func (result *ExecutionResult) Return() []byte { 97 if result.Err != nil { 98 return nil 99 } 100 return common.CopyBytes(result.ReturnData) 101 } 102 103 // Revert returns the concrete revert reason if the execution is aborted by `REVERT` 104 // opcode. Note the reason can be nil if no data supplied with revert opcode. 105 func (result *ExecutionResult) Revert() []byte { 106 if result.Err != vm.ErrExecutionReverted { 107 return nil 108 } 109 return common.CopyBytes(result.ReturnData) 110 } 111 112 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. 113 func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) { 114 // Set the starting gas for the raw transaction 115 var gas uint64 116 if contractCreation && homestead { 117 gas = params.TxGasContractCreation 118 } else { 119 gas = params.TxGas 120 } 121 // Bump the required gas by the amount of transactional data 122 if len(data) > 0 { 123 // Zero and non-zero bytes are priced differently 124 var nz uint64 125 for _, byt := range data { 126 if byt != 0 { 127 nz++ 128 } 129 } 130 // Make sure we don't exceed uint64 for all data combinations 131 nonZeroGas := params.TxDataNonZeroGasFrontier 132 if (math.MaxUint64-gas)/nonZeroGas < nz { 133 return 0, vm.ErrOutOfGas 134 } 135 gas += nz * nonZeroGas 136 137 z := uint64(len(data)) - nz 138 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 139 return 0, vm.ErrOutOfGas 140 } 141 gas += z * params.TxDataZeroGas 142 } 143 return gas, nil 144 } 145 146 // NewStateTransition initialises and returns a new state transition object. 147 func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { 148 return &StateTransition{ 149 gp: gp, 150 evm: evm, 151 msg: msg, 152 gasPrice: msg.GasPrice(), 153 value: msg.Value(), 154 data: msg.Data(), 155 state: evm.StateDB, 156 } 157 } 158 159 // ApplyMessage computes the new state by applying the given message 160 // against the old state within the environment. 161 // 162 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 163 // the gas used (which includes gas refunds) and an error if it failed. An error always 164 // indicates a core error meaning that the message would always fail for that particular 165 // state and would never be accepted within a block. 166 func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) { 167 return NewStateTransition(evm, msg, gp).TransitionDb() 168 } 169 170 func (st *StateTransition) from() vm.AccountRef { 171 f := st.msg.From() 172 if !st.state.Exist(f) { 173 st.state.CreateAccount(f) 174 } 175 return vm.AccountRef(f) 176 } 177 178 func (st *StateTransition) to() vm.AccountRef { 179 if st.msg == nil { 180 return vm.AccountRef{} 181 } 182 to := st.msg.To() 183 if to == nil { 184 return vm.AccountRef{} // contract creation 185 } 186 187 reference := vm.AccountRef(*to) 188 if !st.state.Exist(*to) { 189 st.state.CreateAccount(*to) 190 } 191 return reference 192 } 193 194 func (st *StateTransition) useGas(amount uint64) error { 195 if st.gas < amount { 196 return vm.ErrOutOfGas 197 } 198 st.gas -= amount 199 200 return nil 201 } 202 203 func (st *StateTransition) buyGas() error { 204 var ( 205 state = st.state 206 sender = st.from() 207 ) 208 mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) 209 if state.GetBalance(sender.Address()).Cmp(mgval) < 0 { 210 return errInsufficientBalanceForGas 211 } 212 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 213 return err 214 } 215 st.gas += st.msg.Gas() 216 217 st.initialGas = st.msg.Gas() 218 state.SubBalance(sender.Address(), mgval) 219 return nil 220 } 221 222 func (st *StateTransition) preCheck() error { 223 msg := st.msg 224 sender := st.from() 225 226 // Make sure this transaction's nonce is correct 227 if msg.CheckNonce() { 228 nonce := st.state.GetNonce(sender.Address()) 229 if nonce < msg.Nonce() { 230 return ErrNonceTooHigh 231 } else if nonce > msg.Nonce() { 232 return ErrNonceTooLow 233 } 234 } 235 return st.buyGas() 236 } 237 238 // TransitionDb will transition the state by applying the current message and 239 // returning the result including the the used gas. It returns an error if it 240 // failed. An error indicates a consensus issue. 241 func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { 242 if err := st.preCheck(); err != nil { 243 return nil, err 244 } 245 msg := st.msg 246 sender := st.from() // err checked in preCheck 247 248 homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 249 contractCreation := msg.To() == nil 250 251 // Pay intrinsic gas 252 gas, err := IntrinsicGas(st.data, contractCreation, homestead) 253 if err != nil { 254 return nil, err 255 } 256 if err = st.useGas(gas); err != nil { 257 return nil, err 258 } 259 260 var ( 261 evm = st.evm 262 // vm errors do not effect consensus and are therefor 263 // not assigned to err, except for insufficient balance 264 // error. 265 vmerr error 266 ret []byte 267 ) 268 if contractCreation { 269 ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) 270 } else { 271 // Increment the nonce for the next transaction 272 st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) 273 ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) 274 } 275 //if vmerr != nil { 276 // log.Debug("VM returned with error", "err", vmerr) 277 // // The only possible consensus-error would be if there wasn't 278 // // sufficient balance to make the transfer happen. The first 279 // // balance transfer may never fail. 280 // if vmerr == vm.ErrInsufficientBalance { 281 // return nil, 0, false, vmerr 282 // } 283 //} 284 st.refundGas() 285 st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 286 287 return &ExecutionResult{ 288 UsedGas: st.gasUsed(), 289 Err: vmerr, 290 ReturnData: ret, 291 }, nil 292 } 293 294 func (st *StateTransition) refundGas() { 295 296 // Apply refund counter, capped to half of the used gas. 297 refund := st.gasUsed() / 2 298 if refund > st.state.GetRefund() { 299 refund = st.state.GetRefund() 300 } 301 st.gas += refund 302 303 // Return ETH for remaining gas, exchanged at the original rate. 304 sender := st.from() 305 306 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 307 308 st.state.AddBalance(sender.Address(), remaining) 309 310 // Also return remaining gas to the block gas counter so it is 311 // available for the next transaction. 312 st.gp.AddGas(st.gas) 313 } 314 315 // gasUsed returns the amount of gas used up by the state transition. 316 func (st *StateTransition) gasUsed() uint64 { 317 return st.initialGas - st.gas 318 } 319 320 // ApplyMessage computes the new state by applying the given message 321 // against the old state within the environment. 322 // 323 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 324 // the gas used (which includes gas refunds) and an error if it failed. An error always 325 // indicates a core error meaning that the message would always fail for that particular 326 // state and would never be accepted within a block. 327 func ApplyMessageEx(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, *big.Int, error) { 328 return NewStateTransition(evm, msg, gp).TransitionDbEx() 329 } 330 331 // TransitionDbEx will move the state by applying the message against the given environment. 332 func (st *StateTransition) TransitionDbEx() (*ExecutionResult, *big.Int, error) { 333 334 if err := st.preCheck(); err != nil { 335 return nil, nil, err 336 } 337 msg := st.msg 338 sender := st.from() // err checked in preCheck 339 340 homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 341 contractCreation := msg.To() == nil 342 343 // Pay intrinsic gas 344 gas, err := IntrinsicGas(st.data, contractCreation, homestead) 345 if err != nil { 346 return nil, nil, err 347 } 348 if err = st.useGas(gas); err != nil { 349 return nil, nil, err 350 } 351 352 var ( 353 evm = st.evm 354 // vm errors do not effect consensus and are therefor 355 // not assigned to err, except for insufficient balance 356 // error. 357 vmerr error 358 ret []byte 359 ) 360 361 //log.Debugf("TransitionDbEx 0\n") 362 363 if contractCreation { 364 ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) 365 } else { 366 // Increment the nonce for the next transaction 367 //log.Debugf("TransitionDbEx 1, sender is %x, nonce is \n", sender.Address(), st.state.GetNonce(sender.Address())+1) 368 369 st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) 370 ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) 371 372 //log.Debugf("TransitionDbEx 2\n") 373 374 } 375 376 //log.Debugf("TransitionDbEx 3\n") 377 378 //if vmerr != nil { 379 // log.Debug("VM returned with error", "err", vmerr) 380 // // The only possible consensus-error would be if there wasn't 381 // // sufficient balance to make the transfer happen. The first 382 // // balance transfer may never fail. 383 // if vmerr == vm.ErrInsufficientBalance { 384 // return nil, 0, nil, false, vmerr 385 // } 386 //} 387 388 st.refundGas() 389 390 //log.Debugf("TransitionDbEx 4, coinbase is %x, balance is %v\n", 391 // st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 392 393 //st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 394 usedMoney := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice) 395 396 //log.Debugf("TransitionDbEx 5\n") 397 398 //log.Debugf("TransitionDbEx, send.balance is %v\n", st.state.GetBalance(sender.Address())) 399 //log.Debugf("TransitionDbEx, return ret-%v, st.gasUsed()-%v, usedMoney-%v, vmerr-%v, err-%v\n", 400 // ret, st.gasUsed(), usedMoney, vmerr, err) 401 402 //return ret, st.gasUsed(), usedMoney, vmerr != nil, err 403 404 return &ExecutionResult{ 405 UsedGas: st.gasUsed(), 406 Err: vmerr, 407 ReturnData: ret, 408 }, usedMoney, nil 409 }