github.com/Finschia/finschia-sdk@v0.48.1/store/types/utils.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  
     6  	"github.com/Finschia/finschia-sdk/types/kv"
     7  )
     8  
     9  // Iterator over all the keys with a certain prefix in ascending order
    10  func KVStorePrefixIterator(kvs KVStore, prefix []byte) Iterator {
    11  	return kvs.Iterator(prefix, PrefixEndBytes(prefix))
    12  }
    13  
    14  // Iterator over all the keys with a certain prefix in descending order.
    15  func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator {
    16  	return kvs.ReverseIterator(prefix, PrefixEndBytes(prefix))
    17  }
    18  
    19  // DiffKVStores compares two KVstores and returns all the key/value pairs
    20  // that differ from one another. It also skips value comparison for a set of provided prefixes.
    21  func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []kv.Pair) {
    22  	iterA := a.Iterator(nil, nil)
    23  
    24  	defer iterA.Close()
    25  
    26  	iterB := b.Iterator(nil, nil)
    27  
    28  	defer iterB.Close()
    29  
    30  	for {
    31  		if !iterA.Valid() && !iterB.Valid() {
    32  			return kvAs, kvBs
    33  		}
    34  
    35  		var kvA, kvB kv.Pair
    36  		if iterA.Valid() {
    37  			kvA = kv.Pair{Key: iterA.Key(), Value: iterA.Value()}
    38  
    39  			iterA.Next()
    40  		}
    41  
    42  		if iterB.Valid() {
    43  			kvB = kv.Pair{Key: iterB.Key(), Value: iterB.Value()}
    44  
    45  			iterB.Next()
    46  		}
    47  
    48  		compareValue := true
    49  
    50  		for _, prefix := range prefixesToSkip {
    51  			// Skip value comparison if we matched a prefix
    52  			if bytes.HasPrefix(kvA.Key, prefix) || bytes.HasPrefix(kvB.Key, prefix) {
    53  				compareValue = false
    54  				break
    55  			}
    56  		}
    57  
    58  		if compareValue && (!bytes.Equal(kvA.Key, kvB.Key) || !bytes.Equal(kvA.Value, kvB.Value)) {
    59  			kvAs = append(kvAs, kvA)
    60  			kvBs = append(kvBs, kvB)
    61  		}
    62  	}
    63  }
    64  
    65  // PrefixEndBytes returns the []byte that would end a
    66  // range query for all []byte with a certain prefix
    67  // Deals with last byte of prefix being FF without overflowing
    68  func PrefixEndBytes(prefix []byte) []byte {
    69  	if len(prefix) == 0 {
    70  		return nil
    71  	}
    72  
    73  	end := make([]byte, len(prefix))
    74  	copy(end, prefix)
    75  
    76  	for {
    77  		if end[len(end)-1] != byte(255) {
    78  			end[len(end)-1]++
    79  			break
    80  		}
    81  
    82  		end = end[:len(end)-1]
    83  
    84  		if len(end) == 0 {
    85  			end = nil
    86  			break
    87  		}
    88  	}
    89  
    90  	return end
    91  }
    92  
    93  // InclusiveEndBytes returns the []byte that would end a
    94  // range query such that the input would be included
    95  func InclusiveEndBytes(inclusiveBytes []byte) []byte {
    96  	return append(inclusiveBytes, byte(0x00))
    97  }