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

lightningnetwork / lnd / 13236757158

10 Feb 2025 08:39AM UTC coverage: 57.649% (-1.2%) from 58.815%
13236757158

Pull #9493

github

ziggie1984
lncli: for some cmds we don't replace the data of the response.

For some cmds it is not very practical to replace the json output
because we might pipe it into other commands. For example when
creating the route we want to pipe it into sendtoRoute.
Pull Request #9493: For some lncli cmds we should not replace the content with other data

0 of 9 new or added lines in 2 files covered. (0.0%)

19535 existing lines in 252 files now uncovered.

103517 of 179563 relevant lines covered (57.65%)

24878.49 hits per line

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

76.3
/contractcourt/anchor_resolver.go
1
package contractcourt
2

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

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

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

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

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

32
        // chanPoint is the channel point of the original contract.
33
        chanPoint wire.OutPoint
34

35
        // chanType denotes the type of channel the contract belongs to.
36
        chanType channeldb.ChannelType
37

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

42
        // reportLock prevents concurrent access to the resolver report.
43
        reportLock sync.Mutex
44

45
        contractResolverKit
46
}
47

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

2✔
53
        amt := btcutil.Amount(anchorSignDescriptor.Output.Value)
2✔
54

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

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

2✔
72
        r.initLogger(fmt.Sprintf("%T(%v)", r, r.anchor))
2✔
73

2✔
74
        return r
2✔
75
}
2✔
76

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

84
// Resolve waits for the output to be swept.
85
//
86
// NOTE: Part of the ContractResolver interface.
87
func (c *anchorResolver) Resolve() (ContractResolver, error) {
2✔
88
        // If we're already resolved, then we can exit early.
2✔
89
        if c.IsResolved() {
2✔
90
                c.log.Errorf("already resolved")
×
91
                return nil, nil
×
92
        }
×
93

94
        var (
2✔
95
                outcome channeldb.ResolverOutcome
2✔
96
                spendTx *chainhash.Hash
2✔
97
        )
2✔
98

2✔
99
        select {
2✔
100
        case sweepRes := <-c.sweepResultChan:
2✔
101
                switch sweepRes.Err {
2✔
102
                // Anchor was swept successfully.
103
                case nil:
2✔
104
                        sweepTxID := sweepRes.Tx.TxHash()
2✔
105

2✔
106
                        spendTx = &sweepTxID
2✔
107
                        outcome = channeldb.ResolverOutcomeClaimed
2✔
108

109
                // Anchor was swept by someone else. This is possible after the
110
                // 16 block csv lock.
UNCOV
111
                case sweep.ErrRemoteSpend:
×
UNCOV
112
                        c.log.Warnf("our anchor spent by someone else")
×
UNCOV
113
                        outcome = channeldb.ResolverOutcomeUnclaimed
×
114

115
                // An unexpected error occurred.
116
                default:
×
117
                        c.log.Errorf("unable to sweep anchor: %v", sweepRes.Err)
×
118

×
119
                        return nil, sweepRes.Err
×
120
                }
121

UNCOV
122
        case <-c.quit:
×
UNCOV
123
                return nil, errResolverShuttingDown
×
124
        }
125

126
        c.log.Infof("resolved in tx %v", spendTx)
2✔
127

2✔
128
        // Update report to reflect that funds are no longer in limbo.
2✔
129
        c.reportLock.Lock()
2✔
130
        if outcome == channeldb.ResolverOutcomeClaimed {
4✔
131
                c.currentReport.RecoveredBalance = c.currentReport.LimboBalance
2✔
132
        }
2✔
133
        c.currentReport.LimboBalance = 0
2✔
134
        report := c.currentReport.resolverReport(
2✔
135
                spendTx, channeldb.ResolverTypeAnchor, outcome,
2✔
136
        )
2✔
137
        c.reportLock.Unlock()
2✔
138

2✔
139
        c.markResolved()
2✔
140
        return nil, c.PutResolverReport(nil, report)
2✔
141
}
142

