diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 02b4fa472c..6170c7062c 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -89,7 +89,7 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { } else if event, ok := abi.Events[name]; ok { unpack = event } else { - return fmt.Errorf("abi: could not locate named method or event.") + return fmt.Errorf("abi: could not locate named method or event") } // requires a struct to unpack into for a tuple return... @@ -99,6 +99,7 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { return unpack.singleUnpack(v, output) } +// UnmarshalJSON implements json.Unmarshaler interface func (abi *ABI) UnmarshalJSON(data []byte) error { var fields []struct { Type string diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index cd856061ee..59bcc117ce 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -29,6 +29,7 @@ type Argument struct { Indexed bool // indexed is only used by events } +// UnmarshalJSON implements json.Unmarshaler interface func (a *Argument) UnmarshalJSON(data []byte) error { var extarg struct { Name string diff --git a/accounts/abi/event.go b/accounts/abi/event.go index b67bc96a86..3d4e0b63ce 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -120,7 +120,7 @@ func (e Event) singleUnpack(v interface{}, output []byte) error { } if e.Inputs[0].Indexed { - return fmt.Errorf("abi: attempting to unpack indexed variable into element.") + return fmt.Errorf("abi: attempting to unpack indexed variable into element") } value := valueOf.Elem() @@ -129,8 +129,5 @@ func (e Event) singleUnpack(v interface{}, output []byte) error { if err != nil { return err } - if err := set(value, reflect.ValueOf(marshalledValue), e.Inputs[0]); err != nil { - return err - } - return nil + return set(value, reflect.ValueOf(marshalledValue), e.Inputs[0]) } diff --git a/accounts/abi/method.go b/accounts/abi/method.go index ee79b51cbe..0df7f618ee 100644 --- a/accounts/abi/method.go +++ b/accounts/abi/method.go @@ -24,7 +24,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -// Callable method given a `Name` and whether the method is a constant. +// Method represents a callable given a `Name` and whether the method is a constant. // If the method is `Const` no transaction needs to be created for this // particular Method call. It can easily be simulated using a local VM. // For example a `Balance()` method only needs to retrieve something @@ -91,7 +91,7 @@ func (method Method) pack(args ...interface{}) ([]byte, error) { // unpacks a method return tuple into a struct of corresponding go types // // Unpacking can be done into a struct or a slice/array. -func (method Method) tupleUnpack(v interface{}, output []byte) error { +func (method Method) tupleUnpack(v interface{}, outputSlice []byte) error { // make sure the passed value is a pointer valueOf := reflect.ValueOf(v) if reflect.Ptr != valueOf.Kind() { @@ -108,16 +108,15 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error { } j := 0 - for i := 0; i < len(method.Outputs); i++ { - toUnpack := method.Outputs[i] - marshalledValue, err := toGoType((i+j)*32, toUnpack.Type, output) + for i, output := range method.Outputs { + marshalledValue, err := toGoType((i+j)*32, ouptut.Type, outputSlice) if err != nil { return err } - if toUnpack.Type.T == ArrayTy { + if output.Type.T == ArrayTy { // combined index ('i' + 'j') need to be adjusted only by size of array, thus // we need to decrement 'j' because 'i' was incremented - j += toUnpack.Type.Size - 1 + j += output.Type.Size - 1 } reflectValue := reflect.ValueOf(marshalledValue) @@ -126,8 +125,8 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error { for j := 0; j < typ.NumField(); j++ { field := typ.Field(j) // TODO read tags: `abi:"fieldName"` - if field.Name == strings.ToUpper(method.Outputs[i].Name[:1])+method.Outputs[i].Name[1:] { - if err := set(value.Field(j), reflectValue, method.Outputs[i]); err != nil { + if field.Name == strings.ToUpper(output.Name[:1])+output.Name[1:] { + if err := set(value.Field(j), reflectValue, output); err != nil { return err } } @@ -137,7 +136,7 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error { if err := requireAssignable(v, reflectValue); err != nil { return err } - if err := set(v.Elem(), reflectValue, method.Outputs[i]); err != nil { + if err := set(v.Elem(), reflectValue, output); err != nil { return err } } @@ -160,10 +159,7 @@ func (method Method) singleUnpack(v interface{}, output []byte) error { if err != nil { return err } - if err := set(value, reflect.ValueOf(marshalledValue), method.Outputs[0]); err != nil { - return err - } - return nil + return set(value, reflect.ValueOf(marshalledValue), method.Outputs[0]) } // Sig returns the methods string signature according to the ABI spec. @@ -173,35 +169,35 @@ func (method Method) singleUnpack(v interface{}, output []byte) error { // function foo(uint32 a, int b) = "foo(uint32,int256)" // // Please note that "int" is substitute for its canonical representation "int256" -func (m Method) Sig() string { - types := make([]string, len(m.Inputs)) +func (method Method) Sig() string { + types := make([]string, len(method.Inputs)) i := 0 - for _, input := range m.Inputs { + for _, input := range method.Inputs { types[i] = input.Type.String() i++ } - return fmt.Sprintf("%v(%v)", m.Name, strings.Join(types, ",")) + return fmt.Sprintf("%v(%v)", method.Name, strings.Join(types, ",")) } -func (m Method) String() string { - inputs := make([]string, len(m.Inputs)) - for i, input := range m.Inputs { +func (method Method) String() string { + inputs := make([]string, len(method.Inputs)) + for i, input := range method.Inputs { inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) } - outputs := make([]string, len(m.Outputs)) - for i, output := range m.Outputs { + outputs := make([]string, len(method.Outputs)) + for i, output := range method.Outputs { if len(output.Name) > 0 { outputs[i] = fmt.Sprintf("%v ", output.Name) } outputs[i] += output.Type.String() } constant := "" - if m.Const { + if method.Const { constant = "constant " } - return fmt.Sprintf("function %v(%v) %sreturns(%v)", m.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) + return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) } -func (m Method) Id() []byte { - return crypto.Keccak256([]byte(m.Sig()))[:4] +func (method Method) Id() []byte { + return crypto.Keccak256([]byte(method.Sig()))[:4] } diff --git a/accounts/abi/pack.go b/accounts/abi/pack.go index 072e805368..36c58265bd 100644 --- a/accounts/abi/pack.go +++ b/accounts/abi/pack.go @@ -48,9 +48,8 @@ func packElement(t Type, reflectValue reflect.Value) []byte { case BoolTy: if reflectValue.Bool() { return math.PaddedBigBytes(common.Big1, 32) - } else { - return math.PaddedBigBytes(common.Big0, 32) } + return math.PaddedBigBytes(common.Big0, 32) case BytesTy: if reflectValue.Kind() == reflect.Array { reflectValue = mustArrayToByteSlice(reflectValue) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index fba10b96d2..a1f13ffa29 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -24,6 +24,7 @@ import ( "strings" ) +// Type enumerator const ( IntTy byte = iota UintTy @@ -100,68 +101,65 @@ func NewType(t string) (typ Type, err error) { return Type{}, fmt.Errorf("invalid formatting of array type") } return typ, err + } + // parse the type and size of the abi-type. + parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0] + // varSize is the size of the variable + var varSize int + if len(parsedType[3]) > 0 { + var err error + varSize, err = strconv.Atoi(parsedType[2]) + if err != nil { + return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) + } } else { - // parse the type and size of the abi-type. - parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0] - // varSize is the size of the variable - var varSize int - if len(parsedType[3]) > 0 { - var err error - varSize, err = strconv.Atoi(parsedType[2]) - if err != nil { - return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) - } - } else { - if parsedType[0] == "uint" || parsedType[0] == "int" { - // this should fail because it means that there's something wrong with - // the abi type (the compiler should always format it to the size...always) - return Type{}, fmt.Errorf("unsupported arg type: %s", t) - } + if parsedType[0] == "uint" || parsedType[0] == "int" { + // this should fail because it means that there's something wrong with + // the abi type (the compiler should always format it to the size...always) + return Type{}, fmt.Errorf("unsupported arg type: %s", t) } - // varType is the parsed abi type - varType := parsedType[1] - - switch varType { - case "int": - typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) - typ.Size = varSize - typ.T = IntTy - case "uint": - typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) - typ.Size = varSize - typ.T = UintTy - case "bool": - typ.Kind = reflect.Bool - typ.T = BoolTy - typ.Type = reflect.TypeOf(bool(false)) - case "address": - typ.Kind = reflect.Array - typ.Type = address_t - typ.Size = 20 - typ.T = AddressTy - case "string": - typ.Kind = reflect.String - typ.Type = reflect.TypeOf("") - typ.T = StringTy - case "bytes": - if varSize == 0 { - typ.T = BytesTy - typ.Kind = reflect.Slice - typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) - } else { - typ.T = FixedBytesTy - typ.Kind = reflect.Array - typ.Size = varSize - typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) - } - case "function": + } + // varType is the parsed abi type + switch varType := parsedType[1]; varType { + case "int": + typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) + typ.Size = varSize + typ.T = IntTy + case "uint": + typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) + typ.Size = varSize + typ.T = UintTy + case "bool": + typ.Kind = reflect.Bool + typ.T = BoolTy + typ.Type = reflect.TypeOf(bool(false)) + case "address": + typ.Kind = reflect.Array + typ.Type = address_t + typ.Size = 20 + typ.T = AddressTy + case "string": + typ.Kind = reflect.String + typ.Type = reflect.TypeOf("") + typ.T = StringTy + case "bytes": + if varSize == 0 { + typ.T = BytesTy + typ.Kind = reflect.Slice + typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) + } else { + typ.T = FixedBytesTy typ.Kind = reflect.Array - typ.T = FunctionTy - typ.Size = 24 - typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) - default: - return Type{}, fmt.Errorf("unsupported arg type: %s", t) + typ.Size = varSize + typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) } + case "function": + typ.Kind = reflect.Array + typ.T = FunctionTy + typ.Size = 24 + typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) + default: + return Type{}, fmt.Errorf("unsupported arg type: %s", t) } return diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 5adb91ff75..372a86c869 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -79,7 +79,7 @@ func readBool(word []byte) (bool, error) { // This enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes) func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { if t.T != FunctionTy { - return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array.") + return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array") } if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { err = fmt.Errorf("abi: got improperly encoded function type, got %v", word) @@ -92,7 +92,7 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { // through reflection, creates a fixed array to be read from func readFixedBytes(t Type, word []byte) (interface{}, error) { if t.T != FixedBytesTy { - return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array.") + return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") } // convert array := reflect.New(t.Type).Elem()