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 }