Skip to content

Commit f794333

Browse files
authored
Merge pull request #194 from lightninglabs/triggerforceclose-lnd-19
lnd: improve brontide mock, improve triggerforceclose, make zombierecovery makeoffer CLN compatible
2 parents ea9895c + ec6b7c5 commit f794333

File tree

12 files changed

+392
-106
lines changed

12 files changed

+392
-106
lines changed

btc/summary.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ func SummarizeChannels(api *ExplorerAPI, channels []*dataformat.SummaryEntry,
4747
} else {
4848
summaryFile.OpenChannels++
4949
summaryFile.FundsOpenChannels += channel.LocalBalance
50+
summaryFile.OpenChannelList = append(
51+
summaryFile.OpenChannelList, channel,
52+
)
5053
channel.ClosingTX = nil
5154
channel.HasPotential = true
5255
}

cln/signer.go

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -95,36 +95,22 @@ func (s *Signer) FindMultisigKey(targetPubkey, peerPubKey *btcec.PublicKey,
9595
return nil, errors.New("no matching pubkeys found")
9696
}
9797

98-
func (s *Signer) AddPartialSignature(packet *psbt.Packet,
99-
keyDesc keychain.KeyDescriptor, utxo *wire.TxOut, witnessScript []byte,
100-
inputIndex int) error {
98+
func (s *Signer) AddPartialSignatureWithDesc(packet *psbt.Packet,
99+
signDesc *input.SignDescriptor) error {
101100

102-
// Now we add our partial signature.
103-
prevOutFetcher := wallet.PsbtPrevOutputFetcher(packet)
104-
signDesc := &input.SignDescriptor{
105-
KeyDesc: keyDesc,
106-
WitnessScript: witnessScript,
107-
Output: utxo,
108-
InputIndex: inputIndex,
109-
HashType: txscript.SigHashAll,
110-
PrevOutputFetcher: prevOutFetcher,
111-
SigHashes: txscript.NewTxSigHashes(
112-
packet.UnsignedTx, prevOutFetcher,
113-
),
114-
}
115101
ourSigRaw, err := s.SignOutputRaw(packet.UnsignedTx, signDesc)
116102
if err != nil {
117103
return fmt.Errorf("error signing with our key: %w", err)
118104
}
119-
ourSig := append(ourSigRaw.Serialize(), byte(txscript.SigHashAll))
105+
ourSig := append(ourSigRaw.Serialize(), byte(signDesc.HashType))
120106

121107
// Because of the way we derive keys in CLN, the public key in the key
122108
// descriptor is the peer's public key, not our own. So we need to
123109
// derive our own public key from the private key.
124-
ourPrivKey, err := s.FetchPrivateKey(&keyDesc)
110+
ourPrivKey, err := s.FetchPrivateKey(&signDesc.KeyDesc)
125111
if err != nil {
126112
return fmt.Errorf("error fetching private key for descriptor "+
127-
"%v: %w", keyDesc, err)
113+
"%v: %w", signDesc.KeyDesc, err)
128114
}
129115
ourPubKey := ourPrivKey.PubKey()
130116

@@ -134,8 +120,8 @@ func (s *Signer) AddPartialSignature(packet *psbt.Packet,
134120
return fmt.Errorf("error creating PSBT updater: %w", err)
135121
}
136122
status, err := updater.Sign(
137-
inputIndex, ourSig, ourPubKey.SerializeCompressed(), nil,
138-
witnessScript,
123+
signDesc.InputIndex, ourSig, ourPubKey.SerializeCompressed(),
124+
nil, signDesc.WitnessScript,
139125
)
140126
if err != nil {
141127
return fmt.Errorf("error adding signature to PSBT: %w", err)
@@ -148,4 +134,25 @@ func (s *Signer) AddPartialSignature(packet *psbt.Packet,
148134
return nil
149135
}
150136

137+
func (s *Signer) AddPartialSignature(packet *psbt.Packet,
138+
keyDesc keychain.KeyDescriptor, utxo *wire.TxOut, witnessScript []byte,
139+
inputIndex int) error {
140+
141+
// Now we add our partial signature.
142+
prevOutFetcher := wallet.PsbtPrevOutputFetcher(packet)
143+
signDesc := &input.SignDescriptor{
144+
KeyDesc: keyDesc,
145+
WitnessScript: witnessScript,
146+
Output: utxo,
147+
InputIndex: inputIndex,
148+
HashType: txscript.SigHashAll,
149+
PrevOutputFetcher: prevOutFetcher,
150+
SigHashes: txscript.NewTxSigHashes(
151+
packet.UnsignedTx, prevOutFetcher,
152+
),
153+
}
154+
155+
return s.AddPartialSignatureWithDesc(packet, signDesc)
156+
}
157+
151158
var _ lnd.ChannelSigner = (*Signer)(nil)

cmd/chantools/sweepremoteclosed.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,10 @@ func findTargetsCln(hsmSecret [32]byte, pubKeys []*btcec.PublicKey,
347347
targets []*targetAddr
348348
api = newExplorerAPI(apiURL)
349349
)
350-
for _, pubKey := range pubKeys {
350+
for idx, pubKey := range pubKeys {
351+
log.Infof("Trying to find targets for pubkey %x (%d of %d)",
352+
pubKey.SerializeCompressed(), idx+1, len(pubKeys))
353+
351354
for index := range recoveryWindow {
352355
desc := &keychain.KeyDescriptor{
353356
PubKey: pubKey,
@@ -370,6 +373,14 @@ func findTargetsCln(hsmSecret [32]byte, pubKeys []*btcec.PublicKey,
370373
"for addresses with funds: %w", err)
371374
}
372375
targets = append(targets, foundTargets...)
376+
377+
if idx > 0 && idx%200 == 0 {
378+
log.Infof("Tried %d addresses for pubkey "+
379+
"%x (%d of %d), found %d targets so "+
380+
"far", index+1,
381+
pubKey.SerializeCompressed(), idx+1,
382+
len(pubKeys), len(targets))
383+
}
373384
}
374385
}
375386

cmd/chantools/triggerforceclose.go

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,19 +169,33 @@ func (c *triggerForceCloseCommand) Execute(_ *cobra.Command, _ []string) error {
169169
pubKeys []string
170170
outputs []string
171171
)
172-
for _, openChan := range channels {
172+
for idx, openChan := range channels {
173173
addr := pickAddr(openChan.Node2Info.Node.Addresses)
174174
peerAddr := fmt.Sprintf("%s@%s", openChan.Node2, addr)
175+
176+
if c.TorProxy == "" &&
177+
strings.Contains(addr, ".onion") {
178+
179+
log.Infof("Skipping channel %s with peer %s "+
180+
"because it is a Tor address and no "+
181+
"Tor proxy is configured",
182+
openChan.ChanPoint, peerAddr)
183+
continue
184+
}
185+
175186
log.Infof("Attempting to force close channel %s with "+
176-
"peer %s", openChan.ChanPoint, peerAddr)
187+
"peer %s (channel %d of %d)",
188+
openChan.ChanPoint, peerAddr, idx+1,
189+
len(channels))
177190

178191
outputAddrs, err := closeChannel(
179192
identityPriv, api, openChan.ChanPoint,
180193
peerAddr, c.TorProxy,
181194
)
182195
if err != nil {
183196
log.Errorf("Error closing channel %s, "+
184-
"skipping: %v", openChan.ChanPoint, err)
197+
"skipping and trying next one. "+
198+
"Reason: %v", openChan.ChanPoint, err)
185199
continue
186200
}
187201

@@ -220,7 +234,7 @@ func pickAddr(addrs []*gqAddress) string {
220234

221235
// We'll pick the first address that is not a Tor address.
222236
for _, addr := range addrs {
223-
if !strings.HasSuffix(addr.Address, ".onion") {
237+
if !strings.Contains(addr.Address, ".onion") {
224238
return addr.Address
225239
}
226240
}
@@ -262,13 +276,21 @@ func closeChannel(identityPriv *btcec.PrivateKey, api *btc.ExplorerAPI,
262276
if err != nil {
263277
return nil, fmt.Errorf("error getting spends: %w", err)
264278
}
279+
280+
counter := 0
265281
for len(spends) == 0 {
266282
log.Infof("No spends found yet, waiting 5 seconds...")
267283
time.Sleep(5 * time.Second)
268284
spends, err = api.Spends(channelAddress)
269285
if err != nil {
270286
return nil, fmt.Errorf("error getting spends: %w", err)
271287
}
288+
289+
counter++
290+
if counter >= 12 {
291+
return nil, errors.New("no spends found after 60 " +
292+
"seconds, aborting re-try loop")
293+
}
272294
}
273295

274296
log.Infof("Found force close transaction %v", spends[0].TXID)
@@ -289,7 +311,11 @@ func noiseDial(idKey keychain.SingleKeyECDH, lnAddr *lnwire.NetAddress,
289311
}
290312

291313
func connectPeer(peerHost, torProxy string, identity keychain.SingleKeyECDH,
292-
dialTimeout time.Duration) (*peer.Brontide, error) {
314+
dialTimeout time.Duration) (*peer.Brontide, func() error, error) {
315+
316+
cleanup := func() error {
317+
return nil
318+
}
293319

294320
var dialNet tor.Net = &tor.ClearNet{}
295321
if torProxy != "" {
@@ -306,7 +332,8 @@ func connectPeer(peerHost, torProxy string, identity keychain.SingleKeyECDH,
306332
peerHost, "9735", dialNet.ResolveTCPAddr,
307333
)
308334
if err != nil {
309-
return nil, fmt.Errorf("error parsing peer address: %w", err)
335+
return nil, cleanup, fmt.Errorf("error parsing peer address: "+
336+
"%w", err)
310337
}
311338

312339
peerPubKey := peerAddr.IdentityKey
@@ -315,7 +342,11 @@ func connectPeer(peerHost, torProxy string, identity keychain.SingleKeyECDH,
315342
peerAddr.String())
316343
conn, err := noiseDial(identity, peerAddr, dialNet, dialTimeout)
317344
if err != nil {
318-
return nil, fmt.Errorf("error dialing peer: %w", err)
345+
return nil, cleanup, fmt.Errorf("error dialing peer: %w", err)
346+
}
347+
348+
cleanup = func() error {
349+
return conn.Close()
319350
}
320351

321352
log.Infof("Attempting to establish p2p connection to peer %x, dial"+
@@ -324,9 +355,20 @@ func connectPeer(peerHost, torProxy string, identity keychain.SingleKeyECDH,
324355
Addr: peerAddr,
325356
Permanent: false,
326357
}
327-
p, err := lnd.ConnectPeer(conn, req, chainParams, identity)
358+
p, channelDB, err := lnd.ConnectPeer(conn, req, chainParams, identity)
328359
if err != nil {
329-
return nil, fmt.Errorf("error connecting to peer: %w", err)
360+
return nil, cleanup, fmt.Errorf("error connecting to peer: %w",
361+
err)
362+
}
363+
364+
cleanup = func() error {
365+
p.Disconnect(errors.New("done with peer"))
366+
if channelDB != nil {
367+
if err := channelDB.Close(); err != nil {
368+
log.Errorf("Error closing channel DB: %v", err)
369+
}
370+
}
371+
return conn.Close()
330372
}
331373

332374
log.Infof("Connection established to peer %x",
@@ -336,17 +378,23 @@ func connectPeer(peerHost, torProxy string, identity keychain.SingleKeyECDH,
336378
select {
337379
case <-p.ActiveSignal():
338380
case <-p.QuitSignal():
339-
return nil, fmt.Errorf("peer %x disconnected",
381+
return nil, cleanup, fmt.Errorf("peer %x disconnected",
340382
peerPubKey.SerializeCompressed())
341383
}
342384

343-
return p, nil
385+
return p, cleanup, nil
344386
}
345387

346388
func requestForceClose(peerHost, torProxy string, channelPoint wire.OutPoint,
347389
identity keychain.SingleKeyECDH) error {
348390

349-
p, err := connectPeer(peerHost, torProxy, identity, dialTimeout)
391+
p, cleanup, err := connectPeer(
392+
peerHost, torProxy, identity, dialTimeout,
393+
)
394+
defer func() {
395+
_ = cleanup()
396+
}()
397+
350398
if err != nil {
351399
return fmt.Errorf("error connecting to peer: %w", err)
352400
}
@@ -383,6 +431,9 @@ func requestForceClose(peerHost, torProxy string, channelPoint wire.OutPoint,
383431
return fmt.Errorf("error sending message: %w", err)
384432
}
385433

434+
// Wait a few seconds to give the peer time to process the message.
435+
time.Sleep(5 * time.Second)
436+
386437
return nil
387438
}
388439

0 commit comments

Comments
 (0)