github.com/theQRL/go-zond@v0.1.1/cmd/evm/internal/t8ntool/execution.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-ethereum 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package t8ntool
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/common/math"
    25  	"github.com/theQRL/go-zond/consensus/ethash"
    26  	"github.com/theQRL/go-zond/consensus/misc"
    27  	"github.com/theQRL/go-zond/consensus/misc/eip4844"
    28  	"github.com/theQRL/go-zond/core"
    29  	"github.com/theQRL/go-zond/core/rawdb"
    30  	"github.com/theQRL/go-zond/core/state"
    31  	"github.com/theQRL/go-zond/core/types"
    32  	"github.com/theQRL/go-zond/core/vm"
    33  	"github.com/theQRL/go-zond/crypto"
    34  	"github.com/theQRL/go-zond/zonddb"
    35  	"github.com/theQRL/go-zond/log"
    36  	"github.com/theQRL/go-zond/params"
    37  	"github.com/theQRL/go-zond/rlp"
    38  	"github.com/theQRL/go-zond/trie"
    39  	"golang.org/x/crypto/sha3"
    40  )
    41  
    42  type Prestate struct {
    43  	Env stEnv             `json:"env"`
    44  	Pre core.GenesisAlloc `json:"pre"`
    45  }
    46  
    47  // ExecutionResult contains the execution status after running a state test, any
    48  // error that might have occurred and a dump of the final state if requested.
    49  type ExecutionResult struct {
    50  	StateRoot            common.Hash           `json:"stateRoot"`
    51  	TxRoot               common.Hash           `json:"txRoot"`
    52  	ReceiptRoot          common.Hash           `json:"receiptsRoot"`
    53  	LogsHash             common.Hash           `json:"logsHash"`
    54  	Bloom                types.Bloom           `json:"logsBloom"        gencodec:"required"`
    55  	Receipts             types.Receipts        `json:"receipts"`
    56  	Rejected             []*rejectedTx         `json:"rejected,omitempty"`
    57  	Difficulty           *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
    58  	GasUsed              math.HexOrDecimal64   `json:"gasUsed"`
    59  	BaseFee              *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
    60  	WithdrawalsRoot      *common.Hash          `json:"withdrawalsRoot,omitempty"`
    61  	CurrentExcessBlobGas *math.HexOrDecimal64  `json:"currentExcessBlobGas,omitempty"`
    62  	CurrentBlobGasUsed   *math.HexOrDecimal64  `json:"currentBlobGasUsed,omitempty"`
    63  }
    64  
    65  type ommer struct {
    66  	Delta   uint64         `json:"delta"`
    67  	Address common.Address `json:"address"`
    68  }
    69  
    70  //go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
    71  type stEnv struct {
    72  	Coinbase              common.Address                      `json:"currentCoinbase"   gencodec:"required"`
    73  	Difficulty            *big.Int                            `json:"currentDifficulty"`
    74  	Random                *big.Int                            `json:"currentRandom"`
    75  	ParentDifficulty      *big.Int                            `json:"parentDifficulty"`
    76  	ParentBaseFee         *big.Int                            `json:"parentBaseFee,omitempty"`
    77  	ParentGasUsed         uint64                              `json:"parentGasUsed,omitempty"`
    78  	ParentGasLimit        uint64                              `json:"parentGasLimit,omitempty"`
    79  	GasLimit              uint64                              `json:"currentGasLimit"   gencodec:"required"`
    80  	Number                uint64                              `json:"currentNumber"     gencodec:"required"`
    81  	Timestamp             uint64                              `json:"currentTimestamp"  gencodec:"required"`
    82  	ParentTimestamp       uint64                              `json:"parentTimestamp,omitempty"`
    83  	BlockHashes           map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
    84  	Ommers                []ommer                             `json:"ommers,omitempty"`
    85  	Withdrawals           []*types.Withdrawal                 `json:"withdrawals,omitempty"`
    86  	BaseFee               *big.Int                            `json:"currentBaseFee,omitempty"`
    87  	ParentUncleHash       common.Hash                         `json:"parentUncleHash"`
    88  	ExcessBlobGas         *uint64                             `json:"excessBlobGas,omitempty"`
    89  	ParentExcessBlobGas   *uint64                             `json:"parentExcessBlobGas,omitempty"`
    90  	ParentBlobGasUsed     *uint64                             `json:"parentBlobGasUsed,omitempty"`
    91  	ParentBeaconBlockRoot *common.Hash                        `json:"parentBeaconBlockRoot"`
    92  }
    93  
    94  type stEnvMarshaling struct {
    95  	Coinbase            common.UnprefixedAddress
    96  	Difficulty          *math.HexOrDecimal256
    97  	Random              *math.HexOrDecimal256
    98  	ParentDifficulty    *math.HexOrDecimal256
    99  	ParentBaseFee       *math.HexOrDecimal256
   100  	ParentGasUsed       math.HexOrDecimal64
   101  	ParentGasLimit      math.HexOrDecimal64
   102  	GasLimit            math.HexOrDecimal64
   103  	Number              math.HexOrDecimal64
   104  	Timestamp           math.HexOrDecimal64
   105  	ParentTimestamp     math.HexOrDecimal64
   106  	BaseFee             *math.HexOrDecimal256
   107  	ExcessBlobGas       *math.HexOrDecimal64
   108  	ParentExcessBlobGas *math.HexOrDecimal64
   109  	ParentBlobGasUsed   *math.HexOrDecimal64
   110  }
   111  
   112  type rejectedTx struct {
   113  	Index int    `json:"index"`
   114  	Err   string `json:"error"`
   115  }
   116  
   117  // Apply applies a set of transactions to a pre-state
   118  func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
   119  	txs types.Transactions, miningReward int64,
   120  	getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, error) {
   121  	// Capture errors for BLOCKHASH operation, if we haven't been supplied the
   122  	// required blockhashes
   123  	var hashError error
   124  	getHash := func(num uint64) common.Hash {
   125  		if pre.Env.BlockHashes == nil {
   126  			hashError = fmt.Errorf("getHash(%d) invoked, no blockhashes provided", num)
   127  			return common.Hash{}
   128  		}
   129  		h, ok := pre.Env.BlockHashes[math.HexOrDecimal64(num)]
   130  		if !ok {
   131  			hashError = fmt.Errorf("getHash(%d) invoked, blockhash for that block not provided", num)
   132  		}
   133  		return h
   134  	}
   135  	var (
   136  		statedb     = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
   137  		signer      = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
   138  		gaspool     = new(core.GasPool)
   139  		blockHash   = common.Hash{0x13, 0x37}
   140  		rejectedTxs []*rejectedTx
   141  		includedTxs types.Transactions
   142  		gasUsed     = uint64(0)
   143  		receipts    = make(types.Receipts, 0)
   144  		txIndex     = 0
   145  	)
   146  	gaspool.AddGas(pre.Env.GasLimit)
   147  	vmContext := vm.BlockContext{
   148  		CanTransfer: core.CanTransfer,
   149  		Transfer:    core.Transfer,
   150  		Coinbase:    pre.Env.Coinbase,
   151  		BlockNumber: new(big.Int).SetUint64(pre.Env.Number),
   152  		Time:        pre.Env.Timestamp,
   153  		Difficulty:  pre.Env.Difficulty,
   154  		GasLimit:    pre.Env.GasLimit,
   155  		GetHash:     getHash,
   156  	}
   157  	// If currentBaseFee is defined, add it to the vmContext.
   158  	if pre.Env.BaseFee != nil {
   159  		vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee)
   160  	}
   161  	// If random is defined, add it to the vmContext.
   162  	if pre.Env.Random != nil {
   163  		rnd := common.BigToHash(pre.Env.Random)
   164  		vmContext.Random = &rnd
   165  	}
   166  	// If excessBlobGas is defined, add it to the vmContext.
   167  	if pre.Env.ExcessBlobGas != nil {
   168  		vmContext.ExcessBlobGas = pre.Env.ExcessBlobGas
   169  	} else {
   170  		// If it is not explicitly defined, but we have the parent values, we try
   171  		// to calculate it ourselves.
   172  		parentExcessBlobGas := pre.Env.ParentExcessBlobGas
   173  		parentBlobGasUsed := pre.Env.ParentBlobGasUsed
   174  		if parentExcessBlobGas != nil && parentBlobGasUsed != nil {
   175  			excessBlobGas := eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed)
   176  			vmContext.ExcessBlobGas = &excessBlobGas
   177  		}
   178  	}
   179  	// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
   180  	// done in StateProcessor.Process(block, ...), right before transactions are applied.
   181  	if chainConfig.DAOForkSupport &&
   182  		chainConfig.DAOForkBlock != nil &&
   183  		chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
   184  		misc.ApplyDAOHardFork(statedb)
   185  	}
   186  	if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil {
   187  		evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
   188  		core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
   189  	}
   190  	var blobGasUsed uint64
   191  	for i, tx := range txs {
   192  		if tx.Type() == types.BlobTxType && vmContext.ExcessBlobGas == nil {
   193  			errMsg := "blob tx used but field env.ExcessBlobGas missing"
   194  			log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", errMsg)
   195  			rejectedTxs = append(rejectedTxs, &rejectedTx{i, errMsg})
   196  			continue
   197  		}
   198  		msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee)
   199  		if err != nil {
   200  			log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
   201  			rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
   202  			continue
   203  		}
   204  		tracer, err := getTracerFn(txIndex, tx.Hash())
   205  		if err != nil {
   206  			return nil, nil, err
   207  		}
   208  		vmConfig.Tracer = tracer
   209  		statedb.SetTxContext(tx.Hash(), txIndex)
   210  
   211  		var (
   212  			txContext = core.NewEVMTxContext(msg)
   213  			snapshot  = statedb.Snapshot()
   214  			prevGas   = gaspool.Gas()
   215  		)
   216  		evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
   217  
   218  		// (ret []byte, usedGas uint64, failed bool, err error)
   219  		msgResult, err := core.ApplyMessage(evm, msg, gaspool)
   220  		if err != nil {
   221  			statedb.RevertToSnapshot(snapshot)
   222  			log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
   223  			rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
   224  			gaspool.SetGas(prevGas)
   225  			continue
   226  		}
   227  		if tx.Type() == types.BlobTxType {
   228  			blobGasUsed += params.BlobTxBlobGasPerBlob
   229  		}
   230  		includedTxs = append(includedTxs, tx)
   231  		if hashError != nil {
   232  			return nil, nil, NewError(ErrorMissingBlockhash, hashError)
   233  		}
   234  		gasUsed += msgResult.UsedGas
   235  
   236  		// Receipt:
   237  		{
   238  			var root []byte
   239  			if chainConfig.IsByzantium(vmContext.BlockNumber) {
   240  				statedb.Finalise(true)
   241  			} else {
   242  				root = statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)).Bytes()
   243  			}
   244  
   245  			// Create a new receipt for the transaction, storing the intermediate root and
   246  			// gas used by the tx.
   247  			receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: gasUsed}
   248  			if msgResult.Failed() {
   249  				receipt.Status = types.ReceiptStatusFailed
   250  			} else {
   251  				receipt.Status = types.ReceiptStatusSuccessful
   252  			}
   253  			receipt.TxHash = tx.Hash()
   254  			receipt.GasUsed = msgResult.UsedGas
   255  
   256  			// If the transaction created a contract, store the creation address in the receipt.
   257  			if msg.To == nil {
   258  				receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
   259  			}
   260  
   261  			// Set the receipt logs and create the bloom filter.
   262  			receipt.Logs = statedb.GetLogs(tx.Hash(), vmContext.BlockNumber.Uint64(), blockHash)
   263  			receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
   264  			// These three are non-consensus fields:
   265  			//receipt.BlockHash
   266  			//receipt.BlockNumber
   267  			receipt.TransactionIndex = uint(txIndex)
   268  			receipts = append(receipts, receipt)
   269  		}
   270  
   271  		txIndex++
   272  	}
   273  	statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
   274  	// Add mining reward? (-1 means rewards are disabled)
   275  	if miningReward >= 0 {
   276  		// Add mining reward. The mining reward may be `0`, which only makes a difference in the cases
   277  		// where
   278  		// - the coinbase self-destructed, or
   279  		// - there are only 'bad' transactions, which aren't executed. In those cases,
   280  		//   the coinbase gets no txfee, so isn't created, and thus needs to be touched
   281  		var (
   282  			blockReward = big.NewInt(miningReward)
   283  			minerReward = new(big.Int).Set(blockReward)
   284  			perOmmer    = new(big.Int).Div(blockReward, big.NewInt(32))
   285  		)
   286  		for _, ommer := range pre.Env.Ommers {
   287  			// Add 1/32th for each ommer included
   288  			minerReward.Add(minerReward, perOmmer)
   289  			// Add (8-delta)/8
   290  			reward := big.NewInt(8)
   291  			reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
   292  			reward.Mul(reward, blockReward)
   293  			reward.Div(reward, big.NewInt(8))
   294  			statedb.AddBalance(ommer.Address, reward)
   295  		}
   296  		statedb.AddBalance(pre.Env.Coinbase, minerReward)
   297  	}
   298  	// Apply withdrawals
   299  	for _, w := range pre.Env.Withdrawals {
   300  		// Amount is in gwei, turn into wei
   301  		amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
   302  		statedb.AddBalance(w.Address, amount)
   303  	}
   304  	// Commit block
   305  	root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
   306  	if err != nil {
   307  		return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
   308  	}
   309  	execRs := &ExecutionResult{
   310  		StateRoot:   root,
   311  		TxRoot:      types.DeriveSha(includedTxs, trie.NewStackTrie(nil)),
   312  		ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)),
   313  		Bloom:       types.CreateBloom(receipts),
   314  		LogsHash:    rlpHash(statedb.Logs()),
   315  		Receipts:    receipts,
   316  		Rejected:    rejectedTxs,
   317  		Difficulty:  (*math.HexOrDecimal256)(vmContext.Difficulty),
   318  		GasUsed:     (math.HexOrDecimal64)(gasUsed),
   319  		BaseFee:     (*math.HexOrDecimal256)(vmContext.BaseFee),
   320  	}
   321  	if pre.Env.Withdrawals != nil {
   322  		h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil))
   323  		execRs.WithdrawalsRoot = &h
   324  	}
   325  	if vmContext.ExcessBlobGas != nil {
   326  		execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(vmContext.ExcessBlobGas)
   327  		execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
   328  	}
   329  	// Re-create statedb instance with new root upon the updated database
   330  	// for accessing latest states.
   331  	statedb, err = state.New(root, statedb.Database(), nil)
   332  	if err != nil {
   333  		return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
   334  	}
   335  	return statedb, execRs, nil
   336  }
   337  
   338  func MakePreState(db zonddb.Database, accounts core.GenesisAlloc) *state.StateDB {
   339  	sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true})
   340  	statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
   341  	for addr, a := range accounts {
   342  		statedb.SetCode(addr, a.Code)
   343  		statedb.SetNonce(addr, a.Nonce)
   344  		statedb.SetBalance(addr, a.Balance)
   345  		for k, v := range a.Storage {
   346  			statedb.SetState(addr, k, v)
   347  		}
   348  	}
   349  	// Commit and re-open to start with a clean state.
   350  	root, _ := statedb.Commit(0, false)
   351  	statedb, _ = state.New(root, sdb, nil)
   352  	return statedb
   353  }
   354  
   355  func rlpHash(x interface{}) (h common.Hash) {
   356  	hw := sha3.NewLegacyKeccak256()
   357  	rlp.Encode(hw, x)
   358  	hw.Sum(h[:0])
   359  	return h
   360  }
   361  
   362  // calcDifficulty is based on ethash.CalcDifficulty. This method is used in case
   363  // the caller does not provide an explicit difficulty, but instead provides only
   364  // parent timestamp + difficulty.
   365  // Note: this method only works for ethash engine.
   366  func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime uint64,
   367  	parentDifficulty *big.Int, parentUncleHash common.Hash) *big.Int {
   368  	uncleHash := parentUncleHash
   369  	if uncleHash == (common.Hash{}) {
   370  		uncleHash = types.EmptyUncleHash
   371  	}
   372  	parent := &types.Header{
   373  		ParentHash: common.Hash{},
   374  		UncleHash:  uncleHash,
   375  		Difficulty: parentDifficulty,
   376  		Number:     new(big.Int).SetUint64(number - 1),
   377  		Time:       parentTime,
   378  	}
   379  	return ethash.CalcDifficulty(config, currentTime, parent)
   380  }