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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

81.45
/contractcourt/anchor_resolver.go
1
package contractcourt
2

3
import (
4
        "errors"
5
        "io"
6
        "sync"
7

8
        "github.com/btcsuite/btcd/btcutil"
9
        "github.com/btcsuite/btcd/chaincfg/chainhash"
10
        "github.com/btcsuite/btcd/wire"
11
        "github.com/lightningnetwork/lnd/channeldb"
12
        "github.com/lightningnetwork/lnd/fn"
13
        "github.com/lightningnetwork/lnd/input"
14
        "github.com/lightningnetwork/lnd/sweep"
15
)
16

17
// anchorResolver is a resolver that will attempt to sweep our anchor output.
18
type anchorResolver struct {
19
        // anchorSignDescriptor contains the information that is required to
20
        // sweep the anchor.
21
        anchorSignDescriptor input.SignDescriptor
22

23
        // anchor is the outpoint on the commitment transaction.
24
        anchor wire.OutPoint
25

26
        // resolved reflects if the contract has been fully resolved or not.
27
        resolved bool
28

29
        // broadcastHeight is the height that the original contract was
30
        // broadcast to the main-chain at. We'll use this value to bound any
31
        // historical queries to the chain for spends/confirmations.
32
        broadcastHeight uint32
33

34
        // chanPoint is the channel point of the original contract.
35
        chanPoint wire.OutPoint
36

37
        // chanType denotes the type of channel the contract belongs to.
38
        chanType channeldb.ChannelType
39

40
        // currentReport stores the current state of the resolver for reporting
41
        // over the rpc interface.
42
        currentReport ContractReport
43

44
        // reportLock prevents concurrent access to the resolver report.
45
        reportLock sync.Mutex
46

47
        contractResolverKit
48
}
49

50
// newAnchorResolver instantiates a new anchor resolver.
51
func newAnchorResolver(anchorSignDescriptor input.SignDescriptor,
52
        anchor wire.OutPoint, broadcastHeight uint32,
53
        chanPoint wire.OutPoint, resCfg ResolverConfig) *anchorResolver {
2✔
54

2✔
55
        amt := btcutil.Amount(anchorSignDescriptor.Output.Value)
2✔
56

2✔
57
        report := ContractReport{
2✔
58
                Outpoint:         anchor,
2✔
59
                Type:             ReportOutputAnchor,
2✔
60
                Amount:           amt,
2✔
61
                LimboBalance:     amt,
2✔
62
                RecoveredBalance: 0,
2✔
63
        }
2✔
64

2✔
65
        r := &anchorResolver{
2✔
66
                contractResolverKit:  *newContractResolverKit(resCfg),
2✔
67
                anchorSignDescriptor: anchorSignDescriptor,
2✔
68
                anchor:               anchor,
2✔
69
                broadcastHeight:      broadcastHeight,
2✔
70
                chanPoint:            chanPoint,
2✔
71
                currentReport:        report,
2✔
72
        }
2✔
73

2✔
74
        r.initLogger(r)
2✔
75

2✔
76
        return r
2✔
77
}
2✔
78

79
// ResolverKey returns an identifier which should be globally unique for this
80
// particular resolver within the chain the original contract resides within.
81
func (c *anchorResolver) ResolverKey() []byte {
2✔
82
        // The anchor resolver is stateless and doesn't need a database key.
2✔
83
        return nil
2✔
84
}
2✔
85

