github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/emulator/emulator.go (about) 1 package emulator 2 3 import ( 4 "errors" 5 "math/big" 6 7 "github.com/onflow/atree" 8 gethCommon "github.com/onflow/go-ethereum/common" 9 gethCore "github.com/onflow/go-ethereum/core" 10 gethTypes "github.com/onflow/go-ethereum/core/types" 11 gethVM "github.com/onflow/go-ethereum/core/vm" 12 gethCrypto "github.com/onflow/go-ethereum/crypto" 13 gethParams "github.com/onflow/go-ethereum/params" 14 15 "github.com/onflow/flow-go/fvm/evm/emulator/state" 16 "github.com/onflow/flow-go/fvm/evm/types" 17 "github.com/onflow/flow-go/model/flow" 18 ) 19 20 // Emulator handles operations against evm runtime 21 type Emulator struct { 22 rootAddr flow.Address 23 ledger atree.Ledger 24 } 25 26 var _ types.Emulator = &Emulator{} 27 28 // NewEmulator constructs a new EVM Emulator 29 func NewEmulator( 30 ledger atree.Ledger, 31 rootAddr flow.Address, 32 ) *Emulator { 33 return &Emulator{ 34 rootAddr: rootAddr, 35 ledger: ledger, 36 } 37 } 38 39 func newConfig(ctx types.BlockContext) *Config { 40 return NewConfig( 41 WithChainID(ctx.ChainID), 42 WithBlockNumber(new(big.Int).SetUint64(ctx.BlockNumber)), 43 WithBlockTime(ctx.BlockTimestamp), 44 WithCoinbase(ctx.GasFeeCollector.ToCommon()), 45 WithDirectCallBaseGasUsage(ctx.DirectCallBaseGasUsage), 46 WithExtraPrecompiles(ctx.ExtraPrecompiles), 47 WithGetBlockHashFunction(ctx.GetHashFunc), 48 WithRandom(&ctx.Random), 49 ) 50 } 51 52 // NewReadOnlyBlockView constructs a new readonly block view 53 func (em *Emulator) NewReadOnlyBlockView(ctx types.BlockContext) (types.ReadOnlyBlockView, error) { 54 execState, err := state.NewStateDB(em.ledger, em.rootAddr) 55 return &ReadOnlyBlockView{ 56 state: execState, 57 }, err 58 } 59 60 // NewBlockView constructs a new block view (mutable) 61 func (em *Emulator) NewBlockView(ctx types.BlockContext) (types.BlockView, error) { 62 cfg := newConfig(ctx) 63 return &BlockView{ 64 config: cfg, 65 rootAddr: em.rootAddr, 66 ledger: em.ledger, 67 }, nil 68 } 69 70 // ReadOnlyBlockView provides a read only view of a block 71 // could be used multiple times for queries 72 type ReadOnlyBlockView struct { 73 state types.StateDB 74 } 75 76 // BalanceOf returns the balance of the given address 77 func (bv *ReadOnlyBlockView) BalanceOf(address types.Address) (*big.Int, error) { 78 return bv.state.GetBalance(address.ToCommon()), nil 79 } 80 81 // NonceOf returns the nonce of the given address 82 func (bv *ReadOnlyBlockView) NonceOf(address types.Address) (uint64, error) { 83 return bv.state.GetNonce(address.ToCommon()), nil 84 } 85 86 // CodeOf returns the code of the given address 87 func (bv *ReadOnlyBlockView) CodeOf(address types.Address) (types.Code, error) { 88 return bv.state.GetCode(address.ToCommon()), nil 89 } 90 91 // CodeHashOf returns the code hash of the given address 92 func (bv *ReadOnlyBlockView) CodeHashOf(address types.Address) ([]byte, error) { 93 return bv.state.GetCodeHash(address.ToCommon()).Bytes(), nil 94 } 95 96 // BlockView allows mutation of the evm state as part of a block 97 // 98 // TODO: allow multiple calls per block view 99 // TODO: add block level commit (separation of trie commit to storage) 100 type BlockView struct { 101 config *Config 102 rootAddr flow.Address 103 ledger atree.Ledger 104 } 105 106 // DirectCall executes a direct call 107 func (bl *BlockView) DirectCall(call *types.DirectCall) (*types.Result, error) { 108 proc, err := bl.newProcedure() 109 if err != nil { 110 return nil, err 111 } 112 txHash, err := call.Hash() 113 if err != nil { 114 return nil, err 115 } 116 switch call.SubType { 117 case types.DepositCallSubType: 118 return proc.mintTo(call, txHash) 119 case types.WithdrawCallSubType: 120 return proc.withdrawFrom(call, txHash) 121 case types.DeployCallSubType: 122 if !call.EmptyToField() { 123 return proc.deployAt(call.From, call.To, call.Data, call.GasLimit, call.Value, txHash) 124 } 125 fallthrough 126 default: 127 // TODO: when we support mutiple calls per block, we need 128 // to update the value zero here for tx index 129 return proc.runDirect(call.Message(), txHash, 0) 130 } 131 } 132 133 // RunTransaction runs an evm transaction 134 func (bl *BlockView) RunTransaction( 135 tx *gethTypes.Transaction, 136 ) (*types.Result, error) { 137 proc, err := bl.newProcedure() 138 if err != nil { 139 return nil, err 140 } 141 142 msg, err := gethCore.TransactionToMessage( 143 tx, 144 GetSigner(bl.config), 145 proc.config.BlockContext.BaseFee) 146 if err != nil { 147 // this is not a fatal error (e.g. due to bad signature) 148 // not a valid transaction 149 return types.NewInvalidResult(tx, err), nil 150 } 151 152 // update tx context origin 153 proc.evm.TxContext.Origin = msg.From 154 res, err := proc.run(msg, tx.Hash(), 0, tx.Type()) 155 if err != nil { 156 return nil, err 157 } 158 // all commmit errors (StateDB errors) has to be returned 159 if err := proc.commit(true); err != nil { 160 return nil, err 161 } 162 163 return res, nil 164 } 165 166 func (bl *BlockView) BatchRunTransactions(txs []*gethTypes.Transaction) ([]*types.Result, error) { 167 batchResults := make([]*types.Result, len(txs)) 168 169 proc, err := bl.newProcedure() 170 if err != nil { 171 return nil, err 172 } 173 174 for i, tx := range txs { 175 msg, err := gethCore.TransactionToMessage( 176 tx, 177 GetSigner(bl.config), 178 proc.config.BlockContext.BaseFee) 179 if err != nil { 180 batchResults[i] = types.NewInvalidResult(tx, err) 181 continue 182 } 183 184 // update tx context origin 185 proc.evm.TxContext.Origin = msg.From 186 res, err := proc.run(msg, tx.Hash(), uint(i), tx.Type()) 187 if err != nil { 188 return nil, err 189 } 190 // all commmit errors (StateDB errors) has to be returned 191 if err := proc.commit(false); err != nil { 192 return nil, err 193 } 194 195 // this clears state for any subsequent transaction runs 196 proc.state.Reset() 197 198 batchResults[i] = res 199 } 200 201 // finalize after all the batch transactions are executed to save resources 202 if err := proc.state.Finalize(); err != nil { 203 return nil, err 204 } 205 206 return batchResults, nil 207 } 208 209 // DryRunTransaction run unsigned transaction without persisting the state 210 func (bl *BlockView) DryRunTransaction( 211 tx *gethTypes.Transaction, 212 from gethCommon.Address, 213 ) (*types.Result, error) { 214 proc, err := bl.newProcedure() 215 if err != nil { 216 return nil, err 217 } 218 219 msg, err := gethCore.TransactionToMessage( 220 tx, 221 GetSigner(bl.config), 222 proc.config.BlockContext.BaseFee, 223 ) 224 // we can ignore invalid signature errors since we don't expect signed transctions 225 if !errors.Is(err, gethTypes.ErrInvalidSig) { 226 return nil, err 227 } 228 229 // use the from as the signer 230 proc.evm.TxContext.Origin = from 231 msg.From = from 232 // we need to skip nonce check for dry run 233 msg.SkipAccountChecks = true 234 235 // return without commiting the state 236 return proc.run(msg, tx.Hash(), 0, tx.Type()) 237 } 238 239 func (bl *BlockView) newProcedure() (*procedure, error) { 240 execState, err := state.NewStateDB(bl.ledger, bl.rootAddr) 241 if err != nil { 242 return nil, err 243 } 244 cfg := bl.config 245 return &procedure{ 246 config: cfg, 247 evm: gethVM.NewEVM( 248 *cfg.BlockContext, 249 *cfg.TxContext, 250 execState, 251 cfg.ChainConfig, 252 cfg.EVMConfig, 253 ), 254 state: execState, 255 }, nil 256 } 257 258 type procedure struct { 259 config *Config 260 evm *gethVM.EVM 261 state types.StateDB 262 } 263 264 // commit commits the changes to the state (with optional finalization) 265 func (proc *procedure) commit(finalize bool) error { 266 err := proc.state.Commit(finalize) 267 if err != nil { 268 // if known types (state errors) don't do anything and return 269 if types.IsAFatalError(err) || types.IsAStateError(err) { 270 return err 271 } 272 273 // else is a new fatal error 274 return types.NewFatalError(err) 275 } 276 return nil 277 } 278 279 func (proc *procedure) mintTo( 280 call *types.DirectCall, 281 txHash gethCommon.Hash, 282 ) (*types.Result, error) { 283 bridge := call.From.ToCommon() 284 285 // create bridge account if not exist 286 if !proc.state.Exist(bridge) { 287 proc.state.CreateAccount(bridge) 288 } 289 290 // add balance to the bridge account before transfer 291 proc.state.AddBalance(bridge, call.Value) 292 293 msg := call.Message() 294 proc.evm.TxContext.Origin = msg.From 295 // withdraw the amount and move it to the bridge account 296 res, err := proc.run(msg, txHash, 0, types.DirectCallTxType) 297 if err != nil { 298 return res, err 299 } 300 301 // if any error (invalid or vm) on the internal call, revert and don't commit any change 302 // this prevents having cases that we add balance to the bridge but the transfer 303 // fails due to gas, etc. 304 // TODO: in the future we might just return without error and handle everything on higher level 305 if res.Invalid() || res.Failed() { 306 return res, types.ErrInternalDirectCallFailed 307 } 308 309 // all commmit errors (StateDB errors) has to be returned 310 return res, proc.commit(true) 311 } 312 313 func (proc *procedure) withdrawFrom( 314 call *types.DirectCall, 315 txHash gethCommon.Hash, 316 ) (*types.Result, error) { 317 bridge := call.To.ToCommon() 318 319 // create bridge account if not exist 320 if !proc.state.Exist(bridge) { 321 proc.state.CreateAccount(bridge) 322 } 323 324 // withdraw the amount and move it to the bridge account 325 msg := call.Message() 326 proc.evm.TxContext.Origin = msg.From 327 res, err := proc.run(msg, txHash, 0, types.DirectCallTxType) 328 if err != nil { 329 return res, err 330 } 331 332 // if any error (invalid or vm) on the internal call, revert and don't commit any change 333 // TODO: in the future we might just return without error and handle everything on higher level 334 if res.Invalid() || res.Failed() { 335 return res, types.ErrInternalDirectCallFailed 336 } 337 338 // now deduct the balance from the bridge 339 proc.state.SubBalance(bridge, call.Value) 340 // all commmit errors (StateDB errors) has to be returned 341 return res, proc.commit(true) 342 } 343 344 // deployAt deploys a contract at the given target address 345 // behaviour should be similar to what evm.create internal method does with 346 // a few differences, don't need to check for previous forks given this 347 // functionality was not available to anyone, we don't need to 348 // follow snapshoting, given we do commit/revert style in this code base. 349 // in the future we might optimize this method accepting deploy-ready byte codes 350 // and skip interpreter call, gas calculations and many checks. 351 func (proc *procedure) deployAt( 352 caller types.Address, 353 to types.Address, 354 data types.Code, 355 gasLimit uint64, 356 value *big.Int, 357 txHash gethCommon.Hash, 358 ) (*types.Result, error) { 359 if value.Sign() < 0 { 360 return nil, types.ErrInvalidBalance 361 } 362 363 res := &types.Result{ 364 TxType: types.DirectCallTxType, 365 TxHash: txHash, 366 } 367 368 addr := to.ToCommon() 369 370 // precheck 1 - check balance of the source 371 if value.Sign() != 0 && 372 !proc.evm.Context.CanTransfer(proc.state, caller.ToCommon(), value) { 373 res.SetValidationError(gethCore.ErrInsufficientFundsForTransfer) 374 return res, nil 375 } 376 377 // precheck 2 - ensure there's no existing eoa or contract is deployed at the address 378 contractHash := proc.state.GetCodeHash(addr) 379 if proc.state.GetNonce(addr) != 0 || 380 (contractHash != (gethCommon.Hash{}) && contractHash != gethTypes.EmptyCodeHash) { 381 res.VMError = gethVM.ErrContractAddressCollision 382 return res, nil 383 } 384 385 callerCommon := caller.ToCommon() 386 // setup caller if doesn't exist 387 if !proc.state.Exist(callerCommon) { 388 proc.state.CreateAccount(callerCommon) 389 } 390 // increment the nonce for the caller 391 proc.state.SetNonce(callerCommon, proc.state.GetNonce(callerCommon)+1) 392 393 // setup account 394 proc.state.CreateAccount(addr) 395 proc.state.SetNonce(addr, 1) // (EIP-158) 396 if value.Sign() > 0 { 397 proc.evm.Context.Transfer( // transfer value 398 proc.state, 399 caller.ToCommon(), 400 addr, 401 value, 402 ) 403 } 404 405 // run code through interpreter 406 // this would check for errors and computes the final bytes to be stored under account 407 var err error 408 inter := gethVM.NewEVMInterpreter(proc.evm) 409 contract := gethVM.NewContract( 410 gethVM.AccountRef(caller.ToCommon()), 411 gethVM.AccountRef(addr), 412 value, 413 gasLimit) 414 415 contract.SetCallCode(&addr, gethCrypto.Keccak256Hash(data), data) 416 // update access list (Berlin) 417 proc.state.AddAddressToAccessList(addr) 418 419 ret, err := inter.Run(contract, nil, false) 420 gasCost := uint64(len(ret)) * gethParams.CreateDataGas 421 res.GasConsumed = gasCost 422 423 // handle errors 424 if err != nil { 425 // for all errors except this one consume all the remaining gas (Homestead) 426 if err != gethVM.ErrExecutionReverted { 427 res.GasConsumed = gasLimit 428 } 429 res.VMError = err 430 return res, nil 431 } 432 433 // update gas usage 434 if gasCost > gasLimit { 435 // consume all the remaining gas (Homestead) 436 res.GasConsumed = gasLimit 437 res.VMError = gethVM.ErrCodeStoreOutOfGas 438 return res, nil 439 } 440 441 // check max code size (EIP-158) 442 if len(ret) > gethParams.MaxCodeSize { 443 // consume all the remaining gas (Homestead) 444 res.GasConsumed = gasLimit 445 res.VMError = gethVM.ErrMaxCodeSizeExceeded 446 return res, nil 447 } 448 449 // reject code starting with 0xEF (EIP-3541) 450 if len(ret) >= 1 && ret[0] == 0xEF { 451 // consume all the remaining gas (Homestead) 452 res.GasConsumed = gasLimit 453 res.VMError = gethVM.ErrInvalidCode 454 return res, nil 455 } 456 457 res.DeployedContractAddress = &to 458 459 proc.state.SetCode(addr, ret) 460 return res, proc.commit(true) 461 } 462 463 func (proc *procedure) runDirect( 464 msg *gethCore.Message, 465 txHash gethCommon.Hash, 466 txIndex uint, 467 ) (*types.Result, error) { 468 // set the nonce for the message (needed for some opeartions like deployment) 469 msg.Nonce = proc.state.GetNonce(msg.From) 470 proc.evm.TxContext.Origin = msg.From 471 res, err := proc.run(msg, txHash, txIndex, types.DirectCallTxType) 472 if err != nil { 473 return nil, err 474 } 475 // all commmit errors (StateDB errors) has to be returned 476 return res, proc.commit(true) 477 } 478 479 // run runs a geth core.message and returns the 480 // results, any validation or execution errors 481 // are captured inside the result, the remaining 482 // return errors are errors requires extra handling 483 // on upstream (e.g. backend errors). 484 func (proc *procedure) run( 485 msg *gethCore.Message, 486 txHash gethCommon.Hash, 487 txIndex uint, 488 txType uint8, 489 ) (*types.Result, error) { 490 res := types.Result{ 491 TxType: txType, 492 TxHash: txHash, 493 } 494 495 gasPool := (*gethCore.GasPool)(&proc.config.BlockContext.GasLimit) 496 execResult, err := gethCore.NewStateTransition( 497 proc.evm, 498 msg, 499 gasPool, 500 ).TransitionDb() 501 if err != nil { 502 // if the error is a fatal error or a non-fatal state error or a backend err return it 503 // this condition should never happen given all StateDB errors are withheld for the commit time. 504 if types.IsAFatalError(err) || types.IsAStateError(err) || types.IsABackendError(err) { 505 return nil, err 506 } 507 // otherwise is a validation error (pre-check failure) 508 // no state change, wrap the error and return 509 res.SetValidationError(err) 510 return &res, nil 511 } 512 513 // if prechecks are passed, the exec result won't be nil 514 if execResult != nil { 515 res.GasConsumed = execResult.UsedGas 516 res.Index = uint16(txIndex) 517 518 if !execResult.Failed() { // collect vm errors 519 res.ReturnedValue = execResult.ReturnData 520 // If the transaction created a contract, store the creation address in the receipt, 521 if msg.To == nil { 522 deployedAddress := types.NewAddress(gethCrypto.CreateAddress(msg.From, msg.Nonce)) 523 res.DeployedContractAddress = &deployedAddress 524 } 525 // replace tx index and tx hash 526 res.Logs = proc.state.Logs( 527 proc.config.BlockContext.BlockNumber.Uint64(), 528 txHash, 529 txIndex, 530 ) 531 } else { 532 // execResult.Err is VM errors (we don't return it as error) 533 res.VMError = execResult.Err 534 } 535 } 536 return &res, nil 537 }