github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/core/vm/analysis.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 12:09:35</date> 10 //</624342620939751424> 11 12 13 package vm 14 15 import ( 16 "math/big" 17 18 "github.com/ethereum/go-ethereum/common" 19 ) 20 21 //目的地为每个契约存储一个映射(由代码散列键控)。 22 //地图包含JumpDest的每个位置的条目。 23 //指令。 24 type destinations map[common.Hash]bitvec 25 26 //检查代码在dest是否有JumpDest。 27 func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool { 28 //PC不能超过len(code),当然不能超过63位。 29 //在这种情况下,不要费心检查Jumpdest。 30 udest := dest.Uint64() 31 if dest.BitLen() >= 63 || udest >= uint64(len(code)) { 32 return false 33 } 34 35 m, analysed := d[codehash] 36 if !analysed { 37 m = codeBitmap(code) 38 d[codehash] = m 39 } 40 return OpCode(code[udest]) == JUMPDEST && m.codeSegment(udest) 41 } 42 43 //bitvec是一个位向量,它映射程序中的字节。 44 //未设置位表示字节为操作码,设置位表示 45 //这是数据(即pushxx的参数)。 46 type bitvec []byte 47 48 func (bits *bitvec) set(pos uint64) { 49 (*bits)[pos/8] |= 0x80 >> (pos % 8) 50 } 51 func (bits *bitvec) set8(pos uint64) { 52 (*bits)[pos/8] |= 0xFF >> (pos % 8) 53 (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) 54 } 55 56 //代码段检查位置是否在代码段中。 57 func (bits *bitvec) codeSegment(pos uint64) bool { 58 return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0 59 } 60 61 //codeBitmap以代码的形式收集数据位置。 62 func codeBitmap(code []byte) bitvec { 63 //如果代码 64 //以push32结束,算法将把0推到 65 //位向量超出了实际代码的边界。 66 bits := make(bitvec, len(code)/8+1+4) 67 for pc := uint64(0); pc < uint64(len(code)); { 68 op := OpCode(code[pc]) 69 70 if op >= PUSH1 && op <= PUSH32 { 71 numbits := op - PUSH1 + 1 72 pc++ 73 for ; numbits >= 8; numbits -= 8 { 74 bits.set8(pc) //八 75 pc += 8 76 } 77 for ; numbits > 0; numbits-- { 78 bits.set(pc) 79 pc++ 80 } 81 } else { 82 pc++ 83 } 84 } 85 return bits 86 } 87