86
// Resolve offers the anchor output to the sweeper and waits for it to be swept.
87
func (c *anchorResolver) Resolve(_ bool) (ContractResolver, error) {
2✔
88
        // Attempt to update the sweep parameters to the post-confirmation
2✔
89
        // situation. We don't want to force sweep anymore, because the anchor
2✔
90
        // lost its special purpose to get the commitment confirmed. It is just
2✔
91
        // an output that we want to sweep only if it is economical to do so.
2✔
92
        //
2✔
93
        // An exclusive group is not necessary anymore, because we know that
2✔
94
        // this is the only anchor that can be swept.
2✔
95
        //
2✔
96
        // We also clear the parent tx information for cpfp, because the
2✔
97
        // commitment tx is confirmed.
2✔
98
        //
2✔
99
        // After a restart or when the remote force closes, the sweeper is not
2✔
100
        // yet aware of the anchor. In that case, it will be added as new input
2✔
101
        // to the sweeper.
2✔
102
        witnessType := input.CommitmentAnchor
2✔
103

2✔
104
        // For taproot channels, we need to use the proper witness type.
2✔
105
        if c.chanType.IsTaproot() {
2✔
UNCOV
106
                witnessType = input.TaprootAnchorSweepSpend
×
UNCOV
107
        }
×
108

109
        anchorInput := input.MakeBaseInput(
2✔
110
                &c.anchor, witnessType, &c.anchorSignDescriptor,
2✔
111
                c.broadcastHeight, nil,
2✔
112
        )
2✔
113

2✔
114
        resultChan, err := c.Sweeper.SweepInput(
2✔
115
                &anchorInput,
2✔
116
                sweep.Params{
2✔
117
                        // For normal anchor sweeping, the budget is 330 sats.
2✔
118
                        Budget: btcutil.Amount(
2✔
119
                                anchorInput.SignDesc().Output.Value,
2✔
120
                        ),
2✔
121

2✔
122
                        // There's no rush to sweep the anchor, so we use a nil
2✔
123
                        // deadline here.
2✔
124
                        DeadlineHeight: fn.None[int32](),
2✔
125
                },
2✔
126
        )
2✔
127
        if err != nil {
2✔
128
                return nil, err
×
129
        }
×
130

131
        var (
2✔
132
                outcome channeldb.ResolverOutcome
2✔
133
                spendTx *chainhash.Hash
2✔
134
        )
2✔
135

2✔
136
        select {
2✔
137
        case sweepRes := <-resultChan:
2✔
138
                switch sweepRes.Err {
2✔
139
                // Anchor was swept successfully.
140
                case nil:
2✔
141
                        sweepTxID := sweepRes.Tx.TxHash()
2✔
142

2✔
143
                        spendTx = &sweepTxID
2✔
144
                        outcome = channeldb.ResolverOutcomeClaimed
2✔
145

146
                // Anchor was swept by someone else. This is possible after the
147
                // 16 block csv lock.
UNCOV
148
                case sweep.ErrRemoteSpend:
×
UNCOV
149
                        c.log.Warnf("our anchor spent by someone else")
×
UNCOV
150
                        outcome = channeldb.ResolverOutcomeUnclaimed
×
151

152
                // An unexpected error occurred.
153
                default:
×
154
                        c.log.Errorf("unable to sweep anchor: %v", sweepRes.Err)
×
155

×
156
                        return nil, sweepRes.Err
×
157
                }
158

UNCOV
159
        case <-c.quit:
×
UNCOV
160
                return nil, errResolverShuttingDown
×
161
        }
162

163
        // Update report to reflect that funds are no longer in limbo.
164
        c.reportLock.Lock()
2✔
165
        if outcome == channeldb.ResolverOutcomeClaimed {
4✔
166
                c.currentReport.RecoveredBalance = c.currentReport.LimboBalance
2✔
167
        }
2✔
168
        c.currentReport.LimboBalance = 0
2✔
169
        report := c.currentReport.resolverReport(
2✔
170
                spendTx, channeldb.ResolverTypeAnchor, outcome,
2✔
171
        )
2✔
172
        c.reportLock.Unlock()
2✔
173

2✔
174
        c.resolved = true
2✔
175
        return nil, c.PutResolverReport(nil, report)
2✔
176
}
177

178
// Stop signals the resolver to cancel any current resolution processes, and
179
// suspend.
180
//
181
// NOTE: Part of the ContractResolver interface.
182
func (c *anchorResolver) Stop() {
2✔
183
        close(c.quit)
2✔
184
}
2✔
185

186
// IsResolved returns true if the stored state in the resolve is fully
187
// resolved. In this case the target output can be forgotten.
188
//
189
// NOTE: Part of the ContractResolver interface.
190
func (c *anchorResolver) IsResolved() bool {
5✔
191
        return c.resolved
5✔
192
}
5✔
193

194
// SupplementState allows the user of a ContractResolver to supplement it with
195
// state required for the proper resolution of a contract.
196
//
197
// NOTE: Part of the ContractResolver interface.
198
func (c *anchorResolver) SupplementState(state *channeldb.OpenChannel) {
2✔
199
        c.chanType = state.ChanType
2✔
200
}
2✔
201

202
// report returns a report on the resolution state of the contract.
UNCOV
203
func (c *anchorResolver) report() *ContractReport {
×
UNCOV
204
        c.reportLock.Lock()
×
UNCOV
205
        defer c.reportLock.Unlock()
×
UNCOV
206

×
UNCOV
207
        reportCopy := c.currentReport
×
UNCOV
208
        return &reportCopy
×
UNCOV
209
}
×
210

211
func (c *anchorResolver) Encode(w io.Writer) error {
×
212
        return errors.New("serialization not supported")
×
213
}
×
214

215
// A compile time assertion to ensure anchorResolver meets the
216
// ContractResolver interface.
217
var _ ContractResolver = (*anchorResolver)(nil)
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