github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/accounts/abi/abi.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:30</date>
    10  //</624450059311779840>
    11  
    12  
    13  package abi
    14  
    15  import (
    16  	"bytes"
    17  	"encoding/json"
    18  	"fmt"
    19  	"io"
    20  )
    21  
    22  //ABI保存有关合同上下文的信息,并提供
    23  //可调用方法。它将允许您键入check函数调用和
    24  //相应地打包数据。
    25  type ABI struct {
    26  	Constructor Method
    27  	Methods     map[string]Method
    28  	Events      map[string]Event
    29  }
    30  
    31  //JSON返回已分析的ABI接口,如果失败则返回错误。
    32  func JSON(reader io.Reader) (ABI, error) {
    33  	dec := json.NewDecoder(reader)
    34  
    35  	var abi ABI
    36  	if err := dec.Decode(&abi); err != nil {
    37  		return ABI{}, err
    38  	}
    39  
    40  	return abi, nil
    41  }
    42  
    43  //打包给定的方法名以符合ABI。方法调用的数据
    44  //将由方法“id”、“args0”、“arg1…”组成。阿尔金方法ID由
    45  //其中4个字节和参数都是32个字节。
    46  //方法ID是从
    47  //方法字符串签名。(签名=baz(uint32,string32))
    48  func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
    49  //获取所请求方法的ABI
    50  	if name == "" {
    51  //构造函数
    52  		arguments, err := abi.Constructor.Inputs.Pack(args...)
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		return arguments, nil
    57  	}
    58  	method, exist := abi.Methods[name]
    59  	if !exist {
    60  		return nil, fmt.Errorf("method '%s' not found", name)
    61  	}
    62  	arguments, err := method.Inputs.Pack(args...)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  //如果不是构造函数,也打包方法ID并返回
    67  	return append(method.Id(), arguments...), nil
    68  }
    69  
    70  //根据ABI规范以V为单位解包输出
    71  func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) {
    72  	if len(output) == 0 {
    73  		return fmt.Errorf("abi: unmarshalling empty output")
    74  	}
    75  //既然不能命名与契约和事件的冲突,
    76  //我们需要决定是调用方法还是调用事件
    77  	if method, ok := abi.Methods[name]; ok {
    78  		if len(output)%32 != 0 {
    79  			return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(output), output)
    80  		}
    81  		return method.Outputs.Unpack(v, output)
    82  	} else if event, ok := abi.Events[name]; ok {
    83  		return event.Inputs.Unpack(v, output)
    84  	}
    85  	return fmt.Errorf("abi: could not locate named method or event")
    86  }
    87  
    88  //unmashaljson实现json.unmasheler接口
    89  func (abi *ABI) UnmarshalJSON(data []byte) error {
    90  	var fields []struct {
    91  		Type      string
    92  		Name      string
    93  		Constant  bool
    94  		Anonymous bool
    95  		Inputs    []Argument
    96  		Outputs   []Argument
    97  	}
    98  
    99  	if err := json.Unmarshal(data, &fields); err != nil {
   100  		return err
   101  	}
   102  
   103  	abi.Methods = make(map[string]Method)
   104  	abi.Events = make(map[string]Event)
   105  	for _, field := range fields {
   106  		switch field.Type {
   107  		case "constructor":
   108  			abi.Constructor = Method{
   109  				Inputs: field.Inputs,
   110  			}
   111  //空默认为根据ABI规范的功能
   112  		case "function", "":
   113  			abi.Methods[field.Name] = Method{
   114  				Name:    field.Name,
   115  				Const:   field.Constant,
   116  				Inputs:  field.Inputs,
   117  				Outputs: field.Outputs,
   118  			}
   119  		case "event":
   120  			abi.Events[field.Name] = Event{
   121  				Name:      field.Name,
   122  				Anonymous: field.Anonymous,
   123  				Inputs:    field.Inputs,
   124  			}
   125  		}
   126  	}
   127  
   128  	return nil
   129  }
   130  
   131  //method by id按4字节的ID查找方法
   132  //如果未找到,则返回nil
   133  func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
   134  	if len(sigdata) < 4 {
   135  		return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata))
   136  	}
   137  	for _, method := range abi.Methods {
   138  		if bytes.Equal(method.Id(), sigdata[:4]) {
   139  			return &method, nil
   140  		}
   141  	}
   142  	return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
   143  }
   144