github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/rpc/get_log.go (about)

     1  package rpc
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
     8  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc/query"
     9  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    11  )
    12  
    13  // GetLogsByNumber returns the logs of a block
    14  func (conn *Connection) GetLogsByNumber(bn base.Blknum, ts base.Timestamp) ([]types.Log, error) {
    15  	if conn.StoreReadable() {
    16  		// walk.Cache_Logs
    17  		logGroup := &types.LogGroup{
    18  			BlockNumber:      bn,
    19  			TransactionIndex: base.NOPOSN,
    20  		}
    21  		if err := conn.Store.Read(logGroup, nil); err == nil {
    22  			return logGroup.Logs, nil
    23  		}
    24  	}
    25  
    26  	filter := LogFilter{
    27  		FromBlock: bn,
    28  		ToBlock:   bn,
    29  	}
    30  
    31  	if logs, err := conn.getLogsFromRpc(filter); err != nil {
    32  		return logs, err
    33  	} else {
    34  		isFinal := base.IsFinal(conn.LatestBlockTimestamp, ts)
    35  		if isFinal && conn.StoreWritable() && conn.EnabledMap[walk.Cache_Logs] {
    36  			logGroup := &types.LogGroup{
    37  				BlockNumber:      bn,
    38  				TransactionIndex: base.NOPOSN,
    39  				Logs:             logs,
    40  			}
    41  			if err = conn.Store.Write(logGroup, nil); err != nil {
    42  				logger.Warn("Failed to write logs to cache", err)
    43  			}
    44  		}
    45  		return logs, err
    46  	}
    47  }
    48  
    49  // GetLogsCountInBlock returns the number of logs in a block
    50  func (conn *Connection) GetLogsCountInBlock(bn base.Blknum, ts base.Timestamp) (uint64, error) {
    51  	if logs, err := conn.GetLogsByNumber(bn, ts); err != nil {
    52  		return 0, err
    53  	} else {
    54  		return uint64(len(logs)), nil
    55  	}
    56  }
    57  
    58  func (conn *Connection) getLogsFromRpc(filter LogFilter) ([]types.Log, error) {
    59  	p := struct {
    60  		FromBlock string   `json:"fromBlock"`
    61  		ToBlock   string   `json:"toBlock"`
    62  		Address   []string `json:"address"` // sorry for the weird conversion...
    63  		Topics    []string `json:"topics"`
    64  	}{
    65  		FromBlock: fmt.Sprintf("0x%x", filter.FromBlock),
    66  		ToBlock:   fmt.Sprintf("0x%x", filter.ToBlock),
    67  	}
    68  	for _, addr := range filter.Emitters {
    69  		p.Address = append(p.Address, addr.Hex())
    70  	}
    71  	for _, topic := range filter.Topics {
    72  		p.Topics = append(p.Topics, topic.Hex())
    73  	}
    74  
    75  	method := "eth_getLogs"
    76  	params := query.Params{p}
    77  
    78  	if logs, err := query.Query[[]types.Log](conn.Chain, method, params); err != nil {
    79  		return []types.Log{}, err
    80  
    81  	} else if logs == nil || len(*logs) == 0 {
    82  		return []types.Log{}, nil
    83  
    84  	} else {
    85  		curBlock := types.LightBlock{
    86  			BlockNumber: base.NOPOSN,
    87  			Timestamp:   base.NOPOSI,
    88  		}
    89  		for i := range *logs {
    90  			r := &(*logs)[i] // avoid a copy, don't change
    91  			if r.BlockNumber != curBlock.BlockNumber {
    92  				curBlock = types.LightBlock{
    93  					BlockNumber: (*logs)[i].BlockNumber,
    94  					Timestamp:   conn.GetBlockTimestamp(r.BlockNumber),
    95  				}
    96  			}
    97  			r.BlockNumber = curBlock.BlockNumber
    98  			r.Timestamp = curBlock.Timestamp
    99  		}
   100  
   101  		// TODO: BOGUS - avoid copy
   102  		return *logs, nil
   103  	}
   104  }
   105  
   106  type LogFilter struct {
   107  	BlockHash base.Hash      `json:"blockHash"`
   108  	Emitters  []base.Address `json:"emitters"`
   109  	FromBlock base.Blknum    `json:"fromBlock"`
   110  	ToBlock   base.Blknum    `json:"toBlock"`
   111  	Topics    []base.Hash    `json:"topics"`
   112  }
   113  
   114  func NewLogFilter(emitters []string, topics []string) *LogFilter {
   115  	logFilter := &LogFilter{}
   116  	for _, e := range emitters {
   117  		logFilter.Emitters = append(logFilter.Emitters, base.HexToAddress(e))
   118  	}
   119  	for _, t := range topics {
   120  		logFilter.Topics = append(logFilter.Topics, base.HexToHash(t))
   121  	}
   122  	return logFilter
   123  }
   124  
   125  func (filter *LogFilter) PassesFilter(log *types.Log) bool {
   126  	foundEmitter := false
   127  	for _, e := range filter.Emitters {
   128  		if e == log.Address {
   129  			foundEmitter = true
   130  			break
   131  		}
   132  	}
   133  
   134  	topicsFound := 0
   135  	for _, t := range filter.Topics {
   136  		for _, lt := range log.Topics {
   137  			if t == lt {
   138  				topicsFound++
   139  			}
   140  		}
   141  	}
   142  
   143  	passesEmitter := len(filter.Emitters) == 0 || foundEmitter
   144  	passesTopic := len(filter.Topics) == 0 || topicsFound > 0
   145  
   146  	return passesEmitter && passesTopic
   147  }