Skip to content

Commit

Permalink
accounts, abi: method signature fix and some other fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rjl493456442 committed Jan 10, 2019
1 parent fb75910 commit e5710c3
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 311 deletions.
36 changes: 30 additions & 6 deletions accounts/abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ import (
"fmt"
"log"
"math/big"
"reflect"
"strings"
"testing"

"reflect"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
Expand Down Expand Up @@ -198,6 +197,25 @@ func TestMethodSignature(t *testing.T) {
if m.Sig() != exp {
t.Error("signature mismatch", exp, "!=", m.Sig())
}

// Method with tuple arguments
s, _ := NewType("tuple", []ArgumentMarshaling{
{Name: "a", Type: "int256"},
{Name: "b", Type: "int256[]"},
{Name: "c", Type: "tuple[]", Components: []ArgumentMarshaling{
{Name: "x", Type: "int256"},
{Name: "y", Type: "int256"},
}},
{Name: "d", Type: "tuple[2]", Components: []ArgumentMarshaling{
{Name: "x", Type: "int256"},
{Name: "y", Type: "int256"},
}},
})
m = Method{"foo", false, []Argument{{"s", s, false}, {"bar", String, false}}, nil}
exp = "foo((int256,int256[],(int256,int256)[],(int256,int256)[2]),string)"
if m.Sig() != exp {
t.Error("signature mismatch", exp, "!=", m.Sig())
}
}

func TestMultiPack(t *testing.T) {
Expand Down Expand Up @@ -567,11 +585,13 @@ func TestBareEvents(t *testing.T) {
const definition = `[
{ "type" : "event", "name" : "balance" },
{ "type" : "event", "name" : "anon", "anonymous" : true},
{ "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] }
{ "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] },
{ "type" : "event", "name" : "tuple", "inputs" : [{ "indexed":false, "name":"t", "type":"tuple", "components":[{"name":"a", "type":"uint256"}] }, { "indexed":true, "name":"arg1", "type":"address" }] }
]`

arg0, _ := NewType("uint256", nil)
arg1, _ := NewType("address", nil)
tuple, _ := NewType("tuple", []ArgumentMarshaling{{Name: "a", Type: "uint256"}})

expectedEvents := map[string]struct {
Anonymous bool
Expand All @@ -583,6 +603,10 @@ func TestBareEvents(t *testing.T) {
{Name: "arg0", Type: arg0, Indexed: false},
{Name: "arg1", Type: arg1, Indexed: true},
}},
"tuple": {false, []Argument{
{Name: "t", Type: tuple, Indexed: false},
{Name: "arg1", Type: arg1, Indexed: true},
}},
}

abi, err := JSON(strings.NewReader(definition))
Expand Down Expand Up @@ -649,9 +673,9 @@ func TestUnpackEvent(t *testing.T) {
}

type ReceivedEvent struct {
Address common.Address
Amount *big.Int
Memo []byte
Sender common.Address
Amount *big.Int
Memo []byte
}
var ev ReceivedEvent

Expand Down
54 changes: 32 additions & 22 deletions accounts/abi/argument.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ type ArgumentMarshaling struct {

// UnmarshalJSON implements json.Unmarshaler interface
func (argument *Argument) UnmarshalJSON(data []byte) error {
var dec ArgumentMarshaling
err := json.Unmarshal(data, &dec)
var arg ArgumentMarshaling
err := json.Unmarshal(data, &arg)
if err != nil {
return fmt.Errorf("argument json err: %v", err)
}

argument.Type, err = NewType(dec.Type, dec.Components)
argument.Type, err = NewType(arg.Type, arg.Components)
if err != nil {
return err
}
argument.Name = dec.Name
argument.Indexed = dec.Indexed
argument.Name = arg.Name
argument.Indexed = arg.Indexed

return nil
}
Expand Down Expand Up @@ -97,13 +97,13 @@ func (arguments Arguments) Unpack(v interface{}, data []byte) error {
return err
}
if arguments.isTuple() {
return unpackTuple(arguments, v, marshalledValues)
return arguments.unpackTuple(v, marshalledValues)
}
return unpackAtomic(arguments[0], v, marshalledValues[0])
return arguments.unpackAtomic(v, marshalledValues[0])
}

// unpack sets the unmarshalled value to go format.
// Note the dst here must is settable.
// Note the dst here must be settable.
func unpack(t *Type, dst interface{}, src interface{}) error {
var (
dstVal = reflect.ValueOf(dst).Elem()
Expand All @@ -119,13 +119,17 @@ func unpack(t *Type, dst interface{}, src interface{}) error {
if dstVal.Kind() != reflect.Struct {
return fmt.Errorf("abi: invalid dst value for unpack, want struct, got %s", dstVal.Kind())
}
fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, dstVal)
if err != nil {
return err
}
for i, elem := range t.TupleElems {
fname := t.Type.Field(i).Name
fname := fieldmap[t.TupleRawNames[i]]
field := dstVal.FieldByName(fname)
if !field.IsValid() {
return fmt.Errorf("abi: field %s can't found in the given value", fname)
return fmt.Errorf("abi: field %s can't found in the given value", t.TupleRawNames[i])
}
if err := unpack(elem, field.Addr().Interface(), srcVal.FieldByName(fname).Interface()); err != nil {
if err := unpack(elem, field.Addr().Interface(), srcVal.Field(i).Interface()); err != nil {
return err
}
}
Expand Down Expand Up @@ -156,15 +160,20 @@ func unpack(t *Type, dst interface{}, src interface{}) error {
return nil
}

func unpackAtomic(argument Argument, v interface{}, marshalledValues interface{}) error {
// unpackAtomic unpacks ( hexdata -> go ) a single value
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error {
if arguments.LengthNonIndexed() == 0 {
return nil
}
argument := arguments.NonIndexed()[0]
elem := reflect.ValueOf(v).Elem()

if elem.Kind() == reflect.Struct {
structMap, err := mapToStructFields([]string{argument.Name}, elem)
fieldmap, err := mapArgNamesToStructFields([]string{argument.Name}, elem)
if err != nil {
return err
}
field := elem.FieldByName(structMap[argument.Name])
field := elem.FieldByName(fieldmap[argument.Name])
if !field.IsValid() {
return fmt.Errorf("abi: field %s can't be found in the given value", argument.Name)
}
Expand All @@ -173,7 +182,8 @@ func unpackAtomic(argument Argument, v interface{}, marshalledValues interface{}
return unpack(&argument.Type, elem.Addr().Interface(), marshalledValues)
}

func unpackTuple(arguments Arguments, v interface{}, marshalledValues []interface{}) error {
// unpackTuple unpacks ( hexdata -> go ) a batch of values.
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
var (
value = reflect.ValueOf(v).Elem()
typ = value.Type()
Expand All @@ -184,16 +194,16 @@ func unpackTuple(arguments Arguments, v interface{}, marshalledValues []interfac
}

// If the interface is a struct, get of abi->struct_field mapping
var (
abi2struct map[string]string
err error
)
var abi2struct map[string]string
if kind == reflect.Struct {
var argNames []string
for _, arg := range arguments {
var (
argNames []string
err error
)
for _, arg := range arguments.NonIndexed() {
argNames = append(argNames, arg.Name)
}
abi2struct, err = mapToStructFields(argNames, value)
abi2struct, err = mapArgNamesToStructFields(argNames, value)
if err != nil {
return err
}
Expand Down
44 changes: 33 additions & 11 deletions accounts/abi/pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,12 +481,12 @@ func TestPack(t *testing.T) {
{Name: "f", Type: "address[]"},
},
struct {
A string
B int64
C []byte
D []string
E []*big.Int
F []common.Address
FieldA string `abi:"a"` // Test whether abi tag works
FieldB int64 `abi:"b"`
C []byte
D []string
E []*big.Int
F []common.Address
}{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}},
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset
"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
Expand Down Expand Up @@ -521,14 +521,14 @@ func TestPack(t *testing.T) {
},
struct {
A struct {
A *big.Int
B []*big.Int
FieldA *big.Int `abi:"a"`
B []*big.Int
}
B []*big.Int
}{
A: struct {
A *big.Int
B []*big.Int
FieldA *big.Int `abi:"a"` // Test whether abi tag works for nested tuple
B []*big.Int
}{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(0)}},
B: []*big.Int{big.NewInt(1), big.NewInt(0)}},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // a offset
Expand Down Expand Up @@ -589,6 +589,29 @@ func TestPack(t *testing.T) {
"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].a
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].b
},
{
// dynamic tuple array
"tuple[2]",
[]ArgumentMarshaling{
{Name: "a", Type: "int256[]"},
},
[2]struct {
A []*big.Int
}{
{[]*big.Int{big.NewInt(-1), big.NewInt(1)}},
{[]*big.Int{big.NewInt(1), big.NewInt(-1)}},
},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset
"00000000000000000000000000000000000000000000000000000000000000c0" + // tuple[1] offset
"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[0].A offset
"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].A length
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A[0]
"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].A[1]
"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[1].A offset
"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].A length
"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A[0]
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].A[1]
},
} {
typ, err := NewType(test.typ, test.components)
if err != nil {
Expand Down Expand Up @@ -716,7 +739,6 @@ func TestMethodPack(t *testing.T) {
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)

packed, err = abi.Pack("nestedSlice", [][]uint8{{1, 2}, {1, 2}})
if err != nil {
t.Fatal(err)
Expand Down
4 changes: 2 additions & 2 deletions accounts/abi/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,14 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
return nil
}

// mapToStringField maps a slice of argument names to struct fields.
// mapArgNamesToStructFields maps a slice of argument names to struct fields.
// first round: for each Exportable field that contains a `abi:""` tag
// and this field name exists in the given argument name list, pair them together.
// second round: for each argument name that has not been already linked,
// find what variable is expected to be mapped into, if it exists and has not been
// used, pair them.
// Note this function assumes the given value is a struct value.
func mapToStructFields(argNames []string, value reflect.Value) (map[string]string, error) {
func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[string]string, error) {
typ := value.Type()

abi2struct := make(map[string]string)
Expand Down
Loading

0 comments on commit e5710c3

Please sign in to comment.