github.com/aakash4dev/cometbft@v0.38.2/state/indexer/block/kv/util.go (about) 1 package kv 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math/big" 7 "strconv" 8 9 "github.com/google/orderedcode" 10 11 idxutil "github.com/aakash4dev/cometbft/internal/indexer" 12 "github.com/aakash4dev/cometbft/libs/pubsub/query/syntax" 13 "github.com/aakash4dev/cometbft/state/indexer" 14 "github.com/aakash4dev/cometbft/types" 15 ) 16 17 type HeightInfo struct { 18 heightRange indexer.QueryRange 19 height int64 20 heightEqIdx int 21 onlyHeightRange bool 22 onlyHeightEq bool 23 } 24 25 func intInSlice(a int, list []int) bool { 26 for _, b := range list { 27 if b == a { 28 return true 29 } 30 } 31 32 return false 33 } 34 35 func int64FromBytes(bz []byte) int64 { 36 v, _ := binary.Varint(bz) 37 return v 38 } 39 40 func int64ToBytes(i int64) []byte { 41 buf := make([]byte, binary.MaxVarintLen64) 42 n := binary.PutVarint(buf, i) 43 return buf[:n] 44 } 45 46 func heightKey(height int64) ([]byte, error) { 47 return orderedcode.Append( 48 nil, 49 types.BlockHeightKey, 50 height, 51 ) 52 } 53 54 func eventKey(compositeKey, eventValue string, height int64, eventSeq int64) ([]byte, error) { 55 return orderedcode.Append( 56 nil, 57 compositeKey, 58 eventValue, 59 height, 60 eventSeq, 61 ) 62 } 63 64 func parseValueFromPrimaryKey(key []byte) (string, error) { 65 var ( 66 compositeKey string 67 height int64 68 ) 69 70 remaining, err := orderedcode.Parse(string(key), &compositeKey, &height) 71 if err != nil { 72 return "", fmt.Errorf("failed to parse event key: %w", err) 73 } 74 75 if len(remaining) != 0 { 76 return "", fmt.Errorf("unexpected remainder in key: %s", remaining) 77 } 78 79 return strconv.FormatInt(height, 10), nil 80 } 81 82 func parseValueFromEventKey(key []byte) (string, error) { 83 var ( 84 compositeKey, eventValue string 85 height int64 86 ) 87 88 _, err := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height) 89 if err != nil { 90 return "", fmt.Errorf("failed to parse event key: %w", err) 91 } 92 93 return eventValue, nil 94 } 95 96 func parseHeightFromEventKey(key []byte) (int64, error) { 97 var ( 98 compositeKey, eventValue string 99 height int64 100 ) 101 102 _, err := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height) 103 if err != nil { 104 return -1, fmt.Errorf("failed to parse event key: %w", err) 105 } 106 107 return height, nil 108 } 109 110 func parseEventSeqFromEventKey(key []byte) (int64, error) { 111 var ( 112 compositeKey, eventValue string 113 height int64 114 eventSeq int64 115 ) 116 117 remaining, err := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height) 118 if err != nil { 119 return 0, fmt.Errorf("failed to parse event sequence: %w", err) 120 } 121 122 // We either have an event sequence or a function type (potentially) followed by an event sequence. 123 // Potential scenarios: 124 // 1. Events indexed with v0.38.x and later, will only have an event sequence 125 // 2. Events indexed between v0.34.27 and v0.37.x will have a function type and an event sequence 126 // 3. Events indexed before v0.34.27 will only have a function type 127 // function_type = 'being_block_event' | 'end_block_event' 128 129 if len(remaining) == 0 { // The event was not properly indexed 130 return 0, fmt.Errorf("failed to parse event sequence, invalid event format") 131 } 132 var typ string 133 remaining2, err := orderedcode.Parse(remaining, &typ) // Check if we have scenarios 2. or 3. (described above). 134 if err != nil { // If it cannot parse the event function type, it could be 1. 135 remaining, err2 := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height, &eventSeq) 136 if err2 != nil || len(remaining) != 0 { // We should not have anything else after the eventSeq. 137 return 0, fmt.Errorf("failed to parse event sequence: %w; and %w", err, err2) 138 } 139 } else if len(remaining2) != 0 { // Are we in case 2 or 3 140 remaining, err2 := orderedcode.Parse(remaining2, &eventSeq) // the event follows the scenario in 2., 141 // retrieve the eventSeq 142 // there should be no error 143 if err2 != nil || len(remaining) != 0 { // We should not have anything else after the eventSeq if in 2. 144 return 0, fmt.Errorf("failed to parse event sequence: %w", err2) 145 } 146 } 147 return eventSeq, nil 148 } 149 150 // Remove all occurrences of height equality queries except one. While we are traversing the conditions, check whether the only condition in 151 // addition to match events is the height equality or height range query. At the same time, if we do have a height range condition 152 // ignore the height equality condition. If a height equality exists, place the condition index in the query and the desired height 153 // into the heightInfo struct 154 func dedupHeight(conditions []syntax.Condition) (dedupConditions []syntax.Condition, heightInfo HeightInfo, found bool) { 155 heightInfo.heightEqIdx = -1 156 heightRangeExists := false 157 var heightCondition []syntax.Condition 158 heightInfo.onlyHeightEq = true 159 heightInfo.onlyHeightRange = true 160 for _, c := range conditions { 161 if c.Tag == types.BlockHeightKey { 162 if c.Op == syntax.TEq { 163 if found || heightRangeExists { 164 continue 165 } 166 hFloat := c.Arg.Number() 167 if hFloat != nil { 168 h, _ := hFloat.Int64() 169 heightInfo.height = h 170 heightCondition = append(heightCondition, c) 171 found = true 172 } 173 } else { 174 heightInfo.onlyHeightEq = false 175 heightRangeExists = true 176 dedupConditions = append(dedupConditions, c) 177 } 178 } else { 179 heightInfo.onlyHeightRange = false 180 heightInfo.onlyHeightEq = false 181 dedupConditions = append(dedupConditions, c) 182 } 183 } 184 if !heightRangeExists && len(heightCondition) != 0 { 185 heightInfo.heightEqIdx = len(dedupConditions) 186 heightInfo.onlyHeightRange = false 187 dedupConditions = append(dedupConditions, heightCondition...) 188 } else { 189 // If we found a range make sure we set the hegiht idx to -1 as the height equality 190 // will be removed 191 heightInfo.heightEqIdx = -1 192 heightInfo.height = 0 193 heightInfo.onlyHeightEq = false 194 found = false 195 } 196 return dedupConditions, heightInfo, found 197 } 198 199 func checkHeightConditions(heightInfo HeightInfo, keyHeight int64) (bool, error) { 200 if heightInfo.heightRange.Key != "" { 201 withinBounds, err := idxutil.CheckBounds(heightInfo.heightRange, big.NewInt(keyHeight)) 202 if err != nil || !withinBounds { 203 return false, err 204 } 205 } else { 206 if heightInfo.height != 0 && keyHeight != heightInfo.height { 207 return false, nil 208 } 209 } 210 return true, nil 211 }