github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/core/vm/context.go (about)

     1  // Copyright 2016 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 vm
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/consensus"
    24  	"github.com/ethereum/go-ethereum/core/state"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/params"
    27  )
    28  
    29  // Message represents a message sent to a contract.
    30  type Message interface {
    31  	From() common.Address
    32  	//FromFrontier() (common.Address, error)
    33  	To() *common.Address
    34  
    35  	GasPrice() *big.Int
    36  	Gas() uint64
    37  
    38  	// FeeCurrency specifies the currency for gas and gateway fees.
    39  	// nil correspond to Celo Gold (native currency).
    40  	// All other values should correspond to ERC20 contract addresses extended to be compatible with gas payments.
    41  	FeeCurrency() *common.Address
    42  	GatewayFeeRecipient() *common.Address
    43  	GatewayFee() *big.Int
    44  	Value() *big.Int
    45  
    46  	Nonce() uint64
    47  	CheckNonce() bool
    48  	Data() []byte
    49  }
    50  
    51  // ChainContext supports retrieving chain data and consensus parameters
    52  // from the blockchain to be used during transaction processing.
    53  type ChainContext interface {
    54  	// Engine retrieves the blockchain's consensus engine.
    55  	Engine() consensus.Engine
    56  
    57  	// GetHeader returns the hash corresponding to the given hash and number.
    58  	GetHeader(common.Hash, uint64) *types.Header
    59  
    60  	// GetHeaderByNumber returns the hash corresponding number.
    61  	// FIXME: Use of this function, as implemented, in the EVM context produces undefined behavior
    62  	// in the pressence of forks. A new method needs to be created to retrieve a header by number
    63  	// in the correct fork.
    64  	GetHeaderByNumber(uint64) *types.Header
    65  
    66  	// GetVMConfig returns the node's vm configuration
    67  	GetVMConfig() *Config
    68  
    69  	CurrentHeader() *types.Header
    70  
    71  	State() (*state.StateDB, error)
    72  
    73  	// Config returns the blockchain's chain configuration
    74  	Config() *params.ChainConfig
    75  }
    76  
    77  // NewEVMContext creates a new context for use in the EVM.
    78  func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) Context {
    79  	// If we don't have an explicit author (i.e. not mining), extract from the header
    80  	var beneficiary common.Address
    81  	if author == nil {
    82  		beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
    83  	} else {
    84  		beneficiary = *author
    85  	}
    86  
    87  	var engine consensus.Engine
    88  	var getHeaderByNumberFn func(uint64) *types.Header
    89  	if chain != nil {
    90  		engine = chain.Engine()
    91  		getHeaderByNumberFn = chain.GetHeaderByNumber
    92  	}
    93  
    94  	return Context{
    95  		CanTransfer:       CanTransfer,
    96  		Transfer:          Transfer,
    97  		GetHash:           GetHashFn(header, chain),
    98  		GetHeaderByNumber: getHeaderByNumberFn,
    99  		VerifySeal:        VerifySealFn(header, chain),
   100  		Origin:            msg.From(),
   101  		Coinbase:          beneficiary,
   102  		BlockNumber:       new(big.Int).Set(header.Number),
   103  		Time:              new(big.Int).Set(header.Time),
   104  		Difficulty:        new(big.Int).Set(header.Difficulty),
   105  		GasLimit:          header.GasLimit,
   106  		GasPrice:          new(big.Int).Set(msg.GasPrice()),
   107  		Engine:            engine,
   108  	}
   109  }
   110  
   111  // GetHashFn returns a GetHashFunc which retrieves header hashes by number
   112  func GetHashFn(ref *types.Header, chain ChainContext) func(uint64) common.Hash {
   113  	var cache map[uint64]common.Hash
   114  
   115  	return func(n uint64) common.Hash {
   116  		// If there's no hash cache yet, make one
   117  		if cache == nil {
   118  			cache = map[uint64]common.Hash{
   119  				ref.Number.Uint64() - 1: ref.ParentHash,
   120  			}
   121  		}
   122  		// Try to fulfill the request from the cache
   123  		if hash, ok := cache[n]; ok {
   124  			return hash
   125  		}
   126  		// Not cached, iterate the blocks and cache the hashes (up to a limit of 256)
   127  		for i, header := 0, chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil && i <= 256; i, header = i+1, chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
   128  			cache[header.Number.Uint64()-1] = header.ParentHash
   129  			if n == header.Number.Uint64()-1 {
   130  				return header.ParentHash
   131  			}
   132  		}
   133  		return common.Hash{}
   134  	}
   135  }
   136  
   137  // CanTransfer checks whether there are enough funds in the address' account to make a transfer.
   138  // This does not take the necessary gas into account to make the transfer valid.
   139  func CanTransfer(db StateDB, addr common.Address, amount *big.Int) bool {
   140  	return db.GetBalance(addr).Cmp(amount) >= 0
   141  }
   142  
   143  // Transfer subtracts amount from sender and adds amount to recipient using the given Db
   144  func Transfer(db StateDB, sender, recipient common.Address, amount *big.Int) {
   145  	db.SubBalance(sender, amount)
   146  	db.AddBalance(recipient, amount)
   147  }
   148  
   149  // VerifySealFn returns a function which returns true when the given header has a verifiable seal.
   150  func VerifySealFn(ref *types.Header, chain ChainContext) func(*types.Header) bool {
   151  	return func(header *types.Header) bool {
   152  		// If the block is later than the unsealed reference block, return false.
   153  		if header.Number.Cmp(ref.Number) > 0 {
   154  			return false
   155  		}
   156  
   157  		// FIXME: Implementation currently relies on the Istanbul engine's internal view of the
   158  		// chain, so return false if this is not an Istanbul chain. As a consequence of this the
   159  		// seal is always verified against the canonical chain, which makes behavior undefined if
   160  		// this function is evaluated on a chain which does not have the highest total difficulty.
   161  		if chain.Config().Istanbul == nil {
   162  			return false
   163  		}
   164  
   165  		// Submit the header to the engine's seal verification function.
   166  		return chain.Engine().VerifySeal(nil, header) == nil
   167  	}
   168  }