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  }