Skip to content

Commit 9de21d4

Browse files
Crypt-iQcfromknecht
authored andcommitted
persistlog: fix garbage collector, Get, and tests
This commit reverts some of the work of the previous commit. It fixes the garbage collector to sweep up the CLTV by decrementing the CLTV for evey block notification it receives. It also fixes the Get method to return a CLTV value of math.MaxUint32 upon retrieving no CLTV value. Tests were also cleaned up and fixed.
1 parent f0fc2e7 commit 9de21d4

File tree

7 files changed

+132
-83
lines changed

7 files changed

+132
-83
lines changed

bench_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"testing"
66

7-
"github.com/lightningnetwork/lightning-onion/persistlog"
87
"github.com/roasbeef/btcd/btcec"
98
)
109

@@ -56,27 +55,28 @@ func BenchmarkPathPacketConstruction(b *testing.B) {
5655

5756
func BenchmarkProcessPacket(b *testing.B) {
5857
b.StopTimer()
59-
60-
// Create the DecayedLog object
61-
d := &persistlog.DecayedLog{}
62-
if err := d.Start(); err != nil {
63-
b.Fatalf("unable to start channeldb")
64-
}
65-
66-
path, _, sphinxPacket, err := newTestRoute(1, d)
58+
path, _, sphinxPacket, err := newTestRoute(1)
6759
if err != nil {
6860
b.Fatalf("unable to create test route: %v", err)
6961
}
7062
b.ReportAllocs()
63+
path[0].d.Start("0")
64+
defer shutdown("0", path[0].d)
7165
b.StartTimer()
7266

7367
var (
7468
pkt *ProcessedPacket
7569
)
70+
for i := 0; i < b.N; i++ {
71+
pkt, err = path[0].ProcessOnionPacket(sphinxPacket, nil)
72+
if err != nil {
73+
b.Fatalf("unable to process packet: %v", err)
74+
}
7675

77-
pkt, err = path[0].ProcessOnionPacket(sphinxPacket, nil)
78-
if err != nil {
79-
b.Fatalf("unable to process packet: %v", err)
76+
b.StopTimer()
77+
shutdown("0", path[0].d)
78+
path[0].d.Start("0")
79+
b.StartTimer()
8080
}
8181

8282
p = pkt

glide.lock

Lines changed: 14 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

persistlog/decayedlog.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/boltdb/bolt"
88
"github.com/lightningnetwork/lnd/chainntnfs"
99
"github.com/lightningnetwork/lnd/channeldb"
10+
"math"
1011
"sync"
1112
)
1213

@@ -59,13 +60,14 @@ func (d *DecayedLog) garbageCollector() error {
5960
outer:
6061
for {
6162
select {
62-
case epoch, ok := <-epochClient.Epochs:
63+
case _, ok := <-epochClient.Epochs:
6364
if !ok {
6465
return fmt.Errorf("Epoch client shutting " +
6566
"down")
6667
}
6768

6869
var expiredCltv [][]byte
70+
validCltv := make(map[string]uint32)
6971
err := d.db.View(func(tx *bolt.Tx) error {
7072
// Grab the shared hash bucket
7173
sharedHashes := tx.Bucket(sharedHashBucket)
@@ -76,9 +78,13 @@ outer:
7678

7779
sharedHashes.ForEach(func(k, v []byte) error {
7880
cltv := uint32(binary.BigEndian.Uint32(v))
79-
if uint32(epoch.Height) > cltv {
81+
cltv--
82+
if cltv == 0 {
8083
// Store expired hash in array
8184
expiredCltv = append(expiredCltv, k)
85+
} else {
86+
// Store valid <hash, cltv> in map
87+
validCltv[string(k)] = cltv
8288
}
8389
return nil
8490
})
@@ -94,11 +100,20 @@ outer:
94100
for _, hash := range expiredCltv {
95101
err = d.Delete(hash)
96102
if err != nil {
97-
return fmt.Errorf("Unable to delete"+
103+
return fmt.Errorf("Unable to delete "+
98104
"expired secret: %v", err)
99105
}
100106
}
101107

108+
// Update decremented CLTV's via validCltv
109+
for hash, cltv := range validCltv {
110+
err = d.Put([]byte(hash), cltv)
111+
if err != nil {
112+
return fmt.Errorf("Unable to decrement "+
113+
"cltv value: %v", err)
114+
}
115+
}
116+
102117
case <-d.quit:
103118
break outer
104119
}
@@ -141,9 +156,9 @@ func (d *DecayedLog) Delete(hash []byte) error {
141156

142157
// Get retrieves the CLTV value of a processed HTLC given the first 20 bytes
143158
// of the Sha-256 hash of the shared secret used during sphinx processing.
144-
func (d *DecayedLog) Get(hash []byte) (
145-
uint32, error) {
146-
var value uint32
159+
func (d *DecayedLog) Get(hash []byte) (uint32, error) {
160+
// math.MaxUint32 is returned when Get did not retrieve a value.
161+
var value uint32 = math.MaxUint32
147162

148163
err := d.db.View(func(tx *bolt.Tx) error {
149164
// Grab the shared hash bucket which stores the mapping from
@@ -172,10 +187,9 @@ func (d *DecayedLog) Get(hash []byte) (
172187
return value, nil
173188
}
174189

175-
// Put stores a <shared secret hash, CLTV value> key-pair into the
176-
// sharedHashBucket.
177-
func (d *DecayedLog) Put(hash []byte,
178-
value uint32) error {
190+
// Put stores a shared secret hash as the key and a slice consisting of the
191+
// current blockheight and the outgoing CLTV value
192+
func (d *DecayedLog) Put(hash []byte, value uint32) error {
179193

180194
var scratch [4]byte
181195

@@ -196,13 +210,20 @@ func (d *DecayedLog) Put(hash []byte,
196210
// Start opens the database we will be using to store hashed shared secrets.
197211
// It also starts the garbage collector in a goroutine to remove stale
198212
// database entries.
199-
func (d *DecayedLog) Start() error {
213+
func (d *DecayedLog) Start(dbDir string) error {
200214
// Create the quit channel
201215
d.quit = make(chan struct{})
202216

217+
var directory string
218+
if dbDir == "" {
219+
directory = defaultDbDirectory
220+
} else {
221+
directory = dbDir
222+
}
223+
203224
// Open the channeldb for use.
204225
var err error
205-
if d.db, err = channeldb.Open(defaultDbDirectory); err != nil {
226+
if d.db, err = channeldb.Open(directory); err != nil {
206227
return fmt.Errorf("Could not open channeldb: %v", err)
207228
}
208229

persistlog/decayedlog_test.go

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"github.com/roasbeef/btcd/btcec"
77
"github.com/roasbeef/btcd/chaincfg/chainhash"
88
"github.com/roasbeef/btcd/wire"
9+
"math"
10+
"os"
911
"testing"
1012
"time"
1113
)
@@ -61,12 +63,19 @@ func generateSharedSecret(pub *btcec.PublicKey, priv *btcec.PrivateKey) [32]byte
6163
return sha256.Sum256(s.SerializeCompressed())
6264
}
6365

66+
// shutdown stops the DecayedLog and deletes the folder enclosing the
67+
// temporary channel database.
68+
func shutdown(d *DecayedLog) {
69+
os.RemoveAll("tempdir")
70+
d.Stop()
71+
}
72+
6473
// TestDecayedLogGarbageCollector tests the ability of the garbage collector
6574
// to delete expired cltv values every time a block is received. Expired cltv
6675
// values are cltv values that are <= current block height.
6776
func TestDecayedLogGarbageCollector(t *testing.T) {
68-
// Random (EXPIRED) cltv value
69-
cltv := uint32(200390)
77+
// Random (TO-BE-EXPIRED) cltv value
78+
cltv := uint32(2)
7079

7180
// Create the MockNotifier which triggers the garbage collector
7281
MockNotifier := &mockNotifier{
@@ -77,11 +86,11 @@ func TestDecayedLogGarbageCollector(t *testing.T) {
7786
d := DecayedLog{Notifier: MockNotifier}
7887

7988
// Open the channeldb (start the garbage collector)
80-
err := d.Start()
89+
err := d.Start("tempdir")
8190
if err != nil {
8291
t.Fatalf("Unable to start / open DecayedLog")
8392
}
84-
defer d.Stop()
93+
defer shutdown(&d)
8594

8695
// Create a new private key on elliptic curve secp256k1
8796
priv, err := btcec.NewPrivateKey(btcec.S256())
@@ -110,7 +119,10 @@ func TestDecayedLogGarbageCollector(t *testing.T) {
110119
// should remove the entry we just added to sharedHashBucket as it is
111120
// now expired.
112121
MockNotifier.epochChan <- &chainntnfs.BlockEpoch{
113-
Height: int32(cltv + 1),
122+
Height: int32(101),
123+
}
124+
MockNotifier.epochChan <- &chainntnfs.BlockEpoch{
125+
Height: int32(102),
114126
}
115127

116128
// Wait for database write (GC is in a goroutine)
@@ -122,7 +134,7 @@ func TestDecayedLogGarbageCollector(t *testing.T) {
122134
t.Fatalf("Delete failed - received an error upon Get")
123135
}
124136

125-
if val != 0 {
137+
if val != math.MaxUint32 {
126138
t.Fatalf("cltv was not deleted")
127139
}
128140
}
@@ -132,17 +144,17 @@ func TestDecayedLogGarbageCollector(t *testing.T) {
132144
// longer retrieve it.
133145
func TestDecayedLogInsertionAndDeletion(t *testing.T) {
134146
// Random cltv value
135-
cltv := uint32(503928)
147+
cltv := uint32(5)
136148

137149
// Create a DecayedLog object
138150
d := DecayedLog{}
139151

140152
// Open the channeldb
141-
err := d.Start()
153+
err := d.Start("tempdir")
142154
if err != nil {
143155
t.Fatalf("Unable to start / open DecayedLog")
144156
}
145-
defer d.Stop()
157+
defer shutdown(&d)
146158

147159
// Create a new private key on elliptic curve secp256k1
148160
priv, err := btcec.NewPrivateKey(btcec.S256())
@@ -179,7 +191,7 @@ func TestDecayedLogInsertionAndDeletion(t *testing.T) {
179191
t.Fatalf("Delete failed - received the wrong error message")
180192
}
181193

182-
if val != 0 {
194+
if val != math.MaxUint32 {
183195
t.Fatalf("cltv was not deleted")
184196
}
185197

@@ -192,17 +204,17 @@ func TestDecayedLogInsertionAndDeletion(t *testing.T) {
192204
// the cltv value and check that it persists upon startup.
193205
func TestDecayedLogStartAndStop(t *testing.T) {
194206
// Random cltv value
195-
cltv := uint32(909020)
207+
cltv := uint32(6)
196208

197209
// Create a DecayedLog object
198210
d := DecayedLog{}
199211

200212
// Open the channeldb
201-
err := d.Start()
213+
err := d.Start("tempdir")
202214
if err != nil {
203215
t.Fatalf("Unable to start / open DecayedLog")
204216
}
205-
defer d.Stop()
217+
defer shutdown(&d)
206218

207219
// Create a new private key on elliptic curve secp256k1
208220
priv, err := btcec.NewPrivateKey(btcec.S256())
@@ -231,7 +243,7 @@ func TestDecayedLogStartAndStop(t *testing.T) {
231243
d.Stop()
232244

233245
// Startup the DecayedLog's channeldb
234-
err = d.Start()
246+
err = d.Start("tempdir")
235247
if err != nil {
236248
t.Fatalf("Unable to start / open DecayedLog")
237249
}
@@ -258,18 +270,18 @@ func TestDecayedLogStartAndStop(t *testing.T) {
258270
d.Stop()
259271

260272
// Startup the DecayedLog's channeldb
261-
err = d.Start()
273+
err = d.Start("tempdir")
262274
if err != nil {
263275
t.Fatalf("Unable to start / open DecayedLog")
264276
}
265277

266278
// Assert that hashedSecret is not in the sharedHashBucket
267279
val, err := d.Get(hashedSecret[:])
268280
if err != nil {
269-
t.Fatalf("Delete failed - received the wrong error message")
281+
t.Fatalf("Delete failed")
270282
}
271283

272-
if val != 0 {
284+
if val != math.MaxUint32 {
273285
t.Fatalf("cltv was not deleted")
274286
}
275287

@@ -280,17 +292,17 @@ func TestDecayedLogStartAndStop(t *testing.T) {
280292
// and retrieved cltv values are equal.
281293
func TestDecayedLogStorageAndRetrieval(t *testing.T) {
282294
// Random cltv value
283-
cltv := uint32(302930)
295+
cltv := uint32(7)
284296

285297
// Create a DecayedLog object
286298
d := DecayedLog{}
287299

288300
// Open the channeldb
289-
err := d.Start()
301+
err := d.Start("tempdir")
290302
if err != nil {
291303
t.Fatalf("Unable to start / open DecayedLog")
292304
}
293-
defer d.Stop()
305+
defer shutdown(&d)
294306

295307
// Create a new private key on elliptic curve secp256k1
296308
priv, err := btcec.NewPrivateKey(btcec.S256())

persistlog/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type PersistLog interface {
1919

2020
// Start starts up the on-disk persistent log. It returns an error if
2121
// one occurs.
22-
Start() error
22+
Start(string) error
2323

2424
// Stop safely stops the on-disk persistent log.
2525
Stop()

0 commit comments

Comments
 (0)