• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 12343072627

15 Dec 2024 11:09PM UTC coverage: 57.504% (-1.1%) from 58.636%
12343072627

Pull #9315

github

yyforyongyu
contractcourt: offer outgoing htlc one block earlier before its expiry

We need to offer the outgoing htlc one block earlier to make sure when
the expiry height hits, the sweeper will not miss sweeping it in the
same block. This also means the outgoing contest resolver now only does
one thing - watch for preimage spend till height expiry-1, which can
easily be moved into the timeout resolver instead in the future.
Pull Request #9315: Implement `blockbeat`

1445 of 2007 new or added lines in 26 files covered. (72.0%)

19246 existing lines in 249 files now uncovered.

102342 of 177975 relevant lines covered (57.5%)

24772.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/htlcswitch/sequencer.go
1
package htlcswitch
2

3
import (
4
        "sync"
5

6
        "github.com/go-errors/errors"
7
        "github.com/lightningnetwork/lnd/channeldb"
8
        "github.com/lightningnetwork/lnd/kvdb"
9
)
10

11
// defaultSequenceBatchSize specifies the window of sequence numbers that are
12
// allocated for each write to disk made by the sequencer.
13
const defaultSequenceBatchSize = 1000
14

15
// Sequencer emits sequence numbers for locally initiated HTLCs. These are
16
// only used internally for tracking pending payments, however they must be
17
// unique in order to avoid circuit key collision in the circuit map.
18
type Sequencer interface {
19
        // NextID returns a unique sequence number for each invocation.
20
        NextID() (uint64, error)
21
}
22

23
var (
24
        // nextPaymentIDKey identifies the bucket that will keep track of the
25
        // persistent sequence numbers for payments.
26
        nextPaymentIDKey = []byte("next-payment-id-key")
27

28
        // ErrSequencerCorrupted signals that the persistence engine was not
29
        // initialized, or has been corrupted since startup.
30
        ErrSequencerCorrupted = errors.New(
31
                "sequencer database has been corrupted")
32
)
33

34
// persistentSequencer is a concrete implementation of IDGenerator, that uses
35
// channeldb to allocate sequence numbers.
36
type persistentSequencer struct {
37
        db *channeldb.DB
38

39
        mu sync.Mutex
40

41
        nextID    uint64
42
        horizonID uint64
43
}
44

45
// NewPersistentSequencer initializes a new sequencer using a channeldb backend.
UNCOV
46
func NewPersistentSequencer(db *channeldb.DB) (Sequencer, error) {
×
UNCOV
47
        g := &persistentSequencer{
×
UNCOV
48
                db: db,
×
UNCOV
49
        }
×
UNCOV
50

×
UNCOV
51
        // Ensure the database bucket is created before any updates are
×
UNCOV
52
        // performed.
×
UNCOV
53
        if err := g.initDB(); err != nil {
×
54
                return nil, err
×
55
        }
×
56

UNCOV
57
        return g, nil
×
58
}
59

60
// NextID returns a unique sequence number for every invocation, persisting the
61
// assignment to avoid reuse.
UNCOV
62
func (s *persistentSequencer) NextID() (uint64, error) {
×
UNCOV
63

×
UNCOV
64
        // nextID will be the unique sequence number returned if no errors are
×
UNCOV
65
        // encountered.
×
UNCOV
66
        var nextID uint64
×
UNCOV
67

×
UNCOV
68
        // If our sequence batch has not been exhausted, we can allocate the
×
UNCOV
69
        // next identifier in the range.
×
UNCOV
70
        s.mu.Lock()
×
UNCOV
71
        defer s.mu.Unlock()
×
UNCOV
72

×
UNCOV
73
        if s.nextID < s.horizonID {
×
UNCOV
74
                nextID = s.nextID
×
UNCOV
75
                s.nextID++
×
UNCOV
76

×
UNCOV
77
                return nextID, nil
×
UNCOV
78
        }
×
79

80
        // Otherwise, our sequence batch has been exhausted. We use the last
81
        // known sequence number on disk to mark the beginning of the next
82
        // sequence batch, and allocate defaultSequenceBatchSize (1000) at a
83
        // time.
84
        //
85
        // NOTE: This also will happen on the first invocation after startup,
86
        // i.e. when nextID and horizonID are both 0. The next sequence batch to be
87
        // allocated will start from the last known tip on disk, which is fine
88
        // as we only require uniqueness of the allocated numbers.
UNCOV
89
        var nextHorizonID uint64
×
UNCOV
90
        if err := kvdb.Update(s.db, func(tx kvdb.RwTx) error {
×
UNCOV
91
                nextIDBkt := tx.ReadWriteBucket(nextPaymentIDKey)
×
UNCOV
92
                if nextIDBkt == nil {
×
93
                        return ErrSequencerCorrupted
×
94
                }
×
95

UNCOV
96
                nextID = nextIDBkt.Sequence()
×
UNCOV
97
                nextHorizonID = nextID + defaultSequenceBatchSize
×
UNCOV
98

×
UNCOV
99
                // Cannot fail when used in Update.
×
UNCOV
100
                nextIDBkt.SetSequence(nextHorizonID)
×
UNCOV
101

×
UNCOV
102
                return nil
×
UNCOV
103
        }, func() {
×
UNCOV
104
                nextHorizonID = 0
×
UNCOV
105
        }); err != nil {
×
106
                return 0, err
×
107
        }
×
108

109
        // Never assign index zero, to avoid collisions with the EmptyKeystone.
UNCOV
110
        if nextID == 0 {
×
UNCOV
111
                nextID++
×
UNCOV
112
        }
×
113

114
        // If our batch sequence allocation succeed, update our in-memory values
115
        // so we can continue to allocate sequence numbers without hitting disk.
116
        // The nextID is incremented by one in memory so the in can be used
117
        // issued directly on the next invocation.
UNCOV
118
        s.nextID = nextID + 1
×
UNCOV
119
        s.horizonID = nextHorizonID
×
UNCOV
120

×
UNCOV
121
        return nextID, nil
×
122
}
123

124
// initDB populates the bucket used to generate payment sequence numbers.
UNCOV
125
func (s *persistentSequencer) initDB() error {
×
UNCOV
126
        return kvdb.Update(s.db, func(tx kvdb.RwTx) error {
×
UNCOV
127
                _, err := tx.CreateTopLevelBucket(nextPaymentIDKey)
×
UNCOV
128
                return err
×
UNCOV
129
        }, func() {})
×
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc