github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/evm/abi/spec.go (about)

     1  package abi
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"regexp"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/hyperledger/burrow/crypto"
    11  )
    12  
    13  // Token to use in deploy yaml in order to indicate call to the fallback function.
    14  const FallbackFunctionName = "()"
    15  
    16  // Spec is the ABI for contract decoded.
    17  type Spec struct {
    18  	Constructor  *FunctionSpec
    19  	Fallback     *FunctionSpec
    20  	Functions    map[string]*FunctionSpec
    21  	EventsByName map[string]*EventSpec
    22  	EventsByID   map[EventID]*EventSpec
    23  }
    24  
    25  type specJSON struct {
    26  	Name            string
    27  	Type            string
    28  	Inputs          []argumentJSON
    29  	Outputs         []argumentJSON
    30  	StateMutability string
    31  	Anonymous       bool
    32  }
    33  
    34  func NewSpec() *Spec {
    35  	return &Spec{
    36  		// Zero value for constructor and fallback function is assumed when those functions are not present
    37  		Constructor:  &FunctionSpec{},
    38  		Fallback:     &FunctionSpec{},
    39  		EventsByName: make(map[string]*EventSpec),
    40  		EventsByID:   make(map[EventID]*EventSpec),
    41  		Functions:    make(map[string]*FunctionSpec),
    42  	}
    43  }
    44  
    45  // ReadSpec takes an ABI and decodes it for futher use
    46  func ReadSpec(specBytes []byte) (*Spec, error) {
    47  	var specJ []specJSON
    48  	err := json.Unmarshal(specBytes, &specJ)
    49  	if err != nil {
    50  		// The abi spec file might a bin file, with the Abi under the Abi field in json
    51  		var binFile struct {
    52  			Abi []specJSON
    53  		}
    54  		err = json.Unmarshal(specBytes, &binFile)
    55  		if err != nil {
    56  			return nil, err
    57  		}
    58  		specJ = binFile.Abi
    59  	}
    60  
    61  	abiSpec := NewSpec()
    62  
    63  	for _, s := range specJ {
    64  		switch s.Type {
    65  		case "constructor":
    66  			abiSpec.Constructor.Inputs, err = readArgSpec(s.Inputs)
    67  			if err != nil {
    68  				return nil, err
    69  			}
    70  		case "fallback":
    71  			abiSpec.Fallback.Inputs = make([]Argument, 0)
    72  			abiSpec.Fallback.Outputs = make([]Argument, 0)
    73  			abiSpec.Fallback.SetConstant()
    74  			abiSpec.Functions[FallbackFunctionName] = abiSpec.Fallback
    75  		case "event":
    76  			ev := new(EventSpec)
    77  			err = ev.unmarshalSpec(&s)
    78  			if err != nil {
    79  				return nil, err
    80  			}
    81  			abiSpec.EventsByName[ev.Name] = ev
    82  			abiSpec.EventsByID[ev.ID] = ev
    83  		case "function":
    84  			inputs, err := readArgSpec(s.Inputs)
    85  			if err != nil {
    86  				return nil, err
    87  			}
    88  			outputs, err := readArgSpec(s.Outputs)
    89  			if err != nil {
    90  				return nil, err
    91  			}
    92  			abiSpec.Functions[s.Name] = NewFunctionSpec(s.Name, inputs, outputs).SetConstant()
    93  		}
    94  	}
    95  
    96  	return abiSpec, nil
    97  }
    98  
    99  // MergeSpec takes multiple Specs and merges them into once structure. Note that
   100  // the same function name or event name can occur in different abis, so there might be
   101  // some information loss.
   102  func MergeSpec(abiSpec []*Spec) *Spec {
   103  	newSpec := NewSpec()
   104  
   105  	for _, s := range abiSpec {
   106  		for n, f := range s.Functions {
   107  			newSpec.Functions[n] = f
   108  		}
   109  
   110  		// Different Abis can have the Event name, but with a different signature
   111  		// Loop over the signatures, as these are less likely to have collisions
   112  		for _, e := range s.EventsByID {
   113  			newSpec.EventsByName[e.Name] = e
   114  			newSpec.EventsByID[e.ID] = e
   115  		}
   116  	}
   117  
   118  	return newSpec
   119  }
   120  
   121  func (spec *Spec) GetEventAbi(id EventID, addresses crypto.Address) (*EventSpec, error) {
   122  	eventSpec, ok := spec.EventsByID[id]
   123  	if !ok {
   124  		return nil, fmt.Errorf("could not find ABI for event with ID %v", id)
   125  	}
   126  	return eventSpec, nil
   127  }
   128  
   129  // Pack ABI encodes a function call. The fname specifies which function should called, if
   130  // it doesn't exist exist the fallback function will be called. If fname is the empty
   131  // string, the constructor is called. The arguments must be specified in args. The count
   132  // must match the function being called.
   133  // Returns the ABI encoded function call, whether the function is constant according
   134  // to the ABI (which means it does not modified contract state)
   135  func (spec *Spec) Pack(fname string, args ...interface{}) ([]byte, *FunctionSpec, error) {
   136  	var funcSpec *FunctionSpec
   137  	var argSpec []Argument
   138  	if fname != "" {
   139  		if _, ok := spec.Functions[fname]; ok {
   140  			funcSpec = spec.Functions[fname]
   141  		} else {
   142  			return nil, nil, fmt.Errorf("unknown function in Pack: %s", fname)
   143  		}
   144  	} else {
   145  		if spec.Constructor.Inputs != nil {
   146  			funcSpec = spec.Constructor
   147  		} else {
   148  			return nil, nil, fmt.Errorf("contract does not have a constructor")
   149  		}
   150  	}
   151  
   152  	argSpec = funcSpec.Inputs
   153  
   154  	packed := make([]byte, 0)
   155  
   156  	if fname != "" {
   157  		packed = funcSpec.FunctionID[:]
   158  	}
   159  
   160  	packedArgs, err := Pack(argSpec, args...)
   161  	if err != nil {
   162  		return nil, nil, err
   163  	}
   164  
   165  	return append(packed, packedArgs...), funcSpec, nil
   166  }
   167  
   168  // Unpack decodes the return values from a function call
   169  func (spec *Spec) Unpack(data []byte, fname string, args ...interface{}) error {
   170  	var funcSpec *FunctionSpec
   171  	var argSpec []Argument
   172  	if fname != "" {
   173  		if _, ok := spec.Functions[fname]; ok {
   174  			funcSpec = spec.Functions[fname]
   175  		} else {
   176  			funcSpec = spec.Fallback
   177  		}
   178  	} else {
   179  		funcSpec = spec.Constructor
   180  	}
   181  
   182  	argSpec = funcSpec.Outputs
   183  
   184  	if argSpec == nil {
   185  		return fmt.Errorf("unknown function in Unpack: %s", fname)
   186  	}
   187  
   188  	return unpack(argSpec, data, func(i int) interface{} {
   189  		return args[i]
   190  	})
   191  }
   192  
   193  func (spec *Spec) UnpackWithID(data []byte, args ...interface{}) error {
   194  	var argSpec []Argument
   195  
   196  	var id FunctionID
   197  	copy(id[:], data)
   198  	for _, fspec := range spec.Functions {
   199  		if id == fspec.FunctionID {
   200  			argSpec = fspec.Outputs
   201  		}
   202  	}
   203  
   204  	if argSpec == nil {
   205  		return fmt.Errorf("unknown function in UnpackWithID: %x", id)
   206  	}
   207  
   208  	return unpack(argSpec, data[4:], func(i int) interface{} {
   209  		return args[i]
   210  	})
   211  }
   212  
   213  func readArgSpec(argsJ []argumentJSON) ([]Argument, error) {
   214  	args := make([]Argument, len(argsJ))
   215  	var err error
   216  
   217  	for i, a := range argsJ {
   218  		args[i].Name = a.Name
   219  		args[i].Indexed = a.Indexed
   220  
   221  		baseType := a.Type
   222  		isArray := regexp.MustCompile(`(.*)\[([0-9]+)\]`)
   223  		m := isArray.FindStringSubmatch(a.Type)
   224  		if m != nil {
   225  			args[i].IsArray = true
   226  			args[i].ArrayLength, err = strconv.ParseUint(m[2], 10, 32)
   227  			if err != nil {
   228  				return nil, err
   229  			}
   230  			baseType = m[1]
   231  		} else if strings.HasSuffix(a.Type, "[]") {
   232  			args[i].IsArray = true
   233  			baseType = strings.TrimSuffix(a.Type, "[]")
   234  		}
   235  
   236  		isM := regexp.MustCompile("(bytes|uint|int)([0-9]+)")
   237  		m = isM.FindStringSubmatch(baseType)
   238  		if m != nil {
   239  			M, err := strconv.ParseUint(m[2], 10, 32)
   240  			if err != nil {
   241  				return nil, err
   242  			}
   243  			switch m[1] {
   244  			case "bytes":
   245  				if M < 1 || M > 32 {
   246  					return nil, fmt.Errorf("bytes%d is not valid type", M)
   247  				}
   248  				args[i].EVM = EVMBytes{M}
   249  			case "uint":
   250  				if M < 8 || M > 256 || (M%8) != 0 {
   251  					return nil, fmt.Errorf("uint%d is not valid type", M)
   252  				}
   253  				args[i].EVM = EVMUint{M}
   254  			case "int":
   255  				if M < 8 || M > 256 || (M%8) != 0 {
   256  					return nil, fmt.Errorf("uint%d is not valid type", M)
   257  				}
   258  				args[i].EVM = EVMInt{M}
   259  			}
   260  			continue
   261  		}
   262  
   263  		isMxN := regexp.MustCompile("(fixed|ufixed)([0-9]+)x([0-9]+)")
   264  		m = isMxN.FindStringSubmatch(baseType)
   265  		if m != nil {
   266  			M, err := strconv.ParseUint(m[2], 10, 32)
   267  			if err != nil {
   268  				return nil, err
   269  			}
   270  			N, err := strconv.ParseUint(m[3], 10, 32)
   271  			if err != nil {
   272  				return nil, err
   273  			}
   274  			if M < 8 || M > 256 || (M%8) != 0 {
   275  				return nil, fmt.Errorf("%s is not valid type", baseType)
   276  			}
   277  			if N == 0 || N > 80 {
   278  				return nil, fmt.Errorf("%s is not valid type", baseType)
   279  			}
   280  			if m[1] == "fixed" {
   281  				args[i].EVM = EVMFixed{N: N, M: M, signed: true}
   282  			} else if m[1] == "ufixed" {
   283  				args[i].EVM = EVMFixed{N: N, M: M, signed: false}
   284  			} else {
   285  				panic(m[1])
   286  			}
   287  			continue
   288  		}
   289  		switch baseType {
   290  		case "uint":
   291  			args[i].EVM = EVMUint{M: 256}
   292  		case "int":
   293  			args[i].EVM = EVMInt{M: 256}
   294  		case "address":
   295  			args[i].EVM = EVMAddress{}
   296  		case "bool":
   297  			args[i].EVM = EVMBool{}
   298  		case "fixed":
   299  			args[i].EVM = EVMFixed{M: 128, N: 8, signed: true}
   300  		case "ufixed":
   301  			args[i].EVM = EVMFixed{M: 128, N: 8, signed: false}
   302  		case "bytes":
   303  			args[i].EVM = EVMBytes{M: 0}
   304  		case "string":
   305  			args[i].EVM = EVMString{}
   306  		default:
   307  			// Assume it is a type of Contract
   308  			args[i].EVM = EVMAddress{}
   309  		}
   310  	}
   311  
   312  	return args, nil
   313  }