github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/jsonrpc/query.go (about) 1 package jsonrpc 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "time" 7 8 "github.com/0xPolygon/supernets2-node/hex" 9 "github.com/0xPolygon/supernets2-node/jsonrpc/types" 10 "github.com/ethereum/go-ethereum/common" 11 "github.com/gorilla/websocket" 12 ) 13 14 const ( 15 // FilterTypeLog represents a filter of type log. 16 FilterTypeLog = "log" 17 // FilterTypeBlock represents a filter of type block. 18 FilterTypeBlock = "block" 19 // FilterTypePendingTx represent a filter of type pending Tx. 20 FilterTypePendingTx = "pendingTx" 21 ) 22 23 // Filter represents a filter. 24 type Filter struct { 25 ID string 26 Type FilterType 27 Parameters interface{} 28 LastPoll time.Time 29 WsConn *websocket.Conn 30 } 31 32 // FilterType express the type of the filter, block, logs, pending transactions 33 type FilterType string 34 35 // LogFilter is a filter for logs 36 type LogFilter struct { 37 BlockHash *common.Hash 38 FromBlock *types.BlockNumber 39 ToBlock *types.BlockNumber 40 Addresses []common.Address 41 Topics [][]common.Hash 42 Since *time.Time 43 } 44 45 // addTopic adds specific topics to the log filter topics 46 func (f *LogFilter) addTopic(topics ...string) error { 47 if f.Topics == nil { 48 f.Topics = [][]common.Hash{} 49 } 50 51 topicsHashes := []common.Hash{} 52 53 for _, topic := range topics { 54 topicHash := common.Hash{} 55 if err := topicHash.UnmarshalText([]byte(topic)); err != nil { 56 return err 57 } 58 59 topicsHashes = append(topicsHashes, topicHash) 60 } 61 62 f.Topics = append(f.Topics, topicsHashes) 63 64 return nil 65 } 66 67 // addAddress Adds the address to the log filter 68 func (f *LogFilter) addAddress(raw string) error { 69 if f.Addresses == nil { 70 f.Addresses = []common.Address{} 71 } 72 73 addr := common.Address{} 74 75 if err := addr.UnmarshalText([]byte(raw)); err != nil { 76 return err 77 } 78 79 f.Addresses = append(f.Addresses, addr) 80 81 return nil 82 } 83 84 // MarshalJSON allows to customize the JSON representation. 85 func (f *LogFilter) MarshalJSON() ([]byte, error) { 86 var obj types.LogFilterRequest 87 88 obj.BlockHash = f.BlockHash 89 90 if f.FromBlock != nil && (*f.FromBlock == types.LatestBlockNumber) { 91 fromblock := "" 92 obj.FromBlock = &fromblock 93 } else if f.FromBlock != nil { 94 fromblock := hex.EncodeUint64(uint64(*f.FromBlock)) 95 obj.FromBlock = &fromblock 96 } 97 98 if f.ToBlock != nil && (*f.ToBlock == types.LatestBlockNumber) { 99 toblock := "" 100 obj.ToBlock = &toblock 101 } else if f.ToBlock != nil { 102 toblock := hex.EncodeUint64(uint64(*f.ToBlock)) 103 obj.ToBlock = &toblock 104 } 105 106 if f.Addresses != nil { 107 if len(f.Addresses) == 1 { 108 obj.Address = f.Addresses[0].Hex() 109 } else { 110 obj.Address = f.Addresses 111 } 112 } 113 114 obj.Topics = make([]interface{}, 0, len(f.Topics)) 115 for _, topic := range f.Topics { 116 if len(topic) == 0 { 117 obj.Topics = append(obj.Topics, nil) 118 } else if len(topic) == 1 { 119 obj.Topics = append(obj.Topics, topic[0]) 120 } else { 121 obj.Topics = append(obj.Topics, topic) 122 } 123 } 124 125 return json.Marshal(obj) 126 } 127 128 // UnmarshalJSON decodes a json object 129 func (f *LogFilter) UnmarshalJSON(data []byte) error { 130 var obj types.LogFilterRequest 131 132 err := json.Unmarshal(data, &obj) 133 134 if err != nil { 135 return err 136 } 137 138 f.BlockHash = obj.BlockHash 139 lbb := types.LatestBlockNumber 140 141 if obj.FromBlock != nil && *obj.FromBlock == "" { 142 f.FromBlock = &lbb 143 } else if obj.FromBlock != nil { 144 bn, err := types.StringToBlockNumber(*obj.FromBlock) 145 if err != nil { 146 return err 147 } 148 f.FromBlock = &bn 149 } 150 151 if obj.ToBlock != nil && *obj.ToBlock == "" { 152 f.ToBlock = &lbb 153 } else if obj.ToBlock != nil { 154 bn, err := types.StringToBlockNumber(*obj.ToBlock) 155 if err != nil { 156 return err 157 } 158 f.ToBlock = &bn 159 } 160 161 if obj.Address != nil { 162 // decode address, either "" or [""] 163 switch raw := obj.Address.(type) { 164 case string: 165 // "" 166 if err := f.addAddress(raw); err != nil { 167 return err 168 } 169 170 case []interface{}: 171 // ["", ""] 172 for _, addr := range raw { 173 if item, ok := addr.(string); ok { 174 if err := f.addAddress(item); err != nil { 175 return err 176 } 177 } else { 178 return fmt.Errorf("address expected") 179 } 180 } 181 182 default: 183 return fmt.Errorf("failed to decode address. Expected either '' or ['', '']") 184 } 185 } 186 187 if obj.Topics != nil { 188 // decode topics, either "" or ["", ""] or null 189 for _, item := range obj.Topics { 190 switch raw := item.(type) { 191 case string: 192 // "" 193 if err := f.addTopic(raw); err != nil { 194 return err 195 } 196 197 case []interface{}: 198 // ["", ""] 199 res := []string{} 200 201 for _, i := range raw { 202 if item, ok := i.(string); ok { 203 res = append(res, item) 204 } else { 205 return fmt.Errorf("hash expected") 206 } 207 } 208 209 if err := f.addTopic(res...); err != nil { 210 return err 211 } 212 213 case nil: 214 // null 215 if err := f.addTopic(); err != nil { 216 return err 217 } 218 219 default: 220 return fmt.Errorf("failed to decode topics. Expected '' or [''] or null") 221 } 222 } 223 } 224 225 // decode topics 226 return nil 227 } 228 229 // Match returns whether the receipt includes topics for this filter 230 func (f *LogFilter) Match(log *types.Log) bool { 231 // check addresses 232 if len(f.Addresses) > 0 { 233 match := false 234 235 for _, addr := range f.Addresses { 236 if addr == log.Address { 237 match = true 238 } 239 } 240 241 if !match { 242 return false 243 } 244 } 245 // check topics 246 if len(f.Topics) > len(log.Topics) { 247 return false 248 } 249 250 for i, sub := range f.Topics { 251 match := len(sub) == 0 252 253 for _, topic := range sub { 254 if log.Topics[i] == topic { 255 match = true 256 257 break 258 } 259 } 260 261 if !match { 262 return false 263 } 264 } 265 266 return true 267 }