github.com/tuotoo/go-ethereum@v1.7.4-0.20171121184211-049797d40a24/accounts/abi/event.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package abi 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/crypto" 26 ) 27 28 // Event is an event potentially triggered by the EVM's LOG mechanism. The Event 29 // holds type information (inputs) about the yielded output. Anonymous events 30 // don't get the signature canonical representation as the first LOG topic. 31 type Event struct { 32 Name string 33 Anonymous bool 34 Inputs []Argument 35 } 36 37 // Id returns the canonical representation of the event's signature used by the 38 // abi definition to identify event names and types. 39 func (e Event) Id() common.Hash { 40 types := make([]string, len(e.Inputs)) 41 i := 0 42 for _, input := range e.Inputs { 43 types[i] = input.Type.String() 44 i++ 45 } 46 return common.BytesToHash(crypto.Keccak256([]byte(fmt.Sprintf("%v(%v)", e.Name, strings.Join(types, ","))))) 47 } 48 49 // unpacks an event return tuple into a struct of corresponding go types 50 // 51 // Unpacking can be done into a struct or a slice/array. 52 func (e Event) tupleUnpack(v interface{}, output []byte) error { 53 // make sure the passed value is a pointer 54 valueOf := reflect.ValueOf(v) 55 if reflect.Ptr != valueOf.Kind() { 56 return fmt.Errorf("abi: Unpack(non-pointer %T)", v) 57 } 58 59 var ( 60 value = valueOf.Elem() 61 typ = value.Type() 62 ) 63 64 if value.Kind() != reflect.Struct { 65 return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ) 66 } 67 68 j := 0 69 for i := 0; i < len(e.Inputs); i++ { 70 input := e.Inputs[i] 71 if input.Indexed { 72 // can't read, continue 73 continue 74 } else if input.Type.T == ArrayTy { 75 // need to move this up because they read sequentially 76 j += input.Type.Size 77 } 78 marshalledValue, err := toGoType((i+j)*32, input.Type, output) 79 if err != nil { 80 return err 81 } 82 reflectValue := reflect.ValueOf(marshalledValue) 83 84 switch value.Kind() { 85 case reflect.Struct: 86 for j := 0; j < typ.NumField(); j++ { 87 field := typ.Field(j) 88 // TODO read tags: `abi:"fieldName"` 89 if field.Name == strings.ToUpper(e.Inputs[i].Name[:1])+e.Inputs[i].Name[1:] { 90 if err := set(value.Field(j), reflectValue, e.Inputs[i]); err != nil { 91 return err 92 } 93 } 94 } 95 case reflect.Slice, reflect.Array: 96 if value.Len() < i { 97 return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(e.Inputs), value.Len()) 98 } 99 v := value.Index(i) 100 if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface { 101 return fmt.Errorf("abi: cannot unmarshal %v in to %v", v.Type(), reflectValue.Type()) 102 } 103 reflectValue := reflect.ValueOf(marshalledValue) 104 if err := set(v.Elem(), reflectValue, e.Inputs[i]); err != nil { 105 return err 106 } 107 default: 108 return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ) 109 } 110 } 111 return nil 112 } 113 114 func (e Event) isTupleReturn() bool { return len(e.Inputs) > 1 } 115 116 func (e Event) singleUnpack(v interface{}, output []byte) error { 117 // make sure the passed value is a pointer 118 valueOf := reflect.ValueOf(v) 119 if reflect.Ptr != valueOf.Kind() { 120 return fmt.Errorf("abi: Unpack(non-pointer %T)", v) 121 } 122 123 if e.Inputs[0].Indexed { 124 return fmt.Errorf("abi: attempting to unpack indexed variable into element.") 125 } 126 127 value := valueOf.Elem() 128 129 marshalledValue, err := toGoType(0, e.Inputs[0].Type, output) 130 if err != nil { 131 return err 132 } 133 if err := set(value, reflect.ValueOf(marshalledValue), e.Inputs[0]); err != nil { 134 return err 135 } 136 return nil 137 }