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  }