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