github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/vm/contract.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:36</date>
    10  //</624450081935855616>
    11  
    12  
    13  package vm
    14  
    15  import (
    16  	"math/big"
    17  
    18  	"github.com/ethereum/go-ethereum/common"
    19  )
    20  
    21  //contractRef是对合同支持对象的引用
    22  type ContractRef interface {
    23  	Address() common.Address
    24  }
    25  
    26  //accountRef执行contractRef。
    27  //
    28  //在EVM初始化和
    29  //它的主要用途是获取地址。删除此对象
    30  //由于缓存的跳转目的地
    31  //从父合同(即调用者)中提取,其中
    32  //是ContractRef。
    33  type AccountRef common.Address
    34  
    35  //地址将accountRef强制转换为地址
    36  func (ar AccountRef) Address() common.Address { return (common.Address)(ar) }
    37  
    38  //契约表示状态数据库中的以太坊契约。它包含
    39  //合同代码,调用参数。合同执行合同参考号
    40  type Contract struct {
    41  //CallerAddress是调用方初始化此项的结果
    42  //合同。但是,当“调用方法”被委托时,这个值
    43  //需要初始化为调用方的调用方的调用方。
    44  	CallerAddress common.Address
    45  	caller        ContractRef
    46  	self          ContractRef
    47  
    48  jumpdests map[common.Hash]bitvec //JumpDest分析的汇总结果。
    49  analysis  bitvec                 //JumpDest分析的本地缓存结果
    50  
    51  	Code     []byte
    52  	CodeHash common.Hash
    53  	CodeAddr *common.Address
    54  	Input    []byte
    55  
    56  	Gas   uint64
    57  	value *big.Int
    58  }
    59  
    60  //NewContract返回执行EVM的新合同环境。
    61  func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
    62  	c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object}
    63  
    64  	if parent, ok := caller.(*Contract); ok {
    65  //如果可用,请重新使用父上下文中的JumpDest分析。
    66  		c.jumpdests = parent.jumpdests
    67  	} else {
    68  		c.jumpdests = make(map[common.Hash]bitvec)
    69  	}
    70  
    71  //气体应该是一个指针,这样可以在运行过程中安全地减少气体。
    72  //此指针将关闭状态转换
    73  	c.Gas = gas
    74  //确保设置了值
    75  	c.value = value
    76  
    77  	return c
    78  }
    79  
    80  func (c *Contract) validJumpdest(dest *big.Int) bool {
    81  	udest := dest.Uint64()
    82  //PC不能超过len(code),当然不能超过63位。
    83  //在这种情况下,不要费心检查Jumpdest。
    84  	if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) {
    85  		return false
    86  	}
    87  //仅允许目的地使用JumpDest
    88  	if OpCode(c.Code[udest]) != JUMPDEST {
    89  		return false
    90  	}
    91  //我们已经有合同哈希了吗?
    92  	if c.CodeHash != (common.Hash{}) {
    93  //父上下文有分析吗?
    94  		analysis, exist := c.jumpdests[c.CodeHash]
    95  		if !exist {
    96  //在父上下文中进行分析并保存
    97  //我们不需要将它存储在c.analysis中。
    98  			analysis = codeBitmap(c.Code)
    99  			c.jumpdests[c.CodeHash] = analysis
   100  		}
   101  		return analysis.codeSegment(udest)
   102  	}
   103  //我们没有代码哈希,很可能还没有一段initcode
   104  //在州TIE。在这种情况下,我们进行分析,并将其保存在本地,因此
   105  //我们不必为执行中的每个跳转指令重新计算它
   106  //但是,我们不会在父上下文中保存它。
   107  	if c.analysis == nil {
   108  		c.analysis = codeBitmap(c.Code)
   109  	}
   110  	return c.analysis.codeSegment(udest)
   111  }
   112  
   113  //asdelegate将协定设置为委托调用并返回当前
   114  //合同(用于链接呼叫)
   115  func (c *Contract) AsDelegate() *Contract {
   116  //注:呼叫者必须始终是合同。这不应该发生
   117  //打电话的不是合同。
   118  	parent := c.caller.(*Contract)
   119  	c.CallerAddress = parent.CallerAddress
   120  	c.value = parent.value
   121  
   122  	return c
   123  }
   124  
   125  //getop返回契约字节数组中的第n个元素
   126  func (c *Contract) GetOp(n uint64) OpCode {
   127  	return OpCode(c.GetByte(n))
   128  }
   129  
   130  //GetByte返回协定字节数组中的第n个字节
   131  func (c *Contract) GetByte(n uint64) byte {
   132  	if n < uint64(len(c.Code)) {
   133  		return c.Code[n]
   134  	}
   135  
   136  	return 0
   137  }
   138  
   139  //调用者返回合同的调用者。
   140  //
   141  //当协定是委托时,调用方将递归调用调用方
   142  //呼叫,包括呼叫者的呼叫。
   143  func (c *Contract) Caller() common.Address {
   144  	return c.CallerAddress
   145  }
   146  
   147  //use gas尝试使用气体并减去它,成功后返回true。
   148  func (c *Contract) UseGas(gas uint64) (ok bool) {
   149  	if c.Gas < gas {
   150  		return false
   151  	}
   152  	c.Gas -= gas
   153  	return true
   154  }
   155  
   156  //地址返回合同地址
   157  func (c *Contract) Address() common.Address {
   158  	return c.self.Address()
   159  }
   160  
   161  //value返回合同值(从调用方发送给它)
   162  func (c *Contract) Value() *big.Int {
   163  	return c.value
   164  }
   165  
   166  //setcallcode设置合同的代码和支持数据的地址
   167  //对象
   168  func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
   169  	c.Code = code
   170  	c.CodeHash = hash
   171  	c.CodeAddr = addr
   172  }
   173  
   174  //setcodeoptionalhash可用于提供代码,但提供hash是可选的。
   175  //如果没有提供哈希,JumpDest分析将不会保存到父上下文中。
   176  func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) {
   177  	c.Code = codeAndHash.code
   178  	c.CodeHash = codeAndHash.hash
   179  	c.CodeAddr = addr
   180  }
   181