github.com/amazechain/amc@v0.1.3/internal/evm.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package internal
    18  
    19  import (
    20  	"fmt"
    21  	"github.com/amazechain/amc/common/block"
    22  	"github.com/amazechain/amc/common/types"
    23  	"github.com/amazechain/amc/internal/consensus"
    24  	"github.com/amazechain/amc/internal/vm/evmtypes"
    25  	"github.com/amazechain/amc/params"
    26  	"github.com/holiman/uint256"
    27  )
    28  
    29  // NewEVMBlockContext creates a new context for use in the EVM.
    30  func NewEVMBlockContext(header *block.Header, blockHashFunc func(n uint64) types.Hash, engine consensus.Engine, author *types.Address) evmtypes.BlockContext {
    31  	// If we don't have an explicit author (i.e. not mining), extract from the header
    32  	var beneficiary types.Address
    33  	if author == nil {
    34  		beneficiary, _ = engine.Author(header) // Ignore error, we're past header validation
    35  	} else {
    36  		beneficiary = *author
    37  	}
    38  	var baseFee uint256.Int
    39  	if header.BaseFee != nil {
    40  		overflow := baseFee.SetFromBig(header.BaseFee.ToBig())
    41  		if overflow {
    42  			panic(fmt.Errorf("header.BaseFee higher than 2^256-1"))
    43  		}
    44  	}
    45  
    46  	var prevRandDao *types.Hash
    47  	if header.Difficulty.Cmp(uint256.NewInt(0)) == 0 {
    48  		// EIP-4399. We use SerenityDifficulty (i.e. 0) as a telltale of Proof-of-Stake blocks.
    49  		prevRandDao = &header.MixDigest
    50  	}
    51  
    52  	var transferFunc evmtypes.TransferFunc
    53  	if engine != nil && engine.Type() == params.BorConsensus {
    54  		transferFunc = BorTransfer
    55  	} else {
    56  		transferFunc = Transfer
    57  	}
    58  
    59  	return evmtypes.BlockContext{
    60  		CanTransfer: CanTransfer,
    61  		Transfer:    transferFunc,
    62  		GetHash:     blockHashFunc,
    63  		Coinbase:    beneficiary,
    64  		BlockNumber: header.Number.Uint64(),
    65  		Time:        header.Time,
    66  		Difficulty:  header.Difficulty.ToBig(),
    67  		BaseFee:     &baseFee,
    68  		GasLimit:    header.GasLimit,
    69  		PrevRanDao:  prevRandDao,
    70  	}
    71  }
    72  
    73  // NewEVMTxContext creates a new transaction context for a single transaction.
    74  func NewEVMTxContext(msg Message) evmtypes.TxContext {
    75  	return evmtypes.TxContext{
    76  		Origin:   msg.From(),
    77  		GasPrice: msg.GasPrice(),
    78  	}
    79  }
    80  
    81  // GetHashFn returns a GetHashFunc which retrieves header hashes by number
    82  func GetHashFn(ref *block.Header, getHeader func(hash types.Hash, number uint64) *block.Header) func(n uint64) types.Hash {
    83  	// Cache will initially contain [refHash.parent],
    84  	// Then fill up with [refHash.p, refHash.pp, refHash.ppp, ...]
    85  	var cache []types.Hash
    86  
    87  	return func(n uint64) types.Hash {
    88  		// If there's no hash cache yet, make one
    89  		if len(cache) == 0 {
    90  			cache = append(cache, ref.ParentHash)
    91  		}
    92  		if idx := ref.Number.Uint64() - n - 1; idx < uint64(len(cache)) {
    93  			return cache[idx]
    94  		}
    95  		// No luck in the cache, but we can start iterating from the last element we already know
    96  		lastKnownHash := cache[len(cache)-1]
    97  		lastKnownNumber := ref.Number.Uint64() - uint64(len(cache))
    98  
    99  		for {
   100  			header := getHeader(lastKnownHash, lastKnownNumber)
   101  			if header == nil {
   102  				break
   103  			}
   104  			cache = append(cache, header.ParentHash)
   105  			lastKnownHash = header.ParentHash
   106  			lastKnownNumber = header.Number.Uint64() - 1
   107  			if n == lastKnownNumber {
   108  				return lastKnownHash
   109  			}
   110  		}
   111  		return types.Hash{}
   112  	}
   113  }
   114  
   115  // CanTransfer checks whether there are enough funds in the address' account to make a transfer.
   116  // This does not take the necessary gas in to account to make the transfer valid.
   117  func CanTransfer(db evmtypes.IntraBlockState, addr types.Address, amount *uint256.Int) bool {
   118  	return !db.GetBalance(addr).Lt(amount)
   119  }
   120  
   121  // Transfer subtracts amount from sender and adds amount to recipient using the given Db
   122  func Transfer(db evmtypes.IntraBlockState, sender, recipient types.Address, amount *uint256.Int, bailout bool) {
   123  	if !bailout {
   124  		db.SubBalance(sender, amount)
   125  	}
   126  	db.AddBalance(recipient, amount)
   127  }
   128  
   129  // BorTransfer transfer in Bor
   130  func BorTransfer(db evmtypes.IntraBlockState, sender, recipient types.Address, amount *uint256.Int, bailout bool) {
   131  	// get inputs before
   132  	//input1 := db.GetBalance(sender).Clone()
   133  	//input2 := db.GetBalance(recipient).Clone()
   134  
   135  	if !bailout {
   136  		db.SubBalance(sender, amount)
   137  	}
   138  	db.AddBalance(recipient, amount)
   139  
   140  	//// get outputs after
   141  	//output1 := db.GetBalance(sender).Clone()
   142  	//output2 := db.GetBalance(recipient).Clone()
   143  	//
   144  	//// add transfer log
   145  	//AddTransferLog(db, sender, recipient, amount, input1, input2, output1, output2)
   146  }
   147  
   148  // ChainContext supports retrieving headers and consensus parameters from the
   149  // current blockchain to be used during transaction processing.
   150  type ChainContext interface {
   151  	// Engine retrieves the chain's consensus engine.
   152  	Engine() consensus.Engine
   153  
   154  	// GetHeader returns the header corresponding to the hash/number argument pair.
   155  	GetHeader(types.Hash, uint64) *block.Header
   156  }