github.com/badrootd/celestia-core@v0.0.0-20240305091328-aa4207a4b25d/state/indexer/block/kv/util.go (about) 1 package kv 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "strconv" 7 8 "github.com/google/orderedcode" 9 10 "github.com/badrootd/celestia-core/libs/pubsub/query" 11 "github.com/badrootd/celestia-core/state/indexer" 12 "github.com/badrootd/celestia-core/types" 13 ) 14 15 type HeightInfo struct { 16 heightRange indexer.QueryRange 17 height int64 18 heightEqIdx int 19 onlyHeightRange bool 20 onlyHeightEq bool 21 } 22 23 func intInSlice(a int, list []int) bool { 24 for _, b := range list { 25 if b == a { 26 return true 27 } 28 } 29 30 return false 31 } 32 33 func int64FromBytes(bz []byte) int64 { 34 v, _ := binary.Varint(bz) 35 return v 36 } 37 38 func int64ToBytes(i int64) []byte { 39 buf := make([]byte, binary.MaxVarintLen64) 40 n := binary.PutVarint(buf, i) 41 return buf[:n] 42 } 43 44 func heightKey(height int64) ([]byte, error) { 45 return orderedcode.Append( 46 nil, 47 types.BlockHeightKey, 48 height, 49 ) 50 } 51 52 func eventKey(compositeKey, typ, eventValue string, height int64, eventSeq int64) ([]byte, error) { 53 return orderedcode.Append( 54 nil, 55 compositeKey, 56 eventValue, 57 height, 58 typ, 59 eventSeq, 60 ) 61 } 62 63 func parseValueFromPrimaryKey(key []byte) (string, error) { 64 var ( 65 compositeKey string 66 height int64 67 ) 68 69 remaining, err := orderedcode.Parse(string(key), &compositeKey, &height) 70 if err != nil { 71 return "", fmt.Errorf("failed to parse event key: %w", err) 72 } 73 74 if len(remaining) != 0 { 75 return "", fmt.Errorf("unexpected remainder in key: %s", remaining) 76 } 77 78 return strconv.FormatInt(height, 10), nil 79 } 80 81 func parseValueFromEventKey(key []byte) (string, error) { 82 var ( 83 compositeKey, typ, eventValue string 84 height int64 85 ) 86 87 _, err := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height, &typ) 88 if err != nil { 89 return "", fmt.Errorf("failed to parse event key: %w", err) 90 } 91 92 return eventValue, nil 93 } 94 95 func parseHeightFromEventKey(key []byte) (int64, error) { 96 var ( 97 compositeKey, typ, eventValue string 98 height int64 99 ) 100 101 _, err := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height, &typ) 102 if err != nil { 103 return -1, fmt.Errorf("failed to parse event key: %w", err) 104 } 105 106 return height, nil 107 } 108 109 func parseEventSeqFromEventKey(key []byte) (int64, error) { 110 var ( 111 compositeKey, typ, eventValue string 112 height int64 113 eventSeq int64 114 ) 115 116 remaining, err := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height, &typ) 117 if err != nil { 118 return 0, fmt.Errorf("failed to parse event key: %w", err) 119 } 120 121 // This is done to support previous versions that did not have event sequence in their key 122 if len(remaining) != 0 { 123 remaining, err = orderedcode.Parse(remaining, &eventSeq) 124 if err != nil { 125 return 0, fmt.Errorf("failed to parse event key: %w", err) 126 } 127 if len(remaining) != 0 { 128 return 0, fmt.Errorf("unexpected remainder in key: %s", remaining) 129 } 130 } 131 132 return eventSeq, nil 133 } 134 135 func lookForHeight(conditions []query.Condition) (int64, bool, int) { 136 for i, c := range conditions { 137 if c.CompositeKey == types.BlockHeightKey && c.Op == query.OpEqual { 138 return c.Operand.(int64), true, i 139 } 140 } 141 142 return 0, false, -1 143 } 144 145 // Remove all occurrences of height equality queries except one. While we are traversing the conditions, check whether the only condition in 146 // addition to match events is the height equality or height range query. At the same time, if we do have a height range condition 147 // ignore the height equality condition. If a height equality exists, place the condition index in the query and the desired height 148 // into the heightInfo struct 149 func dedupHeight(conditions []query.Condition) (dedupConditions []query.Condition, heightInfo HeightInfo, found bool) { 150 heightInfo.heightEqIdx = -1 151 heightRangeExists := false 152 var heightCondition []query.Condition 153 heightInfo.onlyHeightEq = true 154 heightInfo.onlyHeightRange = true 155 for _, c := range conditions { 156 if c.CompositeKey == types.BlockHeightKey { 157 if c.Op == query.OpEqual { 158 if found || heightRangeExists { 159 continue 160 } else { 161 heightCondition = append(heightCondition, c) 162 heightInfo.height = c.Operand.(int64) 163 found = true 164 } 165 } else { 166 heightInfo.onlyHeightEq = false 167 heightRangeExists = true 168 dedupConditions = append(dedupConditions, c) 169 } 170 } else { 171 if c.CompositeKey != types.MatchEventKey { 172 heightInfo.onlyHeightRange = false 173 heightInfo.onlyHeightEq = false 174 } 175 dedupConditions = append(dedupConditions, c) 176 } 177 } 178 if !heightRangeExists && len(heightCondition) != 0 { 179 heightInfo.heightEqIdx = len(dedupConditions) 180 heightInfo.onlyHeightRange = false 181 dedupConditions = append(dedupConditions, heightCondition...) 182 } else { 183 // If we found a range make sure we set the hegiht idx to -1 as the height equality 184 // will be removed 185 heightInfo.heightEqIdx = -1 186 heightInfo.height = 0 187 found = false 188 heightInfo.onlyHeightEq = false 189 } 190 return dedupConditions, heightInfo, found 191 } 192 193 func dedupMatchEvents(conditions []query.Condition) ([]query.Condition, bool) { 194 var dedupConditions []query.Condition 195 matchEvents := false 196 for i, c := range conditions { 197 if c.CompositeKey == types.MatchEventKey { 198 // Match events should be added only via RPC as the very first query condition 199 if i == 0 && c.Op == query.OpEqual && c.Operand.(int64) == 1 { 200 dedupConditions = append(dedupConditions, c) 201 matchEvents = true 202 } 203 } else { 204 dedupConditions = append(dedupConditions, c) 205 } 206 207 } 208 return dedupConditions, matchEvents 209 } 210 211 func checkHeightConditions(heightInfo HeightInfo, keyHeight int64) bool { 212 if heightInfo.heightRange.Key != "" { 213 if !checkBounds(heightInfo.heightRange, keyHeight) { 214 return false 215 } 216 } else { 217 if heightInfo.height != 0 && keyHeight != heightInfo.height { 218 return false 219 } 220 } 221 return true 222 }