|
|
|
@ -18,14 +18,12 @@ package core |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"fmt" |
|
|
|
|
"math/big" |
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/misc" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/state" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/types" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/vm" |
|
|
|
|
"github.com/ethereum/go-ethereum/crypto" |
|
|
|
|
"github.com/ethereum/go-ethereum/params" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
@ -55,15 +53,12 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro |
|
|
|
|
// transactions failed to execute due to insufficient gas it will return an error.
|
|
|
|
|
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) { |
|
|
|
|
var ( |
|
|
|
|
receipts types.Receipts |
|
|
|
|
usedGas = new(uint64) |
|
|
|
|
header = block.Header() |
|
|
|
|
blockHash = block.Hash() |
|
|
|
|
blockNumber = block.Number() |
|
|
|
|
allLogs []*types.Log |
|
|
|
|
gp = new(GasPool).AddGas(block.GasLimit()) |
|
|
|
|
receipts types.Receipts |
|
|
|
|
usedGas = new(uint64) |
|
|
|
|
header = block.Header() |
|
|
|
|
allLogs [][]*types.Log |
|
|
|
|
gp = new(GasPool).AddGas(block.GasLimit()) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// Mutate the block and state according to any hard-fork specs
|
|
|
|
|
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { |
|
|
|
|
misc.ApplyDAOHardFork(statedb) |
|
|
|
@ -96,12 +91,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg |
|
|
|
|
} |
|
|
|
|
statedb.SetTxContext(tx.Hash(), i) |
|
|
|
|
|
|
|
|
|
receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, tx, usedGas, evm) |
|
|
|
|
receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, tx, usedGas, evm) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) |
|
|
|
|
} |
|
|
|
|
receipts = append(receipts, receipt) |
|
|
|
|
allLogs = append(allLogs, receipt.Logs...) |
|
|
|
|
allLogs = append(allLogs, receipt.Logs) |
|
|
|
|
} |
|
|
|
|
// Read requests if Prague is enabled.
|
|
|
|
|
var requests [][]byte |
|
|
|
@ -134,16 +129,17 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg |
|
|
|
|
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
|
|
|
|
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
|
|
|
|
// this method takes an already created EVM instance as input.
|
|
|
|
|
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { |
|
|
|
|
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { |
|
|
|
|
if hooks := evm.Config.Tracer; hooks != nil { |
|
|
|
|
if hooks.OnTxStart != nil { |
|
|
|
|
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) |
|
|
|
|
} |
|
|
|
|
if hooks.OnTxEnd != nil { |
|
|
|
|
// TODO (rjl493456442) the receipt only contain consensus fields,
|
|
|
|
|
// should we derive the others here?
|
|
|
|
|
defer func() { hooks.OnTxEnd(receipt, err) }() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create a new context to be used in the EVM environment.
|
|
|
|
|
txContext := NewEVMTxContext(msg) |
|
|
|
|
evm.SetTxContext(txContext) |
|
|
|
@ -153,9 +149,9 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update the state with pending changes.
|
|
|
|
|
var root []byte |
|
|
|
|
blockNumber := evm.Context.BlockNumber |
|
|
|
|
if evm.ChainConfig().IsByzantium(blockNumber) { |
|
|
|
|
evm.StateDB.Finalise(true) |
|
|
|
|
} else { |
|
|
|
@ -163,11 +159,13 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, |
|
|
|
|
} |
|
|
|
|
*usedGas += result.UsedGas |
|
|
|
|
|
|
|
|
|
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), nil |
|
|
|
|
return MakeReceipt(evm, result, statedb, tx, *usedGas, root), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MakeReceipt generates the receipt object for a transaction given its execution result.
|
|
|
|
|
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt { |
|
|
|
|
// MakeReceipt generates the receipt object for a transaction based on its execution
|
|
|
|
|
// result. Note that the generated receipt only includes the consensus fields. Any
|
|
|
|
|
// additional fields must be derived separately by the caller if needed.
|
|
|
|
|
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt { |
|
|
|
|
// Create a new receipt for the transaction, storing the intermediate root and gas used
|
|
|
|
|
// by the tx.
|
|
|
|
|
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas} |
|
|
|
@ -176,31 +174,17 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b |
|
|
|
|
} else { |
|
|
|
|
receipt.Status = types.ReceiptStatusSuccessful |
|
|
|
|
} |
|
|
|
|
receipt.TxHash = tx.Hash() |
|
|
|
|
receipt.GasUsed = result.UsedGas |
|
|
|
|
|
|
|
|
|
if tx.Type() == types.BlobTxType { |
|
|
|
|
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob) |
|
|
|
|
receipt.BlobGasPrice = evm.Context.BlobBaseFee |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If the transaction created a contract, store the creation address in the receipt.
|
|
|
|
|
if tx.To() == nil { |
|
|
|
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) |
|
|
|
|
} |
|
|
|
|
// Set the receipt logs and create the bloom filter.
|
|
|
|
|
receipt.Logs = statedb.GetLogs(tx.Hash()) |
|
|
|
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) |
|
|
|
|
|
|
|
|
|
// Merge the tx-local access event into the "block-local" one, in order to collect
|
|
|
|
|
// all values, so that the witness can be built.
|
|
|
|
|
//
|
|
|
|
|
// TODO (rjl493456442) relocate it to a better place.
|
|
|
|
|
if statedb.GetTrie().IsVerkle() { |
|
|
|
|
statedb.AccessEvents().Merge(evm.AccessEvents) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Set the receipt logs and create the bloom filter.
|
|
|
|
|
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) |
|
|
|
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) |
|
|
|
|
receipt.BlockHash = blockHash |
|
|
|
|
receipt.BlockNumber = blockNumber |
|
|
|
|
receipt.TransactionIndex = uint(statedb.TxIndex()) |
|
|
|
|
return receipt |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -208,13 +192,16 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b |
|
|
|
|
// and uses the input parameters for its environment. It returns the receipt
|
|
|
|
|
// for the transaction, gas used and an error if the transaction failed,
|
|
|
|
|
// indicating the block was invalid.
|
|
|
|
|
//
|
|
|
|
|
// Note that the generated receipt only includes the consensus fields. Any
|
|
|
|
|
// additional fields must be derived separately by the caller if needed.
|
|
|
|
|
func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) { |
|
|
|
|
msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
// Create a new context to be used in the EVM environment
|
|
|
|
|
return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm) |
|
|
|
|
return ApplyTransactionWithEVM(msg, gp, statedb, tx, usedGas, evm) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
|
|
|
@ -312,15 +299,17 @@ func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Addres |
|
|
|
|
|
|
|
|
|
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
|
|
|
|
// BeaconDepositContract.
|
|
|
|
|
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, error) { |
|
|
|
|
func ParseDepositLogs(logs [][]*types.Log, config *params.ChainConfig) ([]byte, error) { |
|
|
|
|
deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type)
|
|
|
|
|
for _, log := range logs { |
|
|
|
|
if log.Address == config.DepositContractAddress { |
|
|
|
|
request, err := types.DepositLogToRequest(log.Data) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("unable to parse deposit data: %v", err) |
|
|
|
|
for _, subLogs := range logs { |
|
|
|
|
for _, log := range subLogs { |
|
|
|
|
if log.Address == config.DepositContractAddress { |
|
|
|
|
request, err := types.DepositLogToRequest(log.Data) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("unable to parse deposit data: %v", err) |
|
|
|
|
} |
|
|
|
|
deposits = append(deposits, request...) |
|
|
|
|
} |
|
|
|
|
deposits = append(deposits, request...) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return deposits, nil |
|
|
|
|