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  }