github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/signer/core/abihelper.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2018 Go Ethereum作者 10 //此文件是Go以太坊的一部分。 11 // 12 //Go以太坊是免费软件:您可以重新发布和/或修改它 13 //根据GNU通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊的分布希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU通用公共许可证了解更多详细信息。 21 // 22 //你应该已经收到一份GNU通用公共许可证的副本 23 //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package core 26 27 import ( 28 "encoding/json" 29 "fmt" 30 "io/ioutil" 31 "strings" 32 33 "github.com/ethereum/go-ethereum/accounts/abi" 34 "github.com/ethereum/go-ethereum/common" 35 36 "bytes" 37 "os" 38 "regexp" 39 ) 40 41 type decodedArgument struct { 42 soltype abi.Argument 43 value interface{} 44 } 45 type decodedCallData struct { 46 signature string 47 name string 48 inputs []decodedArgument 49 } 50 51 //字符串实现Stringer接口,尝试使用基础值类型 52 func (arg decodedArgument) String() string { 53 var value string 54 switch val := arg.value.(type) { 55 case fmt.Stringer: 56 value = val.String() 57 default: 58 value = fmt.Sprintf("%v", val) 59 } 60 return fmt.Sprintf("%v: %v", arg.soltype.Type.String(), value) 61 } 62 63 //字符串实现用于decodedcalldata的字符串接口 64 func (cd decodedCallData) String() string { 65 args := make([]string, len(cd.inputs)) 66 for i, arg := range cd.inputs { 67 args[i] = arg.String() 68 } 69 return fmt.Sprintf("%s(%s)", cd.name, strings.Join(args, ",")) 70 } 71 72 //ParseCallData将提供的调用数据与ABI定义匹配, 73 //并返回包含实际go类型值的结构 74 func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) { 75 76 if len(calldata) < 4 { 77 return nil, fmt.Errorf("Invalid ABI-data, incomplete method signature of (%d bytes)", len(calldata)) 78 } 79 80 sigdata, argdata := calldata[:4], calldata[4:] 81 if len(argdata)%32 != 0 { 82 return nil, fmt.Errorf("Not ABI-encoded data; length should be a multiple of 32 (was %d)", len(argdata)) 83 } 84 85 abispec, err := abi.JSON(strings.NewReader(abidata)) 86 if err != nil { 87 return nil, fmt.Errorf("Failed parsing JSON ABI: %v, abidata: %v", err, abidata) 88 } 89 90 method, err := abispec.MethodById(sigdata) 91 if err != nil { 92 return nil, err 93 } 94 95 v, err := method.Inputs.UnpackValues(argdata) 96 if err != nil { 97 return nil, err 98 } 99 100 decoded := decodedCallData{signature: method.Sig(), name: method.Name} 101 102 for n, argument := range method.Inputs { 103 if err != nil { 104 return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err) 105 } 106 decodedArg := decodedArgument{ 107 soltype: argument, 108 value: v[n], 109 } 110 decoded.inputs = append(decoded.inputs, decodedArg) 111 } 112 113 //数据解码完毕。此时,我们对解码后的数据进行编码,以查看它是否与 114 //原始数据。如果我们不这样做,就可以在参数中填充额外的数据,例如 115 //仅通过解码数据检测不到。 116 117 var ( 118 encoded []byte 119 ) 120 encoded, err = method.Inputs.PackValues(v) 121 122 if err != nil { 123 return nil, err 124 } 125 126 if !bytes.Equal(encoded, argdata) { 127 was := common.Bytes2Hex(encoded) 128 exp := common.Bytes2Hex(argdata) 129 return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. \nWant %s\nHave %s\nfor method %v", exp, was, method.Sig()) 130 } 131 return &decoded, nil 132 } 133 134 //methodSelectorToAbi将方法选择器转换为ABI结构。返回的数据是有效的JSON字符串 135 //可由标准ABI包装使用。 136 func MethodSelectorToAbi(selector string) ([]byte, error) { 137 138 re := regexp.MustCompile(`^([^\)]+)\(([a-z0-9,\[\]]*)\)`) 139 140 type fakeArg struct { 141 Type string `json:"type"` 142 } 143 type fakeABI struct { 144 Name string `json:"name"` 145 Type string `json:"type"` 146 Inputs []fakeArg `json:"inputs"` 147 } 148 groups := re.FindStringSubmatch(selector) 149 if len(groups) != 3 { 150 return nil, fmt.Errorf("Did not match: %v (%v matches)", selector, len(groups)) 151 } 152 name := groups[1] 153 args := groups[2] 154 arguments := make([]fakeArg, 0) 155 if len(args) > 0 { 156 for _, arg := range strings.Split(args, ",") { 157 arguments = append(arguments, fakeArg{arg}) 158 } 159 } 160 abicheat := fakeABI{ 161 name, "function", arguments, 162 } 163 return json.Marshal([]fakeABI{abicheat}) 164 165 } 166 167 type AbiDb struct { 168 db map[string]string 169 customdb map[string]string 170 customdbPath string 171 } 172 173 //出于测试目的,存在newEmptyBidb 174 func NewEmptyAbiDB() (*AbiDb, error) { 175 return &AbiDb{make(map[string]string), make(map[string]string), ""}, nil 176 } 177 178 //newabidbfrmfile从文件加载签名数据库,以及 179 //如果文件不是有效的JSON,则会出错。没有其他内容验证 180 func NewAbiDBFromFile(path string) (*AbiDb, error) { 181 raw, err := ioutil.ReadFile(path) 182 if err != nil { 183 return nil, err 184 } 185 db, err := NewEmptyAbiDB() 186 if err != nil { 187 return nil, err 188 } 189 json.Unmarshal(raw, &db.db) 190 return db, nil 191 } 192 193 //newabidbfrmfiles同时加载标准签名数据库和自定义数据库。后者将被使用 194 //如果通过API提交新值,则将其写入 195 func NewAbiDBFromFiles(standard, custom string) (*AbiDb, error) { 196 197 db := &AbiDb{make(map[string]string), make(map[string]string), custom} 198 db.customdbPath = custom 199 200 raw, err := ioutil.ReadFile(standard) 201 if err != nil { 202 return nil, err 203 } 204 json.Unmarshal(raw, &db.db) 205 //自定义文件可能不存在。如果需要,将在保存期间创建 206 if _, err := os.Stat(custom); err == nil { 207 raw, err = ioutil.ReadFile(custom) 208 if err != nil { 209 return nil, err 210 } 211 json.Unmarshal(raw, &db.customdb) 212 } 213 214 return db, nil 215 } 216 217 //LookupMethodSelector对照已知的ABI方法检查给定的4字节序列。 218 //obs:此方法不验证匹配,假定调用方将验证匹配 219 func (db *AbiDb) LookupMethodSelector(id []byte) (string, error) { 220 if len(id) < 4 { 221 return "", fmt.Errorf("Expected 4-byte id, got %d", len(id)) 222 } 223 sig := common.ToHex(id[:4]) 224 if key, exists := db.db[sig]; exists { 225 return key, nil 226 } 227 if key, exists := db.customdb[sig]; exists { 228 return key, nil 229 } 230 return "", fmt.Errorf("Signature %v not found", sig) 231 } 232 func (db *AbiDb) Size() int { 233 return len(db.db) 234 } 235 236 //savecustomabi临时保存签名。如果使用自定义文件,也将保存到磁盘 237 func (db *AbiDb) saveCustomAbi(selector, signature string) error { 238 db.customdb[signature] = selector 239 if db.customdbPath == "" { 240 return nil //本身不是错误,只是没有使用 241 } 242 d, err := json.Marshal(db.customdb) 243 if err != nil { 244 return err 245 } 246 err = ioutil.WriteFile(db.customdbPath, d, 0600) 247 return err 248 } 249 250 //如果启用了自定义数据库保存,则向数据库添加签名。 251 //OBS:这种方法不能验证数据的正确性, 252 //假定呼叫者已经这样做了 253 func (db *AbiDb) AddSignature(selector string, data []byte) error { 254 if len(data) < 4 { 255 return nil 256 } 257 _, err := db.LookupMethodSelector(data[:4]) 258 if err == nil { 259 return nil 260 } 261 sig := common.ToHex(data[:4]) 262 return db.saveCustomAbi(selector, sig) 263 }