func (e *Event) LogIndex() uint {
	return e.logPayload.Index
}
LogIndex is the log index position in the block
package model  
import (
	"fmt"
	"math/big"
	"reflect"
	"strconv"
	"strings"
	log "github.com/golang/glog"
	"github.com/pkg/errors"
	specs "github.com/joincivil/civil-events-crawler/pkg/contractspecs"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/rlp"
	"github.com/fatih/structs"
)
const (
	Filterer RetrievalMethod = iota
	Watcher
)
type RetrievalMethod int
func ReturnEventFromABI(_abi abi.ABI, eventType string) (abi.Event, error) {
	event, ok := _abi.Events[eventType]
	if !ok {
		event, ok = _abi.Events[fmt.Sprintf("_%s", eventType)]
		if !ok {
			return abi.Event{}, errors.Errorf("no event type %v in contract", eventType)
		}
	}
	return event, nil
}
func NewEventFromContractEvent(eventType string, contractName string, contractAddress common.Address,
	eventData interface{}, timestamp int64, retrievalMethod RetrievalMethod) (*Event, error) {
	event := &Event{}
	payload := NewEventPayload(eventData)
	logPayload, err := extractRawFieldFromEvent(payload)
	if err != nil {
		return event, err
	}
	eventPayload, err := extractFieldsFromEvent(payload, eventData, eventType, contractName)
	if err != nil {
		return event, err
	}
	event, err = NewEvent(eventType, contractName, contractAddress, timestamp, retrievalMethod, eventPayload, logPayload)
	return event, err
}
func NewEvent(eventType string, contractName string, contractAddress common.Address, timestamp int64,
	retrievalMethod RetrievalMethod, eventPayload map[string]interface{}, logPayload *types.Log) (*Event, error) {
	event := &Event{}
	event.eventType = eventType
	event.contractName = contractName
	event.contractAddress = contractAddress
	event.eventPayload = eventPayload
	event.logPayload = logPayload
	event.timestamp = timestamp
	event.retrievalMethod = retrievalMethod
	event.eventHash = event.hashEvent()
	return event, nil
}
type Event struct {
	eventHash string
	eventType string
	contractAddress common.Address
	contractName string
	timestamp int64
	retrievalMethod RetrievalMethod
	eventPayload map[string]interface{}
	logPayload *types.Log
}
func extractFieldsFromEvent(payload *EventPayload, eventData interface{}, eventType string, contractName string) (map[string]interface{}, error) {
	eventPayload := make(map[string]interface{}, len(payload.data.Fields()))
	_abi, err := AbiJSON(contractName)
	if err != nil {
		return eventPayload, err
	}
	abiEvent, err := ReturnEventFromABI(_abi, eventType)
	if err != nil {
		return eventPayload, err
	}
	for _, input := range abiEvent.Inputs {
		eventFieldName := strings.Title(input.Name)
		eventField, ok := payload.Value(eventFieldName)
		if !ok {
			return eventPayload, errors.New("can't get event name in event")
		}
		switch input.Type.String() {
		case "address":
			addressVal, ok := eventField.Address()
			if !ok {
				return eventPayload, errors.New("could not convert to common.address type")
			}
			eventPayload[eventFieldName] = addressVal
		case "uint256":
			bigintVal, ok := eventField.BigInt()
			if !ok {
				return eventPayload, errors.New("could not convert to big.int")
			}
			eventPayload[eventFieldName] = bigintVal
		case "string":
			stringVal, ok := eventField.String()
			if !ok {
				return eventPayload, errors.New("could not convert to string")
			}
			eventPayload[eventFieldName] = stringVal
		case "bytes32":
			bytesVal, ok := eventField.Bytes32()
			if !ok {
				return eventPayload, errors.New("Could not convert to bytes32")
			}
			eventPayload[eventFieldName] = bytesVal
		default:
			return eventPayload, errors.Errorf("unsupported type encountered when parsing %v field for %v event %v",
				input.Type.String(), contractName, eventType)
		}
	}
	return eventPayload, nil
}
func AbiJSON(contractName string) (abi.ABI, error) {
	contractType, ok := specs.NameToContractTypes.GetFromContractName(contractName)
	if !ok {
		return abi.ABI{}, errors.New("contract name does not exist")
	}
	contractSpecs, ok := specs.ContractTypeToSpecs.Get(contractType)
	if !ok {
		return abi.ABI{}, errors.New("invalid contract type")
	}
	_abi, err := abi.JSON(strings.NewReader(contractSpecs.AbiStr()))
	if err != nil {
		return abi.ABI{}, errors.New("cannot parse abi string")
	}
	return _abi, nil
}
func extractRawFieldFromEvent(payload *EventPayload) (*types.Log, error) {
	rawPayload, ok := payload.Value("Raw")
	if !ok {
		return &types.Log{}, errors.New("can't get raw value for event")
	}
	logPayload, ok := rawPayload.Log()
	if !ok {
		return &types.Log{}, errors.New("can't get log field of raw value for event")
	}
	return logPayload, nil
}
func (e *Event) hashEvent() string {
	logIndex := int(e.logPayload.Index)
	txHash := e.logPayload.TxHash.Hex()
	eventBytes, err := rlp.EncodeToBytes([]interface{}{
		e.contractAddress.Hex(),
		e.eventType,  
		strconv.Itoa(logIndex),
		txHash,
	})
	if err != nil {
		log.Errorf("Error encoding to bytes: err: %v", err)
		return ""
	}
	h := crypto.Keccak256Hash(eventBytes)
	return h.Hex()
}
func (e *Event) Hash() string {
	return e.eventHash
}
func (e *Event) EventType() string {
	return e.eventType
}
func (e *Event) ContractAddress() common.Address {
	return e.contractAddress
}
func (e *Event) Timestamp() int64 {
	return e.timestamp
}
func (e *Event) SetTimestamp(ts int64) {
	e.timestamp = ts
}
func (e *Event) RetrievalMethod() RetrievalMethod {
	return e.retrievalMethod
}
func (e *Event) EventPayload() map[string]interface{} {
	return e.eventPayload
}
func (e *Event) ContractName() string {
	return e.contractName
}
func (e *Event) LogPayload() *types.Log {
	logPayloadCopy := &types.Log{
		Address:     e.logPayload.Address,
		Topics:      e.logPayload.Topics,
		Data:        e.logPayload.Data,
		BlockNumber: e.logPayload.BlockNumber,
		TxHash:      e.logPayload.TxHash,
		TxIndex:     e.logPayload.TxIndex,
		BlockHash:   e.logPayload.BlockHash,
		Index:       e.logPayload.Index,
		Removed:     e.logPayload.Removed}
	return logPayloadCopy
}
func (e *Event) LogTopics() []common.Hash {
	return e.logPayload.Topics
}
func (e *Event) LogData() []byte {
	return e.logPayload.Data
}
func (e *Event) BlockNumber() uint64 {
	return e.logPayload.BlockNumber
}
func (e *Event) TxHash() common.Hash {
	return e.logPayload.TxHash
}
func (e *Event) TxIndex() uint {
	return e.logPayload.TxIndex
}
func (e *Event) BlockHash() common.Hash {
	return e.logPayload.BlockHash
}