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

lightningnetwork / lnd / 12430538171

20 Dec 2024 11:21AM UTC coverage: 58.716% (+0.1%) from 58.576%
12430538171

push

github

web-flow
Merge pull request #9381 from yyforyongyu/fix-no-space-left

workflows: fix no space left error

135265 of 230373 relevant lines covered (58.72%)

19174.52 hits per line

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

88.89
/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 {
5✔
52

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

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

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

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

5✔
74
        return r
5✔
75
}
5✔
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 {
5✔
80
        // The anchor resolver is stateless and doesn't need a database key.
5✔
81
        return nil
5✔
82
}
5✔
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) {
5✔
88
        // If we're already resolved, then we can exit early.
5✔
89
        if c.IsResolved() {
5✔
90
                c.log.Errorf("already resolved")
×
91
                return nil, nil
×
92
        }
×
93

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

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

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

109
                // Anchor was swept by someone else. This is possible after the
110
                // 16 block csv lock.
111
                case sweep.ErrRemoteSpend:
3✔
112
                        c.log.Warnf("our anchor spent by someone else")
3✔
113
                        outcome = channeldb.ResolverOutcomeUnclaimed
3✔
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

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

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

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

5✔
139
        c.markResolved()
5✔
140
        return nil, c.PutResolverReport(nil, report)
5✔
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() {
5✔
148
        c.log.Debugf("stopping...")
5✔
149
        defer c.log.Debugf("stopped")
5✔
150

5✔
151
        close(c.quit)
5✔
152
}
5✔
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) {
5✔
159
        c.chanType = state.ChanType
5✔
160
}
5✔
161

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

3✔
167
        reportCopy := c.currentReport
3✔
168
        return &reportCopy
3✔
169
}
3✔
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 {
5✔
181
        if c.isLaunched() {
8✔
182
                c.log.Tracef("already launched")
3✔
183
                return nil
3✔
184
        }
3✔
185

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

5✔
189
        // If we're already resolved, then we can exit early.
5✔
190
        if c.IsResolved() {
5✔
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
5✔
210

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

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

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

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

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

239
        c.sweepResultChan = resultChan
5✔
240

5✔
241
        return nil
5✔
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