Skip to content

Commit 347e719

Browse files
Roasbeefguggero
authored andcommitted
peer: decorate delivery addr w/ internal key
In this commit, we move to add the internal key to the delivery addr. This way, we give the aux chan closer the extra information it may need to properly augment the normal co-op close process.
1 parent 482d2ba commit 347e719

File tree

4 files changed

+129
-17
lines changed

4 files changed

+129
-17
lines changed

lntest/mock/walletcontroller.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,8 @@ func (w *WalletController) ConfirmedBalance(int32, string) (btcutil.Amount,
7878
func (w *WalletController) NewAddress(lnwallet.AddressType, bool,
7979
string) (btcutil.Address, error) {
8080

81-
addr, _ := btcutil.NewAddressPubKey(
82-
w.RootKey.PubKey().SerializeCompressed(), &chaincfg.MainNetParams,
83-
)
81+
pkh := btcutil.Hash160(w.RootKey.PubKey().SerializeCompressed())
82+
addr, _ := btcutil.NewAddressPubKeyHash(pkh, &chaincfg.MainNetParams)
8483
return addr, nil
8584
}
8685

lnwallet/chancloser/chancloser.go

+23-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"fmt"
66

7+
"github.com/btcsuite/btcd/btcec/v2"
78
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
89
"github.com/btcsuite/btcd/btcutil"
910
"github.com/btcsuite/btcd/chaincfg"
@@ -106,6 +107,18 @@ const (
106107
defaultMaxFeeMultiplier = 3
107108
)
108109

110+
// DeliveryAddrWithKey wraps a normal delivery addr, but also includes the
111+
// internal key for the delivery addr if known.
112+
type DeliveryAddrWithKey struct {
113+
// DeliveryAddress is the raw, serialized pkScript of the delivery
114+
// address.
115+
lnwire.DeliveryAddress
116+
117+
// InternalKey is the Taproot internal key of the delivery address, if
118+
// the address is a P2TR output.
119+
InternalKey fn.Option[btcec.PublicKey]
120+
}
121+
109122
// ChanCloseCfg holds all the items that a ChanCloser requires to carry out its
110123
// duties.
111124
type ChanCloseCfg struct {
@@ -208,6 +221,10 @@ type ChanCloser struct {
208221
// funds to.
209222
localDeliveryScript []byte
210223

224+
// localInternalKey is the local delivery address Taproot internal key,
225+
// if the local delivery script is a P2TR output.
226+
localInternalKey fn.Option[btcec.PublicKey]
227+
211228
// remoteDeliveryScript is the script that we'll send the remote party's
212229
// settled channel funds to.
213230
remoteDeliveryScript []byte
@@ -284,7 +301,7 @@ func (d *SimpleCoopFeeEstimator) EstimateFee(chanType channeldb.ChannelType,
284301
// NewChanCloser creates a new instance of the channel closure given the passed
285302
// configuration, and delivery+fee preference. The final argument should only
286303
// be populated iff, we're the initiator of this closing request.
287-
func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
304+
func NewChanCloser(cfg ChanCloseCfg, deliveryScript DeliveryAddrWithKey,
288305
idealFeePerKw chainfee.SatPerKWeight, negotiationHeight uint32,
289306
closeReq *htlcswitch.ChanClose,
290307
closer lntypes.ChannelParty) *ChanCloser {
@@ -299,7 +316,8 @@ func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
299316
cfg: cfg,
300317
negotiationHeight: negotiationHeight,
301318
idealFeeRate: idealFeePerKw,
302-
localDeliveryScript: deliveryScript,
319+
localInternalKey: deliveryScript.InternalKey,
320+
localDeliveryScript: deliveryScript.DeliveryAddress,
303321
priorFeeOffers: make(
304322
map[btcutil.Amount]*lnwire.ClosingSigned,
305323
),
@@ -362,6 +380,7 @@ func (c *ChanCloser) initChanShutdown() (*lnwire.Shutdown, error) {
362380
ChanPoint: c.chanPoint,
363381
ShortChanID: c.cfg.Channel.ShortChanID(),
364382
Initiator: c.cfg.Channel.IsInitiator(),
383+
InternalKey: c.localInternalKey,
365384
CommitBlob: c.cfg.Channel.LocalCommitmentBlob(),
366385
FundingBlob: c.cfg.Channel.FundingBlob(),
367386
})
@@ -966,6 +985,7 @@ func (c *ChanCloser) ReceiveClosingSigned( //nolint:funlen
966985
req := AuxShutdownReq{
967986
ChanPoint: c.chanPoint,
968987
ShortChanID: c.cfg.Channel.ShortChanID(),
988+
InternalKey: c.localInternalKey,
969989
Initiator: channel.IsInitiator(),
970990
CommitBlob: channel.LocalCommitmentBlob(),
971991
FundingBlob: channel.FundingBlob(),
@@ -1042,6 +1062,7 @@ func (c *ChanCloser) auxCloseOutputs(
10421062
req := AuxShutdownReq{
10431063
ChanPoint: c.chanPoint,
10441064
ShortChanID: c.cfg.Channel.ShortChanID(),
1065+
InternalKey: c.localInternalKey,
10451066
Initiator: c.cfg.Channel.IsInitiator(),
10461067
CommitBlob: c.cfg.Channel.LocalCommitmentBlob(),
10471068
FundingBlob: c.cfg.Channel.FundingBlob(),

lnwallet/chancloser/chancloser_test.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,8 @@ func TestMaxFeeClamp(t *testing.T) {
361361
Channel: &channel,
362362
MaxFee: test.inputMaxFee,
363363
FeeEstimator: &SimpleCoopFeeEstimator{},
364-
}, nil, test.idealFee, 0, nil, lntypes.Remote,
364+
}, DeliveryAddrWithKey{}, test.idealFee, 0, nil,
365+
lntypes.Remote,
365366
)
366367

367368
// We'll call initFeeBaseline early here since we need
@@ -402,7 +403,8 @@ func TestMaxFeeBailOut(t *testing.T) {
402403
MaxFee: idealFee * 2,
403404
}
404405
chanCloser := NewChanCloser(
405-
closeCfg, nil, idealFee, 0, nil, lntypes.Remote,
406+
closeCfg, DeliveryAddrWithKey{}, idealFee, 0,
407+
nil, lntypes.Remote,
406408
)
407409

408410
// We'll now force the channel state into the
@@ -526,7 +528,7 @@ func TestTaprootFastClose(t *testing.T) {
526528
DisableChannel: func(wire.OutPoint) error {
527529
return nil
528530
},
529-
}, nil, idealFee, 0, nil, lntypes.Local,
531+
}, DeliveryAddrWithKey{}, idealFee, 0, nil, lntypes.Local,
530532
)
531533
aliceCloser.initFeeBaseline()
532534

@@ -543,7 +545,7 @@ func TestTaprootFastClose(t *testing.T) {
543545
DisableChannel: func(wire.OutPoint) error {
544546
return nil
545547
},
546-
}, nil, idealFee, 0, nil, lntypes.Remote,
548+
}, DeliveryAddrWithKey{}, idealFee, 0, nil, lntypes.Remote,
547549
)
548550
bobCloser.initFeeBaseline()
549551

peer/brontide.go

+98-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/btcsuite/btcd/txscript"
1919
"github.com/btcsuite/btcd/wire"
2020
"github.com/btcsuite/btclog"
21+
"github.com/btcsuite/btcwallet/waddrmgr"
2122
"github.com/davecgh/go-spew/spew"
2223
"github.com/lightningnetwork/lnd/buffer"
2324
"github.com/lightningnetwork/lnd/build"
@@ -885,6 +886,72 @@ func (p *Brontide) QuitSignal() <-chan struct{} {
885886
return p.quit
886887
}
887888

889+
// internalKeyForAddr returns the internal key associated with a taproot
890+
// address.
891+
func internalKeyForAddr(wallet *lnwallet.LightningWallet,
892+
deliveryScript []byte) (fn.Option[btcec.PublicKey], error) {
893+
894+
none := fn.None[btcec.PublicKey]()
895+
896+
pkScript, err := txscript.ParsePkScript(deliveryScript)
897+
if err != nil {
898+
return none, err
899+
}
900+
addr, err := pkScript.Address(&wallet.Cfg.NetParams)
901+
if err != nil {
902+
return none, err
903+
}
904+
905+
walletAddr, err := wallet.AddressInfo(addr)
906+
if err != nil {
907+
return none, err
908+
}
909+
910+
// If the address isn't known to the wallet, we can't determine the
911+
// internal key.
912+
if walletAddr == nil {
913+
return none, nil
914+
}
915+
916+
// If it's not a taproot address, we don't require to know the internal
917+
// key in the first place. So we don't return an error here, but also no
918+
// internal key.
919+
if walletAddr.AddrType() != waddrmgr.TaprootPubKey {
920+
return none, nil
921+
}
922+
923+
pubKeyAddr, ok := walletAddr.(waddrmgr.ManagedPubKeyAddress)
924+
if !ok {
925+
return none, fmt.Errorf("expected pubkey addr, got %T",
926+
pubKeyAddr)
927+
}
928+
929+
return fn.Some(*pubKeyAddr.PubKey()), nil
930+
}
931+
932+
// addrWithInternalKey takes a delivery script, then attempts to supplement it
933+
// with information related to the internal key for the addr, but only if it's
934+
// a taproot addr.
935+
func (p *Brontide) addrWithInternalKey(
936+
deliveryScript []byte) fn.Result[chancloser.DeliveryAddrWithKey] {
937+
938+
// TODO(roasbeef): not compatible with external shutdown addr?
939+
// Currently, custom channels cannot be created with external upfront
940+
// shutdown addresses, so this shouldn't be an issue. We only require
941+
// the internal key for taproot addresses to be able to provide a non
942+
// inclusion proof of any scripts.
943+
944+
internalKey, err := internalKeyForAddr(p.cfg.Wallet, deliveryScript)
945+
if err != nil {
946+
return fn.Err[chancloser.DeliveryAddrWithKey](err)
947+
}
948+
949+
return fn.Ok(chancloser.DeliveryAddrWithKey{
950+
DeliveryAddress: deliveryScript,
951+
InternalKey: internalKey,
952+
})
953+
}
954+
888955
// loadActiveChannels creates indexes within the peer for tracking all active
889956
// channels returned by the database. It returns a slice of channel reestablish
890957
// messages that should be sent to the peer immediately, in case we have borked
@@ -1125,9 +1192,16 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) (
11251192
return
11261193
}
11271194

1195+
addr, err := p.addrWithInternalKey(
1196+
info.DeliveryScript.Val,
1197+
).Unpack()
1198+
if err != nil {
1199+
shutdownInfoErr = fmt.Errorf("unable to make "+
1200+
"delivery addr: %w", err)
1201+
return
1202+
}
11281203
chanCloser, err := p.createChanCloser(
1129-
lnChan, info.DeliveryScript.Val, feePerKw, nil,
1130-
info.Closer(),
1204+
lnChan, addr, feePerKw, nil, info.Closer(),
11311205
)
11321206
if err != nil {
11331207
shutdownInfoErr = fmt.Errorf("unable to "+
@@ -2886,8 +2960,12 @@ func (p *Brontide) fetchActiveChanCloser(chanID lnwire.ChannelID) (
28862960
return nil, fmt.Errorf("unable to estimate fee")
28872961
}
28882962

2963+
addr, err := p.addrWithInternalKey(deliveryScript).Unpack()
2964+
if err != nil {
2965+
return nil, fmt.Errorf("unable to parse addr: %w", err)
2966+
}
28892967
chanCloser, err = p.createChanCloser(
2890-
channel, deliveryScript, feePerKw, nil, lntypes.Remote,
2968+
channel, addr, feePerKw, nil, lntypes.Remote,
28912969
)
28922970
if err != nil {
28932971
p.log.Errorf("unable to create chan closer: %v", err)
@@ -3129,8 +3207,12 @@ func (p *Brontide) restartCoopClose(lnChan *lnwallet.LightningChannel) (
31293207
closingParty = lntypes.Local
31303208
}
31313209

3210+
addr, err := p.addrWithInternalKey(deliveryScript).Unpack()
3211+
if err != nil {
3212+
return nil, fmt.Errorf("unable to parse addr: %w", err)
3213+
}
31323214
chanCloser, err := p.createChanCloser(
3133-
lnChan, deliveryScript, feePerKw, nil, closingParty,
3215+
lnChan, addr, feePerKw, nil, closingParty,
31343216
)
31353217
if err != nil {
31363218
p.log.Errorf("unable to create chan closer: %v", err)
@@ -3157,8 +3239,8 @@ func (p *Brontide) restartCoopClose(lnChan *lnwallet.LightningChannel) (
31573239
// createChanCloser constructs a ChanCloser from the passed parameters and is
31583240
// used to de-duplicate code.
31593241
func (p *Brontide) createChanCloser(channel *lnwallet.LightningChannel,
3160-
deliveryScript lnwire.DeliveryAddress, fee chainfee.SatPerKWeight,
3161-
req *htlcswitch.ChanClose,
3242+
deliveryScript chancloser.DeliveryAddrWithKey,
3243+
fee chainfee.SatPerKWeight, req *htlcswitch.ChanClose,
31623244
closer lntypes.ChannelParty) (*chancloser.ChanCloser, error) {
31633245

31643246
_, startingHeight, err := p.cfg.ChainIO.GetBestBlock()
@@ -3179,6 +3261,7 @@ func (p *Brontide) createChanCloser(channel *lnwallet.LightningChannel,
31793261
MusigSession: NewMusigChanCloser(channel),
31803262
FeeEstimator: &chancloser.SimpleCoopFeeEstimator{},
31813263
BroadcastTx: p.cfg.Wallet.PublishTransaction,
3264+
AuxCloser: p.cfg.AuxChanCloser,
31823265
DisableChannel: func(op wire.OutPoint) error {
31833266
return p.cfg.ChanStatusMgr.RequestDisable(
31843267
op, false,
@@ -3250,10 +3333,17 @@ func (p *Brontide) handleLocalCloseReq(req *htlcswitch.ChanClose) {
32503333
return
32513334
}
32523335
}
3336+
addr, err := p.addrWithInternalKey(deliveryScript).Unpack()
3337+
if err != nil {
3338+
err = fmt.Errorf("unable to parse addr for channel "+
3339+
"%v: %w", req.ChanPoint, err)
3340+
p.log.Errorf(err.Error())
3341+
req.Err <- err
32533342

3343+
return
3344+
}
32543345
chanCloser, err := p.createChanCloser(
3255-
channel, deliveryScript, req.TargetFeePerKw, req,
3256-
lntypes.Local,
3346+
channel, addr, req.TargetFeePerKw, req, lntypes.Local,
32573347
)
32583348
if err != nil {
32593349
p.log.Errorf(err.Error())

0 commit comments

Comments
 (0)