github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/evmcore/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 evmcore
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/unicornultrafoundation/go-u2u/common"
    24  	"github.com/unicornultrafoundation/go-u2u/core/state"
    25  	"github.com/unicornultrafoundation/go-u2u/core/types"
    26  	"github.com/unicornultrafoundation/go-u2u/core/vm"
    27  	"github.com/unicornultrafoundation/go-u2u/crypto"
    28  	"github.com/unicornultrafoundation/go-u2u/evmcore/txtracer"
    29  	"github.com/unicornultrafoundation/go-u2u/params"
    30  	"github.com/unicornultrafoundation/go-u2u/utils/signers/gsignercache"
    31  	"github.com/unicornultrafoundation/go-u2u/utils/signers/internaltx"
    32  )
    33  
    34  // StateProcessor is a basic Processor, which takes care of transitioning
    35  // state from one point to another.
    36  //
    37  // StateProcessor implements Processor.
    38  type StateProcessor struct {
    39  	config *params.ChainConfig // Chain configuration options
    40  	bc     DummyChain          // Canonical block chain
    41  }
    42  
    43  // NewStateProcessor initialises a new StateProcessor.
    44  func NewStateProcessor(config *params.ChainConfig, bc DummyChain) *StateProcessor {
    45  	return &StateProcessor{
    46  		config: config,
    47  		bc:     bc,
    48  	}
    49  }
    50  
    51  // Process processes the state changes according to the Ethereum rules by running
    52  // the transaction messages using the statedb and applying any rewards to both
    53  // the processor (coinbase) and any included uncles.
    54  //
    55  // Process returns the receipts and logs accumulated during the process and
    56  // returns the amount of gas that was used in the process. If any of the
    57  // transactions failed to execute due to insufficient gas it will return an error.
    58  func (p *StateProcessor) Process(
    59  	block *EvmBlock, statedb *state.StateDB, cfg vm.Config, usedGas *uint64, onNewLog func(*types.Log, *state.StateDB),
    60  ) (
    61  	receipts types.Receipts, allLogs []*types.Log, skipped []uint32, err error,
    62  ) {
    63  	skipped = make([]uint32, 0, len(block.Transactions))
    64  	var (
    65  		gp           = new(GasPool).AddGas(block.GasLimit)
    66  		receipt      *types.Receipt
    67  		skip         bool
    68  		header       = block.Header()
    69  		blockContext = NewEVMBlockContext(header, p.bc, nil)
    70  		vmenv        = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
    71  		blockHash    = block.Hash
    72  		blockNumber  = block.Number
    73  		signer       = gsignercache.Wrap(types.MakeSigner(p.config, header.Number))
    74  	)
    75  	// Iterate over and process the individual transactions
    76  	for i, tx := range block.Transactions {
    77  		msg, err := TxAsMessage(tx, signer, header.BaseFee)
    78  		if err != nil {
    79  			return nil, nil, nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
    80  		}
    81  
    82  		statedb.Prepare(tx.Hash(), i)
    83  		receipt, _, skip, err = ApplyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, cfg, onNewLog)
    84  		if skip {
    85  			skipped = append(skipped, uint32(i))
    86  			err = nil
    87  			continue
    88  		}
    89  		if err != nil {
    90  			return nil, nil, nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
    91  		}
    92  		receipts = append(receipts, receipt)
    93  		allLogs = append(allLogs, receipt.Logs...)
    94  	}
    95  	return
    96  }
    97  
    98  func ApplyTransaction(
    99  	msg types.Message,
   100  	config *params.ChainConfig,
   101  	gp *GasPool,
   102  	statedb *state.StateDB,
   103  	blockNumber *big.Int,
   104  	blockHash common.Hash,
   105  	tx *types.Transaction,
   106  	usedGas *uint64,
   107  	evm *vm.EVM,
   108  	cfg vm.Config,
   109  	onNewLog func(*types.Log, *state.StateDB),
   110  ) (
   111  	*types.Receipt,
   112  	uint64,
   113  	bool,
   114  	error,
   115  ) {
   116  	// Create a new context to be used in the EVM environment.
   117  	txContext := NewEVMTxContext(msg)
   118  	evm.Reset(txContext, statedb)
   119  
   120  	// Test if type of tracer is transaction tracing
   121  	// logger, in that case, set a info for it
   122  	var traceLogger *txtracer.TraceStructLogger
   123  	switch cfg.Tracer.(type) {
   124  	case *txtracer.TraceStructLogger:
   125  		traceLogger = cfg.Tracer.(*txtracer.TraceStructLogger)
   126  		traceLogger.SetTx(tx.Hash())
   127  		traceLogger.SetFrom(msg.From())
   128  		traceLogger.SetTo(msg.To())
   129  		traceLogger.SetValue(*msg.Value())
   130  		traceLogger.SetBlockHash(blockHash)
   131  		traceLogger.SetBlockNumber(blockNumber)
   132  		traceLogger.SetTxIndex(uint(statedb.TxIndex()))
   133  	}
   134  	// Apply the transaction to the current state (included in the env).
   135  	result, err := ApplyMessage(evm, msg, gp)
   136  	if err != nil {
   137  		return nil, 0, result == nil, err
   138  	}
   139  	// Notify about logs with potential state changes
   140  	logs := statedb.GetLogs(tx.Hash(), blockHash)
   141  	for _, l := range logs {
   142  		onNewLog(l, statedb)
   143  	}
   144  
   145  	// Update the state with pending changes.
   146  	var root []byte
   147  	if config.IsByzantium(blockNumber) {
   148  		statedb.Finalise(true)
   149  	} else {
   150  		root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
   151  	}
   152  	*usedGas += result.UsedGas
   153  
   154  	// Create a new receipt for the transaction, storing the intermediate root and gas used
   155  	// by the tx.
   156  	receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
   157  	if result.Failed() {
   158  		receipt.Status = types.ReceiptStatusFailed
   159  	} else {
   160  		receipt.Status = types.ReceiptStatusSuccessful
   161  	}
   162  	receipt.TxHash = tx.Hash()
   163  	receipt.GasUsed = result.UsedGas
   164  
   165  	// If the transaction created a contract, store the creation address in the receipt.
   166  	if msg.To() == nil {
   167  		receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
   168  	}
   169  
   170  	// Set the receipt logs.
   171  	receipt.Logs = logs
   172  	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
   173  	receipt.BlockHash = blockHash
   174  	receipt.BlockNumber = blockNumber
   175  	receipt.TransactionIndex = uint(statedb.TxIndex())
   176  
   177  	// Set post informations and save trace
   178  	if traceLogger != nil {
   179  		traceLogger.SetGasUsed(result.UsedGas)
   180  		traceLogger.SetNewAddress(receipt.ContractAddress)
   181  		traceLogger.ProcessTx()
   182  		traceLogger.SaveTrace()
   183  	}
   184  
   185  	return receipt, result.UsedGas, false, err
   186  }
   187  
   188  func TxAsMessage(tx *types.Transaction, signer types.Signer, baseFee *big.Int) (types.Message, error) {
   189  	if !internaltx.IsInternal(tx) {
   190  		return tx.AsMessage(signer, baseFee)
   191  	} else {
   192  		msg := types.NewMessage(internaltx.InternalSender(tx), tx.To(), tx.Nonce(), tx.Value(), tx.Gas(), tx.GasPrice(), tx.GasFeeCap(), tx.GasTipCap(), tx.Data(), tx.AccessList(), true)
   193  		return msg, nil
   194  	}
   195  }