Unverified Commit 420b7865 authored by Marius van der Wijden's avatar Marius van der Wijden Committed by GitHub

accounts/abi: ABI explicit difference between Unpack and UnpackIntoInterface (#21091)

* accounts/abi: refactored abi.Unpack

* accounts/abi/bind: fixed error

* accounts/abi/bind: modified template

* accounts/abi/bind: added ToStruct for conversion

* accounts/abi: reenabled tests

* accounts/abi: fixed tests

* accounts/abi: fixed tests for packing/unpacking

* accounts/abi: fixed tests

* accounts/abi: added more logic to ToStruct

* accounts/abi/bind: fixed template

* accounts/abi/bind: fixed ToStruct conversion

* accounts/abi/: removed unused code

* accounts/abi: updated template

* accounts/abi: refactored unused code

* contracts/checkpointoracle: updated contracts to sol ^0.6.0

* accounts/abi: refactored reflection logic

* accounts/abi: less code duplication in Unpack*

* accounts/abi: fixed rebasing bug

* fix a few typos in comments

* rebase on master
Co-authored-by: 's avatarGuillaume Ballet <gballet@gmail.com>
parent c9959145
...@@ -80,36 +80,56 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { ...@@ -80,36 +80,56 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
return append(method.ID, arguments...), nil return append(method.ID, arguments...), nil
} }
// Unpack output in v according to the abi specification. func (abi ABI) getArguments(name string, data []byte) (Arguments, error) {
func (abi ABI) Unpack(v interface{}, name string, data []byte) (err error) {
// since there can't be naming collisions with contracts and events, // since there can't be naming collisions with contracts and events,
// we need to decide whether we're calling a method or an event // we need to decide whether we're calling a method or an event
var args Arguments
if method, ok := abi.Methods[name]; ok { if method, ok := abi.Methods[name]; ok {
if len(data)%32 != 0 { if len(data)%32 != 0 {
return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data) return nil, fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data)
} }
return method.Outputs.Unpack(v, data) args = method.Outputs
} }
if event, ok := abi.Events[name]; ok { if event, ok := abi.Events[name]; ok {
return event.Inputs.Unpack(v, data) args = event.Inputs
} }
return fmt.Errorf("abi: could not locate named method or event") if args == nil {
return nil, errors.New("abi: could not locate named method or event")
}
return args, nil
}
// Unpack unpacks the output according to the abi specification.
func (abi ABI) Unpack(name string, data []byte) ([]interface{}, error) {
args, err := abi.getArguments(name, data)
if err != nil {
return nil, err
}
return args.Unpack(data)
}
// UnpackIntoInterface unpacks the output in v according to the abi specification.
// It performs an additional copy. Please only use, if you want to unpack into a
// structure that does not strictly conform to the abi structure (e.g. has additional arguments)
func (abi ABI) UnpackIntoInterface(v interface{}, name string, data []byte) error {
args, err := abi.getArguments(name, data)
if err != nil {
return err
}
unpacked, err := args.Unpack(data)
if err != nil {
return err
}
return args.Copy(v, unpacked)
} }
// UnpackIntoMap unpacks a log into the provided map[string]interface{}. // UnpackIntoMap unpacks a log into the provided map[string]interface{}.
func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) { func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) {
// since there can't be naming collisions with contracts and events, args, err := abi.getArguments(name, data)
// we need to decide whether we're calling a method or an event if err != nil {
if method, ok := abi.Methods[name]; ok { return err
if len(data)%32 != 0 {
return fmt.Errorf("abi: improperly formatted output")
}
return method.Outputs.UnpackIntoMap(v, data)
}
if event, ok := abi.Events[name]; ok {
return event.Inputs.UnpackIntoMap(v, data)
} }
return fmt.Errorf("abi: could not locate named method or event") return args.UnpackIntoMap(v, data)
} }
// UnmarshalJSON implements json.Unmarshaler interface. // UnmarshalJSON implements json.Unmarshaler interface.
...@@ -250,10 +270,10 @@ func UnpackRevert(data []byte) (string, error) { ...@@ -250,10 +270,10 @@ func UnpackRevert(data []byte) (string, error) {
if !bytes.Equal(data[:4], revertSelector) { if !bytes.Equal(data[:4], revertSelector) {
return "", errors.New("invalid data for unpacking") return "", errors.New("invalid data for unpacking")
} }
var reason string
typ, _ := NewType("string", "", nil) typ, _ := NewType("string", "", nil)
if err := (Arguments{{Type: typ}}).Unpack(&reason, data[4:]); err != nil { unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
if err != nil {
return "", err return "", err
} }
return reason, nil return unpacked[0].(string), nil
} }
...@@ -181,18 +181,15 @@ func TestConstructor(t *testing.T) { ...@@ -181,18 +181,15 @@ func TestConstructor(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
v := struct { unpacked, err := abi.Constructor.Inputs.Unpack(packed)
A *big.Int if err != nil {
B *big.Int
}{new(big.Int), new(big.Int)}
//abi.Unpack(&v, "", packed)
if err := abi.Constructor.Inputs.Unpack(&v, packed); err != nil {
t.Error(err) t.Error(err)
} }
if !reflect.DeepEqual(v.A, big.NewInt(1)) {
if !reflect.DeepEqual(unpacked[0], big.NewInt(1)) {
t.Error("Unable to pack/unpack from constructor") t.Error("Unable to pack/unpack from constructor")
} }
if !reflect.DeepEqual(v.B, big.NewInt(2)) { if !reflect.DeepEqual(unpacked[1], big.NewInt(2)) {
t.Error("Unable to pack/unpack from constructor") t.Error("Unable to pack/unpack from constructor")
} }
} }
...@@ -743,7 +740,7 @@ func TestUnpackEvent(t *testing.T) { ...@@ -743,7 +740,7 @@ func TestUnpackEvent(t *testing.T) {
} }
var ev ReceivedEvent var ev ReceivedEvent
err = abi.Unpack(&ev, "received", data) err = abi.UnpackIntoInterface(&ev, "received", data)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -752,7 +749,7 @@ func TestUnpackEvent(t *testing.T) { ...@@ -752,7 +749,7 @@ func TestUnpackEvent(t *testing.T) {
Sender common.Address Sender common.Address
} }
var receivedAddrEv ReceivedAddrEvent var receivedAddrEv ReceivedAddrEvent
err = abi.Unpack(&receivedAddrEv, "receivedAddr", data) err = abi.UnpackIntoInterface(&receivedAddrEv, "receivedAddr", data)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
......
...@@ -76,28 +76,20 @@ func (arguments Arguments) isTuple() bool { ...@@ -76,28 +76,20 @@ func (arguments Arguments) isTuple() bool {
} }
// Unpack performs the operation hexdata -> Go format. // Unpack performs the operation hexdata -> Go format.
func (arguments Arguments) Unpack(v interface{}, data []byte) error { func (arguments Arguments) Unpack(data []byte) ([]interface{}, error) {
if len(data) == 0 { if len(data) == 0 {
if len(arguments) != 0 { if len(arguments) != 0 {
return fmt.Errorf("abi: attempting to unmarshall an empty string while arguments are expected") return nil, fmt.Errorf("abi: attempting to unmarshall an empty string while arguments are expected")
} }
return nil // Nothing to unmarshal, return // Nothing to unmarshal, return default variables
} nonIndexedArgs := arguments.NonIndexed()
// make sure the passed value is arguments pointer defaultVars := make([]interface{}, len(nonIndexedArgs))
if reflect.Ptr != reflect.ValueOf(v).Kind() { for index, arg := range nonIndexedArgs {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v) defaultVars[index] = reflect.New(arg.Type.GetType())
} }
marshalledValues, err := arguments.UnpackValues(data) return defaultVars, nil
if err != nil {
return err
}
if len(marshalledValues) == 0 {
return fmt.Errorf("abi: Unpack(no-values unmarshalled %T)", v)
}
if arguments.isTuple() {
return arguments.unpackTuple(v, marshalledValues)
} }
return arguments.unpackAtomic(v, marshalledValues[0]) return arguments.UnpackValues(data)
} }
// UnpackIntoMap performs the operation hexdata -> mapping of argument name to argument value. // UnpackIntoMap performs the operation hexdata -> mapping of argument name to argument value.
...@@ -122,8 +114,26 @@ func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) ...@@ -122,8 +114,26 @@ func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte)
return nil return nil
} }
// unpackAtomic unpacks ( hexdata -> go ) a single value. // Copy performs the operation go format -> provided struct.
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error { func (arguments Arguments) Copy(v interface{}, values []interface{}) error {
// make sure the passed value is arguments pointer
if reflect.Ptr != reflect.ValueOf(v).Kind() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
}
if len(values) == 0 {
if len(arguments) != 0 {
return fmt.Errorf("abi: attempting to copy no values while %d arguments are expected", len(arguments))
}
return nil // Nothing to copy, return
}
if arguments.isTuple() {
return arguments.copyTuple(v, values)
}
return arguments.copyAtomic(v, values[0])
}
// unpackAtomic unpacks ( hexdata -> go ) a single value
func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{}) error {
dst := reflect.ValueOf(v).Elem() dst := reflect.ValueOf(v).Elem()
src := reflect.ValueOf(marshalledValues) src := reflect.ValueOf(marshalledValues)
...@@ -133,8 +143,8 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interfac ...@@ -133,8 +143,8 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interfac
return set(dst, src) return set(dst, src)
} }
// unpackTuple unpacks ( hexdata -> go ) a batch of values. // copyTuple copies a batch of values from marshalledValues to v.
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { func (arguments Arguments) copyTuple(v interface{}, marshalledValues []interface{}) error {
value := reflect.ValueOf(v).Elem() value := reflect.ValueOf(v).Elem()
nonIndexedArgs := arguments.NonIndexed() nonIndexedArgs := arguments.NonIndexed()
......
...@@ -117,11 +117,14 @@ func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend Co ...@@ -117,11 +117,14 @@ func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend Co
// sets the output to result. The result type might be a single field for simple // sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named // returns, a slice of interfaces for anonymous returns and a struct for named
// returns. // returns.
func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, params ...interface{}) error { func (c *BoundContract) Call(opts *CallOpts, results *[]interface{}, method string, params ...interface{}) error {
// Don't crash on a lazy user // Don't crash on a lazy user
if opts == nil { if opts == nil {
opts = new(CallOpts) opts = new(CallOpts)
} }
if results == nil {
results = new([]interface{})
}
// Pack the input, call and unpack the results // Pack the input, call and unpack the results
input, err := c.abi.Pack(method, params...) input, err := c.abi.Pack(method, params...)
if err != nil { if err != nil {
...@@ -158,10 +161,14 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, ...@@ -158,10 +161,14 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
} }
} }
} }
if err != nil {
if len(*results) == 0 {
res, err := c.abi.Unpack(method, output)
*results = res
return err return err
} }
return c.abi.Unpack(result, method, output) res := *results
return c.abi.UnpackIntoInterface(res[0], method, output)
} }
// Transact invokes the (paid) contract method with params as input values. // Transact invokes the (paid) contract method with params as input values.
...@@ -339,7 +346,7 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter ...@@ -339,7 +346,7 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter
// UnpackLog unpacks a retrieved log into the provided output structure. // UnpackLog unpacks a retrieved log into the provided output structure.
func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error {
if len(log.Data) > 0 { if len(log.Data) > 0 {
if err := c.abi.Unpack(out, event, log.Data); err != nil { if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil {
return err return err
} }
} }
......
...@@ -71,11 +71,10 @@ func TestPassingBlockNumber(t *testing.T) { ...@@ -71,11 +71,10 @@ func TestPassingBlockNumber(t *testing.T) {
}, },
}, },
}, mc, nil, nil) }, mc, nil, nil)
var ret string
blockNumber := big.NewInt(42) blockNumber := big.NewInt(42)
bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something") bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, nil, "something")
if mc.callContractBlockNumber != blockNumber { if mc.callContractBlockNumber != blockNumber {
t.Fatalf("CallContract() was not passed the block number") t.Fatalf("CallContract() was not passed the block number")
...@@ -85,7 +84,7 @@ func TestPassingBlockNumber(t *testing.T) { ...@@ -85,7 +84,7 @@ func TestPassingBlockNumber(t *testing.T) {
t.Fatalf("CodeAt() was not passed the block number") t.Fatalf("CodeAt() was not passed the block number")
} }
bc.Call(&bind.CallOpts{}, &ret, "something") bc.Call(&bind.CallOpts{}, nil, "something")
if mc.callContractBlockNumber != nil { if mc.callContractBlockNumber != nil {
t.Fatalf("CallContract() was passed a block number when it should not have been") t.Fatalf("CallContract() was passed a block number when it should not have been")
...@@ -95,7 +94,7 @@ func TestPassingBlockNumber(t *testing.T) { ...@@ -95,7 +94,7 @@ func TestPassingBlockNumber(t *testing.T) {
t.Fatalf("CodeAt() was passed a block number when it should not have been") t.Fatalf("CodeAt() was passed a block number when it should not have been")
} }
bc.Call(&bind.CallOpts{BlockNumber: blockNumber, Pending: true}, &ret, "something") bc.Call(&bind.CallOpts{BlockNumber: blockNumber, Pending: true}, nil, "something")
if !mc.pendingCallContractCalled { if !mc.pendingCallContractCalled {
t.Fatalf("CallContract() was not passed the block number") t.Fatalf("CallContract() was not passed the block number")
......
...@@ -1696,11 +1696,11 @@ func TestGolangBindings(t *testing.T) { ...@@ -1696,11 +1696,11 @@ func TestGolangBindings(t *testing.T) {
t.Skip("go sdk not found for testing") t.Skip("go sdk not found for testing")
} }
// Create a temporary workspace for the test suite // Create a temporary workspace for the test suite
ws, err := ioutil.TempDir("", "") ws, err := ioutil.TempDir("", "binding-test")
if err != nil { if err != nil {
t.Fatalf("failed to create temporary workspace: %v", err) t.Fatalf("failed to create temporary workspace: %v", err)
} }
defer os.RemoveAll(ws) //defer os.RemoveAll(ws)
pkg := filepath.Join(ws, "bindtest") pkg := filepath.Join(ws, "bindtest")
if err = os.MkdirAll(pkg, 0700); err != nil { if err = os.MkdirAll(pkg, 0700); err != nil {
......
...@@ -261,7 +261,7 @@ var ( ...@@ -261,7 +261,7 @@ var (
// sets the output to result. The result type might be a single field for simple // sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named // returns, a slice of interfaces for anonymous returns and a struct for named
// returns. // returns.
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...) return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...)
} }
...@@ -280,7 +280,7 @@ var ( ...@@ -280,7 +280,7 @@ var (
// sets the output to result. The result type might be a single field for simple // sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named // returns, a slice of interfaces for anonymous returns and a struct for named
// returns. // returns.
func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...) return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...)
} }
...@@ -300,19 +300,23 @@ var ( ...@@ -300,19 +300,23 @@ var (
// //
// Solidity: {{.Original.String}} // Solidity: {{.Original.String}}
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) { func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
{{if .Structured}}ret := new(struct{ var out []interface{}
{{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}} err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
{{end}} {{if .Structured}}
}){{else}}var ( outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} })
{{range $i, $_ := .Normalized.Outputs}}ret{{$i}} = new({{bindtype .Type $structs}}) {{range $i, $t := .Normalized.Outputs}}
{{end}} outstruct.{{.Name}} = out[{{$i}}].({{bindtype .Type $structs}}){{end}}
){{end}}
out := {{if .Structured}}ret{{else}}{{if eq (len .Normalized.Outputs) 1}}ret0{{else}}&[]interface{}{ return *outstruct, err
{{range $i, $_ := .Normalized.Outputs}}ret{{$i}}, {{else}}
{{end}} if err != nil {
}{{end}}{{end}} return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err
err := _{{$contract.Type}}.contract.Call(opts, out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) }
return {{if .Structured}}*ret,{{else}}{{range $i, $_ := .Normalized.Outputs}}*ret{{$i}},{{end}}{{end}} err {{range $i, $t := .Normalized.Outputs}}
out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err
{{end}}
} }
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
......
...@@ -147,10 +147,6 @@ func TestEventString(t *testing.T) { ...@@ -147,10 +147,6 @@ func TestEventString(t *testing.T) {
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array. // TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
func TestEventMultiValueWithArrayUnpack(t *testing.T) { func TestEventMultiValueWithArrayUnpack(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
type testStruct struct {
Value1 [2]uint8
Value2 uint8
}
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
require.NoError(t, err) require.NoError(t, err)
var b bytes.Buffer var b bytes.Buffer
...@@ -158,10 +154,10 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) { ...@@ -158,10 +154,10 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) {
for ; i <= 3; i++ { for ; i <= 3; i++ {
b.Write(packNum(reflect.ValueOf(i))) b.Write(packNum(reflect.ValueOf(i)))
} }
var rst testStruct unpacked, err := abi.Unpack("test", b.Bytes())
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) require.NoError(t, err)
require.Equal(t, [2]uint8{1, 2}, rst.Value1) require.Equal(t, [2]uint8{1, 2}, unpacked[0])
require.Equal(t, uint8(3), rst.Value2) require.Equal(t, uint8(3), unpacked[1])
} }
func TestEventTupleUnpack(t *testing.T) { func TestEventTupleUnpack(t *testing.T) {
...@@ -351,14 +347,14 @@ func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, ass ...@@ -351,14 +347,14 @@ func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, ass
var e Event var e Event
assert.NoError(json.Unmarshal(jsonEvent, &e), "Should be able to unmarshal event ABI") assert.NoError(json.Unmarshal(jsonEvent, &e), "Should be able to unmarshal event ABI")
a := ABI{Events: map[string]Event{"e": e}} a := ABI{Events: map[string]Event{"e": e}}
return a.Unpack(dest, "e", data) return a.UnpackIntoInterface(dest, "e", data)
} }
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder. // TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
func TestEventUnpackIndexed(t *testing.T) { func TestEventUnpackIndexed(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
type testStruct struct { type testStruct struct {
Value1 uint8 Value1 uint8 // indexed
Value2 uint8 Value2 uint8
} }
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
...@@ -366,7 +362,7 @@ func TestEventUnpackIndexed(t *testing.T) { ...@@ -366,7 +362,7 @@ func TestEventUnpackIndexed(t *testing.T) {
var b bytes.Buffer var b bytes.Buffer
b.Write(packNum(reflect.ValueOf(uint8(8)))) b.Write(packNum(reflect.ValueOf(uint8(8))))
var rst testStruct var rst testStruct
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) require.NoError(t, abi.UnpackIntoInterface(&rst, "test", b.Bytes()))
require.Equal(t, uint8(0), rst.Value1) require.Equal(t, uint8(0), rst.Value1)
require.Equal(t, uint8(8), rst.Value2) require.Equal(t, uint8(8), rst.Value2)
} }
...@@ -375,7 +371,7 @@ func TestEventUnpackIndexed(t *testing.T) { ...@@ -375,7 +371,7 @@ func TestEventUnpackIndexed(t *testing.T) {
func TestEventIndexedWithArrayUnpack(t *testing.T) { func TestEventIndexedWithArrayUnpack(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]` definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
type testStruct struct { type testStruct struct {
Value1 [2]uint8 Value1 [2]uint8 // indexed
Value2 string Value2 string
} }
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
...@@ -388,7 +384,7 @@ func TestEventIndexedWithArrayUnpack(t *testing.T) { ...@@ -388,7 +384,7 @@ func TestEventIndexedWithArrayUnpack(t *testing.T) {
b.Write(common.RightPadBytes([]byte(stringOut), 32)) b.Write(common.RightPadBytes([]byte(stringOut), 32))
var rst testStruct var rst testStruct
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) require.NoError(t, abi.UnpackIntoInterface(&rst, "test", b.Bytes()))
require.Equal(t, [2]uint8{0, 0}, rst.Value1) require.Equal(t, [2]uint8{0, 0}, rst.Value1)
require.Equal(t, stringOut, rst.Value2) require.Equal(t, stringOut, rst.Value2)
} }
...@@ -44,18 +44,7 @@ func TestPack(t *testing.T) { ...@@ -44,18 +44,7 @@ func TestPack(t *testing.T) {
t.Fatalf("invalid ABI definition %s, %v", inDef, err) t.Fatalf("invalid ABI definition %s, %v", inDef, err)
} }
var packed []byte var packed []byte
if reflect.TypeOf(test.unpacked).Kind() != reflect.Struct { packed, err = inAbi.Pack("method", test.unpacked)
packed, err = inAbi.Pack("method", test.unpacked)
} else {
// if want is a struct we need to use the components.
elem := reflect.ValueOf(test.unpacked)
var values []interface{}
for i := 0; i < elem.NumField(); i++ {
field := elem.Field(i)
values = append(values, field.Interface())
}
packed, err = inAbi.Pack("method", values...)
}
if err != nil { if err != nil {
t.Fatalf("test %d (%v) failed: %v", i, test.def, err) t.Fatalf("test %d (%v) failed: %v", i, test.def, err)
......
...@@ -620,7 +620,7 @@ var packUnpackTests = []packUnpackTest{ ...@@ -620,7 +620,7 @@ var packUnpackTests = []packUnpackTest{
{ {
def: `[{"type": "bytes32[]"}]`, def: `[{"type": "bytes32[]"}]`,
unpacked: []common.Hash{{1}, {2}}, unpacked: [][32]byte{{1}, {2}},
packed: "0000000000000000000000000000000000000000000000000000000000000020" + packed: "0000000000000000000000000000000000000000000000000000000000000020" +
"0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000002" +
"0100000000000000000000000000000000000000000000000000000000000000" + "0100000000000000000000000000000000000000000000000000000000000000" +
...@@ -722,7 +722,7 @@ var packUnpackTests = []packUnpackTest{ ...@@ -722,7 +722,7 @@ var packUnpackTests = []packUnpackTest{
}, },
// struct outputs // struct outputs
{ {
def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`, def: `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`,
packed: "0000000000000000000000000000000000000000000000000000000000000001" + packed: "0000000000000000000000000000000000000000000000000000000000000001" +
"0000000000000000000000000000000000000000000000000000000000000002", "0000000000000000000000000000000000000000000000000000000000000002",
unpacked: struct { unpacked: struct {
...@@ -731,28 +731,28 @@ var packUnpackTests = []packUnpackTest{ ...@@ -731,28 +731,28 @@ var packUnpackTests = []packUnpackTest{
}{big.NewInt(1), big.NewInt(2)}, }{big.NewInt(1), big.NewInt(2)},
}, },
{ {
def: `[{"name":"int_one","type":"int256"}]`, def: `[{"components": [{"name":"int_one","type":"int256"}], "type":"tuple"}]`,
packed: "0000000000000000000000000000000000000000000000000000000000000001", packed: "0000000000000000000000000000000000000000000000000000000000000001",
unpacked: struct { unpacked: struct {
IntOne *big.Int IntOne *big.Int
}{big.NewInt(1)}, }{big.NewInt(1)},
}, },
{ {
def: `[{"name":"int__one","type":"int256"}]`, def: `[{"components": [{"name":"int__one","type":"int256"}], "type":"tuple"}]`,
packed: "0000000000000000000000000000000000000000000000000000000000000001", packed: "0000000000000000000000000000000000000000000000000000000000000001",
unpacked: struct { unpacked: struct {
IntOne *big.Int IntOne *big.Int
}{big.NewInt(1)}, }{big.NewInt(1)},
}, },
{ {
def: `[{"name":"int_one_","type":"int256"}]`, def: `[{"components": [{"name":"int_one_","type":"int256"}], "type":"tuple"}]`,
packed: "0000000000000000000000000000000000000000000000000000000000000001", packed: "0000000000000000000000000000000000000000000000000000000000000001",
unpacked: struct { unpacked: struct {
IntOne *big.Int IntOne *big.Int
}{big.NewInt(1)}, }{big.NewInt(1)},
}, },
{ {
def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`, def: `[{"components": [{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}], "type":"tuple"}]`,
packed: "0000000000000000000000000000000000000000000000000000000000000001" + packed: "0000000000000000000000000000000000000000000000000000000000000001" +
"0000000000000000000000000000000000000000000000000000000000000002", "0000000000000000000000000000000000000000000000000000000000000002",
unpacked: struct { unpacked: struct {
...@@ -831,11 +831,11 @@ var packUnpackTests = []packUnpackTest{ ...@@ -831,11 +831,11 @@ var packUnpackTests = []packUnpackTest{
}, },
{ {
// static tuple // static tuple
def: `[{"name":"a","type":"int64"}, def: `[{"components": [{"name":"a","type":"int64"},
{"name":"b","type":"int256"}, {"name":"b","type":"int256"},
{"name":"c","type":"int256"}, {"name":"c","type":"int256"},
{"name":"d","type":"bool"}, {"name":"d","type":"bool"},
{"name":"e","type":"bytes32[3][2]"}]`, {"name":"e","type":"bytes32[3][2]"}], "type":"tuple"}]`,
unpacked: struct { unpacked: struct {
A int64 A int64
B *big.Int B *big.Int
...@@ -855,21 +855,22 @@ var packUnpackTests = []packUnpackTest{ ...@@ -855,21 +855,22 @@ var packUnpackTests = []packUnpackTest{
"0500000000000000000000000000000000000000000000000000000000000000", // struct[e] array[1][2] "0500000000000000000000000000000000000000000000000000000000000000", // struct[e] array[1][2]
}, },
{ {
def: `[{"name":"a","type":"string"}, def: `[{"components": [{"name":"a","type":"string"},
{"name":"b","type":"int64"}, {"name":"b","type":"int64"},
{"name":"c","type":"bytes"}, {"name":"c","type":"bytes"},
{"name":"d","type":"string[]"}, {"name":"d","type":"string[]"},
{"name":"e","type":"int256[]"}, {"name":"e","type":"int256[]"},
{"name":"f","type":"address[]"}]`, {"name":"f","type":"address[]"}], "type":"tuple"}]`,
unpacked: struct { unpacked: struct {
FieldA string `abi:"a"` // Test whether abi tag works A string
FieldB int64 `abi:"b"` B int64
C []byte C []byte
D []string D []string
E []*big.Int E []*big.Int
F []common.Address F []common.Address
}{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}}, }{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}},
packed: "00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset packed: "0000000000000000000000000000000000000000000000000000000000000020" + // struct a
"00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset
"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b] "0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
"0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset "0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset
"0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset "0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset
...@@ -894,23 +895,24 @@ var packUnpackTests = []packUnpackTest{ ...@@ -894,23 +895,24 @@ var packUnpackTests = []packUnpackTest{
"0000000000000000000000000200000000000000000000000000000000000000", // common.Address{2} "0000000000000000000000000200000000000000000000000000000000000000", // common.Address{2}
}, },
{ {
def: `[{"components": [{"name": "a","type": "uint256"}, def: `[{"components": [{ "type": "tuple","components": [{"name": "a","type": "uint256"},
{"name": "b","type": "uint256[]"}], {"name": "b","type": "uint256[]"}],
"name": "a","type": "tuple"}, "name": "a","type": "tuple"},
{"name": "b","type": "uint256[]"}]`, {"name": "b","type": "uint256[]"}], "type": "tuple"}]`,
unpacked: struct { unpacked: struct {
A struct { A struct {
FieldA *big.Int `abi:"a"` A *big.Int
B []*big.Int B []*big.Int
} }
B []*big.Int B []*big.Int
}{ }{
A: struct { A: struct {
FieldA *big.Int `abi:"a"` // Test whether abi tag works for nested tuple A *big.Int
B []*big.Int B []*big.Int
}{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(2)}}, }{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(2)}},
B: []*big.Int{big.NewInt(1), big.NewInt(2)}}, B: []*big.Int{big.NewInt(1), big.NewInt(2)}},
packed: "0000000000000000000000000000000000000000000000000000000000000040" + // a offset packed: "0000000000000000000000000000000000000000000000000000000000000020" + // struct a
"0000000000000000000000000000000000000000000000000000000000000040" + // a offset
"00000000000000000000000000000000000000000000000000000000000000e0" + // b offset "00000000000000000000000000000000000000000000000000000000000000e0" + // b offset
"0000000000000000000000000000000000000000000000000000000000000001" + // a.a value "0000000000000000000000000000000000000000000000000000000000000001" + // a.a value
"0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset "0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset
......
...@@ -24,6 +24,29 @@ import ( ...@@ -24,6 +24,29 @@ import (
"strings" "strings"
) )
// ConvertType converts an interface of a runtime type into a interface of the
// given type
// e.g. turn
// var fields []reflect.StructField
// fields = append(fields, reflect.StructField{
// Name: "X",
// Type: reflect.TypeOf(new(big.Int)),
// Tag: reflect.StructTag("json:\"" + "x" + "\""),
// }
// into
// type TupleT struct { X *big.Int }
func ConvertType(in interface{}, proto interface{}) interface{} {
protoType := reflect.TypeOf(proto)
if reflect.TypeOf(in).ConvertibleTo(protoType) {
return reflect.ValueOf(in).Convert(protoType).Interface()
}
// Use set as a last ditch effort
if err := set(reflect.ValueOf(proto), reflect.ValueOf(in)); err != nil {
panic(err)
}
return proto
}
// indirect recursively dereferences the value until it either gets the value // indirect recursively dereferences the value until it either gets the value
// or finds a big.Int // or finds a big.Int
func indirect(v reflect.Value) reflect.Value { func indirect(v reflect.Value) reflect.Value {
...@@ -119,6 +142,9 @@ func setSlice(dst, src reflect.Value) error { ...@@ -119,6 +142,9 @@ func setSlice(dst, src reflect.Value) error {
} }
func setArray(dst, src reflect.Value) error { func setArray(dst, src reflect.Value) error {
if src.Kind() == reflect.Ptr {
return set(dst, indirect(src))
}
array := reflect.New(dst.Type()).Elem() array := reflect.New(dst.Type()).Elem()
min := src.Len() min := src.Len()
if src.Len() > dst.Len() { if src.Len() > dst.Len() {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package abi package abi
import ( import (
"math/big"
"reflect" "reflect"
"testing" "testing"
) )
...@@ -189,3 +190,72 @@ func TestReflectNameToStruct(t *testing.T) { ...@@ -189,3 +190,72 @@ func TestReflectNameToStruct(t *testing.T) {
}) })
} }
} }
func TestConvertType(t *testing.T) {
// Test Basic Struct
type T struct {
X *big.Int
Y *big.Int
}
// Create on-the-fly structure
var fields []reflect.StructField
fields = append(fields, reflect.StructField{
Name: "X",
Type: reflect.TypeOf(new(big.Int)),
Tag: reflect.StructTag("json:\"" + "x" + "\""),
})
fields = append(fields, reflect.StructField{
Name: "Y",
Type: reflect.TypeOf(new(big.Int)),
Tag: reflect.StructTag("json:\"" + "y" + "\""),
})
val := reflect.New(reflect.StructOf(fields))
val.Elem().Field(0).Set(reflect.ValueOf(big.NewInt(1)))
val.Elem().Field(1).Set(reflect.ValueOf(big.NewInt(2)))
// ConvertType
out := *ConvertType(val.Interface(), new(T)).(*T)
if out.X.Cmp(big.NewInt(1)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out.X, big.NewInt(1))
}
if out.Y.Cmp(big.NewInt(2)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out.Y, big.NewInt(2))
}
// Slice Type
val2 := reflect.MakeSlice(reflect.SliceOf(reflect.StructOf(fields)), 2, 2)
val2.Index(0).Field(0).Set(reflect.ValueOf(big.NewInt(1)))
val2.Index(0).Field(1).Set(reflect.ValueOf(big.NewInt(2)))
val2.Index(1).Field(0).Set(reflect.ValueOf(big.NewInt(3)))
val2.Index(1).Field(1).Set(reflect.ValueOf(big.NewInt(4)))
out2 := *ConvertType(val2.Interface(), new([]T)).(*[]T)
if out2[0].X.Cmp(big.NewInt(1)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out2[0].X, big.NewInt(1))
}
if out2[0].Y.Cmp(big.NewInt(2)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out2[1].Y, big.NewInt(2))
}
if out2[1].X.Cmp(big.NewInt(3)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out2[0].X, big.NewInt(1))
}
if out2[1].Y.Cmp(big.NewInt(4)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out2[1].Y, big.NewInt(2))
}
// Array Type
val3 := reflect.New(reflect.ArrayOf(2, reflect.StructOf(fields)))
val3.Elem().Index(0).Field(0).Set(reflect.ValueOf(big.NewInt(1)))
val3.Elem().Index(0).Field(1).Set(reflect.ValueOf(big.NewInt(2)))
val3.Elem().Index(1).Field(0).Set(reflect.ValueOf(big.NewInt(3)))
val3.Elem().Index(1).Field(1).Set(reflect.ValueOf(big.NewInt(4)))
out3 := *ConvertType(val3.Interface(), new([2]T)).(*[2]T)
if out3[0].X.Cmp(big.NewInt(1)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out3[0].X, big.NewInt(1))
}
if out3[0].Y.Cmp(big.NewInt(2)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out3[1].Y, big.NewInt(2))
}
if out3[1].X.Cmp(big.NewInt(3)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out3[0].X, big.NewInt(1))
}
if out3[1].Y.Cmp(big.NewInt(4)) != 0 {
t.Errorf("ConvertType failed, got %v want %v", out3[1].Y, big.NewInt(2))
}
}
...@@ -44,15 +44,13 @@ func TestUnpack(t *testing.T) { ...@@ -44,15 +44,13 @@ func TestUnpack(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("invalid hex %s: %v", test.packed, err) t.Fatalf("invalid hex %s: %v", test.packed, err)
} }
outptr := reflect.New(reflect.TypeOf(test.unpacked)) out, err := abi.Unpack("method", encb)
err = abi.Unpack(outptr.Interface(), "method", encb)
if err != nil { if err != nil {
t.Errorf("test %d (%v) failed: %v", i, test.def, err) t.Errorf("test %d (%v) failed: %v", i, test.def, err)
return return
} }
out := outptr.Elem().Interface() if !reflect.DeepEqual(test.unpacked, ConvertType(out[0], test.unpacked)) {
if !reflect.DeepEqual(test.unpacked, out) { t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.unpacked, out[0])
t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.unpacked, out)
} }
}) })
} }
...@@ -221,7 +219,7 @@ func TestLocalUnpackTests(t *testing.T) { ...@@ -221,7 +219,7 @@ func TestLocalUnpackTests(t *testing.T) {
t.Fatalf("invalid hex %s: %v", test.enc, err) t.Fatalf("invalid hex %s: %v", test.enc, err)
} }
outptr := reflect.New(reflect.TypeOf(test.want)) outptr := reflect.New(reflect.TypeOf(test.want))
err = abi.Unpack(outptr.Interface(), "method", encb) err = abi.UnpackIntoInterface(outptr.Interface(), "method", encb)
if err := test.checkError(err); err != nil { if err := test.checkError(err); err != nil {
t.Errorf("test %d (%v) failed: %v", i, test.def, err) t.Errorf("test %d (%v) failed: %v", i, test.def, err)
return return
...@@ -234,7 +232,7 @@ func TestLocalUnpackTests(t *testing.T) { ...@@ -234,7 +232,7 @@ func TestLocalUnpackTests(t *testing.T) {
} }
} }
func TestUnpackSetDynamicArrayOutput(t *testing.T) { func TestUnpackIntoInterfaceSetDynamicArrayOutput(t *testing.T) {
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`)) abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -249,7 +247,7 @@ func TestUnpackSetDynamicArrayOutput(t *testing.T) { ...@@ -249,7 +247,7 @@ func TestUnpackSetDynamicArrayOutput(t *testing.T) {
) )
// test 32 // test 32
err = abi.Unpack(&out32, "testDynamicFixedBytes32", marshalledReturn32) err = abi.UnpackIntoInterface(&out32, "testDynamicFixedBytes32", marshalledReturn32)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -266,7 +264,7 @@ func TestUnpackSetDynamicArrayOutput(t *testing.T) { ...@@ -266,7 +264,7 @@ func TestUnpackSetDynamicArrayOutput(t *testing.T) {
} }
// test 15 // test 15
err = abi.Unpack(&out15, "testDynamicFixedBytes32", marshalledReturn15) err = abi.UnpackIntoInterface(&out15, "testDynamicFixedBytes32", marshalledReturn15)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -367,7 +365,7 @@ func TestMethodMultiReturn(t *testing.T) { ...@@ -367,7 +365,7 @@ func TestMethodMultiReturn(t *testing.T) {
tc := tc tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
require := require.New(t) require := require.New(t)
err := abi.Unpack(tc.dest, "multi", data) err := abi.UnpackIntoInterface(tc.dest, "multi", data)
if tc.error == "" { if tc.error == "" {
require.Nil(err, "Should be able to unpack method outputs.") require.Nil(err, "Should be able to unpack method outputs.")
require.Equal(tc.expected, tc.dest) require.Equal(tc.expected, tc.dest)
...@@ -390,7 +388,7 @@ func TestMultiReturnWithArray(t *testing.T) { ...@@ -390,7 +388,7 @@ func TestMultiReturnWithArray(t *testing.T) {
ret1, ret1Exp := new([3]uint64), [3]uint64{9, 9, 9} ret1, ret1Exp := new([3]uint64), [3]uint64{9, 9, 9}
ret2, ret2Exp := new(uint64), uint64(8) ret2, ret2Exp := new(uint64), uint64(8)
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil { if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !reflect.DeepEqual(*ret1, ret1Exp) { if !reflect.DeepEqual(*ret1, ret1Exp) {
...@@ -414,7 +412,7 @@ func TestMultiReturnWithStringArray(t *testing.T) { ...@@ -414,7 +412,7 @@ func TestMultiReturnWithStringArray(t *testing.T) {
ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f") ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f")
ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"} ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"}
ret4, ret4Exp := new(bool), false ret4, ret4Exp := new(bool), false
if err := abi.Unpack(&[]interface{}{ret1, ret2, ret3, ret4}, "multi", buff.Bytes()); err != nil { if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2, ret3, ret4}, "multi", buff.Bytes()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !reflect.DeepEqual(*ret1, ret1Exp) { if !reflect.DeepEqual(*ret1, ret1Exp) {
...@@ -452,7 +450,7 @@ func TestMultiReturnWithStringSlice(t *testing.T) { ...@@ -452,7 +450,7 @@ func TestMultiReturnWithStringSlice(t *testing.T) {
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000065")) // output[1][1] value buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000065")) // output[1][1] value
ret1, ret1Exp := new([]string), []string{"ethereum", "go-ethereum"} ret1, ret1Exp := new([]string), []string{"ethereum", "go-ethereum"}
ret2, ret2Exp := new([]*big.Int), []*big.Int{big.NewInt(100), big.NewInt(101)} ret2, ret2Exp := new([]*big.Int), []*big.Int{big.NewInt(100), big.NewInt(101)}
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil { if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !reflect.DeepEqual(*ret1, ret1Exp) { if !reflect.DeepEqual(*ret1, ret1Exp) {
...@@ -492,7 +490,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { ...@@ -492,7 +490,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
{{0x411, 0x412, 0x413}, {0x421, 0x422, 0x423}}, {{0x411, 0x412, 0x413}, {0x421, 0x422, 0x423}},
} }
ret2, ret2Exp := new(uint64), uint64(0x9876) ret2, ret2Exp := new(uint64), uint64(0x9876)
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil { if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !reflect.DeepEqual(*ret1, ret1Exp) { if !reflect.DeepEqual(*ret1, ret1Exp) {
...@@ -531,7 +529,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -531,7 +529,7 @@ func TestUnmarshal(t *testing.T) {
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000a")) buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000a"))
buff.Write(common.Hex2Bytes("0102000000000000000000000000000000000000000000000000000000000000")) buff.Write(common.Hex2Bytes("0102000000000000000000000000000000000000000000000000000000000000"))
err = abi.Unpack(&mixedBytes, "mixedBytes", buff.Bytes()) err = abi.UnpackIntoInterface(&mixedBytes, "mixedBytes", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} else { } else {
...@@ -546,7 +544,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -546,7 +544,7 @@ func TestUnmarshal(t *testing.T) {
// marshal int // marshal int
var Int *big.Int var Int *big.Int
err = abi.Unpack(&Int, "int", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) err = abi.UnpackIntoInterface(&Int, "int", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -557,7 +555,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -557,7 +555,7 @@ func TestUnmarshal(t *testing.T) {
// marshal bool // marshal bool
var Bool bool var Bool bool
err = abi.Unpack(&Bool, "bool", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) err = abi.UnpackIntoInterface(&Bool, "bool", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -574,7 +572,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -574,7 +572,7 @@ func TestUnmarshal(t *testing.T) {
buff.Write(bytesOut) buff.Write(bytesOut)
var Bytes []byte var Bytes []byte
err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -590,7 +588,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -590,7 +588,7 @@ func TestUnmarshal(t *testing.T) {
bytesOut = common.RightPadBytes([]byte("hello"), 64) bytesOut = common.RightPadBytes([]byte("hello"), 64)
buff.Write(bytesOut) buff.Write(bytesOut)
err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -606,7 +604,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -606,7 +604,7 @@ func TestUnmarshal(t *testing.T) {
bytesOut = common.RightPadBytes([]byte("hello"), 64) bytesOut = common.RightPadBytes([]byte("hello"), 64)
buff.Write(bytesOut) buff.Write(bytesOut)
err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -616,7 +614,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -616,7 +614,7 @@ func TestUnmarshal(t *testing.T) {
} }
// marshal dynamic bytes output empty // marshal dynamic bytes output empty
err = abi.Unpack(&Bytes, "bytes", nil) err = abi.UnpackIntoInterface(&Bytes, "bytes", nil)
if err == nil { if err == nil {
t.Error("expected error") t.Error("expected error")
} }
...@@ -627,7 +625,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -627,7 +625,7 @@ func TestUnmarshal(t *testing.T) {
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
buff.Write(common.RightPadBytes([]byte("hello"), 32)) buff.Write(common.RightPadBytes([]byte("hello"), 32))
err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -641,7 +639,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -641,7 +639,7 @@ func TestUnmarshal(t *testing.T) {
buff.Write(common.RightPadBytes([]byte("hello"), 32)) buff.Write(common.RightPadBytes([]byte("hello"), 32))
var hash common.Hash var hash common.Hash
err = abi.Unpack(&hash, "fixed", buff.Bytes()) err = abi.UnpackIntoInterface(&hash, "fixed", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -654,12 +652,12 @@ func TestUnmarshal(t *testing.T) { ...@@ -654,12 +652,12 @@ func TestUnmarshal(t *testing.T) {
// marshal error // marshal error
buff.Reset() buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
if err == nil { if err == nil {
t.Error("expected error") t.Error("expected error")
} }
err = abi.Unpack(&Bytes, "multi", make([]byte, 64)) err = abi.UnpackIntoInterface(&Bytes, "multi", make([]byte, 64))
if err == nil { if err == nil {
t.Error("expected error") t.Error("expected error")
} }
...@@ -670,7 +668,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -670,7 +668,7 @@ func TestUnmarshal(t *testing.T) {
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
// marshal int array // marshal int array
var intArray [3]*big.Int var intArray [3]*big.Int
err = abi.Unpack(&intArray, "intArraySingle", buff.Bytes()) err = abi.UnpackIntoInterface(&intArray, "intArraySingle", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -691,7 +689,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -691,7 +689,7 @@ func TestUnmarshal(t *testing.T) {
buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000")) buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000"))
var outAddr []common.Address var outAddr []common.Address
err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes()) err = abi.UnpackIntoInterface(&outAddr, "addressSliceSingle", buff.Bytes())
if err != nil { if err != nil {
t.Fatal("didn't expect error:", err) t.Fatal("didn't expect error:", err)
} }
...@@ -718,7 +716,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -718,7 +716,7 @@ func TestUnmarshal(t *testing.T) {
A []common.Address A []common.Address
B []common.Address B []common.Address
} }
err = abi.Unpack(&outAddrStruct, "addressSliceDouble", buff.Bytes()) err = abi.UnpackIntoInterface(&outAddrStruct, "addressSliceDouble", buff.Bytes())
if err != nil { if err != nil {
t.Fatal("didn't expect error:", err) t.Fatal("didn't expect error:", err)
} }
...@@ -746,7 +744,7 @@ func TestUnmarshal(t *testing.T) { ...@@ -746,7 +744,7 @@ func TestUnmarshal(t *testing.T) {
buff.Reset() buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100"))
err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes()) err = abi.UnpackIntoInterface(&outAddr, "addressSliceSingle", buff.Bytes())
if err == nil { if err == nil {
t.Fatal("expected error:", err) t.Fatal("expected error:", err)
} }
...@@ -769,7 +767,7 @@ func TestUnpackTuple(t *testing.T) { ...@@ -769,7 +767,7 @@ func TestUnpackTuple(t *testing.T) {
B *big.Int B *big.Int
}{new(big.Int), new(big.Int)} }{new(big.Int), new(big.Int)}
err = abi.Unpack(&v, "tuple", buff.Bytes()) err = abi.UnpackIntoInterface(&v, "tuple", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} else { } else {
...@@ -841,7 +839,7 @@ func TestUnpackTuple(t *testing.T) { ...@@ -841,7 +839,7 @@ func TestUnpackTuple(t *testing.T) {
A: big.NewInt(1), A: big.NewInt(1),
} }
err = abi.Unpack(&ret, "tuple", buff.Bytes()) err = abi.UnpackIntoInterface(&ret, "tuple", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
......
pragma solidity ^0.5.10; pragma solidity ^0.6.0;
/** /**
* @title CheckpointOracle * @title CheckpointOracle
......
...@@ -68,5 +68,5 @@ require ( ...@@ -68,5 +68,5 @@ require (
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
gopkg.in/urfave/cli.v1 v1.20.0 gopkg.in/urfave/cli.v1 v1.20.0
gotest.tools v2.2.0+incompatible // indirect gotest.tools v2.2.0+incompatible
) )
...@@ -171,20 +171,12 @@ func (c *BoundContract) GetDeployer() *Transaction { ...@@ -171,20 +171,12 @@ func (c *BoundContract) GetDeployer() *Transaction {
// Call invokes the (constant) contract method with params as input values and // Call invokes the (constant) contract method with params as input values and
// sets the output to result. // sets the output to result.
func (c *BoundContract) Call(opts *CallOpts, out *Interfaces, method string, args *Interfaces) error { func (c *BoundContract) Call(opts *CallOpts, out *Interfaces, method string, args *Interfaces) error {
if len(out.objects) == 1 { results := make([]interface{}, len(out.objects))
result := out.objects[0] copy(results, out.objects)
if err := c.contract.Call(&opts.opts, result, method, args.objects...); err != nil { if err := c.contract.Call(&opts.opts, &results, method, args.objects...); err != nil {
return err return err
}
out.objects[0] = result
} else {
results := make([]interface{}, len(out.objects))
copy(results, out.objects)
if err := c.contract.Call(&opts.opts, &results, method, args.objects...); err != nil {
return err
}
copy(out.objects, results)
} }
copy(out.objects, results)
return nil return nil
} }
......
...@@ -30,7 +30,7 @@ import ( ...@@ -30,7 +30,7 @@ import (
func unpackPack(abi abi.ABI, method string, inputType []interface{}, input []byte) bool { func unpackPack(abi abi.ABI, method string, inputType []interface{}, input []byte) bool {
outptr := reflect.New(reflect.TypeOf(inputType)) outptr := reflect.New(reflect.TypeOf(inputType))
if err := abi.Unpack(outptr.Interface(), method, input); err == nil { if err := abi.UnpackIntoInterface(outptr.Interface(), method, input); err == nil {
output, err := abi.Pack(method, input) output, err := abi.Pack(method, input)
if err != nil { if err != nil {
// We have some false positives as we can unpack these type successfully, but not pack them // We have some false positives as we can unpack these type successfully, but not pack them
...@@ -51,7 +51,7 @@ func unpackPack(abi abi.ABI, method string, inputType []interface{}, input []byt ...@@ -51,7 +51,7 @@ func unpackPack(abi abi.ABI, method string, inputType []interface{}, input []byt
func packUnpack(abi abi.ABI, method string, input []interface{}) bool { func packUnpack(abi abi.ABI, method string, input []interface{}) bool {
if packed, err := abi.Pack(method, input); err == nil { if packed, err := abi.Pack(method, input); err == nil {
outptr := reflect.New(reflect.TypeOf(input)) outptr := reflect.New(reflect.TypeOf(input))
err := abi.Unpack(outptr.Interface(), method, packed) err := abi.UnpackIntoInterface(outptr.Interface(), method, packed)
if err != nil { if err != nil {
panic(err) panic(err)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment