github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/vm/evm.go (about) 1 package vm 2 3 import ( 4 "math/big" 5 "sync/atomic" 6 "time" 7 8 "github.com/neatlab/neatio/params" 9 "github.com/neatlab/neatio/utilities/common" 10 "github.com/neatlab/neatio/utilities/crypto" 11 ) 12 13 var emptyCodeHash = crypto.Keccak256Hash(nil) 14 15 type ( 16 CanTransferFunc func(StateDB, common.Address, *big.Int) bool 17 18 TransferFunc func(StateDB, common.Address, common.Address, *big.Int) 19 20 GetHashFunc func(uint64) common.Hash 21 ) 22 23 func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { 24 if contract.CodeAddr != nil { 25 precompiles := PrecompiledContractsHomestead 26 if evm.chainRules.IsByzantium { 27 precompiles = PrecompiledContractsByzantium 28 } 29 if evm.chainRules.IsIstanbul { 30 precompiles = PrecompiledContractsIstanbul 31 } 32 if p := precompiles[*contract.CodeAddr]; p != nil { 33 return RunPrecompiledContract(p, input, contract) 34 } 35 } 36 for _, interpreter := range evm.interpreters { 37 if interpreter.CanRun(contract.Code) { 38 if evm.interpreter != interpreter { 39 40 defer func(i Interpreter) { 41 evm.interpreter = i 42 }(evm.interpreter) 43 evm.interpreter = interpreter 44 } 45 return interpreter.Run(contract, input, readOnly) 46 } 47 } 48 return nil, ErrNoCompatibleInterpreter 49 } 50 51 type Context struct { 52 CanTransfer CanTransferFunc 53 54 Transfer TransferFunc 55 56 GetHash GetHashFunc 57 58 Origin common.Address 59 GasPrice *big.Int 60 61 Coinbase common.Address 62 GasLimit uint64 63 BlockNumber *big.Int 64 Time *big.Int 65 Difficulty *big.Int 66 } 67 68 type EVM struct { 69 Context 70 71 StateDB StateDB 72 73 depth int 74 75 chainConfig *params.ChainConfig 76 77 chainRules params.Rules 78 79 vmConfig Config 80 81 interpreters []Interpreter 82 interpreter Interpreter 83 84 abort int32 85 86 callGasTemp uint64 87 } 88 89 func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { 90 evm := &EVM{ 91 Context: ctx, 92 StateDB: statedb, 93 vmConfig: vmConfig, 94 chainConfig: chainConfig, 95 chainRules: chainConfig.Rules(ctx.BlockNumber), 96 interpreters: make([]Interpreter, 0, 1), 97 } 98 99 if chainConfig.IsEWASM(ctx.BlockNumber) { 100 101 panic("No supported ewasm interpreter yet.") 102 } 103 104 evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig)) 105 evm.interpreter = evm.interpreters[0] 106 107 return evm 108 } 109 110 func (evm *EVM) Cancel() { 111 atomic.StoreInt32(&evm.abort, 1) 112 } 113 114 func (evm *EVM) Cancelled() bool { 115 return atomic.LoadInt32(&evm.abort) == 1 116 } 117 118 func (evm *EVM) Interpreter() Interpreter { 119 return evm.interpreter 120 } 121 122 func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 123 if evm.vmConfig.NoRecursion && evm.depth > 0 { 124 return nil, gas, nil 125 } 126 127 if evm.depth > int(params.CallCreateDepth) { 128 return nil, gas, ErrDepth 129 } 130 131 if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { 132 return nil, gas, ErrInsufficientBalance 133 } 134 135 var ( 136 to = AccountRef(addr) 137 snapshot = evm.StateDB.Snapshot() 138 ) 139 if !evm.StateDB.Exist(addr) { 140 precompiles := PrecompiledContractsHomestead 141 if evm.chainRules.IsByzantium { 142 precompiles = PrecompiledContractsByzantium 143 } 144 if evm.chainRules.IsIstanbul { 145 precompiles = PrecompiledContractsIstanbul 146 } 147 if precompiles[addr] == nil && evm.chainRules.IsEIP158 && value.Sign() == 0 { 148 149 if evm.vmConfig.Debug && evm.depth == 0 { 150 evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 151 evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) 152 } 153 return nil, gas, nil 154 } 155 evm.StateDB.CreateAccount(addr) 156 } 157 evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) 158 159 contract := NewContract(caller, to, value, gas) 160 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 161 162 start := time.Now() 163 164 if evm.vmConfig.Debug && evm.depth == 0 { 165 evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 166 167 defer func() { 168 evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 169 }() 170 } 171 ret, err = run(evm, contract, input, false) 172 173 if err != nil { 174 evm.StateDB.RevertToSnapshot(snapshot) 175 if err != ErrExecutionReverted { 176 contract.UseGas(contract.Gas) 177 } 178 } 179 return ret, contract.Gas, err 180 } 181 182 func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 183 if evm.vmConfig.NoRecursion && evm.depth > 0 { 184 return nil, gas, nil 185 } 186 187 if evm.depth > int(params.CallCreateDepth) { 188 return nil, gas, ErrDepth 189 } 190 191 if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 192 return nil, gas, ErrInsufficientBalance 193 } 194 195 var ( 196 snapshot = evm.StateDB.Snapshot() 197 to = AccountRef(caller.Address()) 198 ) 199 200 contract := NewContract(caller, to, value, gas) 201 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 202 203 ret, err = run(evm, contract, input, false) 204 if err != nil { 205 evm.StateDB.RevertToSnapshot(snapshot) 206 if err != ErrExecutionReverted { 207 contract.UseGas(contract.Gas) 208 } 209 } 210 return ret, contract.Gas, err 211 } 212 213 func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 214 if evm.vmConfig.NoRecursion && evm.depth > 0 { 215 return nil, gas, nil 216 } 217 218 if evm.depth > int(params.CallCreateDepth) { 219 return nil, gas, ErrDepth 220 } 221 222 var ( 223 snapshot = evm.StateDB.Snapshot() 224 to = AccountRef(caller.Address()) 225 ) 226 227 contract := NewContract(caller, to, nil, gas).AsDelegate() 228 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 229 230 ret, err = run(evm, contract, input, false) 231 if err != nil { 232 evm.StateDB.RevertToSnapshot(snapshot) 233 if err != ErrExecutionReverted { 234 contract.UseGas(contract.Gas) 235 } 236 } 237 return ret, contract.Gas, err 238 } 239 240 func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 241 if evm.vmConfig.NoRecursion && evm.depth > 0 { 242 return nil, gas, nil 243 } 244 245 if evm.depth > int(params.CallCreateDepth) { 246 return nil, gas, ErrDepth 247 } 248 249 var ( 250 to = AccountRef(addr) 251 snapshot = evm.StateDB.Snapshot() 252 ) 253 254 contract := NewContract(caller, to, new(big.Int), gas) 255 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 256 257 evm.StateDB.AddBalance(addr, bigZero) 258 259 ret, err = run(evm, contract, input, true) 260 if err != nil { 261 evm.StateDB.RevertToSnapshot(snapshot) 262 if err != ErrExecutionReverted { 263 contract.UseGas(contract.Gas) 264 } 265 } 266 return ret, contract.Gas, err 267 } 268 269 type codeAndHash struct { 270 code []byte 271 hash common.Hash 272 } 273 274 func (c *codeAndHash) Hash() common.Hash { 275 if c.hash == (common.Hash{}) { 276 c.hash = crypto.Keccak256Hash(c.code) 277 } 278 return c.hash 279 } 280 281 func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { 282 283 if evm.depth > int(params.CallCreateDepth) { 284 return nil, common.Address{}, gas, ErrDepth 285 } 286 if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 287 return nil, common.Address{}, gas, ErrInsufficientBalance 288 } 289 nonce := evm.StateDB.GetNonce(caller.Address()) 290 evm.StateDB.SetNonce(caller.Address(), nonce+1) 291 292 contractHash := evm.StateDB.GetCodeHash(address) 293 if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { 294 return nil, common.Address{}, 0, ErrContractAddressCollision 295 } 296 297 snapshot := evm.StateDB.Snapshot() 298 evm.StateDB.CreateAccount(address) 299 if evm.chainRules.IsEIP158 { 300 evm.StateDB.SetNonce(address, 1) 301 } 302 evm.Transfer(evm.StateDB, caller.Address(), address, value) 303 304 contract := NewContract(caller, AccountRef(address), value, gas) 305 contract.SetCodeOptionalHash(&address, codeAndHash) 306 307 if evm.vmConfig.NoRecursion && evm.depth > 0 { 308 return nil, address, gas, nil 309 } 310 311 if evm.vmConfig.Debug && evm.depth == 0 { 312 evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) 313 } 314 start := time.Now() 315 316 ret, err := run(evm, contract, nil, false) 317 318 maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize 319 320 if err == nil && !maxCodeSizeExceeded { 321 createDataGas := uint64(len(ret)) * params.CreateDataGas 322 if contract.UseGas(createDataGas) { 323 evm.StateDB.SetCode(address, ret) 324 } else { 325 err = ErrCodeStoreOutOfGas 326 } 327 } 328 329 if maxCodeSizeExceeded || (err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas)) { 330 evm.StateDB.RevertToSnapshot(snapshot) 331 if err != ErrExecutionReverted { 332 contract.UseGas(contract.Gas) 333 } 334 } 335 336 if maxCodeSizeExceeded && err == nil { 337 err = ErrMaxCodeSizeExceeded 338 } 339 if evm.vmConfig.Debug && evm.depth == 0 { 340 evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 341 } 342 return ret, address, contract.Gas, err 343 344 } 345 346 func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { 347 contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) 348 return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr) 349 } 350 351 func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { 352 codeAndHash := &codeAndHash{code: code} 353 contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes()) 354 return evm.create(caller, codeAndHash, gas, endowment, contractAddr) 355 } 356 357 func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }