forked from pylls/gosmt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcache.go
158 lines (133 loc) · 5 KB
/
cache.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package gosmt
import (
"bytes"
"crypto/rand"
"math/big"
"strconv"
)
// Cache specifies a caching approach.
type Cache interface {
Exists(height uint64, base []byte) bool
Get(height uint64, base []byte) []byte
HashCache(left, right []byte, height uint64, base, split []byte,
interiorHash func(left, right []byte, height uint64, base []byte) []byte,
defaultHashes [][]byte) []byte
Entries() int
}
// CacheNothing caches nothing.
type CacheNothing int
// Exists checks if a value exists in the cache.
func (c CacheNothing) Exists(height uint64, base []byte) bool { return false }
// Get returns a value that exists from the cache.
func (c CacheNothing) Get(height uint64, base []byte) []byte { return nil }
// HashCache hashes the provided values and maybe caches.
func (c CacheNothing) HashCache(left, right []byte, height uint64, base, split []byte,
interiorHash func(left, right []byte, height uint64, base []byte) []byte,
defaultHashes [][]byte) []byte {
return interiorHash(left, right, height, base)
}
// Entries returns the number of entries in the cache.
func (c CacheNothing) Entries() int {
return 0
}
// CacheBranch caches every branch where both children have non-default values.
type CacheBranch map[string][]byte
// Exists checks if a value exists in the cache.
func (c CacheBranch) Exists(height uint64, base []byte) bool {
_, exists := c[strconv.Itoa(int(height))+string(base)]
return exists
}
// Get returns a value that exists from the cache.
func (c CacheBranch) Get(height uint64, base []byte) []byte {
return c[strconv.Itoa(int(height))+string(base)]
}
// HashCache hashes the provided values and maybe caches.
func (c CacheBranch) HashCache(left, right []byte, height uint64, base, split []byte,
interiorHash func(left, right []byte, height uint64, base []byte) []byte,
defaultHashes [][]byte) []byte {
h := interiorHash(left, right, height, base)
if !bytes.Equal(defaultHashes[height-1], left) && !bytes.Equal(defaultHashes[height-1], right) {
c[strconv.Itoa(int(height))+string(base)] = h
} else {
delete(c, strconv.Itoa(int(height))+string(base))
}
return h
}
// Entries returns the number of entries in the cache.
func (c CacheBranch) Entries() int {
return len(c)
}
// CacheBranchPlus caches the two children of every branch where both children have non-default values.
type CacheBranchPlus map[string][]byte
// Exists checks if a value exists in the cache.
func (c CacheBranchPlus) Exists(height uint64, base []byte) bool {
_, exists := c[strconv.Itoa(int(height))+string(base)]
return exists
}
// Get returns a value that exists from the cache.
func (c CacheBranchPlus) Get(height uint64, base []byte) []byte {
return c[strconv.Itoa(int(height))+string(base)]
}
// HashCache hashes the provided values and maybe caches.
func (c CacheBranchPlus) HashCache(left, right []byte, height uint64, base, split []byte,
interiorHash func(left, right []byte, height uint64, base []byte) []byte,
defaultHashes [][]byte) []byte {
h := interiorHash(left, right, height, base)
if !bytes.Equal(defaultHashes[height-1], left) && !bytes.Equal(defaultHashes[height-1], right) {
c[strconv.Itoa(int(height-1))+string(base)] = left
c[strconv.Itoa(int(height-1))+string(split)] = right
} else {
delete(c, strconv.Itoa(int(height))+string(base))
}
return h
}
// Entries returns the number of entries in the cache.
func (c CacheBranchPlus) Entries() int {
return len(c)
}
// CacheBranchMinus caches every branch where both children have non-default values with the
// provided probability [0,1]).
type CacheBranchMinus struct {
data map[string][]byte
probability float64
}
// NewCacheBranchMinus creates a new CacheBranchMinus with the provided caching probability.
func NewCacheBranchMinus(prob float64) *CacheBranchMinus {
c := new(CacheBranchMinus)
c.data = make(map[string][]byte)
c.probability = prob
return c
}
// Exists checks if a value exists in the cache.
func (c CacheBranchMinus) Exists(height uint64, base []byte) bool {
_, exists := c.data[strconv.Itoa(int(height))+string(base)]
return exists
}
// Get returns a value that exists from the cache.
func (c CacheBranchMinus) Get(height uint64, base []byte) []byte {
return c.data[strconv.Itoa(int(height))+string(base)]
}
// HashCache hashes the provided values and maybe caches.
func (c CacheBranchMinus) HashCache(left, right []byte, height uint64, base, split []byte,
interiorHash func(left, right []byte, height uint64, base []byte) []byte,
defaultHashes [][]byte) []byte {
h := interiorHash(left, right, height, base)
if randLess(c.probability) &&
!bytes.Equal(defaultHashes[height-1], left) && !bytes.Equal(defaultHashes[height-1], right) {
c.data[strconv.Itoa(int(height))+string(base)] = h
} else {
delete(c.data, strconv.Itoa(int(height))+string(base))
}
return h
}
// Entries returns the number of entries in the cache.
func (c CacheBranchMinus) Entries() int {
return len(c.data)
}
func randLess(x float64) bool {
b, err := rand.Int(rand.Reader, big.NewInt(100))
if err != nil {
panic(err)
}
return float64(b.Int64())/float64(100) < x
}