Skip to content

Commit 3466252

Browse files
Crypt-iQcfromknecht
authored andcommitted
persistlog: reverting incorrect GC, test changes
This commit reverts incorrect garbage collector and test changes from previous commits. Specifically, boltdb's Delete funcion should not have been called in a ForEach loop. This is undefined behavior. The CLTV's were being treated as a relative timelock instead of an absolute timelock. Finally, t.Parallel() should not have been used in conjunction with boltdb.
1 parent a287245 commit 3466252

File tree

2 files changed

+62
-81
lines changed

2 files changed

+62
-81
lines changed

persistlog/decayedlog.go

Lines changed: 26 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -75,57 +75,35 @@ outer:
7575
"is nil")
7676
}
7777

78+
var expiredCltv [][]byte
7879
sharedHashes.ForEach(func(k, v []byte) error {
7980
// The CLTV value in question.
80-
cltv := uint32(binary.BigEndian.Uint32(v[:4]))
81-
// The last recorded block height that
82-
// the garbage collector received.
83-
lastHeight := uint32(binary.BigEndian.Uint32(v[4:8]))
84-
85-
if cltv == 0 {
86-
// This CLTV just expired. We
87-
// must delete it from the db.
88-
err := sharedHashes.Delete(k)
89-
if err != nil {
90-
return err
91-
}
92-
} else if lastHeight != 0 && uint32(epoch.Height)-lastHeight > cltv {
93-
// This CLTV just expired or
94-
// expired in the past but the
95-
// garbage collector was not
96-
// running and therefore could
97-
// not handle it. We delete it
98-
// from the db now.
99-
err := sharedHashes.Delete(k)
100-
if err != nil {
101-
return err
102-
}
103-
} else {
104-
// The CLTV is still valid. We
105-
// decrement the CLTV value and
106-
// store the new CLTV value along
107-
// with the current block height.
108-
var scratch [8]byte
109-
110-
// Store decremented CLTV in
111-
// scratch[:4]
112-
cltv--
113-
binary.BigEndian.PutUint32(scratch[:4], cltv)
114-
115-
// Store current blockheight in
116-
// scratch[4:8]
117-
binary.BigEndian.PutUint32(scratch[4:8], uint32(epoch.Height))
118-
119-
// Store <hash, CLTV + blockheight>
120-
err := sharedHashes.Put(k, scratch[:])
121-
if err != nil {
122-
return err
123-
}
81+
cltv := uint32(binary.BigEndian.Uint32(v))
82+
83+
// Current blockheight
84+
height := uint32(epoch.Height)
85+
86+
if cltv < height {
87+
// This CLTV is expired. We must
88+
// add it to an array which we'll
89+
// loop over and delete every
90+
// hash contained from the db.
91+
expiredCltv = append(expiredCltv, k)
12492
}
12593

12694
return nil
12795
})
12896

97+
// Delete every item in the array. This must
98+
// be done explicitly outside of the ForEach
99+
// function for safety reasons.
100+
for _, hash := range expiredCltv {
101+
err := sharedHashes.Delete(hash)
102+
if err != nil {
103+
return err
104+
}
105+
}
106+
129107
return nil
130108
})
131109
if err != nil {
@@ -189,14 +167,14 @@ func (d *DecayedLog) Get(hash []byte) (uint32, error) {
189167
"not retrieve CLTV value")
190168
}
191169

192-
// Retrieve the bytes which represents the CLTV + blockheight.
170+
// Retrieve the bytes which represents the CLTV
193171
valueBytes := sharedHashes.Get(hash)
194172
if valueBytes == nil {
195173
return nil
196174
}
197175

198176
// The first 4 bytes represent the CLTV, store it in value.
199-
value = uint32(binary.BigEndian.Uint32(valueBytes[:4]))
177+
value = uint32(binary.BigEndian.Uint32(valueBytes))
200178