143
// Stop signals the resolver to cancel any current resolution processes, and
144
// suspend.
145
//
146
// NOTE: Part of the ContractResolver interface.
147
func (c *anchorResolver) Stop() {
2✔
148
        c.log.Debugf("stopping...")
2✔
149
        defer c.log.Debugf("stopped")
2✔
150

2✔
151
        close(c.quit)
2✔
152
}
2✔
153

154
// SupplementState allows the user of a ContractResolver to supplement it with
155
// state required for the proper resolution of a contract.
156
//
157
// NOTE: Part of the ContractResolver interface.
158
func (c *anchorResolver) SupplementState(state *channeldb.OpenChannel) {
2✔
159
        c.chanType = state.ChanType
2✔
160
}
2✔
161

162
// report returns a report on the resolution state of the contract.
UNCOV
163
func (c *anchorResolver) report() *ContractReport {
×
UNCOV
164
        c.reportLock.Lock()
×
UNCOV
165
        defer c.reportLock.Unlock()
×
UNCOV
166

×
UNCOV
167
        reportCopy := c.currentReport
×
UNCOV
168
        return &reportCopy
×
UNCOV
169
}
×
170

171
func (c *anchorResolver) Encode(w io.Writer) error {
×
172
        return errors.New("serialization not supported")
×
173
}
×
174

175
// A compile time assertion to ensure anchorResolver meets the
176
// ContractResolver interface.
177
var _ ContractResolver = (*anchorResolver)(nil)
178

179
// Launch offers the anchor output to the sweeper.
180
func (c *anchorResolver) Launch() error {
2✔
181
        if c.isLaunched() {
2✔
UNCOV
182
                c.log.Tracef("already launched")
×
UNCOV
183
                return nil
×
UNCOV
184
        }
×
185

186
        c.log.Debugf("launching resolver...")
2✔
187
        c.markLaunched()
2✔
188

2✔
189
        // If we're already resolved, then we can exit early.
2✔
190
        if c.IsResolved() {
2✔
191
                c.log.Errorf("already resolved")
×
192
                return nil
×
193
        }
×
194

195
        // Attempt to update the sweep parameters to the post-confirmation
196
        // situation. We don't want to force sweep anymore, because the anchor
197
        // lost its special purpose to get the commitment confirmed. It is just
198
        // an output that we want to sweep only if it is economical to do so.
199
        //
200
        // An exclusive group is not necessary anymore, because we know that
201
        // this is the only anchor that can be swept.
202
        //
203
        // We also clear the parent tx information for cpfp, because the
204
        // commitment tx is confirmed.
205
        //
206
        // After a restart or when the remote force closes, the sweeper is not
207
        // yet aware of the anchor. In that case, it will be added as new input
208
        // to the sweeper.
209
        witnessType := input.CommitmentAnchor
2✔
210

2✔
211
        // For taproot channels, we need to use the proper witness type.
2✔
212
        if c.chanType.IsTaproot() {
2✔
UNCOV
213
                witnessType = input.TaprootAnchorSweepSpend
×
UNCOV
214
        }
×
215

216
        anchorInput := input.MakeBaseInput(
2✔
217
                &c.anchor, witnessType, &c.anchorSignDescriptor,
2✔
218
                c.broadcastHeight, nil,
2✔
219
        )
2✔
220

2✔
221
        resultChan, err := c.Sweeper.SweepInput(
2✔
222
                &anchorInput,
2✔
223
                sweep.Params{
2✔
224
                        // For normal anchor sweeping, the budget is 330 sats.
2✔
225
                        Budget: btcutil.Amount(
2✔
226
                                anchorInput.SignDesc().Output.Value,
2✔
227
                        ),
2✔
228

2✔
229
                        // There's no rush to sweep the anchor, so we use a nil
2✔
230
                        // deadline here.
2✔
231
                        DeadlineHeight: fn.None[int32](),
2✔
232
                },
2✔
233
        )
2✔
234

2✔
235
        if err != nil {
2✔
236
                return err
×
237
        }
×
238

239
        c.sweepResultChan = resultChan
2✔
240

2✔
241
        return nil
2✔
242
}
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