accouns/abi: refactored ABI package

Refactored the abi package parsing and type handling. Relying mostly on
package reflect as opposed to most of our own type reflection. Our own
type reflection is still used however for cases such as Bytes and
FixedBytes (abi: bytes•).

This also inclused several fixes for slice handling of arbitrary and
fixed size for all supported types.

This also further removes implicit type casting such as assigning,
for example `[2]T{} = []T{1}` will fail, however `[2]T{} == []T{1, 2}`
(notice assigning *slice* to fixed size *array*). Assigning arrays to
slices will always succeed if they are of the same element type.

Incidentally also fixes #2379
This commit is contained in:
Jeffrey Wilcke
2016-04-07 11:39:22 +02:00
parent 18580e152c
commit 5127ec10cb
8 changed files with 491 additions and 314 deletions

View File

@ -18,6 +18,7 @@ package abi
import (
"fmt"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/crypto"
@ -38,6 +39,44 @@ type Method struct {
Outputs []Argument
}
func (m Method) pack(method Method, args ...interface{}) ([]byte, error) {
// Make sure arguments match up and pack them
if len(args) != len(method.Inputs) {
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs))
}
// variable input is the output appended at the end of packed
// output. This is used for strings and bytes types input.
var variableInput []byte
var ret []byte
for i, a := range args {
input := method.Inputs[i]
// pack the input
packed, err := input.Type.pack(reflect.ValueOf(a))
if err != nil {
return nil, fmt.Errorf("`%s` %v", method.Name, err)
}
// check for a slice type (string, bytes, slice)
if input.Type.T == StringTy || input.Type.T == BytesTy || input.Type.IsSlice || input.Type.IsArray {
// calculate the offset
offset := len(method.Inputs)*32 + len(variableInput)
// set the offset
ret = append(ret, packNum(reflect.ValueOf(offset), UintTy)...)
// Append the packed output to the variable input. The variable input
// will be appended at the end of the input.
variableInput = append(variableInput, packed...)
} else {
// append the packed value to the input
ret = append(ret, packed...)
}
}
// append the variable input at the end of the packed input
ret = append(ret, variableInput...)
return ret, nil
}
// Sig returns the methods string signature according to the ABI spec.
//
// Example