// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved. // See the file LICENSE for licensing terms. // // This file is a derived work, based on the go-ethereum library whose original // notices appear below. // // It is distributed under a license compatible with the licensing terms of the // original code from which it is derived. // // Much love to the original authors for their work. // ********** // Copyright 2016 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package core import ( "context" "math/big" "github.com/holiman/uint256" "github.com/luxfi/evm/consensus" "github.com/luxfi/evm/params" "github.com/luxfi/geth/common" "github.com/luxfi/geth/consensus/misc/eip4844" "github.com/luxfi/geth/core/tracing" "github.com/luxfi/geth/core/types" "github.com/luxfi/geth/core/vm" ) type hooks struct{} var Hooks = &hooks{} // NewEVMBlockContext creates a new context for use in the EVM. func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address) vm.BlockContext { // Ensure BaseFee is not nil for EIP-1559 transactions baseFee := header.BaseFee if baseFee == nil && chain != nil && chain.Config() != nil { // If BaseFee is nil, check if EIP-1559 is enabled and set a default if params.GetExtra(chain.Config()).IsEVM(header.Time) { // EVM requires base fee baseFee = new(big.Int).Set(params.GetExtra(chain.Config()).FeeConfig.MinBaseFee) } } blockContext := vm.BlockContext{ CanTransfer: CanTransfer, Transfer: Transfer, GetHash: GetHashFn(header, chain), Coinbase: GetCoinbase(author, header), BlockNumber: new(big.Int).Set(header.Number), Time: header.Time, Difficulty: new(big.Int).Set(header.Difficulty), BaseFee: baseFee, GasLimit: header.GasLimit, Random: nil, BlobBaseFee: func() *big.Int { // Only calculate blob fee if Cancun fork is active AND header has ExcessBlobGas. // CalcBlobFee panics with "calculating blob fee on unsupported fork" otherwise. if chain != nil && chain.Config() != nil && header.ExcessBlobGas != nil && chain.Config().IsCancun(header.Number, header.Time) { return eip4844.CalcBlobFee(chain.Config(), header) } return nil }(), } // Shangai rules - set Random to Difficulty value if chain != nil && chain.Config() != nil { rules := chain.Config().Rules(header.Number, params.IsMergeTODO, header.Time) if rules.IsShanghai { blockContext.Random = new(common.Hash) blockContext.Random.SetBytes(header.Difficulty.Bytes()) blockContext.Difficulty = new(big.Int) } } // Set consensus context for warp precompiles if chain != nil { if ctx := chain.ConsensusContext(); ctx != nil { blockContext.ConsensusContext = ctx } } return blockContext } // NewEVMTxContext creates a new transaction context for a single transaction. func NewEVMTxContext(msg *Message) vm.TxContext { ctx := vm.TxContext{ Origin: msg.From, GasPrice: new(big.Int).Set(msg.GasPrice), BlobHashes: msg.BlobHashes, // AccessEvents is not yet part of the Message type in luxfi/geth. } if msg.BlobGasFeeCap != nil { ctx.BlobFeeCap = new(big.Int).Set(msg.BlobGasFeeCap) } return ctx } // GetHashFn returns a GetHashFunc which retrieves header hashes by number func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { // Cache will initially contain [refHash.parent], // Then fill up with [refHash.p, refHash.pp, refHash.ppp, ...] var cache []common.Hash return func(n uint64) common.Hash { if ref.Number.Uint64() <= n { // This situation can happen if we're doing tracing and using // block overrides. return common.Hash{} } // If there's no hash cache yet, make one if len(cache) == 0 { cache = append(cache, ref.ParentHash) } if idx := ref.Number.Uint64() - n - 1; idx < uint64(len(cache)) { return cache[idx] } // No luck in the cache, but we can start iterating from the last element we already know lastKnownHash := cache[len(cache)-1] lastKnownNumber := ref.Number.Uint64() - uint64(len(cache)) for { header := chain.GetHeader(lastKnownHash, lastKnownNumber) if header == nil { break } cache = append(cache, header.ParentHash) lastKnownHash = header.ParentHash lastKnownNumber = header.Number.Uint64() - 1 if n == lastKnownNumber { return lastKnownHash } } return common.Hash{} } } // CanTransfer checks whether there are enough funds in the address' account to make a transfer. // This does not take the necessary gas into account to make the transfer valid. func CanTransfer(db vm.StateDB, addr common.Address, amount *uint256.Int) bool { return db.GetBalance(addr).Cmp(amount) >= 0 } // Transfer subtracts amount from sender and adds amount to recipient using the given Db func Transfer(db vm.StateDB, sender, recipient common.Address, amount *uint256.Int) { db.SubBalance(sender, amount, tracing.BalanceChangeTransfer) db.AddBalance(recipient, amount, tracing.BalanceChangeTransfer) } // ChainContext supports retrieving headers and consensus parameters from the // current blockchain to be used during transaction processing. type ChainContext interface { // Engine retrieves the chain's consensus engine. Engine() consensus.Engine // GetHeader returns the header corresponding to the hash/number argument pair. GetHeader(common.Hash, uint64) *types.Header // Config returns the blockchain's chain configuration Config() *params.ChainConfig // ConsensusContext returns the consensus context for warp messages. // May return nil if not set. ConsensusContext() context.Context } func wrapStateDB(rules params.Rules, db vm.StateDB) vm.StateDB { // AP1 was activated at genesis for mainnet; testnet activated at block 3,114,811. // No StateDB wrapper is currently required because all active networks // are past the AP1 activation point. return db } // GetCoinbase returns the coinbase for the given header and author. func GetCoinbase(author *common.Address, header *types.Header) common.Address { if author != nil { return *author } return header.Coinbase }