github.com/ethereum/go-ethereum@v1.16.1/internal/ethapi/simulate.go (about) 1 // Copyright 2023 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 ethapi 18 19 import ( 20 "context" 21 "encoding/json" 22 "errors" 23 "fmt" 24 "math/big" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/hexutil" 29 "github.com/ethereum/go-ethereum/consensus" 30 "github.com/ethereum/go-ethereum/consensus/misc/eip1559" 31 "github.com/ethereum/go-ethereum/consensus/misc/eip4844" 32 "github.com/ethereum/go-ethereum/core" 33 "github.com/ethereum/go-ethereum/core/state" 34 "github.com/ethereum/go-ethereum/core/types" 35 "github.com/ethereum/go-ethereum/core/vm" 36 "github.com/ethereum/go-ethereum/internal/ethapi/override" 37 "github.com/ethereum/go-ethereum/params" 38 "github.com/ethereum/go-ethereum/rpc" 39 ) 40 41 const ( 42 // maxSimulateBlocks is the maximum number of blocks that can be simulated 43 // in a single request. 44 maxSimulateBlocks = 256 45 46 // timestampIncrement is the default increment between block timestamps. 47 timestampIncrement = 12 48 ) 49 50 // simBlock is a batch of calls to be simulated sequentially. 51 type simBlock struct { 52 BlockOverrides *override.BlockOverrides 53 StateOverrides *override.StateOverride 54 Calls []TransactionArgs 55 } 56 57 // simCallResult is the result of a simulated call. 58 type simCallResult struct { 59 ReturnValue hexutil.Bytes `json:"returnData"` 60 Logs []*types.Log `json:"logs"` 61 GasUsed hexutil.Uint64 `json:"gasUsed"` 62 Status hexutil.Uint64 `json:"status"` 63 Error *callError `json:"error,omitempty"` 64 } 65 66 func (r *simCallResult) MarshalJSON() ([]byte, error) { 67 type callResultAlias simCallResult 68 // Marshal logs to be an empty array instead of nil when empty 69 if r.Logs == nil { 70 r.Logs = []*types.Log{} 71 } 72 return json.Marshal((*callResultAlias)(r)) 73 } 74 75 // simBlockResult is the result of a simulated block. 76 type simBlockResult struct { 77 fullTx bool 78 chainConfig *params.ChainConfig 79 Block *types.Block 80 Calls []simCallResult 81 // senders is a map of transaction hashes to their senders. 82 senders map[common.Hash]common.Address 83 } 84 85 func (r *simBlockResult) MarshalJSON() ([]byte, error) { 86 blockData := RPCMarshalBlock(r.Block, true, r.fullTx, r.chainConfig) 87 blockData["calls"] = r.Calls 88 // Set tx sender if user requested full tx objects. 89 if r.fullTx { 90 if raw, ok := blockData["transactions"].([]any); ok { 91 for _, tx := range raw { 92 if tx, ok := tx.(*RPCTransaction); ok { 93 tx.From = r.senders[tx.Hash] 94 } else { 95 return nil, errors.New("simulated transaction result has invalid type") 96 } 97 } 98 } 99 } 100 return json.Marshal(blockData) 101 } 102 103 // simOpts are the inputs to eth_simulateV1. 104 type simOpts struct { 105 BlockStateCalls []simBlock 106 TraceTransfers bool 107 Validation bool 108 ReturnFullTransactions bool 109 } 110 111 // simChainHeadReader implements ChainHeaderReader which is needed as input for FinalizeAndAssemble. 112 type simChainHeadReader struct { 113 context.Context 114 Backend 115 } 116 117 func (m *simChainHeadReader) Config() *params.ChainConfig { 118 return m.Backend.ChainConfig() 119 } 120 121 func (m *simChainHeadReader) CurrentHeader() *types.Header { 122 return m.Backend.CurrentHeader() 123 } 124 125 func (m *simChainHeadReader) GetHeader(hash common.Hash, number uint64) *types.Header { 126 header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number)) 127 if err != nil || header == nil { 128 return nil 129 } 130 if header.Hash() != hash { 131 return nil 132 } 133 return header 134 } 135 136 func (m *simChainHeadReader) GetHeaderByNumber(number uint64) *types.Header { 137 header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number)) 138 if err != nil { 139 return nil 140 } 141 return header 142 } 143 144 func (m *simChainHeadReader) GetHeaderByHash(hash common.Hash) *types.Header { 145 header, err := m.Backend.HeaderByHash(m.Context, hash) 146 if err != nil { 147 return nil 148 } 149 return header 150 } 151 152 // simulator is a stateful object that simulates a series of blocks. 153 // it is not safe for concurrent use. 154 type simulator struct { 155 b Backend 156 state *state.StateDB 157 base *types.Header 158 chainConfig *params.ChainConfig 159 gp *core.GasPool 160 traceTransfers bool 161 validate bool 162 fullTx bool 163 } 164 165 // execute runs the simulation of a series of blocks. 166 func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlockResult, error) { 167 if err := ctx.Err(); err != nil { 168 return nil, err 169 } 170 var ( 171 cancel context.CancelFunc 172 timeout = sim.b.RPCEVMTimeout() 173 ) 174 if timeout > 0 { 175 ctx, cancel = context.WithTimeout(ctx, timeout) 176 } else { 177 ctx, cancel = context.WithCancel(ctx) 178 } 179 // Make sure the context is cancelled when the call has completed 180 // this makes sure resources are cleaned up. 181 defer cancel() 182 183 var err error 184 blocks, err = sim.sanitizeChain(blocks) 185 if err != nil { 186 return nil, err 187 } 188 // Prepare block headers with preliminary fields for the response. 189 headers, err := sim.makeHeaders(blocks) 190 if err != nil { 191 return nil, err 192 } 193 var ( 194 results = make([]*simBlockResult, len(blocks)) 195 parent = sim.base 196 ) 197 for bi, block := range blocks { 198 result, callResults, senders, err := sim.processBlock(ctx, &block, headers[bi], parent, headers[:bi], timeout) 199 if err != nil { 200 return nil, err 201 } 202 headers[bi] = result.Header() 203 results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults, senders: senders} 204 parent = result.Header() 205 } 206 return results, nil 207 } 208 209 func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, timeout time.Duration) (*types.Block, []simCallResult, map[common.Hash]common.Address, error) { 210 // Set header fields that depend only on parent block. 211 // Parent hash is needed for evm.GetHashFn to work. 212 header.ParentHash = parent.Hash() 213 if sim.chainConfig.IsLondon(header.Number) { 214 // In non-validation mode base fee is set to 0 if it is not overridden. 215 // This is because it creates an edge case in EVM where gasPrice < baseFee. 216 // Base fee could have been overridden. 217 if header.BaseFee == nil { 218 if sim.validate { 219 header.BaseFee = eip1559.CalcBaseFee(sim.chainConfig, parent) 220 } else { 221 header.BaseFee = big.NewInt(0) 222 } 223 } 224 } 225 if sim.chainConfig.IsCancun(header.Number, header.Time) { 226 var excess uint64 227 if sim.chainConfig.IsCancun(parent.Number, parent.Time) { 228 excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent, header.Time) 229 } 230 header.ExcessBlobGas = &excess 231 } 232 blockContext := core.NewEVMBlockContext(header, sim.newSimulatedChainContext(ctx, headers), nil) 233 if block.BlockOverrides.BlobBaseFee != nil { 234 blockContext.BlobBaseFee = block.BlockOverrides.BlobBaseFee.ToInt() 235 } 236 precompiles := sim.activePrecompiles(sim.base) 237 // State overrides are applied prior to execution of a block 238 if err := block.StateOverrides.Apply(sim.state, precompiles); err != nil { 239 return nil, nil, nil, err 240 } 241 var ( 242 gasUsed, blobGasUsed uint64 243 txes = make([]*types.Transaction, len(block.Calls)) 244 callResults = make([]simCallResult, len(block.Calls)) 245 receipts = make([]*types.Receipt, len(block.Calls)) 246 // Block hash will be repaired after execution. 247 tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), common.Hash{}, common.Hash{}, 0) 248 vmConfig = &vm.Config{ 249 NoBaseFee: !sim.validate, 250 Tracer: tracer.Hooks(), 251 } 252 // senders is a map of transaction hashes to their senders. 253 // Transaction objects contain only the signature, and we lose track 254 // of the sender when translating the arguments into a transaction object. 255 senders = make(map[common.Hash]common.Address) 256 ) 257 tracingStateDB := vm.StateDB(sim.state) 258 if hooks := tracer.Hooks(); hooks != nil { 259 tracingStateDB = state.NewHookedState(sim.state, hooks) 260 } 261 evm := vm.NewEVM(blockContext, tracingStateDB, sim.chainConfig, *vmConfig) 262 // It is possible to override precompiles with EVM bytecode, or 263 // move them to another address. 264 if precompiles != nil { 265 evm.SetPrecompiles(precompiles) 266 } 267 if sim.chainConfig.IsPrague(header.Number, header.Time) || sim.chainConfig.IsVerkle(header.Number, header.Time) { 268 core.ProcessParentBlockHash(header.ParentHash, evm) 269 } 270 if header.ParentBeaconRoot != nil { 271 core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, evm) 272 } 273 var allLogs []*types.Log 274 for i, call := range block.Calls { 275 if err := ctx.Err(); err != nil { 276 return nil, nil, nil, err 277 } 278 if err := sim.sanitizeCall(&call, sim.state, header, blockContext, &gasUsed); err != nil { 279 return nil, nil, nil, err 280 } 281 var ( 282 tx = call.ToTransaction(types.DynamicFeeTxType) 283 txHash = tx.Hash() 284 ) 285 txes[i] = tx 286 senders[txHash] = call.from() 287 tracer.reset(txHash, uint(i)) 288 sim.state.SetTxContext(txHash, i) 289 // EoA check is always skipped, even in validation mode. 290 msg := call.ToMessage(header.BaseFee, !sim.validate, true) 291 result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) 292 if err != nil { 293 txErr := txValidationError(err) 294 return nil, nil, nil, txErr 295 } 296 // Update the state with pending changes. 297 var root []byte 298 if sim.chainConfig.IsByzantium(blockContext.BlockNumber) { 299 tracingStateDB.Finalise(true) 300 } else { 301 root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes() 302 } 303 gasUsed += result.UsedGas 304 receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, blockContext.Time, tx, gasUsed, root) 305 blobGasUsed += receipts[i].BlobGasUsed 306 logs := tracer.Logs() 307 callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)} 308 if result.Failed() { 309 callRes.Status = hexutil.Uint64(types.ReceiptStatusFailed) 310 if errors.Is(result.Err, vm.ErrExecutionReverted) { 311 // If the result contains a revert reason, try to unpack it. 312 revertErr := newRevertError(result.Revert()) 313 callRes.Error = &callError{Message: revertErr.Error(), Code: errCodeReverted, Data: revertErr.ErrorData().(string)} 314 } else { 315 callRes.Error = &callError{Message: result.Err.Error(), Code: errCodeVMError} 316 } 317 } else { 318 callRes.Status = hexutil.Uint64(types.ReceiptStatusSuccessful) 319 allLogs = append(allLogs, callRes.Logs...) 320 } 321 callResults[i] = callRes 322 } 323 header.GasUsed = gasUsed 324 if sim.chainConfig.IsCancun(header.Number, header.Time) { 325 header.BlobGasUsed = &blobGasUsed 326 } 327 var requests [][]byte 328 // Process EIP-7685 requests 329 if sim.chainConfig.IsPrague(header.Number, header.Time) { 330 requests = [][]byte{} 331 // EIP-6110 332 if err := core.ParseDepositLogs(&requests, allLogs, sim.chainConfig); err != nil { 333 return nil, nil, nil, err 334 } 335 // EIP-7002 336 if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { 337 return nil, nil, nil, err 338 } 339 // EIP-7251 340 if err := core.ProcessConsolidationQueue(&requests, evm); err != nil { 341 return nil, nil, nil, err 342 } 343 } 344 if requests != nil { 345 reqHash := types.CalcRequestsHash(requests) 346 header.RequestsHash = &reqHash 347 } 348 blockBody := &types.Body{Transactions: txes, Withdrawals: *block.BlockOverrides.Withdrawals} 349 chainHeadReader := &simChainHeadReader{ctx, sim.b} 350 b, err := sim.b.Engine().FinalizeAndAssemble(chainHeadReader, header, sim.state, blockBody, receipts) 351 if err != nil { 352 return nil, nil, nil, err 353 } 354 repairLogs(callResults, b.Hash()) 355 return b, callResults, senders, nil 356 } 357 358 // repairLogs updates the block hash in the logs present in the result of 359 // a simulated block. This is needed as during execution when logs are collected 360 // the block hash is not known. 361 func repairLogs(calls []simCallResult, hash common.Hash) { 362 for i := range calls { 363 for j := range calls[i].Logs { 364 calls[i].Logs[j].BlockHash = hash 365 } 366 } 367 } 368 369 func (sim *simulator) sanitizeCall(call *TransactionArgs, state vm.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error { 370 if call.Nonce == nil { 371 nonce := state.GetNonce(call.from()) 372 call.Nonce = (*hexutil.Uint64)(&nonce) 373 } 374 // Let the call run wild unless explicitly specified. 375 if call.Gas == nil { 376 remaining := blockContext.GasLimit - *gasUsed 377 call.Gas = (*hexutil.Uint64)(&remaining) 378 } 379 if *gasUsed+uint64(*call.Gas) > blockContext.GasLimit { 380 return &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: %d >= %d", gasUsed, blockContext.GasLimit)} 381 } 382 if err := call.CallDefaults(sim.gp.Gas(), header.BaseFee, sim.chainConfig.ChainID); err != nil { 383 return err 384 } 385 return nil 386 } 387 388 func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContracts { 389 var ( 390 isMerge = (base.Difficulty.Sign() == 0) 391 rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) 392 ) 393 return vm.ActivePrecompiledContracts(rules) 394 } 395 396 // sanitizeChain checks the chain integrity. Specifically it checks that 397 // block numbers and timestamp are strictly increasing, setting default values 398 // when necessary. Gaps in block numbers are filled with empty blocks. 399 // Note: It modifies the block's override object. 400 func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) { 401 var ( 402 res = make([]simBlock, 0, len(blocks)) 403 base = sim.base 404 prevNumber = base.Number 405 prevTimestamp = base.Time 406 ) 407 for _, block := range blocks { 408 if block.BlockOverrides == nil { 409 block.BlockOverrides = new(override.BlockOverrides) 410 } 411 if block.BlockOverrides.Number == nil { 412 n := new(big.Int).Add(prevNumber, big.NewInt(1)) 413 block.BlockOverrides.Number = (*hexutil.Big)(n) 414 } 415 if block.BlockOverrides.Withdrawals == nil { 416 block.BlockOverrides.Withdrawals = &types.Withdrawals{} 417 } 418 diff := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), prevNumber) 419 if diff.Cmp(common.Big0) <= 0 { 420 return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", block.BlockOverrides.Number.ToInt().Uint64(), prevNumber)} 421 } 422 if total := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), base.Number); total.Cmp(big.NewInt(maxSimulateBlocks)) > 0 { 423 return nil, &clientLimitExceededError{message: "too many blocks"} 424 } 425 if diff.Cmp(big.NewInt(1)) > 0 { 426 // Fill the gap with empty blocks. 427 gap := new(big.Int).Sub(diff, big.NewInt(1)) 428 // Assign block number to the empty blocks. 429 for i := uint64(0); i < gap.Uint64(); i++ { 430 n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1))) 431 t := prevTimestamp + timestampIncrement 432 b := simBlock{ 433 BlockOverrides: &override.BlockOverrides{ 434 Number: (*hexutil.Big)(n), 435 Time: (*hexutil.Uint64)(&t), 436 Withdrawals: &types.Withdrawals{}, 437 }, 438 } 439 prevTimestamp = t 440 res = append(res, b) 441 } 442 } 443 // Only append block after filling a potential gap. 444 prevNumber = block.BlockOverrides.Number.ToInt() 445 var t uint64 446 if block.BlockOverrides.Time == nil { 447 t = prevTimestamp + timestampIncrement 448 block.BlockOverrides.Time = (*hexutil.Uint64)(&t) 449 } else { 450 t = uint64(*block.BlockOverrides.Time) 451 if t <= prevTimestamp { 452 return nil, &invalidBlockTimestampError{fmt.Sprintf("block timestamps must be in order: %d <= %d", t, prevTimestamp)} 453 } 454 } 455 prevTimestamp = t 456 res = append(res, block) 457 } 458 return res, nil 459 } 460 461 // makeHeaders makes header object with preliminary fields based on a simulated block. 462 // Some fields have to be filled post-execution. 463 // It assumes blocks are in order and numbers have been validated. 464 func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) { 465 var ( 466 res = make([]*types.Header, len(blocks)) 467 base = sim.base 468 header = base 469 ) 470 for bi, block := range blocks { 471 if block.BlockOverrides == nil || block.BlockOverrides.Number == nil { 472 return nil, errors.New("empty block number") 473 } 474 overrides := block.BlockOverrides 475 476 var withdrawalsHash *common.Hash 477 if sim.chainConfig.IsShanghai(overrides.Number.ToInt(), (uint64)(*overrides.Time)) { 478 withdrawalsHash = &types.EmptyWithdrawalsHash 479 } 480 var parentBeaconRoot *common.Hash 481 if sim.chainConfig.IsCancun(overrides.Number.ToInt(), (uint64)(*overrides.Time)) { 482 parentBeaconRoot = &common.Hash{} 483 if overrides.BeaconRoot != nil { 484 parentBeaconRoot = overrides.BeaconRoot 485 } 486 } 487 header = overrides.MakeHeader(&types.Header{ 488 UncleHash: types.EmptyUncleHash, 489 ReceiptHash: types.EmptyReceiptsHash, 490 TxHash: types.EmptyTxsHash, 491 Coinbase: header.Coinbase, 492 Difficulty: header.Difficulty, 493 GasLimit: header.GasLimit, 494 WithdrawalsHash: withdrawalsHash, 495 ParentBeaconRoot: parentBeaconRoot, 496 }) 497 res[bi] = header 498 } 499 return res, nil 500 } 501 502 func (sim *simulator) newSimulatedChainContext(ctx context.Context, headers []*types.Header) *ChainContext { 503 return NewChainContext(ctx, &simBackend{base: sim.base, b: sim.b, headers: headers}) 504 } 505 506 type simBackend struct { 507 b ChainContextBackend 508 base *types.Header 509 headers []*types.Header 510 } 511 512 func (b *simBackend) Engine() consensus.Engine { 513 return b.b.Engine() 514 } 515 516 func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { 517 if uint64(number) == b.base.Number.Uint64() { 518 return b.base, nil 519 } 520 if uint64(number) < b.base.Number.Uint64() { 521 // Resolve canonical header. 522 return b.b.HeaderByNumber(ctx, number) 523 } 524 // Simulated block. 525 for _, header := range b.headers { 526 if header.Number.Uint64() == uint64(number) { 527 return header, nil 528 } 529 } 530 return nil, errors.New("header not found") 531 } 532 533 func (b *simBackend) ChainConfig() *params.ChainConfig { 534 return b.b.ChainConfig() 535 }