github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:26</date>
    10  //</624342582222131200>
    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  	}
    59  	method, exist := abi.Methods[name]
    60  	if !exist {
    61  		return nil, fmt.Errorf("method '%s' not found", name)
    62  	}
    63  
    64  	arguments, err := method.Inputs.Pack(args...)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  //如果不是构造函数,也打包方法ID并返回
    69  	return append(method.Id(), arguments...), nil
    70  }
    71  
    72  //根据ABI规范以V为单位解包输出
    73  func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) {
    74  	if len(output) == 0 {
    75  		return fmt.Errorf("abi: unmarshalling empty output")
    76  	}
    77  //既然不能命名与契约和事件的冲突,
    78  //我们需要决定是调用方法还是调用事件
    79  	if method, ok := abi.Methods[name]; ok {
    80  		if len(output)%32 != 0 {
    81  			return fmt.Errorf("abi: improperly formatted output")
    82  		}
    83  		return method.Outputs.Unpack(v, output)
    84  	} else if event, ok := abi.Events[name]; ok {
    85  		return event.Inputs.Unpack(v, output)
    86  	}
    87  	return fmt.Errorf("abi: could not locate named method or event")
    88  }
    89  
    90  //unmashaljson实现json.unmasheler接口
    91  func (abi *ABI) UnmarshalJSON(data []byte) error {
    92  	var fields []struct {
    93  		Type      string
    94  		Name      string
    95  		Constant  bool
    96  		Anonymous bool
    97  		Inputs    []Argument
    98  		Outputs   []Argument
    99  	}
   100  
   101  	if err := json.Unmarshal(data, &fields); err != nil {
   102  		return err
   103  	}
   104  
   105  	abi.Methods = make(map[string]Method)
   106  	abi.Events = make(map[string]Event)
   107  	for _, field := range fields {
   108  		switch field.Type {
   109  		case "constructor":
   110  			abi.Constructor = Method{
   111  				Inputs: field.Inputs,
   112  			}
   113  //空默认为根据ABI规范的功能
   114  		case "function", "":
   115  			abi.Methods[field.Name] = Method{
   116  				Name:    field.Name,
   117  				Const:   field.Constant,
   118  				Inputs:  field.Inputs,
   119  				Outputs: field.Outputs,
   120  			}
   121  		case "event":
   122  			abi.Events[field.Name] = Event{
   123  				Name:      field.Name,
   124  				Anonymous: field.Anonymous,
   125  				Inputs:    field.Inputs,
   126  			}
   127  		}
   128  	}
   129  
   130  	return nil
   131  }
   132  
   133  //method by id按4字节的ID查找方法
   134  //如果未找到,则返回nil
   135  func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
   136  	for _, method := range abi.Methods {
   137  		if bytes.Equal(method.Id(), sigdata[:4]) {
   138  			return &method, nil
   139  		}
   140  	}
   141  	return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
   142  }
   143