github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/core/state_transition.go (about) 1 package core 2 3 import ( 4 "errors" 5 "math" 6 "math/big" 7 8 "github.com/neatio-net/neatio/chain/core/vm" 9 "github.com/neatio-net/neatio/params" 10 "github.com/neatio-net/neatio/utilities/common" 11 ) 12 13 var ( 14 errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") 15 ) 16 17 type StateTransition struct { 18 gp *GasPool 19 msg Message 20 gas uint64 21 gasPrice *big.Int 22 initialGas uint64 23 value *big.Int 24 data []byte 25 state vm.StateDB 26 evm *vm.EVM 27 } 28 29 type Message interface { 30 From() common.Address 31 32 To() *common.Address 33 34 GasPrice() *big.Int 35 Gas() uint64 36 Value() *big.Int 37 38 Nonce() uint64 39 CheckNonce() bool 40 Data() []byte 41 } 42 43 type ExecutionResult struct { 44 UsedGas uint64 45 Err error 46 ReturnData []byte 47 } 48 49 func (result *ExecutionResult) Unwrap() error { 50 return result.Err 51 } 52 53 func (result *ExecutionResult) Failed() bool { return result.Err != nil } 54 55 func (result *ExecutionResult) Return() []byte { 56 if result.Err != nil { 57 return nil 58 } 59 return common.CopyBytes(result.ReturnData) 60 } 61 62 func (result *ExecutionResult) Revert() []byte { 63 if result.Err != vm.ErrExecutionReverted { 64 return nil 65 } 66 return common.CopyBytes(result.ReturnData) 67 } 68 69 func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) { 70 71 var gas uint64 72 if contractCreation && homestead { 73 gas = params.TxGasContractCreation 74 } else { 75 gas = params.TxGas 76 } 77 78 if len(data) > 0 { 79 80 var nz uint64 81 for _, byt := range data { 82 if byt != 0 { 83 nz++ 84 } 85 } 86 87 nonZeroGas := params.TxDataNonZeroGasFrontier 88 if (math.MaxUint64-gas)/nonZeroGas < nz { 89 return 0, vm.ErrOutOfGas 90 } 91 gas += nz * nonZeroGas 92 93 z := uint64(len(data)) - nz 94 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 95 return 0, vm.ErrOutOfGas 96 } 97 gas += z * params.TxDataZeroGas 98 } 99 return gas, nil 100 } 101 102 func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { 103 return &StateTransition{ 104 gp: gp, 105 evm: evm, 106 msg: msg, 107 gasPrice: msg.GasPrice(), 108 value: msg.Value(), 109 data: msg.Data(), 110 state: evm.StateDB, 111 } 112 } 113 114 func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) { 115 return NewStateTransition(evm, msg, gp).TransitionDb() 116 } 117 118 func (st *StateTransition) from() vm.AccountRef { 119 f := st.msg.From() 120 if !st.state.Exist(f) { 121 st.state.CreateAccount(f) 122 } 123 return vm.AccountRef(f) 124 } 125 126 func (st *StateTransition) to() vm.AccountRef { 127 if st.msg == nil { 128 return vm.AccountRef{} 129 } 130 to := st.msg.To() 131 if to == nil { 132 return vm.AccountRef{} 133 } 134 135 reference := vm.AccountRef(*to) 136 if !st.state.Exist(*to) { 137 st.state.CreateAccount(*to) 138 } 139 return reference 140 } 141 142 func (st *StateTransition) useGas(amount uint64) error { 143 if st.gas < amount { 144 return vm.ErrOutOfGas 145 } 146 st.gas -= amount 147 148 return nil 149 } 150 151 func (st *StateTransition) buyGas() error { 152 var ( 153 state = st.state 154 sender = st.from() 155 ) 156 mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) 157 if state.GetBalance(sender.Address()).Cmp(mgval) < 0 { 158 return errInsufficientBalanceForGas 159 } 160 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 161 return err 162 } 163 st.gas += st.msg.Gas() 164 165 st.initialGas = st.msg.Gas() 166 state.SubBalance(sender.Address(), mgval) 167 return nil 168 } 169 170 func (st *StateTransition) preCheck() error { 171 msg := st.msg 172 sender := st.from() 173 174 if msg.CheckNonce() { 175 nonce := st.state.GetNonce(sender.Address()) 176 if nonce < msg.Nonce() { 177 return ErrNonceTooHigh 178 } else if nonce > msg.Nonce() { 179 return ErrNonceTooLow 180 } 181 } 182 return st.buyGas() 183 } 184 185 func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { 186 if err := st.preCheck(); err != nil { 187 return nil, err 188 } 189 msg := st.msg 190 sender := st.from() 191 192 homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 193 contractCreation := msg.To() == nil 194 195 gas, err := IntrinsicGas(st.data, contractCreation, homestead) 196 if err != nil { 197 return nil, err 198 } 199 if err = st.useGas(gas); err != nil { 200 return nil, err 201 } 202 203 var ( 204 evm = st.evm 205 206 vmerr error 207 ret []byte 208 ) 209 if contractCreation { 210 ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) 211 } else { 212 213 st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) 214 ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) 215 } 216 217 st.refundGas() 218 st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 219 220 return &ExecutionResult{ 221 UsedGas: st.gasUsed(), 222 Err: vmerr, 223 ReturnData: ret, 224 }, nil 225 } 226 227 func (st *StateTransition) refundGas() { 228 229 refund := st.gasUsed() / 2 230 if refund > st.state.GetRefund() { 231 refund = st.state.GetRefund() 232 } 233 st.gas += refund 234 235 sender := st.from() 236 237 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 238 239 st.state.AddBalance(sender.Address(), remaining) 240 241 st.gp.AddGas(st.gas) 242 } 243 244 func (st *StateTransition) gasUsed() uint64 { 245 return st.initialGas - st.gas 246 } 247 248 func ApplyMessageEx(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, *big.Int, error) { 249 return NewStateTransition(evm, msg, gp).TransitionDbEx() 250 } 251 252 func (st *StateTransition) TransitionDbEx() (*ExecutionResult, *big.Int, error) { 253 254 if err := st.preCheck(); err != nil { 255 return nil, nil, err 256 } 257 msg := st.msg 258 sender := st.from() 259 260 homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 261 contractCreation := msg.To() == nil 262 263 gas, err := IntrinsicGas(st.data, contractCreation, homestead) 264 if err != nil { 265 return nil, nil, err 266 } 267 if err = st.useGas(gas); err != nil { 268 return nil, nil, err 269 } 270 271 var ( 272 evm = st.evm 273 274 vmerr error 275 ret []byte 276 ) 277 278 if contractCreation { 279 ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) 280 } else { 281 282 st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) 283 ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) 284 285 } 286 287 st.refundGas() 288 289 usedMoney := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice) 290 291 return &ExecutionResult{ 292 UsedGas: st.gasUsed(), 293 Err: vmerr, 294 ReturnData: ret, 295 }, usedMoney, nil 296 }