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 }