github.com/aswedchain/aswed@v1.0.1/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 "github.com/aswedchain/aswed/common" 21 "github.com/aswedchain/aswed/consensus" 22 "github.com/aswedchain/aswed/core/types" 23 "github.com/aswedchain/aswed/core/vm" 24 "github.com/aswedchain/aswed/params" 25 "math" 26 "math/big" 27 ) 28 29 /* 30 The State Transitioning Model 31 32 A state transition is a change made when a transaction is applied to the current world state 33 The state transitioning model does all the necessary work to work out a valid new state root. 34 35 1) Nonce handling 36 2) Pre pay gas 37 3) Create a new state object if the recipient is \0*32 38 4) Value transfer 39 == If contract creation == 40 4a) Attempt to run transaction data 41 4b) If valid, use result as code for the new state object 42 == end == 43 5) Run Script section 44 6) Derive new state root 45 */ 46 type StateTransition struct { 47 gp *GasPool 48 msg Message 49 gas uint64 50 gasPrice *big.Int 51 initialGas uint64 52 value *big.Int 53 data []byte 54 state vm.StateDB 55 evm *vm.EVM 56 isMeta bool 57 feeAddress common.Address 58 feePercent uint64 //meta transaction fee percent 59 realPayload []byte //the real transaction fee percent 60 } 61 62 // Message represents a message sent to a contract. 63 type Message interface { 64 From() common.Address 65 To() *common.Address 66 67 GasPrice() *big.Int 68 Gas() uint64 69 Value() *big.Int 70 71 Nonce() uint64 72 CheckNonce() bool 73 Data() []byte 74 } 75 76 // ExecutionResult includes all output after executing given evm 77 // message no matter the execution itself is successful or not. 78 type ExecutionResult struct { 79 UsedGas uint64 // Total used gas but include the refunded gas 80 Err error // Any error encountered during the execution(listed in core/vm/errors.go) 81 ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) 82 } 83 84 // Unwrap returns the internal evm error which allows us for further 85 // analysis outside. 86 func (result *ExecutionResult) Unwrap() error { 87 return result.Err 88 } 89 90 // Failed returns the indicator whether the execution is successful or not 91 func (result *ExecutionResult) Failed() bool { return result.Err != nil } 92 93 // Return is a helper function to help caller distinguish between revert reason 94 // and function return. Return returns the data after execution if no error occurs. 95 func (result *ExecutionResult) Return() []byte { 96 if result.Err != nil { 97 return nil 98 } 99 return common.CopyBytes(result.ReturnData) 100 } 101 102 // Revert returns the concrete revert reason if the execution is aborted by `REVERT` 103 // opcode. Note the reason can be nil if no data supplied with revert opcode. 104 func (result *ExecutionResult) Revert() []byte { 105 if result.Err != vm.ErrExecutionReverted { 106 return nil 107 } 108 return common.CopyBytes(result.ReturnData) 109 } 110 111 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. 112 func IntrinsicGas(data []byte, contractCreation, isHomestead bool, isEIP2028 bool) (uint64, error) { 113 // Set the starting gas for the raw transaction 114 var gas uint64 115 if contractCreation && isHomestead { 116 gas = params.TxGasContractCreation 117 } else { 118 gas = params.TxGas 119 } 120 // Bump the required gas by the amount of transactional data 121 if len(data) > 0 { 122 // Zero and non-zero bytes are priced differently 123 var nz uint64 124 for _, byt := range data { 125 if byt != 0 { 126 nz++ 127 } 128 } 129 // Make sure we don't exceed uint64 for all data combinations 130 nonZeroGas := params.TxDataNonZeroGasFrontier 131 if isEIP2028 { 132 nonZeroGas = params.TxDataNonZeroGasEIP2028 133 } 134 if (math.MaxUint64-gas)/nonZeroGas < nz { 135 return 0, ErrGasUintOverflow 136 } 137 gas += nz * nonZeroGas 138 139 z := uint64(len(data)) - nz 140 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 141 return 0, ErrGasUintOverflow 142 } 143 gas += z * params.TxDataZeroGas 144 } 145 return gas, nil 146 } 147 148 // NewStateTransition initialises and returns a new state transition object. 149 func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { 150 return &StateTransition{ 151 gp: gp, 152 evm: evm, 153 msg: msg, 154 gasPrice: msg.GasPrice(), 155 value: msg.Value(), 156 data: msg.Data(), 157 state: evm.StateDB, 158 } 159 } 160 161 // ApplyMessage computes the new state by applying the given message 162 // against the old state within the environment. 163 // 164 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 165 // the gas used (which includes gas refunds) and an error if it failed. An error always 166 // indicates a core error meaning that the message would always fail for that particular 167 // state and would never be accepted within a block. 168 func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) { 169 return NewStateTransition(evm, msg, gp).TransitionDb() 170 } 171 172 // to returns the recipient of the message. 173 func (st *StateTransition) to() common.Address { 174 if st.msg == nil || st.msg.To() == nil /* contract creation */ { 175 return common.Address{} 176 } 177 return *st.msg.To() 178 } 179 180 func (st *StateTransition) buyGas() error { 181 mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) 182 if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { 183 return ErrInsufficientFunds 184 } 185 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 186 return err 187 } 188 st.gas += st.msg.Gas() 189 190 st.initialGas = st.msg.Gas() 191 st.state.SubBalance(st.msg.From(), mgval) 192 return nil 193 } 194 195 func (st *StateTransition) buyGasMeta() error { 196 197 mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) 198 mgFeeAddrVal := new(big.Int).Div(new(big.Int).Mul(mgval, new(big.Int).SetUint64(st.feePercent)), types.BIG10000) //value deduct from fee address 199 mgSelfVal := new(big.Int).Div(new(big.Int).Mul(mgval, new(big.Int).SetUint64(types.BIG10000.Uint64()-st.feePercent)), types.BIG10000) //value deduct from sender address 200 201 if st.state.GetBalance(st.feeAddress).Cmp(mgFeeAddrVal) < 0 || st.state.GetBalance(st.msg.From()).Cmp(mgSelfVal) < 0 { 202 return ErrInsufficientFunds 203 } 204 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 205 return err 206 } 207 st.gas += st.msg.Gas() 208 209 st.initialGas = st.msg.Gas() 210 st.state.SubBalance(st.feeAddress, mgFeeAddrVal) 211 st.state.SubBalance(st.msg.From(), mgSelfVal) 212 return nil 213 } 214 215 /** 216 检查是普通交易还是元交易类型, 元交易和普通交易的区别在于extraData开头的标识位 217 */ 218 func (st *StateTransition) preCheck() error { 219 // Make sure this transaction's nonce is correct. 220 if st.msg.CheckNonce() { 221 nonce := st.state.GetNonce(st.msg.From()) 222 if nonce < st.msg.Nonce() { 223 return ErrNonceTooHigh 224 } else if nonce > st.msg.Nonce() { 225 return ErrNonceTooLow 226 } 227 } 228 229 if err := st.metaTransactionCheck(); err != nil { 230 return err 231 } 232 if st.isMeta { 233 return st.buyGasMeta() 234 } 235 return st.buyGas() 236 } 237 238 //check if tx is meta tx 239 func (st *StateTransition) metaTransactionCheck() error { 240 if types.IsMetaTransaction(st.data) { 241 metaData, err := types.DecodeMetaData(st.data, st.evm.BlockNumber) 242 if err != nil { 243 return err 244 } 245 chainID := st.evm.ChainConfig().ChainID 246 addr, err := metaData.ParseMetaData(st.msg.Nonce(), st.msg.GasPrice(), st.msg.Gas(), st.msg.To(), st.msg.Value(), metaData.Payload, st.msg.From(), chainID) 247 if err != nil { 248 return err 249 } 250 st.isMeta = true 251 st.feeAddress = addr 252 st.realPayload = st.data 253 st.data = metaData.Payload 254 st.feePercent = metaData.FeePercent 255 return nil 256 } 257 return nil 258 } 259 260 // TransitionDb will transition the state by applying the current message and 261 // returning the evm execution result with following fields. 262 // 263 // - used gas: 264 // total gas used (including gas being refunded) 265 // - returndata: 266 // the returned data from evm 267 // - concrete execution error: 268 // various **EVM** error which aborts the execution, 269 // e.g. ErrOutOfGas, ErrExecutionReverted 270 // 271 // However if any consensus issue encountered, return the error directly with 272 // nil evm execution result. 273 func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { 274 // First check this message satisfies all consensus rules before 275 // applying the message. The rules include these clauses 276 // 277 // 1. the nonce of the message caller is correct 278 // 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) 279 // 3. the amount of gas required is available in the block 280 // 4. the purchased gas is enough to cover intrinsic usage 281 // 5. there is no overflow when calculating intrinsic gas 282 // 6. caller has enough balance to cover asset transfer for **topmost** call 283 284 // Check clauses 1-3, buy gas if everything is correct 285 if err := st.preCheck(); err != nil { 286 return nil, err 287 } 288 msg := st.msg 289 sender := vm.AccountRef(msg.From()) 290 homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 291 istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber) 292 contractCreation := msg.To() == nil 293 294 // Check clauses 4-5, subtract intrinsic gas if everything is correct 295 gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul) 296 if err != nil { 297 return nil, err 298 } 299 if st.gas < gas { 300 return nil, ErrIntrinsicGas 301 } 302 st.gas -= gas 303 304 // Check clause 6 305 if msg.Value().Sign() > 0 && !st.evm.CanTransfer(st.state, msg.From(), msg.Value()) { 306 return nil, ErrInsufficientFundsForTransfer 307 } 308 // Check if can create 309 if contractCreation && st.evm.CanCreate != nil { 310 if !st.evm.CanCreate(st.evm.StateDB, msg.From(), st.evm.BlockNumber) { 311 return nil, ErrUnauthorizedDeveloper 312 } 313 } 314 315 var ( 316 ret []byte 317 vmerr error // vm errors do not effect consensus and are therefore not assigned to err 318 ) 319 if contractCreation { 320 ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value) 321 } else { 322 // Increment the nonce for the next transaction 323 st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) 324 ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) 325 } 326 st.refundGas() 327 328 if st.evm.ChainConfig().Congress != nil { 329 st.state.AddBalance(consensus.FeeRecoder, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 330 } else { 331 st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 332 } 333 334 return &ExecutionResult{ 335 UsedGas: st.gasUsed(), 336 Err: vmerr, 337 ReturnData: ret, 338 }, nil 339 } 340 341 func (st *StateTransition) refundGas() { 342 // Apply refund counter, capped to half of the used gas. 343 refund := st.gasUsed() / 2 344 if refund > st.state.GetRefund() { 345 refund = st.state.GetRefund() 346 } 347 st.gas += refund 348 349 // Return ETH for remaining gas, exchanged at the original rate. 350 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 351 352 if st.isMeta { 353 mgFeeAddrVal := new(big.Int).Div(new(big.Int).Mul(remaining, new(big.Int).SetUint64(st.feePercent)), types.BIG10000) 354 mgSelfVal := new(big.Int).Div(new(big.Int).Mul(remaining, new(big.Int).SetUint64(types.BIG10000.Uint64()-st.feePercent)), types.BIG10000) 355 st.state.AddBalance(st.feeAddress, mgFeeAddrVal) 356 st.state.AddBalance(st.msg.From(), mgSelfVal) 357 st.data = st.realPayload 358 } else { 359 st.state.AddBalance(st.msg.From(), remaining) 360 } 361 362 // Also return remaining gas to the block gas counter so it is 363 // available for the next transaction. 364 st.gp.AddGas(st.gas) 365 } 366 367 // gasUsed returns the amount of gas used up by the state transition. 368 func (st *StateTransition) gasUsed() uint64 { 369 return st.initialGas - st.gas 370 }