github.com/ethereum/go-ethereum@v1.16.1/core/state_processor.go (about) 1 // Copyright 2015 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 "fmt" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/consensus/misc" 25 "github.com/ethereum/go-ethereum/core/state" 26 "github.com/ethereum/go-ethereum/core/tracing" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/core/vm" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/params" 31 ) 32 33 // StateProcessor is a basic Processor, which takes care of transitioning 34 // state from one point to another. 35 // 36 // StateProcessor implements Processor. 37 type StateProcessor struct { 38 config *params.ChainConfig // Chain configuration options 39 chain *HeaderChain // Canonical header chain 40 } 41 42 // NewStateProcessor initialises a new StateProcessor. 43 func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor { 44 return &StateProcessor{ 45 config: config, 46 chain: chain, 47 } 48 } 49 50 // Process processes the state changes according to the Ethereum rules by running 51 // the transaction messages using the statedb and applying any rewards to both 52 // the processor (coinbase) and any included uncles. 53 // 54 // Process returns the receipts and logs accumulated during the process and 55 // returns the amount of gas that was used in the process. If any of the 56 // transactions failed to execute due to insufficient gas it will return an error. 57 func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) { 58 var ( 59 receipts types.Receipts 60 usedGas = new(uint64) 61 header = block.Header() 62 blockHash = block.Hash() 63 blockNumber = block.Number() 64 allLogs []*types.Log 65 gp = new(GasPool).AddGas(block.GasLimit()) 66 ) 67 68 // Mutate the block and state according to any hard-fork specs 69 if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { 70 misc.ApplyDAOHardFork(statedb) 71 } 72 var ( 73 context vm.BlockContext 74 signer = types.MakeSigner(p.config, header.Number, header.Time) 75 ) 76 77 // Apply pre-execution system calls. 78 var tracingStateDB = vm.StateDB(statedb) 79 if hooks := cfg.Tracer; hooks != nil { 80 tracingStateDB = state.NewHookedState(statedb, hooks) 81 } 82 context = NewEVMBlockContext(header, p.chain, nil) 83 evm := vm.NewEVM(context, tracingStateDB, p.config, cfg) 84 85 if beaconRoot := block.BeaconRoot(); beaconRoot != nil { 86 ProcessBeaconBlockRoot(*beaconRoot, evm) 87 } 88 if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) { 89 ProcessParentBlockHash(block.ParentHash(), evm) 90 } 91 92 // Iterate over and process the individual transactions 93 for i, tx := range block.Transactions() { 94 msg, err := TransactionToMessage(tx, signer, header.BaseFee) 95 if err != nil { 96 return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 97 } 98 statedb.SetTxContext(tx.Hash(), i) 99 100 receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, usedGas, evm) 101 if err != nil { 102 return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 103 } 104 receipts = append(receipts, receipt) 105 allLogs = append(allLogs, receipt.Logs...) 106 } 107 // Read requests if Prague is enabled. 108 var requests [][]byte 109 if p.config.IsPrague(block.Number(), block.Time()) { 110 requests = [][]byte{} 111 // EIP-6110 112 if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil { 113 return nil, err 114 } 115 // EIP-7002 116 if err := ProcessWithdrawalQueue(&requests, evm); err != nil { 117 return nil, err 118 } 119 // EIP-7251 120 if err := ProcessConsolidationQueue(&requests, evm); err != nil { 121 return nil, err 122 } 123 } 124 125 // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) 126 p.chain.engine.Finalize(p.chain, header, tracingStateDB, block.Body()) 127 128 return &ProcessResult{ 129 Receipts: receipts, 130 Requests: requests, 131 Logs: allLogs, 132 GasUsed: *usedGas, 133 }, nil 134 } 135 136 // ApplyTransactionWithEVM attempts to apply a transaction to the given state database 137 // and uses the input parameters for its environment similar to ApplyTransaction. However, 138 // this method takes an already created EVM instance as input. 139 func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { 140 if hooks := evm.Config.Tracer; hooks != nil { 141 if hooks.OnTxStart != nil { 142 hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) 143 } 144 if hooks.OnTxEnd != nil { 145 defer func() { hooks.OnTxEnd(receipt, err) }() 146 } 147 } 148 // Apply the transaction to the current state (included in the env). 149 result, err := ApplyMessage(evm, msg, gp) 150 if err != nil { 151 return nil, err 152 } 153 // Update the state with pending changes. 154 var root []byte 155 if evm.ChainConfig().IsByzantium(blockNumber) { 156 evm.StateDB.Finalise(true) 157 } else { 158 root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes() 159 } 160 *usedGas += result.UsedGas 161 162 // Merge the tx-local access event into the "block-local" one, in order to collect 163 // all values, so that the witness can be built. 164 if statedb.Database().TrieDB().IsVerkle() { 165 statedb.AccessEvents().Merge(evm.AccessEvents) 166 } 167 return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, *usedGas, root), nil 168 } 169 170 // MakeReceipt generates the receipt object for a transaction given its execution result. 171 func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt { 172 // Create a new receipt for the transaction, storing the intermediate root and gas used 173 // by the tx. 174 receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas} 175 if result.Failed() { 176 receipt.Status = types.ReceiptStatusFailed 177 } else { 178 receipt.Status = types.ReceiptStatusSuccessful 179 } 180 receipt.TxHash = tx.Hash() 181 receipt.GasUsed = result.UsedGas 182 183 if tx.Type() == types.BlobTxType { 184 receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob) 185 receipt.BlobGasPrice = evm.Context.BlobBaseFee 186 } 187 188 // If the transaction created a contract, store the creation address in the receipt. 189 if tx.To() == nil { 190 receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) 191 } 192 193 // Set the receipt logs and create the bloom filter. 194 receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash, blockTime) 195 receipt.Bloom = types.CreateBloom(receipt) 196 receipt.BlockHash = blockHash 197 receipt.BlockNumber = blockNumber 198 receipt.TransactionIndex = uint(statedb.TxIndex()) 199 return receipt 200 } 201 202 // ApplyTransaction attempts to apply a transaction to the given state database 203 // and uses the input parameters for its environment. It returns the receipt 204 // for the transaction, gas used and an error if the transaction failed, 205 // indicating the block was invalid. 206 func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) { 207 msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee) 208 if err != nil { 209 return nil, err 210 } 211 // Create a new context to be used in the EVM environment 212 return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, usedGas, evm) 213 } 214 215 // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root 216 // contract. This method is exported to be used in tests. 217 func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { 218 if tracer := evm.Config.Tracer; tracer != nil { 219 onSystemCallStart(tracer, evm.GetVMContext()) 220 if tracer.OnSystemCallEnd != nil { 221 defer tracer.OnSystemCallEnd() 222 } 223 } 224 msg := &Message{ 225 From: params.SystemAddress, 226 GasLimit: 30_000_000, 227 GasPrice: common.Big0, 228 GasFeeCap: common.Big0, 229 GasTipCap: common.Big0, 230 To: ¶ms.BeaconRootsAddress, 231 Data: beaconRoot[:], 232 } 233 evm.SetTxContext(NewEVMTxContext(msg)) 234 evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress) 235 _, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) 236 evm.StateDB.Finalise(true) 237 } 238 239 // ProcessParentBlockHash stores the parent block hash in the history storage contract 240 // as per EIP-2935/7709. 241 func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { 242 if tracer := evm.Config.Tracer; tracer != nil { 243 onSystemCallStart(tracer, evm.GetVMContext()) 244 if tracer.OnSystemCallEnd != nil { 245 defer tracer.OnSystemCallEnd() 246 } 247 } 248 msg := &Message{ 249 From: params.SystemAddress, 250 GasLimit: 30_000_000, 251 GasPrice: common.Big0, 252 GasFeeCap: common.Big0, 253 GasTipCap: common.Big0, 254 To: ¶ms.HistoryStorageAddress, 255 Data: prevHash.Bytes(), 256 } 257 evm.SetTxContext(NewEVMTxContext(msg)) 258 evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress) 259 _, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) 260 if err != nil { 261 panic(err) 262 } 263 if evm.StateDB.AccessEvents() != nil { 264 evm.StateDB.AccessEvents().Merge(evm.AccessEvents) 265 } 266 evm.StateDB.Finalise(true) 267 } 268 269 // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract. 270 // It returns the opaque request data returned by the contract. 271 func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) error { 272 return processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress) 273 } 274 275 // ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract. 276 // It returns the opaque request data returned by the contract. 277 func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) error { 278 return processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress) 279 } 280 281 func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error { 282 if tracer := evm.Config.Tracer; tracer != nil { 283 onSystemCallStart(tracer, evm.GetVMContext()) 284 if tracer.OnSystemCallEnd != nil { 285 defer tracer.OnSystemCallEnd() 286 } 287 } 288 msg := &Message{ 289 From: params.SystemAddress, 290 GasLimit: 30_000_000, 291 GasPrice: common.Big0, 292 GasFeeCap: common.Big0, 293 GasTipCap: common.Big0, 294 To: &addr, 295 } 296 evm.SetTxContext(NewEVMTxContext(msg)) 297 evm.StateDB.AddAddressToAccessList(addr) 298 ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) 299 evm.StateDB.Finalise(true) 300 if err != nil { 301 return fmt.Errorf("system call failed to execute: %v", err) 302 } 303 if len(ret) == 0 { 304 return nil // skip empty output 305 } 306 // Append prefixed requestsData to the requests list. 307 requestsData := make([]byte, len(ret)+1) 308 requestsData[0] = requestType 309 copy(requestsData[1:], ret) 310 *requests = append(*requests, requestsData) 311 return nil 312 } 313 314 var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5") 315 316 // ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by 317 // BeaconDepositContract. 318 func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.ChainConfig) error { 319 deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type) 320 for _, log := range logs { 321 if log.Address == config.DepositContractAddress && len(log.Topics) > 0 && log.Topics[0] == depositTopic { 322 request, err := types.DepositLogToRequest(log.Data) 323 if err != nil { 324 return fmt.Errorf("unable to parse deposit data: %v", err) 325 } 326 deposits = append(deposits, request...) 327 } 328 } 329 if len(deposits) > 1 { 330 *requests = append(*requests, deposits) 331 } 332 return nil 333 } 334 335 func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) { 336 if tracer.OnSystemCallStartV2 != nil { 337 tracer.OnSystemCallStartV2(ctx) 338 } else if tracer.OnSystemCallStart != nil { 339 tracer.OnSystemCallStart() 340 } 341 }