github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/accounts/abi/bind/topics.go (about)

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