Commit 5f5de49c authored by gary rong's avatar gary rong Committed by Guillaume Ballet

accounts/abi: enable struct golang binding generation (#18491)

* accounts/abi, cmd/abigen: support tuple

accounts/abi/bind, cmd/abigen: add objc back

accounts/abi/bind: use byte[24] as function indicator

accounts/abi/bind: resolve struct slice or array

accounts/abi/bind: remove sort logic

accounts: fix issues in abi

* accounts/abi: address comment
parent ca6c8c2a
...@@ -119,11 +119,22 @@ func unpack(t *Type, dst interface{}, src interface{}) error { ...@@ -119,11 +119,22 @@ func unpack(t *Type, dst interface{}, src interface{}) error {
dstVal = reflect.ValueOf(dst).Elem() dstVal = reflect.ValueOf(dst).Elem()
srcVal = reflect.ValueOf(src) srcVal = reflect.ValueOf(src)
) )
tuple, typ := false, t
if t.T != TupleTy && !((t.T == SliceTy || t.T == ArrayTy) && t.Elem.T == TupleTy) { for {
if typ.T == SliceTy || typ.T == ArrayTy {
typ = typ.Elem
continue
}
tuple = typ.T == TupleTy
break
}
if !tuple {
return set(dstVal, srcVal) return set(dstVal, srcVal)
} }
// Dereferences interface or pointer wrapper
dstVal = indirectInterfaceOrPtr(dstVal)
switch t.T { switch t.T {
case TupleTy: case TupleTy:
if dstVal.Kind() != reflect.Struct { if dstVal.Kind() != reflect.Struct {
...@@ -191,7 +202,7 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interfac ...@@ -191,7 +202,7 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interfac
argument := arguments.NonIndexed()[0] argument := arguments.NonIndexed()[0]
elem := reflect.ValueOf(v).Elem() elem := reflect.ValueOf(v).Elem()
if elem.Kind() == reflect.Struct { if elem.Kind() == reflect.Struct && argument.Type.T != TupleTy {
fieldmap, err := mapArgNamesToStructFields([]string{argument.Name}, elem) fieldmap, err := mapArgNamesToStructFields([]string{argument.Name}, elem)
if err != nil { if err != nil {
return err return err
......
...@@ -22,6 +22,7 @@ package bind ...@@ -22,6 +22,7 @@ package bind
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"go/format" "go/format"
"regexp" "regexp"
...@@ -38,6 +39,7 @@ type Lang int ...@@ -38,6 +39,7 @@ type Lang int
const ( const (
LangGo Lang = iota LangGo Lang = iota
LangJava LangJava
LangObjC
) )
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant // Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
...@@ -62,11 +64,12 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] ...@@ -62,11 +64,12 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
return r return r
}, abis[i]) }, abis[i])
// Extract the call and transact methods; events; and sort them alphabetically // Extract the call and transact methods; events, struct definitions; and sort them alphabetically
var ( var (
calls = make(map[string]*tmplMethod) calls = make(map[string]*tmplMethod)
transacts = make(map[string]*tmplMethod) transacts = make(map[string]*tmplMethod)
events = make(map[string]*tmplEvent) events = make(map[string]*tmplEvent)
structs = make(map[string]*tmplStruct)
) )
for _, original := range evmABI.Methods { for _, original := range evmABI.Methods {
// Normalize the method for capital cases and non-anonymous inputs/outputs // Normalize the method for capital cases and non-anonymous inputs/outputs
...@@ -79,6 +82,9 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] ...@@ -79,6 +82,9 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
if input.Name == "" { if input.Name == "" {
normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
} }
if _, exist := structs[input.Type.String()]; input.Type.T == abi.TupleTy && !exist {
bindStructType[lang](input.Type, structs)
}
} }
normalized.Outputs = make([]abi.Argument, len(original.Outputs)) normalized.Outputs = make([]abi.Argument, len(original.Outputs))
copy(normalized.Outputs, original.Outputs) copy(normalized.Outputs, original.Outputs)
...@@ -86,6 +92,9 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] ...@@ -86,6 +92,9 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
if output.Name != "" { if output.Name != "" {
normalized.Outputs[j].Name = capitalise(output.Name) normalized.Outputs[j].Name = capitalise(output.Name)
} }
if _, exist := structs[output.Type.String()]; output.Type.T == abi.TupleTy && !exist {
bindStructType[lang](output.Type, structs)
}
} }
// Append the methods to the call or transact lists // Append the methods to the call or transact lists
if original.Const { if original.Const {
...@@ -111,11 +120,20 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] ...@@ -111,11 +120,20 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
if input.Name == "" { if input.Name == "" {
normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
} }
if _, exist := structs[input.Type.String()]; input.Type.T == abi.TupleTy && !exist {
bindStructType[lang](input.Type, structs)
}
} }
} }
// Append the event to the accumulator list // Append the event to the accumulator list
events[original.Name] = &tmplEvent{Original: original, Normalized: normalized} events[original.Name] = &tmplEvent{Original: original, Normalized: normalized}
} }
// There is no easy way to pass arbitrary java objects to the Go side.
if len(structs) > 0 && lang == LangJava {
return "", errors.New("java binding for tuple arguments is not supported yet")
}
contracts[types[i]] = &tmplContract{ contracts[types[i]] = &tmplContract{
Type: capitalise(types[i]), Type: capitalise(types[i]),
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1), InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
...@@ -124,6 +142,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] ...@@ -124,6 +142,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
Calls: calls, Calls: calls,
Transacts: transacts, Transacts: transacts,
Events: events, Events: events,
Structs: structs,
} }
if len(fsigs) > i { if len(fsigs) > i {
contracts[types[i]].FuncSigs = fsigs[i] contracts[types[i]].FuncSigs = fsigs[i]
...@@ -140,6 +159,8 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] ...@@ -140,6 +159,8 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
"bindtype": bindType[lang], "bindtype": bindType[lang],
"bindtopictype": bindTopicType[lang], "bindtopictype": bindTopicType[lang],
"namedtype": namedType[lang], "namedtype": namedType[lang],
"formatmethod": formatMethod,
"formatevent": formatEvent,
"capitalise": capitalise, "capitalise": capitalise,
"decapitalise": decapitalise, "decapitalise": decapitalise,
} }
...@@ -161,7 +182,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] ...@@ -161,7 +182,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
// bindType is a set of type binders that convert Solidity types to some supported // bindType is a set of type binders that convert Solidity types to some supported
// programming language types. // programming language types.
var bindType = map[Lang]func(kind abi.Type) string{ var bindType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
LangGo: bindTypeGo, LangGo: bindTypeGo,
LangJava: bindTypeJava, LangJava: bindTypeJava,
} }
...@@ -193,13 +214,14 @@ func bindBasicTypeGo(kind abi.Type) string { ...@@ -193,13 +214,14 @@ func bindBasicTypeGo(kind abi.Type) string {
// bindTypeGo converts solidity types to Go ones. Since there is no clear mapping // bindTypeGo converts solidity types to Go ones. Since there is no clear mapping
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly // from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. BigDecimal). // mapped will use an upscaled type (e.g. BigDecimal).
func bindTypeGo(kind abi.Type) string { func bindTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
// todo(rjl493456442) tuple
switch kind.T { switch kind.T {
case abi.TupleTy:
return structs[kind.String()].Name
case abi.ArrayTy: case abi.ArrayTy:
return fmt.Sprintf("[%d]", kind.Size) + bindTypeGo(*kind.Elem) return fmt.Sprintf("[%d]", kind.Size) + bindTypeGo(*kind.Elem, structs)
case abi.SliceTy: case abi.SliceTy:
return "[]" + bindTypeGo(*kind.Elem) return "[]" + bindTypeGo(*kind.Elem, structs)
default: default:
return bindBasicTypeGo(kind) return bindBasicTypeGo(kind)
} }
...@@ -248,27 +270,33 @@ func bindBasicTypeJava(kind abi.Type) string { ...@@ -248,27 +270,33 @@ func bindBasicTypeJava(kind abi.Type) string {
} }
} }
// pluralizeJavaType explicitly converts multidimensional types to predefined
// type in go side.
func pluralizeJavaType(typ string) string {
switch typ {
case "boolean":
return "Bools"
case "String":
return "Strings"
case "Address":
return "Addresses"
case "byte[]":
return "Binaries"
case "BigInt":
return "BigInts"
}
return typ + "[]"
}
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping // bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly // from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. BigDecimal). // mapped will use an upscaled type (e.g. BigDecimal).
func bindTypeJava(kind abi.Type) string { func bindTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
switch kind.T { switch kind.T {
case abi.TupleTy:
return structs[kind.String()].Name
case abi.ArrayTy, abi.SliceTy: case abi.ArrayTy, abi.SliceTy:
// Explicitly convert multidimensional types to predefined type in go side. return pluralizeJavaType(bindTypeJava(*kind.Elem, structs))
inner := bindTypeJava(*kind.Elem)
switch inner {
case "boolean":
return "Bools"
case "String":
return "Strings"
case "Address":
return "Addresses"
case "byte[]":
return "Binaries"
case "BigInt":
return "BigInts"
}
return inner + "[]"
default: default:
return bindBasicTypeJava(kind) return bindBasicTypeJava(kind)
} }
...@@ -276,15 +304,15 @@ func bindTypeJava(kind abi.Type) string { ...@@ -276,15 +304,15 @@ func bindTypeJava(kind abi.Type) string {
// bindTopicType is a set of type binders that convert Solidity types to some // bindTopicType is a set of type binders that convert Solidity types to some
// supported programming language topic types. // supported programming language topic types.
var bindTopicType = map[Lang]func(kind abi.Type) string{ var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
LangGo: bindTopicTypeGo, LangGo: bindTopicTypeGo,
LangJava: bindTopicTypeJava, LangJava: bindTopicTypeJava,
} }
// bindTypeGo converts a Solidity topic type to a Go one. It is almost the same // bindTypeGo converts a Solidity topic type to a Go one. It is almost the same
// funcionality as for simple types, but dynamic types get converted to hashes. // funcionality as for simple types, but dynamic types get converted to hashes.
func bindTopicTypeGo(kind abi.Type) string { func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
bound := bindTypeGo(kind) bound := bindTypeGo(kind, structs)
if bound == "string" || bound == "[]byte" { if bound == "string" || bound == "[]byte" {
bound = "common.Hash" bound = "common.Hash"
} }
...@@ -293,14 +321,77 @@ func bindTopicTypeGo(kind abi.Type) string { ...@@ -293,14 +321,77 @@ func bindTopicTypeGo(kind abi.Type) string {
// bindTypeGo converts a Solidity topic type to a Java one. It is almost the same // bindTypeGo converts a Solidity topic type to a Java one. It is almost the same
// funcionality as for simple types, but dynamic types get converted to hashes. // funcionality as for simple types, but dynamic types get converted to hashes.
func bindTopicTypeJava(kind abi.Type) string { func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
bound := bindTypeJava(kind) bound := bindTypeJava(kind, structs)
if bound == "String" || bound == "byte[]" { if bound == "String" || bound == "byte[]" {
bound = "Hash" bound = "Hash"
} }
return bound return bound
} }
// bindStructType is a set of type binders that convert Solidity tuple types to some supported
// programming language struct definition.
var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
LangGo: bindStructTypeGo,
LangJava: bindStructTypeJava,
}
// bindStructTypeGo converts a Solidity tuple type to a Go one and records the mapping
// in the given map.
// Notably, this function will resolve and record nested struct recursively.
func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
switch kind.T {
case abi.TupleTy:
if s, exist := structs[kind.String()]; exist {
return s.Name
}
var fields []*tmplField
for i, elem := range kind.TupleElems {
field := bindStructTypeGo(*elem, structs)
fields = append(fields, &tmplField{Type: field, Name: capitalise(kind.TupleRawNames[i]), SolKind: *elem})
}
name := fmt.Sprintf("Struct%d", len(structs))
structs[kind.String()] = &tmplStruct{
Name: name,
Fields: fields,
}
return name
case abi.ArrayTy:
return fmt.Sprintf("[%d]", kind.Size) + bindStructTypeGo(*kind.Elem, structs)
case abi.SliceTy:
return "[]" + bindStructTypeGo(*kind.Elem, structs)
default:
return bindBasicTypeGo(kind)
}
}
// bindStructTypeJava converts a Solidity tuple type to a Java one and records the mapping
// in the given map.
// Notably, this function will resolve and record nested struct recursively.
func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
switch kind.T {
case abi.TupleTy:
if s, exist := structs[kind.String()]; exist {
return s.Name
}
var fields []*tmplField
for i, elem := range kind.TupleElems {
field := bindStructTypeJava(*elem, structs)
fields = append(fields, &tmplField{Type: field, Name: decapitalise(kind.TupleRawNames[i]), SolKind: *elem})
}
name := fmt.Sprintf("Class%d", len(structs))
structs[kind.String()] = &tmplStruct{
Name: name,
Fields: fields,
}
return name
case abi.ArrayTy, abi.SliceTy:
return pluralizeJavaType(bindStructTypeJava(*kind.Elem, structs))
default:
return bindBasicTypeJava(kind)
}
}
// namedType is a set of functions that transform language specific types to // namedType is a set of functions that transform language specific types to
// named versions that my be used inside method names. // named versions that my be used inside method names.
var namedType = map[Lang]func(string, abi.Type) string{ var namedType = map[Lang]func(string, abi.Type) string{
...@@ -378,3 +469,63 @@ func structured(args abi.Arguments) bool { ...@@ -378,3 +469,63 @@ func structured(args abi.Arguments) bool {
} }
return true return true
} }
// resolveArgName converts a raw argument representation into a user friendly format.
func resolveArgName(arg abi.Argument, structs map[string]*tmplStruct) string {
var (
prefix string
embedded string
typ = &arg.Type
)
loop:
for {
switch typ.T {
case abi.SliceTy:
prefix += "[]"
case abi.ArrayTy:
prefix += fmt.Sprintf("[%d]", typ.Size)
default:
embedded = typ.String()
break loop
}
typ = typ.Elem
}
if s, exist := structs[embedded]; exist {
return prefix + s.Name
} else {
return arg.Type.String()
}
}
// formatMethod transforms raw method representation into a user friendly one.
func formatMethod(method abi.Method, structs map[string]*tmplStruct) string {
inputs := make([]string, len(method.Inputs))
for i, input := range method.Inputs {
inputs[i] = fmt.Sprintf("%v %v", resolveArgName(input, structs), input.Name)
}
outputs := make([]string, len(method.Outputs))
for i, output := range method.Outputs {
outputs[i] = resolveArgName(output, structs)
if len(output.Name) > 0 {
outputs[i] += fmt.Sprintf(" %v", output.Name)
}
}
constant := ""
if method.Const {
constant = "constant "
}
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
}
// formatEvent transforms raw event representation into a user friendly one.
func formatEvent(event abi.Event, structs map[string]*tmplStruct) string {
inputs := make([]string, len(event.Inputs))
for i, input := range event.Inputs {
if input.Indexed {
inputs[i] = fmt.Sprintf("%v indexed %v", resolveArgName(input, structs), input.Name)
} else {
inputs[i] = fmt.Sprintf("%v %v", resolveArgName(input, structs), input.Name)
}
}
return fmt.Sprintf("event %v(%v)", event.Name, strings.Join(inputs, ", "))
}
...@@ -1014,6 +1014,137 @@ var bindTests = []struct { ...@@ -1014,6 +1014,137 @@ var bindTests = []struct {
"test(function)": "d7a5aba2", "test(function)": "d7a5aba2",
}, },
}, },
}, {
`Tuple`,
`
pragma solidity >=0.4.19 <0.6.0;
pragma experimental ABIEncoderV2;
contract Tuple {
struct S { uint a; uint[] b; T[] c; }
struct T { uint x; uint y; }
event TupleEvent(S a, T[2][] b, T[][2] c, S[] d, uint[] e);
function func1(S memory a, T[2][] memory b, T[][2] memory c, S[] memory d, uint[] memory e) public pure returns (S memory, T[2][] memory, T[][2] memory, S[] memory, uint[] memory) {
return (a, b, c, d, e);
}
function func2(S memory a, T[2][] memory b, T[][2] memory c, S[] memory d, uint[] memory e) public {
emit TupleEvent(a, b, c, d, e);
}
}
`,
`608060405234801561001057600080fd5b50610eb2806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063443c79b41461003b578063d0062cdd1461006f575b600080fd5b61005560048036036100509190810190610624565b61008b565b604051610066959493929190610b28565b60405180910390f35b61008960048036036100849190810190610624565b6100bc565b005b610093610102565b606061009d610123565b6060808989898989945094509450945094509550955095509550959050565b7f18d6e66efa53739ca6d13626f35ebc700b31cced3eddb50c70bbe9c082c6cd0085858585856040516100f3959493929190610b28565b60405180910390a15050505050565b60405180606001604052806000815260200160608152602001606081525090565b60405180604001604052806002905b60608152602001906001900390816101325790505090565b600082601f83011261015b57600080fd5b813561016e61016982610bcb565b610b9e565b9150818183526020840193506020810190508385608084028201111561019357600080fd5b60005b838110156101c357816101a988826102a6565b845260208401935060808301925050600181019050610196565b5050505092915050565b600082601f8301126101de57600080fd5b60026101f16101ec82610bf3565b610b9e565b9150818360005b83811015610228578135860161020e888261031a565b8452602084019350602083019250506001810190506101f8565b5050505092915050565b600082601f83011261024357600080fd5b813561025661025182610c15565b610b9e565b9150818183526020840193506020810190508360005b8381101561029c578135860161028288826104a3565b84526020840193506020830192505060018101905061026c565b5050505092915050565b600082601f8301126102b757600080fd5b60026102ca6102c582610c3d565b610b9e565b915081838560408402820111156102e057600080fd5b60005b8381101561031057816102f688826105c3565b8452602084019350604083019250506001810190506102e3565b5050505092915050565b600082601f83011261032b57600080fd5b813561033e61033982610c5f565b610b9e565b9150818183526020840193506020810190508385604084028201111561036357600080fd5b60005b83811015610393578161037988826105c3565b845260208401935060408301925050600181019050610366565b5050505092915050565b600082601f8301126103ae57600080fd5b81356103c16103bc82610c87565b610b9e565b915081818352602084019350602081019050838560208402820111156103e657600080fd5b60005b8381101561041657816103fc888261060f565b8452602084019350602083019250506001810190506103e9565b5050505092915050565b600082601f83011261043157600080fd5b813561044461043f82610caf565b610b9e565b9150818183526020840193506020810190508385602084028201111561046957600080fd5b60005b83811015610499578161047f888261060f565b84526020840193506020830192505060018101905061046c565b5050505092915050565b6000606082840312156104b557600080fd5b6104bf6060610b9e565b905060006104cf8482850161060f565b600083015250602082013567ffffffffffffffff8111156104ef57600080fd5b6104fb8482850161039d565b602083015250604082013567ffffffffffffffff81111561051b57600080fd5b6105278482850161031a565b60408301525092915050565b60006060828403121561054557600080fd5b61054f6060610b9e565b9050600061055f8482850161060f565b600083015250602082013567ffffffffffffffff81111561057f57600080fd5b61058b8482850161039d565b602083015250604082013567ffffffffffffffff8111156105ab57600080fd5b6105b78482850161031a565b60408301525092915050565b6000604082840312156105d557600080fd5b6105df6040610b9e565b905060006105ef8482850161060f565b60008301525060206106038482850161060f565b60208301525092915050565b60008135905061061e81610e58565b92915050565b600080600080600060a0868803121561063c57600080fd5b600086013567ffffffffffffffff81111561065657600080fd5b61066288828901610533565b955050602086013567ffffffffffffffff81111561067f57600080fd5b61068b8882890161014a565b945050604086013567ffffffffffffffff8111156106a857600080fd5b6106b4888289016101cd565b935050606086013567ffffffffffffffff8111156106d157600080fd5b6106dd88828901610232565b925050608086013567ffffffffffffffff8111156106fa57600080fd5b61070688828901610420565b9150509295509295909350565b600061071f83836108cb565b60808301905092915050565b60006107378383610922565b905092915050565b600061074b8383610a93565b905092915050565b600061075f8383610aea565b60408301905092915050565b60006107778383610b19565b60208301905092915050565b600061078e82610d3b565b6107988185610de3565b93506107a383610cd7565b8060005b838110156107d45781516107bb8882610713565b97506107c683610d88565b9250506001810190506107a7565b5085935050505092915050565b60006107ec82610d46565b6107f68185610df4565b93508360208202850161080885610ce7565b8060005b858110156108445784840389528151610825858261072b565b945061083083610d95565b925060208a0199505060018101905061080c565b50829750879550505050505092915050565b600061086182610d51565b61086b8185610dff565b93508360208202850161087d85610cf1565b8060005b858110156108b9578484038952815161089a858261073f565b94506108a583610da2565b925060208a01995050600181019050610881565b50829750879550505050505092915050565b6108d481610d5c565b6108de8184610e10565b92506108e982610d01565b8060005b8381101561091a5781516109018782610753565b965061090c83610daf565b9250506001810190506108ed565b505050505050565b600061092d82610d67565b6109378185610e1b565b935061094283610d0b565b8060005b8381101561097357815161095a8882610753565b975061096583610dbc565b925050600181019050610946565b5085935050505092915050565b600061098b82610d7d565b6109958185610e3d565b93506109a083610d2b565b8060005b838110156109d15781516109b8888261076b565b97506109c383610dd6565b9250506001810190506109a4565b5085935050505092915050565b60006109e982610d72565b6109f38185610e2c565b93506109fe83610d1b565b8060005b83811015610a2f578151610a16888261076b565b9750610a2183610dc9565b925050600181019050610a02565b5085935050505092915050565b6000606083016000830151610a546000860182610b19565b5060208301518482036020860152610a6c82826109de565b91505060408301518482036040860152610a868282610922565b9150508091505092915050565b6000606083016000830151610aab6000860182610b19565b5060208301518482036020860152610ac382826109de565b91505060408301518482036040860152610add8282610922565b9150508091505092915050565b604082016000820151610b006000850182610b19565b506020820151610b136020850182610b19565b50505050565b610b2281610e4e565b82525050565b600060a0820190508181036000830152610b428188610a3c565b90508181036020830152610b568187610783565b90508181036040830152610b6a81866107e1565b90508181036060830152610b7e8185610856565b90508181036080830152610b928184610980565b90509695505050505050565b6000604051905081810181811067ffffffffffffffff82111715610bc157600080fd5b8060405250919050565b600067ffffffffffffffff821115610be257600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610c0a57600080fd5b602082029050919050565b600067ffffffffffffffff821115610c2c57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610c5457600080fd5b602082029050919050565b600067ffffffffffffffff821115610c7657600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610c9e57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610cc657600080fd5b602082029050602081019050919050565b6000819050602082019050919050565b6000819050919050565b6000819050602082019050919050565b6000819050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b6000819050919050565b610e6181610e4e565b8114610e6c57600080fd5b5056fea365627a7a72305820405a6336d8c302cee779de6788527018e5a2393892328fbf12b96065df2de00a6c6578706572696d656e74616cf564736f6c634300050a0040`,
`
[{"constant":true,"inputs":[{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"name":"a","type":"tuple"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"b","type":"tuple[2][]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[][2]"},{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"name":"d","type":"tuple[]"},{"name":"e","type":"uint256[]"}],"name":"func1","outputs":[{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"name":"","type":"tuple"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"","type":"tuple[2][]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"","type":"tuple[][2]"},{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"name":"","type":"tuple[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"name":"a","type":"tuple"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"b","type":"tuple[2][]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[][2]"},{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"name":"d","type":"tuple[]"},{"name":"e","type":"uint256[]"}],"name":"func2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"indexed":false,"name":"a","type":"tuple"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"indexed":false,"name":"b","type":"tuple[2][]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"indexed":false,"name":"c","type":"tuple[][2]"},{"components":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256[]"},{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"c","type":"tuple[]"}],"indexed":false,"name":"d","type":"tuple[]"},{"indexed":false,"name":"e","type":"uint256[]"}],"name":"TupleEvent","type":"event"}]
`,
`
"math/big"
"reflect"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
`,
`
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
backend := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
_, _, contract, err := DeployTuple(auth, backend)
if err != nil {
t.Fatalf("deploy contract failed %v", err)
}
backend.Commit()
check := func(a, b interface{}, errMsg string) {
if !reflect.DeepEqual(a, b) {
t.Fatal(errMsg)
}
}
a := Struct1{
A: big.NewInt(1),
B: []*big.Int{big.NewInt(2), big.NewInt(3)},
C: []Struct0{
{
X: big.NewInt(4),
Y: big.NewInt(5),
},
{
X: big.NewInt(6),
Y: big.NewInt(7),
},
},
}
b := [][2]Struct0{
{
{
X: big.NewInt(8),
Y: big.NewInt(9),
},
{
X: big.NewInt(10),
Y: big.NewInt(11),
},
},
}
c := [2][]Struct0{
{
{
X: big.NewInt(12),
Y: big.NewInt(13),
},
{
X: big.NewInt(14),
Y: big.NewInt(15),
},
},
{
{
X: big.NewInt(16),
Y: big.NewInt(17),
},
},
}
d := []Struct1{a}
e := []*big.Int{big.NewInt(18), big.NewInt(19)}
ret1, ret2, ret3, ret4, ret5, err := contract.Func1(nil, a, b, c, d, e)
if err != nil {
t.Fatalf("invoke contract failed, err %v", err)
}
check(ret1, a, "ret1 mismatch")
check(ret2, b, "ret2 mismatch")
check(ret3, c, "ret3 mismatch")
check(ret4, d, "ret4 mismatch")
check(ret5, e, "ret5 mismatch")
_, err = contract.Func2(auth, a, b, c, d, e)
if err != nil {
t.Fatalf("invoke contract failed, err %v", err)
}
backend.Commit()
iter, err := contract.FilterTupleEvent(nil)
if err != nil {
t.Fatalf("failed to create event filter, err %v", err)
}
defer iter.Close()
iter.Next()
check(iter.Event.A, a, "field1 mismatch")
check(iter.Event.B, b, "field2 mismatch")
check(iter.Event.C, c, "field3 mismatch")
check(iter.Event.D, d, "field4 mismatch")
check(iter.Event.E, e, "field5 mismatch")
`,
nil,
}, },
} }
...@@ -1133,6 +1264,7 @@ import org.ethereum.geth.*; ...@@ -1133,6 +1264,7 @@ import org.ethereum.geth.*;
import java.util.*; import java.util.*;
public class Test { public class Test {
// ABI is the input ABI used to generate the binding from. // ABI is the input ABI used to generate the binding from.
public final static String ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"u16\",\"type\":\"uint16\"}],\"name\":\"setUint16\",\"outputs\":[{\"name\":\"\",\"type\":\"uint16\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b_a\",\"type\":\"bool[2]\"}],\"name\":\"setBoolArray\",\"outputs\":[{\"name\":\"\",\"type\":\"bool[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a_a\",\"type\":\"address[2]\"}],\"name\":\"setAddressArray\",\"outputs\":[{\"name\":\"\",\"type\":\"address[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs_l\",\"type\":\"bytes[]\"}],\"name\":\"setBytesList\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u8\",\"type\":\"uint8\"}],\"name\":\"setUint8\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u32\",\"type\":\"uint32\"}],\"name\":\"setUint32\",\"outputs\":[{\"name\":\"\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"setBool\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256_l\",\"type\":\"int256[]\"}],\"name\":\"setInt256List\",\"outputs\":[{\"name\":\"\",\"type\":\"int256[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256_a\",\"type\":\"uint256[2]\"}],\"name\":\"setUint256Array\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b_l\",\"type\":\"bool[]\"}],\"name\":\"setBoolList\",\"outputs\":[{\"name\":\"\",\"type\":\"bool[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs_a\",\"type\":\"bytes[2]\"}],\"name\":\"setBytesArray\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a_l\",\"type\":\"address[]\"}],\"name\":\"setAddressList\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256_a\",\"type\":\"int256[2]\"}],\"name\":\"setInt256Array\",\"outputs\":[{\"name\":\"\",\"type\":\"int256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s_a\",\"type\":\"string[2]\"}],\"name\":\"setStringArray\",\"outputs\":[{\"name\":\"\",\"type\":\"string[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setString\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u64\",\"type\":\"uint64\"}],\"name\":\"setUint64\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i16\",\"type\":\"int16\"}],\"name\":\"setInt16\",\"outputs\":[{\"name\":\"\",\"type\":\"int16\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i8\",\"type\":\"int8\"}],\"name\":\"setInt8\",\"outputs\":[{\"name\":\"\",\"type\":\"int8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256_l\",\"type\":\"uint256[]\"}],\"name\":\"setUint256List\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256\",\"type\":\"int256\"}],\"name\":\"setInt256\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i32\",\"type\":\"int32\"}],\"name\":\"setInt32\",\"outputs\":[{\"name\":\"\",\"type\":\"int32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b32\",\"type\":\"bytes32\"}],\"name\":\"setBytes32\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s_l\",\"type\":\"string[]\"}],\"name\":\"setStringList\",\"outputs\":[{\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256\",\"type\":\"uint256\"}],\"name\":\"setUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs\",\"type\":\"bytes\"}],\"name\":\"setBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"address\"}],\"name\":\"setAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i64\",\"type\":\"int64\"}],\"name\":\"setInt64\",\"outputs\":[{\"name\":\"\",\"type\":\"int64\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b1\",\"type\":\"bytes1\"}],\"name\":\"setBytes1\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes1\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; public final static String ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"u16\",\"type\":\"uint16\"}],\"name\":\"setUint16\",\"outputs\":[{\"name\":\"\",\"type\":\"uint16\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b_a\",\"type\":\"bool[2]\"}],\"name\":\"setBoolArray\",\"outputs\":[{\"name\":\"\",\"type\":\"bool[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a_a\",\"type\":\"address[2]\"}],\"name\":\"setAddressArray\",\"outputs\":[{\"name\":\"\",\"type\":\"address[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs_l\",\"type\":\"bytes[]\"}],\"name\":\"setBytesList\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u8\",\"type\":\"uint8\"}],\"name\":\"setUint8\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u32\",\"type\":\"uint32\"}],\"name\":\"setUint32\",\"outputs\":[{\"name\":\"\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"setBool\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256_l\",\"type\":\"int256[]\"}],\"name\":\"setInt256List\",\"outputs\":[{\"name\":\"\",\"type\":\"int256[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256_a\",\"type\":\"uint256[2]\"}],\"name\":\"setUint256Array\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b_l\",\"type\":\"bool[]\"}],\"name\":\"setBoolList\",\"outputs\":[{\"name\":\"\",\"type\":\"bool[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs_a\",\"type\":\"bytes[2]\"}],\"name\":\"setBytesArray\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a_l\",\"type\":\"address[]\"}],\"name\":\"setAddressList\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256_a\",\"type\":\"int256[2]\"}],\"name\":\"setInt256Array\",\"outputs\":[{\"name\":\"\",\"type\":\"int256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s_a\",\"type\":\"string[2]\"}],\"name\":\"setStringArray\",\"outputs\":[{\"name\":\"\",\"type\":\"string[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setString\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u64\",\"type\":\"uint64\"}],\"name\":\"setUint64\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i16\",\"type\":\"int16\"}],\"name\":\"setInt16\",\"outputs\":[{\"name\":\"\",\"type\":\"int16\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i8\",\"type\":\"int8\"}],\"name\":\"setInt8\",\"outputs\":[{\"name\":\"\",\"type\":\"int8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256_l\",\"type\":\"uint256[]\"}],\"name\":\"setUint256List\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256\",\"type\":\"int256\"}],\"name\":\"setInt256\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i32\",\"type\":\"int32\"}],\"name\":\"setInt32\",\"outputs\":[{\"name\":\"\",\"type\":\"int32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b32\",\"type\":\"bytes32\"}],\"name\":\"setBytes32\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s_l\",\"type\":\"string[]\"}],\"name\":\"setStringList\",\"outputs\":[{\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256\",\"type\":\"uint256\"}],\"name\":\"setUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs\",\"type\":\"bytes\"}],\"name\":\"setBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"address\"}],\"name\":\"setAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i64\",\"type\":\"int64\"}],\"name\":\"setInt64\",\"outputs\":[{\"name\":\"\",\"type\":\"int64\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b1\",\"type\":\"bytes1\"}],\"name\":\"setBytes1\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes1\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]";
......
...@@ -34,6 +34,7 @@ type tmplContract struct { ...@@ -34,6 +34,7 @@ type tmplContract struct {
Calls map[string]*tmplMethod // Contract calls that only read state data Calls map[string]*tmplMethod // Contract calls that only read state data
Transacts map[string]*tmplMethod // Contract calls that write state data Transacts map[string]*tmplMethod // Contract calls that write state data
Events map[string]*tmplEvent // Contract events accessors Events map[string]*tmplEvent // Contract events accessors
Structs map[string]*tmplStruct // Contract struct type definitions
} }
// tmplMethod is a wrapper around an abi.Method that contains a few preprocessed // tmplMethod is a wrapper around an abi.Method that contains a few preprocessed
...@@ -50,6 +51,21 @@ type tmplEvent struct { ...@@ -50,6 +51,21 @@ type tmplEvent struct {
Normalized abi.Event // Normalized version of the parsed fields Normalized abi.Event // Normalized version of the parsed fields
} }
// tmplField is a wrapper around a struct field with binding language
// struct type definition and relative filed name.
type tmplField struct {
Type string // Field type representation depends on target binding language
Name string // Field name converted from the raw user-defined field name
SolKind abi.Type // Raw abi type information
}
// tmplStruct is a wrapper around an abi.tuple contains a auto-generated
// struct name.
type tmplStruct struct {
Name string // Auto-generated struct name(We can't obtain the raw struct name through abi)
Fields []*tmplField // Struct fields definition depends on the binding language.
}
// tmplSource is language to template mapping containing all the supported // tmplSource is language to template mapping containing all the supported
// programming languages the package can generate to. // programming languages the package can generate to.
var tmplSource = map[Lang]string{ var tmplSource = map[Lang]string{
...@@ -90,6 +106,7 @@ var ( ...@@ -90,6 +106,7 @@ var (
) )
{{range $contract := .Contracts}} {{range $contract := .Contracts}}
{{$structs := $contract.Structs}}
// {{.Type}}ABI is the input ABI used to generate the binding from. // {{.Type}}ABI is the input ABI used to generate the binding from.
const {{.Type}}ABI = "{{.InputABI}}" const {{.Type}}ABI = "{{.InputABI}}"
...@@ -107,7 +124,7 @@ var ( ...@@ -107,7 +124,7 @@ var (
const {{.Type}}Bin = ` + "`" + `{{.InputBin}}` + "`" + ` const {{.Type}}Bin = ` + "`" + `{{.InputBin}}` + "`" + `
// Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it. // Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) { func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) {
parsed, err := abi.JSON(strings.NewReader({{.Type}}ABI)) parsed, err := abi.JSON(strings.NewReader({{.Type}}ABI))
if err != nil { if err != nil {
return common.Address{}, nil, nil, err return common.Address{}, nil, nil, err
...@@ -124,7 +141,7 @@ var ( ...@@ -124,7 +141,7 @@ var (
type {{.Type}} struct { type {{.Type}} struct {
{{.Type}}Caller // Read-only binding to the contract {{.Type}}Caller // Read-only binding to the contract
{{.Type}}Transactor // Write-only binding to the contract {{.Type}}Transactor // Write-only binding to the contract
{{.Type}}Filterer // Log filterer for contract events {{.Type}}Filterer // Log filterer for contract events
} }
// {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract. // {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract.
...@@ -262,16 +279,24 @@ var ( ...@@ -262,16 +279,24 @@ var (
return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...) return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...)
} }
{{range .Structs}}
// {{.Name}} is an auto generated low-level Go binding around an user-defined struct.
type {{.Name}} struct {
{{range $field := .Fields}}
{{$field.Name}} {{$field.Type}}{{end}}
}
{{end}}
{{range .Calls}} {{range .Calls}}
// {{.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}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatmethod .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type}},{{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{ {{if .Structured}}ret := new(struct{
{{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type}} {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}}
{{end}} {{end}}
}){{else}}var ( }){{else}}var (
{{range $i, $_ := .Normalized.Outputs}}ret{{$i}} = new({{bindtype .Type}}) {{range $i, $_ := .Normalized.Outputs}}ret{{$i}} = new({{bindtype .Type $structs}})
{{end}} {{end}}
){{end}} ){{end}}
out := {{if .Structured}}ret{{else}}{{if eq (len .Normalized.Outputs) 1}}ret0{{else}}&[]interface{}{ out := {{if .Structured}}ret{{else}}{{if eq (len .Normalized.Outputs) 1}}ret0{{else}}&[]interface{}{
...@@ -284,15 +309,15 @@ var ( ...@@ -284,15 +309,15 @@ var (
// {{.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}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatmethod .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type}},{{end}} {{end}} error) { func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.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) {
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{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}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatmethod .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type}},{{end}} {{end}} error) { func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.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) {
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
} }
{{end}} {{end}}
...@@ -300,22 +325,22 @@ var ( ...@@ -300,22 +325,22 @@ var (
{{range .Transacts}} {{range .Transacts}}
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}. // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatmethod .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type}} {{end}}) (*types.Transaction, error) { func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
} }
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}. // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatmethod .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type}} {{end}}) (*types.Transaction, error) { func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
} }
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}. // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatmethod .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type}} {{end}}) (*types.Transaction, error) { func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
} }
{{end}} {{end}}
...@@ -387,14 +412,14 @@ var ( ...@@ -387,14 +412,14 @@ var (
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract. // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract.
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}} type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type}}{{else}}{{bindtype .Type}}{{end}}; {{end}} {{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}}
Raw types.Log // Blockchain specific contextual infos Raw types.Log // Blockchain specific contextual infos
} }
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.Id}}. // Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.Id}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatevent .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) { func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) {
{{range .Normalized.Inputs}} {{range .Normalized.Inputs}}
{{if .Indexed}}var {{.Name}}Rule []interface{} {{if .Indexed}}var {{.Name}}Rule []interface{}
for _, {{.Name}}Item := range {{.Name}} { for _, {{.Name}}Item := range {{.Name}} {
...@@ -410,8 +435,8 @@ var ( ...@@ -410,8 +435,8 @@ var (
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.Id}}. // Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.Id}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{formatevent .Original $structs}}
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type}}{{end}}{{end}}) (event.Subscription, error) { func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) {
{{range .Normalized.Inputs}} {{range .Normalized.Inputs}}
{{if .Indexed}}var {{.Name}}Rule []interface{} {{if .Indexed}}var {{.Name}}Rule []interface{}
for _, {{.Name}}Item := range {{.Name}} { for _, {{.Name}}Item := range {{.Name}} {
...@@ -477,6 +502,7 @@ import org.ethereum.geth.*; ...@@ -477,6 +502,7 @@ import org.ethereum.geth.*;
import java.util.*; import java.util.*;
{{range $contract := .Contracts}} {{range $contract := .Contracts}}
{{$structs := $contract.Structs}}
public class {{.Type}} { public class {{.Type}} {
// ABI is the input ABI used to generate the binding from. // ABI is the input ABI used to generate the binding from.
public final static String ABI = "{{.InputABI}}"; public final static String ABI = "{{.InputABI}}";
...@@ -496,9 +522,9 @@ public class {{.Type}} { ...@@ -496,9 +522,9 @@ public class {{.Type}} {
public final static String BYTECODE = "0x{{.InputBin}}"; public final static String BYTECODE = "0x{{.InputBin}}";
// deploy deploys a new Ethereum contract, binding an instance of {{.Type}} to it. // deploy deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
public static {{.Type}} deploy(TransactOpts auth, EthereumClient client{{range .Constructor.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception { public static {{.Type}} deploy(TransactOpts auth, EthereumClient client{{range .Constructor.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception {
Interfaces args = Geth.newInterfaces({{(len .Constructor.Inputs)}}); Interfaces args = Geth.newInterfaces({{(len .Constructor.Inputs)}});
{{range $index, $element := .Constructor.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); {{range $index, $element := .Constructor.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}});
{{end}} {{end}}
return new {{.Type}}(Geth.deployContract(auth, ABI, Geth.decodeFromHex(BYTECODE), client, args)); return new {{.Type}}(Geth.deployContract(auth, ABI, Geth.decodeFromHex(BYTECODE), client, args));
} }
...@@ -529,7 +555,7 @@ public class {{.Type}} { ...@@ -529,7 +555,7 @@ public class {{.Type}} {
{{if gt (len .Normalized.Outputs) 1}} {{if gt (len .Normalized.Outputs) 1}}
// {{capitalise .Normalized.Name}}Results is the output of a call to {{.Normalized.Name}}. // {{capitalise .Normalized.Name}}Results is the output of a call to {{.Normalized.Name}}.
public class {{capitalise .Normalized.Name}}Results { public class {{capitalise .Normalized.Name}}Results {
{{range $index, $item := .Normalized.Outputs}}public {{bindtype .Type}} {{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}}; {{range $index, $item := .Normalized.Outputs}}public {{bindtype .Type $structs}} {{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}};
{{end}} {{end}}
} }
{{end}} {{end}}
...@@ -537,13 +563,13 @@ public class {{.Type}} { ...@@ -537,13 +563,13 @@ public class {{.Type}} {
// {{.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}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{.Original.String}}
public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else}}{{range .Normalized.Outputs}}{{bindtype .Type}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception { public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception {
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}}); Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
{{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); {{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}});
{{end}} {{end}}
Interfaces results = Geth.newInterfaces({{(len .Normalized.Outputs)}}); Interfaces results = Geth.newInterfaces({{(len .Normalized.Outputs)}});
{{range $index, $item := .Normalized.Outputs}}Interface result{{$index}} = Geth.newInterface(); result{{$index}}.setDefault{{namedtype (bindtype .Type) .Type}}(); results.set({{$index}}, result{{$index}}); {{range $index, $item := .Normalized.Outputs}}Interface result{{$index}} = Geth.newInterface(); result{{$index}}.setDefault{{namedtype (bindtype .Type $structs) .Type}}(); results.set({{$index}}, result{{$index}});
{{end}} {{end}}
if (opts == null) { if (opts == null) {
...@@ -552,10 +578,10 @@ public class {{.Type}} { ...@@ -552,10 +578,10 @@ public class {{.Type}} {
this.Contract.call(opts, results, "{{.Original.Name}}", args); this.Contract.call(opts, results, "{{.Original.Name}}", args);
{{if gt (len .Normalized.Outputs) 1}} {{if gt (len .Normalized.Outputs) 1}}
{{capitalise .Normalized.Name}}Results result = new {{capitalise .Normalized.Name}}Results(); {{capitalise .Normalized.Name}}Results result = new {{capitalise .Normalized.Name}}Results();
{{range $index, $item := .Normalized.Outputs}}result.{{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}} = results.get({{$index}}).get{{namedtype (bindtype .Type) .Type}}(); {{range $index, $item := .Normalized.Outputs}}result.{{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}} = results.get({{$index}}).get{{namedtype (bindtype .Type $structs) .Type}}();
{{end}} {{end}}
return result; return result;
{{else}}{{range .Normalized.Outputs}}return results.get(0).get{{namedtype (bindtype .Type) .Type}}();{{end}} {{else}}{{range .Normalized.Outputs}}return results.get(0).get{{namedtype (bindtype .Type $structs) .Type}}();{{end}}
{{end}} {{end}}
} }
{{end}} {{end}}
...@@ -564,9 +590,9 @@ public class {{.Type}} { ...@@ -564,9 +590,9 @@ public class {{.Type}} {
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}. // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
// //
// Solidity: {{.Original.String}} // Solidity: {{.Original.String}}
public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception { public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception {
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}}); Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
{{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); {{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}});
{{end}} {{end}}
return this.Contract.transact(opts, "{{.Original.Name}}" , args); return this.Contract.transact(opts, "{{.Original.Name}}" , args);
} }
......
...@@ -23,9 +23,13 @@ import ( ...@@ -23,9 +23,13 @@ import (
const methoddata = ` const methoddata = `
[ [
{ "type" : "function", "name" : "balance", "constant" : true }, {"type": "function", "name": "balance", "constant": true },
{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }, {"type": "function", "name": "send", "constant": false, "inputs": [{ "name": "amount", "type": "uint256" }]},
{ "type" : "function", "name" : "transfer", "constant" : false, "inputs" : [ { "name" : "from", "type" : "address" }, { "name" : "to", "type" : "address" }, { "name" : "value", "type" : "uint256" } ], "outputs" : [ { "name" : "success", "type" : "bool" } ] } {"type": "function", "name": "transfer", "constant": false, "inputs": [{"name": "from", "type": "address"}, {"name": "to", "type": "address"}, {"name": "value", "type": "uint256"}], "outputs": [{"name": "success", "type": "bool"}]},
{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple"}],"name":"tuple","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},
{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[]"}],"name":"tupleSlice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},
{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[5]"}],"name":"tupleArray","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},
{"constant":false,"inputs":[{"components":[{"name":"x","type":"uint256"},{"name":"y","type":"uint256"}],"name":"a","type":"tuple[5][]"}],"name":"complexTuple","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}
]` ]`
func TestMethodString(t *testing.T) { func TestMethodString(t *testing.T) {
...@@ -45,6 +49,22 @@ func TestMethodString(t *testing.T) { ...@@ -45,6 +49,22 @@ func TestMethodString(t *testing.T) {
method: "transfer", method: "transfer",
expectation: "function transfer(address from, address to, uint256 value) returns(bool success)", expectation: "function transfer(address from, address to, uint256 value) returns(bool success)",
}, },
{
method: "tuple",
expectation: "function tuple((uint256,uint256) a) returns()",
},
{
method: "tupleArray",
expectation: "function tupleArray((uint256,uint256)[5] a) returns()",
},
{
method: "tupleSlice",
expectation: "function tupleSlice((uint256,uint256)[] a) returns()",
},
{
method: "complexTuple",
expectation: "function complexTuple((uint256,uint256)[5][] a) returns()",
},
} }
abi, err := JSON(strings.NewReader(methoddata)) abi, err := JSON(strings.NewReader(methoddata))
...@@ -59,3 +79,50 @@ func TestMethodString(t *testing.T) { ...@@ -59,3 +79,50 @@ func TestMethodString(t *testing.T) {
} }
} }
} }
func TestMethodSig(t *testing.T) {
var cases = []struct {
method string
expect string
}{
{
method: "balance",
expect: "balance()",
},
{
method: "send",
expect: "send(uint256)",
},
{
method: "transfer",
expect: "transfer(address,address,uint256)",
},
{
method: "tuple",
expect: "tuple((uint256,uint256))",
},
{
method: "tupleArray",
expect: "tupleArray((uint256,uint256)[5])",
},
{
method: "tupleSlice",
expect: "tupleSlice((uint256,uint256)[])",
},
{
method: "complexTuple",
expect: "complexTuple((uint256,uint256)[5][])",
},
}
abi, err := JSON(strings.NewReader(methoddata))
if err != nil {
t.Fatal(err)
}
for _, test := range cases {
got := abi.Methods[test.method].Sig()
if got != test.expect {
t.Errorf("expected string to be %s, got %s", test.expect, got)
}
}
}
...@@ -31,6 +31,14 @@ func indirect(v reflect.Value) reflect.Value { ...@@ -31,6 +31,14 @@ func indirect(v reflect.Value) reflect.Value {
return v return v
} }
// indirectInterfaceOrPtr recursively dereferences the value until value is not interface.
func indirectInterfaceOrPtr(v reflect.Value) reflect.Value {
if (v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr) && v.Elem().IsValid() {
return indirect(v.Elem())
}
return v
}
// reflectIntKind returns the reflect using the given size and // reflectIntKind returns the reflect using the given size and
// unsignedness. // unsignedness.
func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) { func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) {
......
...@@ -68,7 +68,6 @@ func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) { ...@@ -68,7 +68,6 @@ func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) {
if strings.Count(t, "[") != strings.Count(t, "]") { if strings.Count(t, "[") != strings.Count(t, "]") {
return Type{}, fmt.Errorf("invalid arg type in abi") return Type{}, fmt.Errorf("invalid arg type in abi")
} }
typ.stringKind = t typ.stringKind = t
// if there are brackets, get ready to go into slice/array mode and // if there are brackets, get ready to go into slice/array mode and
...@@ -92,9 +91,7 @@ func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) { ...@@ -92,9 +91,7 @@ func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) {
typ.Kind = reflect.Slice typ.Kind = reflect.Slice
typ.Elem = &embeddedType typ.Elem = &embeddedType
typ.Type = reflect.SliceOf(embeddedType.Type) typ.Type = reflect.SliceOf(embeddedType.Type)
if embeddedType.T == TupleTy { typ.stringKind = embeddedType.stringKind + sliced
typ.stringKind = embeddedType.stringKind + sliced
}
} else if len(intz) == 1 { } else if len(intz) == 1 {
// is a array // is a array
typ.T = ArrayTy typ.T = ArrayTy
...@@ -105,9 +102,7 @@ func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) { ...@@ -105,9 +102,7 @@ func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) {
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
} }
typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
if embeddedType.T == TupleTy { typ.stringKind = embeddedType.stringKind + sliced
typ.stringKind = embeddedType.stringKind + sliced
}
} else { } else {
return Type{}, fmt.Errorf("invalid formatting of array type") return Type{}, fmt.Errorf("invalid formatting of array type")
} }
......
...@@ -965,25 +965,21 @@ func TestUnpackTuple(t *testing.T) { ...@@ -965,25 +965,21 @@ func TestUnpackTuple(t *testing.T) {
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // ret[a] = 1 buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // ret[a] = 1
buff.Write(common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) // ret[b] = -1 buff.Write(common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) // ret[b] = -1
// If the result is single tuple, use struct as return value container directly.
v := struct { v := struct {
Ret struct {
A *big.Int
B *big.Int
}
}{Ret: struct {
A *big.Int A *big.Int
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.Unpack(&v, "tuple", buff.Bytes())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} else { } else {
if v.Ret.A.Cmp(big.NewInt(1)) != 0 { if v.A.Cmp(big.NewInt(1)) != 0 {
t.Errorf("unexpected value unpacked: want %x, got %x", 1, v.Ret.A) t.Errorf("unexpected value unpacked: want %x, got %x", 1, v.A)
} }
if v.Ret.B.Cmp(big.NewInt(-1)) != 0 { if v.B.Cmp(big.NewInt(-1)) != 0 {
t.Errorf("unexpected value unpacked: want %x, got %x", v.Ret.B, -1) t.Errorf("unexpected value unpacked: want %x, got %x", v.B, -1)
} }
} }
......
...@@ -69,6 +69,8 @@ func main() { ...@@ -69,6 +69,8 @@ func main() {
lang = bind.LangGo lang = bind.LangGo
case "java": case "java":
lang = bind.LangJava lang = bind.LangJava
case "objc":
lang = bind.LangObjC
default: default:
fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", *langFlag) fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", *langFlag)
os.Exit(-1) os.Exit(-1)
......
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