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