github.com/ethereum/go-ethereum@v1.16.1/core/vm/contract.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 vm
    18  
    19  import (
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/core/tracing"
    22  	"github.com/holiman/uint256"
    23  )
    24  
    25  // Contract represents an ethereum contract in the state database. It contains
    26  // the contract code, calling arguments. Contract implements ContractRef
    27  type Contract struct {
    28  	// caller is the result of the caller which initialised this
    29  	// contract. However, when the "call method" is delegated this
    30  	// value needs to be initialised to that of the caller's caller.
    31  	caller  common.Address
    32  	address common.Address
    33  
    34  	jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis.
    35  	analysis  bitvec                 // Locally cached result of JUMPDEST analysis
    36  
    37  	Code     []byte
    38  	CodeHash common.Hash
    39  	Input    []byte
    40  
    41  	// is the execution frame represented by this object a contract deployment
    42  	IsDeployment bool
    43  	IsSystemCall bool
    44  
    45  	Gas   uint64
    46  	value *uint256.Int
    47  }
    48  
    49  // NewContract returns a new contract environment for the execution of EVM.
    50  func NewContract(caller common.Address, address common.Address, value *uint256.Int, gas uint64, jumpDests map[common.Hash]bitvec) *Contract {
    51  	// Initialize the jump analysis map if it's nil, mostly for tests
    52  	if jumpDests == nil {
    53  		jumpDests = make(map[common.Hash]bitvec)
    54  	}
    55  	return &Contract{
    56  		caller:    caller,
    57  		address:   address,
    58  		jumpdests: jumpDests,
    59  		Gas:       gas,
    60  		value:     value,
    61  	}
    62  }
    63  
    64  func (c *Contract) validJumpdest(dest *uint256.Int) bool {
    65  	udest, overflow := dest.Uint64WithOverflow()
    66  	// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
    67  	// Don't bother checking for JUMPDEST in that case.
    68  	if overflow || udest >= uint64(len(c.Code)) {
    69  		return false
    70  	}
    71  	// Only JUMPDESTs allowed for destinations
    72  	if OpCode(c.Code[udest]) != JUMPDEST {
    73  		return false
    74  	}
    75  	return c.isCode(udest)
    76  }
    77  
    78  // isCode returns true if the provided PC location is an actual opcode, as
    79  // opposed to a data-segment following a PUSHN operation.
    80  func (c *Contract) isCode(udest uint64) bool {
    81  	// Do we already have an analysis laying around?
    82  	if c.analysis != nil {
    83  		return c.analysis.codeSegment(udest)
    84  	}
    85  	// Do we have a contract hash already?
    86  	// If we do have a hash, that means it's a 'regular' contract. For regular
    87  	// contracts ( not temporary initcode), we store the analysis in a map
    88  	if c.CodeHash != (common.Hash{}) {
    89  		// Does parent context have the analysis?
    90  		analysis, exist := c.jumpdests[c.CodeHash]
    91  		if !exist {
    92  			// Do the analysis and save in parent context
    93  			// We do not need to store it in c.analysis
    94  			analysis = codeBitmap(c.Code)
    95  			c.jumpdests[c.CodeHash] = analysis
    96  		}
    97  		// Also stash it in current contract for faster access
    98  		c.analysis = analysis
    99  		return analysis.codeSegment(udest)
   100  	}
   101  	// We don't have the code hash, most likely a piece of initcode not already
   102  	// in state trie. In that case, we do an analysis, and save it locally, so
   103  	// we don't have to recalculate it for every JUMP instruction in the execution
   104  	// However, we don't save it within the parent context
   105  	if c.analysis == nil {
   106  		c.analysis = codeBitmap(c.Code)
   107  	}
   108  	return c.analysis.codeSegment(udest)
   109  }
   110  
   111  // GetOp returns the n'th element in the contract's byte array
   112  func (c *Contract) GetOp(n uint64) OpCode {
   113  	if n < uint64(len(c.Code)) {
   114  		return OpCode(c.Code[n])
   115  	}
   116  
   117  	return STOP
   118  }
   119  
   120  // Caller returns the caller of the contract.
   121  //
   122  // Caller will recursively call caller when the contract is a delegate
   123  // call, including that of caller's caller.
   124  func (c *Contract) Caller() common.Address {
   125  	return c.caller
   126  }
   127  
   128  // UseGas attempts the use gas and subtracts it and returns true on success
   129  func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) {
   130  	if c.Gas < gas {
   131  		return false
   132  	}
   133  	if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
   134  		logger.OnGasChange(c.Gas, c.Gas-gas, reason)
   135  	}
   136  	c.Gas -= gas
   137  	return true
   138  }
   139  
   140  // RefundGas refunds gas to the contract
   141  func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
   142  	if gas == 0 {
   143  		return
   144  	}
   145  	if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
   146  		logger.OnGasChange(c.Gas, c.Gas+gas, reason)
   147  	}
   148  	c.Gas += gas
   149  }
   150  
   151  // Address returns the contracts address
   152  func (c *Contract) Address() common.Address {
   153  	return c.address
   154  }
   155  
   156  // Value returns the contract's value (sent to it from it's caller)
   157  func (c *Contract) Value() *uint256.Int {
   158  	return c.value
   159  }
   160  
   161  // SetCallCode sets the code of the contract,
   162  func (c *Contract) SetCallCode(hash common.Hash, code []byte) {
   163  	c.Code = code
   164  	c.CodeHash = hash
   165  }