diff options
author | RJ Catalano <catalanor0220@gmail.com> | 2017-10-17 19:07:08 +0800 |
---|---|---|
committer | Felix Lange <fjl@users.noreply.github.com> | 2017-10-17 19:07:08 +0800 |
commit | dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d (patch) | |
tree | 7e4713ca276ac1a2cef7cd2dd19dcf8c6fd1f6c4 /accounts/abi/abi.go | |
parent | e9295163aa25479e817efee4aac23eaeb7554bba (diff) | |
download | go-tangerine-dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d.tar go-tangerine-dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d.tar.gz go-tangerine-dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d.tar.bz2 go-tangerine-dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d.tar.lz go-tangerine-dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d.tar.xz go-tangerine-dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d.tar.zst go-tangerine-dec8bba9d4c5fcb3dd7e51f0f794b3e895c7f52d.zip |
accounts/abi: improve type handling, add event support (#14743)
Diffstat (limited to 'accounts/abi/abi.go')
-rw-r--r-- | accounts/abi/abi.go | 115 |
1 files changed, 16 insertions, 99 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 2a06d474b..205dc300b 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -20,10 +20,6 @@ import ( "encoding/json" "fmt" "io" - "reflect" - "strings" - - "github.com/ethereum/go-ethereum/common" ) // The ABI holds information about a contract's context and available @@ -76,106 +72,27 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { return append(method.Id(), arguments...), nil } -// these variable are used to determine certain types during type assertion for -// assignment. -var ( - r_interSlice = reflect.TypeOf([]interface{}{}) - r_hash = reflect.TypeOf(common.Hash{}) - r_bytes = reflect.TypeOf([]byte{}) - r_byte = reflect.TypeOf(byte(0)) -) - // Unpack output in v according to the abi specification -func (abi ABI) Unpack(v interface{}, name string, output []byte) error { - var method = abi.Methods[name] - - if len(output) == 0 { - return fmt.Errorf("abi: unmarshalling empty output") - } - - // make sure the passed value is a pointer - valueOf := reflect.ValueOf(v) - if reflect.Ptr != valueOf.Kind() { - return fmt.Errorf("abi: Unpack(non-pointer %T)", v) +func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { + if err = bytesAreProper(output); err != nil { + return err } - - var ( - value = valueOf.Elem() - typ = value.Type() - ) - - if len(method.Outputs) > 1 { - switch value.Kind() { - // struct will match named return values to the struct's field - // names - case reflect.Struct: - for i := 0; i < len(method.Outputs); i++ { - marshalledValue, err := toGoType(i, method.Outputs[i], output) - if err != nil { - return err - } - reflectValue := reflect.ValueOf(marshalledValue) - - 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 { - return err - } - } - } - } - case reflect.Slice: - if !value.Type().AssignableTo(r_interSlice) { - return fmt.Errorf("abi: cannot marshal tuple in to slice %T (only []interface{} is supported)", v) - } - - // if the slice already contains values, set those instead of the interface slice itself. - if value.Len() > 0 { - if len(method.Outputs) > value.Len() { - return fmt.Errorf("abi: cannot marshal in to slices of unequal size (require: %v, got: %v)", len(method.Outputs), value.Len()) - } - - for i := 0; i < len(method.Outputs); i++ { - marshalledValue, err := toGoType(i, method.Outputs[i], output) - if err != nil { - return err - } - reflectValue := reflect.ValueOf(marshalledValue) - if err := set(value.Index(i).Elem(), reflectValue, method.Outputs[i]); err != nil { - return err - } - } - return nil - } - - // create a new slice and start appending the unmarshalled - // values to the new interface slice. - z := reflect.MakeSlice(typ, 0, len(method.Outputs)) - for i := 0; i < len(method.Outputs); i++ { - marshalledValue, err := toGoType(i, method.Outputs[i], output) - if err != nil { - return err - } - z = reflect.Append(z, reflect.ValueOf(marshalledValue)) - } - value.Set(z) - default: - return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ) - } - + // since there can't be naming collisions with contracts and events, + // we need to decide whether we're calling a method or an event + var unpack unpacker + if method, ok := abi.Methods[name]; ok { + unpack = method + } else if event, ok := abi.Events[name]; ok { + unpack = event } else { - marshalledValue, err := toGoType(0, method.Outputs[0], output) - if err != nil { - return err - } - if err := set(value, reflect.ValueOf(marshalledValue), method.Outputs[0]); err != nil { - return err - } + return fmt.Errorf("abi: could not locate named method or event.") } - return nil + // requires a struct to unpack into for a tuple return... + if unpack.isTupleReturn() { + return unpack.tupleUnpack(v, output) + } + return unpack.singleUnpack(v, output) } func (abi *ABI) UnmarshalJSON(data []byte) error { |