201179
return nil
202180
})
@@ -211,10 +189,10 @@ func (d *DecayedLog) Get(hash []byte) (uint32, error) {
211189
func (d *DecayedLog) Put(hash []byte, cltv uint32) error {
212190
// The CLTV will be stored into scratch and then stored into the
213191
// sharedHashBucket.
214-
var scratch [8]byte
192+
var scratch [4]byte
215193

216194
// Store value into scratch
217-
binary.BigEndian.PutUint32(scratch[:4], cltv)
195+
binary.BigEndian.PutUint32(scratch[:], cltv)
218196

219197
return d.db.Batch(func(tx *bolt.Tx) error {
220198
sharedHashes, err := tx.CreateBucketIfNotExists(sharedHashBucket)

persistlog/decayedlog_test.go

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
)
1515

1616
const (
17-
cltv uint32 = 5
17+
cltv uint32 = 100000
1818
)
1919

2020
var (
@@ -121,10 +121,8 @@ func shutdown(d *DecayedLog) {
121121

122122
// TestDecayedLogGarbageCollector tests the ability of the garbage collector
123123
// to delete expired cltv values every time a block is received. Expired cltv
124-
// values are cltv values that are <= current block height.
124+
// values are cltv values that are < current block height.
125125
func TestDecayedLogGarbageCollector(t *testing.T) {
126-
t.Parallel()
127-
128126
d, notifier, hashedSecret, err := startup(true)
129127
if err != nil {
130128
t.Fatalf("Unable to start up DecayedLog: %v", err)
@@ -137,37 +135,52 @@ func TestDecayedLogGarbageCollector(t *testing.T) {
137135
t.Fatalf("Unable to store in channeldb: %v", err)
138136
}
139137

138+
// Wait for database write (GC is in a goroutine)
139+
time.Sleep(500 * time.Millisecond)
140+
140141
// Send block notifications to garbage collector. The garbage collector
141-
// should remove the entry we just added to sharedHashBucket as it will
142-
// expire by the 6th block notification.
143-
for i := 0; i < 6; i++ {
144-
notifier.epochChan <- &chainntnfs.BlockEpoch{
145-
Height: int32(100 + i),
146-
}
142+
// should remove the entry by block 100001.
143+
144+
// Send block 100000
145+
notifier.epochChan <- &chainntnfs.BlockEpoch{
146+
Height: 100000,
147+
}
148+
149+
// Assert that hashedSecret is still in the sharedHashBucket
150+
val, err := d.Get(hashedSecret[:])
151+
if err != nil {
152+
t.Fatalf("Get failed - received an error upon Get: %v", err)
153+
}
154+
155+
if val != cltv {
156+
t.Fatalf("GC incorrectly deleted CLTV")
157+
}
158+
159+
// Send block 100001 (expiry block)
160+
notifier.epochChan <- &chainntnfs.BlockEpoch{
161+
Height: 100001,
147162
}
148163

149164
// Wait for database write (GC is in a goroutine)
150165
time.Sleep(500 * time.Millisecond)
151166

152167
// Assert that hashedSecret is not in the sharedHashBucket
153-
val, err := d.Get(hashedSecret[:])
168+
val, err = d.Get(hashedSecret[:])
154169
if err != nil {
155-
t.Fatalf("Delete failed - received an error upon Get: %v", err)
170+
t.Fatalf("Get failed - received an error upon Get: %v", err)
156171
}
157172

158173
if val != math.MaxUint32 {
159-
t.Fatalf("cltv was not deleted")
174+
t.Fatalf("CLTV was not deleted")
160175
}
161176
}
162177

163178
// TestDecayedLogPersistentGarbageCollector tests the persistence property of
164-
// the garbage collector. A block will be sent to the garbage collector, the
165-
// garbage collector will be shut down, and then a much later block will be sent
166-
// (past the expiry of our test CLTV) that causes the <sharedHash, cltv) key-pair
167-
// to be deleted.
179+
// the garbage collector. The garbage collector will be restarted immediately and
180+
// a block that expires the stored CLTV value will be sent to the ChainNotifier.
181+
// We test that this causes the <hashedSecret, CLTV> pair to be deleted even
182+
// on GC restarts.
168183
func TestDecayedLogPersistentGarbageCollector(t *testing.T) {
169-
t.Parallel()
170-
171184
d, notifier, hashedSecret, err := startup(true)
172185
if err != nil {
173186
t.Fatalf("Unable to start up DecayedLog: %v", err)
@@ -179,11 +192,6 @@ func TestDecayedLogPersistentGarbageCollector(t *testing.T) {
179192
t.Fatalf("Unable to store in channeldb: %v", err)
180193
}
181194

182-
// Send a single block notification to the garbage collector.
183-
notifier.epochChan <- &chainntnfs.BlockEpoch{
184-
Height: int32(100),
185-
}
186-
187195
// Wait for database write (GC is in a goroutine)
188196
time.Sleep(500 * time.Millisecond)
189197

@@ -195,9 +203,10 @@ func TestDecayedLogPersistentGarbageCollector(t *testing.T) {
195203
t.Fatalf("Unable to restart DecayedLog: %v", err)
196204
}
197205

198-
// Send a much later block notification to the garbage collector.
206+
// Send a block notification to the garbage collector that expires
207+
// the stored CLTV.
199208
notifier.epochChan <- &chainntnfs.BlockEpoch{
200-
Height: int32(150),
209+
Height: int32(100001),
201210
}
202211

203212
// Wait for database write (GC is in a goroutine)
@@ -214,12 +223,10 @@ func TestDecayedLogPersistentGarbageCollector(t *testing.T) {
214223
}
215224
}
216225

217-
// TestDecayedLogInsertionAndRetrieval inserts a cltv value into the nested
226+
// TestDecayedLogInsertionAndRetrieval inserts a cltv value into the
218227
// sharedHashBucket and then deletes it and finally asserts that we can no
219228
// longer retrieve it.
220229
func TestDecayedLogInsertionAndDeletion(t *testing.T) {
221-
t.Parallel()
222-
223230
d, _, hashedSecret, err := startup(false)
224231
if err != nil {
225232
t.Fatalf("Unable to start up DecayedLog: %v", err)
@@ -256,8 +263,6 @@ func TestDecayedLogInsertionAndDeletion(t *testing.T) {
256263
// cltv value is indeed still stored in the sharedHashBucket. We then delete
257264
// the cltv value and check that it persists upon startup.
258265
func TestDecayedLogStartAndStop(t *testing.T) {
259-
t.Parallel()
260-
261266
d, _, hashedSecret, err := startup(false)
262267
if err != nil {
263268
t.Fatalf("Unable to start up DecayedLog: %v", err)
@@ -322,8 +327,6 @@ func TestDecayedLogStartAndStop(t *testing.T) {
322327
// via the nested sharedHashBucket and finally asserts that the original stored
323328
// and retrieved cltv values are equal.
324329
func TestDecayedLogStorageAndRetrieval(t *testing.T) {
325-
t.Parallel()
326-
327330
d, _, hashedSecret, err := startup(false)
328331
if err != nil {
329332
t.Fatalf("Unable to start up DecayedLog: %v", err)

0 commit comments

Comments
 (0)