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