github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/accounts/abi/bind/topics.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package bind
    13  
    14  import (
    15  	"errors"
    16  	"fmt"
    17  	"math/big"
    18  	"reflect"
    19  
    20  	"github.com/Sberex/go-sberex/accounts/abi"
    21  	"github.com/Sberex/go-sberex/common"
    22  	"github.com/Sberex/go-sberex/crypto"
    23  )
    24  
    25  // makeTopics converts a filter query argument list into a filter topic set.
    26  func makeTopics(query ...[]interface{}) ([][]common.Hash, error) {
    27  	topics := make([][]common.Hash, len(query))
    28  	for i, filter := range query {
    29  		for _, rule := range filter {
    30  			var topic common.Hash
    31  
    32  			// Try to generate the topic based on simple types
    33  			switch rule := rule.(type) {
    34  			case common.Hash:
    35  				copy(topic[:], rule[:])
    36  			case common.Address:
    37  				copy(topic[common.HashLength-common.AddressLength:], rule[:])
    38  			case *big.Int:
    39  				blob := rule.Bytes()
    40  				copy(topic[common.HashLength-len(blob):], blob)
    41  			case bool:
    42  				if rule {
    43  					topic[common.HashLength-1] = 1
    44  				}
    45  			case int8:
    46  				blob := big.NewInt(int64(rule)).Bytes()
    47  				copy(topic[common.HashLength-len(blob):], blob)
    48  			case int16:
    49  				blob := big.NewInt(int64(rule)).Bytes()
    50  				copy(topic[common.HashLength-len(blob):], blob)
    51  			case int32:
    52  				blob := big.NewInt(int64(rule)).Bytes()
    53  				copy(topic[common.HashLength-len(blob):], blob)
    54  			case int64:
    55  				blob := big.NewInt(rule).Bytes()
    56  				copy(topic[common.HashLength-len(blob):], blob)
    57  			case uint8:
    58  				blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
    59  				copy(topic[common.HashLength-len(blob):], blob)
    60  			case uint16:
    61  				blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
    62  				copy(topic[common.HashLength-len(blob):], blob)
    63  			case uint32:
    64  				blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
    65  				copy(topic[common.HashLength-len(blob):], blob)
    66  			case uint64:
    67  				blob := new(big.Int).SetUint64(rule).Bytes()
    68  				copy(topic[common.HashLength-len(blob):], blob)
    69  			case string:
    70  				hash := crypto.Keccak256Hash([]byte(rule))
    71  				copy(topic[:], hash[:])
    72  			case []byte:
    73  				hash := crypto.Keccak256Hash(rule)
    74  				copy(topic[:], hash[:])
    75  
    76  			default:
    77  				// Attempt to generate the topic from funky types
    78  				val := reflect.ValueOf(rule)
    79  
    80  				switch {
    81  				case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8:
    82  					reflect.Copy(reflect.ValueOf(topic[common.HashLength-val.Len():]), val)
    83  
    84  				default:
    85  					return nil, fmt.Errorf("unsupported indexed type: %T", rule)
    86  				}
    87  			}
    88  			topics[i] = append(topics[i], topic)
    89  		}
    90  	}
    91  	return topics, nil
    92  }
    93  
    94  // Big batch of reflect types for topic reconstruction.
    95  var (
    96  	reflectHash    = reflect.TypeOf(common.Hash{})
    97  	reflectAddress = reflect.TypeOf(common.Address{})
    98  	reflectBigInt  = reflect.TypeOf(new(big.Int))
    99  )
   100  
   101  // parseTopics converts the indexed topic fields into actual log field values.
   102  //
   103  // Note, dynamic types cannot be reconstructed since they get mapped to Keccak256
   104  // hashes as the topic value!
   105  func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) error {
   106  	// Sanity check that the fields and topics match up
   107  	if len(fields) != len(topics) {
   108  		return errors.New("topic/field count mismatch")
   109  	}
   110  	// Iterate over all the fields and reconstruct them from topics
   111  	for _, arg := range fields {
   112  		if !arg.Indexed {
   113  			return errors.New("non-indexed field in topic reconstruction")
   114  		}
   115  		field := reflect.ValueOf(out).Elem().FieldByName(capitalise(arg.Name))
   116  
   117  		// Try to parse the topic back into the fields based on primitive types
   118  		switch field.Kind() {
   119  		case reflect.Bool:
   120  			if topics[0][common.HashLength-1] == 1 {
   121  				field.Set(reflect.ValueOf(true))
   122  			}
   123  		case reflect.Int8:
   124  			num := new(big.Int).SetBytes(topics[0][:])
   125  			field.Set(reflect.ValueOf(int8(num.Int64())))
   126  
   127  		case reflect.Int16:
   128  			num := new(big.Int).SetBytes(topics[0][:])
   129  			field.Set(reflect.ValueOf(int16(num.Int64())))
   130  
   131  		case reflect.Int32:
   132  			num := new(big.Int).SetBytes(topics[0][:])
   133  			field.Set(reflect.ValueOf(int32(num.Int64())))
   134  
   135  		case reflect.Int64:
   136  			num := new(big.Int).SetBytes(topics[0][:])
   137  			field.Set(reflect.ValueOf(num.Int64()))
   138  
   139  		case reflect.Uint8:
   140  			num := new(big.Int).SetBytes(topics[0][:])
   141  			field.Set(reflect.ValueOf(uint8(num.Uint64())))
   142  
   143  		case reflect.Uint16:
   144  			num := new(big.Int).SetBytes(topics[0][:])
   145  			field.Set(reflect.ValueOf(uint16(num.Uint64())))
   146  
   147  		case reflect.Uint32:
   148  			num := new(big.Int).SetBytes(topics[0][:])
   149  			field.Set(reflect.ValueOf(uint32(num.Uint64())))
   150  
   151  		case reflect.Uint64:
   152  			num := new(big.Int).SetBytes(topics[0][:])
   153  			field.Set(reflect.ValueOf(num.Uint64()))
   154  
   155  		default:
   156  			// Ran out of plain primitive types, try custom types
   157  			switch field.Type() {
   158  			case reflectHash: // Also covers all dynamic types
   159  				field.Set(reflect.ValueOf(topics[0]))
   160  
   161  			case reflectAddress:
   162  				var addr common.Address
   163  				copy(addr[:], topics[0][common.HashLength-common.AddressLength:])
   164  				field.Set(reflect.ValueOf(addr))
   165  
   166  			case reflectBigInt:
   167  				num := new(big.Int).SetBytes(topics[0][:])
   168  				field.Set(reflect.ValueOf(num))
   169  
   170  			default:
   171  				// Ran out of custom types, try the crazies
   172  				switch {
   173  				case arg.Type.T == abi.FixedBytesTy:
   174  					reflect.Copy(field, reflect.ValueOf(topics[0][common.HashLength-arg.Type.Size:]))
   175  
   176  				default:
   177  					return fmt.Errorf("unsupported indexed type: %v", arg.Type)
   178  				}
   179  			}
   180  		}
   181  		topics = topics[1:]
   182  	}
   183  	return nil
   184  }