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

lightningnetwork / lnd / 12312390362

13 Dec 2024 08:44AM UTC coverage: 57.458% (+8.5%) from 48.92%
12312390362

Pull #9343

github

ellemouton
fn: rework the ContextGuard and add tests

In this commit, the ContextGuard struct is re-worked such that the
context that its new main WithCtx method provides is cancelled in sync
with a parent context being cancelled or with it's quit channel being
cancelled. Tests are added to assert the behaviour. In order for the
close of the quit channel to be consistent with the cancelling of the
derived context, the quit channel _must_ be contained internal to the
ContextGuard so that callers are only able to close the channel via the
exposed Quit method which will then take care to first cancel any
derived context that depend on the quit channel before returning.
Pull Request #9343: fn: expand the ContextGuard and add tests

101853 of 177264 relevant lines covered (57.46%)

24972.93 hits per line

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

76.19
/chainntnfs/best_block_view.go
1
package chainntnfs
2

3
import (
4
        "errors"
5
        "fmt"
6
        "sync"
7
        "sync/atomic"
8

9
        "github.com/btcsuite/btcd/wire"
10
)
11

12
// BestBlockView is an interface that allows the querying of the most
13
// up-to-date blockchain state with low overhead. Valid implementations of this
14
// interface must track the latest chain state.
15
type BestBlockView interface {
16
        // BestHeight gets the most recent block height known to the view.
17
        BestHeight() (uint32, error)
18

19
        // BestBlockHeader gets the most recent block header known to the view.
20
        BestBlockHeader() (*wire.BlockHeader, error)
21
}
22

23
// BestBlockTracker is a tiny subsystem that tracks the blockchain tip
24
// and saves the most recent tip information in memory for querying. It is a
25
// valid implementation of BestBlockView and additionally includes
26
// methods for starting and stopping the system.
27
type BestBlockTracker struct {
28
        notifier        ChainNotifier
29
        blockNtfnStream *BlockEpochEvent
30
        current         atomic.Pointer[BlockEpoch]
31
        mu              sync.Mutex
32
        quit            chan struct{}
33
        wg              sync.WaitGroup
34
}
35

36
// This is a compile time check to ensure that BestBlockTracker implements
37
// BestBlockView.
38
var _ BestBlockView = (*BestBlockTracker)(nil)
39

40
// NewBestBlockTracker creates a new BestBlockTracker that isn't running yet.
41
// It will not provide up to date information unless it has been started. The
42
// ChainNotifier parameter must also be started prior to starting the
43
// BestBlockTracker.
44
func NewBestBlockTracker(chainNotifier ChainNotifier) *BestBlockTracker {
1✔
45
        return &BestBlockTracker{
1✔
46
                notifier:        chainNotifier,
1✔
47
                blockNtfnStream: nil,
1✔
48
                quit:            make(chan struct{}),
1✔
49
        }
1✔
50
}
1✔
51

52
// BestHeight gets the most recent block height known to the
53
// BestBlockTracker.
54
func (t *BestBlockTracker) BestHeight() (uint32, error) {
250✔
55
        epoch := t.current.Load()
250✔
56
        if epoch == nil {
250✔
57
                return 0, errors.New("best block height not yet known")
×
58
        }
×
59

60
        return uint32(epoch.Height), nil
250✔
61
}
62

63
// BestBlockHeader gets the most recent block header known to the
64
// BestBlockTracker.
65
func (t *BestBlockTracker) BestBlockHeader() (*wire.BlockHeader, error) {
150✔
66
        epoch := t.current.Load()
150✔
67
        if epoch == nil {
150✔
68
                return nil, errors.New("best block header not yet known")
×
69
        }
×
70

71
        return epoch.BlockHeader, nil
150✔
72
}
73

74
// updateLoop is a helper that subscribes to the underlying BlockEpochEvent
75
// stream and updates the internal values to match the new BlockEpochs that
76
// are discovered.
77
//
78
// MUST be run as a goroutine.
79
func (t *BestBlockTracker) updateLoop() {
1✔
80
        defer t.wg.Done()
1✔
81
        for {
102✔
82
                select {
101✔
83
                case epoch, ok := <-t.blockNtfnStream.Epochs:
100✔
84
                        if !ok {
100✔
85
                                Log.Error("dead epoch stream in " +
×
86
                                        "BestBlockTracker")
×
87

×
88
                                return
×
89
                        }
×
90
                        t.current.Store(epoch)
100✔
91
                case <-t.quit:
1✔
92
                        t.current.Store(nil)
1✔
93
                        return
1✔
94
                }
95
        }
96
}
97

98
// Start starts the BestBlockTracker. It is an error to start it if it
99
// is already started.
100
func (t *BestBlockTracker) Start() error {
1✔
101
        t.mu.Lock()
1✔
102
        defer t.mu.Unlock()
1✔
103

1✔
104
        if t.blockNtfnStream != nil {
1✔
105
                return fmt.Errorf("BestBlockTracker is already started")
×
106
        }
×
107

108
        var err error
1✔
109
        t.blockNtfnStream, err = t.notifier.RegisterBlockEpochNtfn(nil)
1✔
110
        if err != nil {
1✔
111
                return err
×
112
        }
×
113

114
        t.wg.Add(1)
1✔
115
        go t.updateLoop()
1✔
116

1✔
117
        return nil
1✔
118
}
119

120
// Stop stops the BestBlockTracker. It is an error to stop it if it has
121
// not been started or if it has already been stopped.
122
func (t *BestBlockTracker) Stop() error {
1✔
123
        t.mu.Lock()
1✔
124
        defer t.mu.Unlock()
1✔
125

1✔
126
        if t.blockNtfnStream == nil {
1✔
127
                return fmt.Errorf("BestBlockTracker is not running")
×
128
        }
×
129
        close(t.quit)
1✔
130
        t.wg.Wait()
1✔
131
        t.blockNtfnStream.Cancel()
1✔
132
        t.blockNtfnStream = nil
1✔
133

1✔
134
        return nil
1✔
135
}
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