Skip to content

Commit ff20dd2

Browse files
authored
Merge pull request #9432 from NishantBansal2003/close-addr-conf
multi: add upfront-shutdown-address to lnd.conf.
2 parents bb6e8f3 + 36fb79e commit ff20dd2

File tree

8 files changed

+146
-6
lines changed

8 files changed

+146
-6
lines changed

config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,15 @@ type Config struct {
537537
// NoDisconnectOnPongFailure controls if we'll disconnect if a peer
538538
// doesn't respond to a pong in time.
539539
NoDisconnectOnPongFailure bool `long:"no-disconnect-on-pong-failure" description:"If true, a peer will *not* be disconnected if a pong is not received in time or is mismatched. Defaults to false, meaning peers *will* be disconnected on pong failure."`
540+
541+
// UpfrontShutdownAddr specifies an address that our funds will be paid
542+
// out to on cooperative channel close. This applies to all new channel
543+
// opens unless overridden by an option in openchannel or by a channel
544+
// acceptor.
545+
// Note: If this field is set when opening a channel with a peer that
546+
// does not advertise support for the upfront shutdown feature, the
547+
// channel open will fail.
548+
UpfrontShutdownAddr string `long:"upfront-shutdown-address" description:"The address to which funds will be paid out during a cooperative channel close. This applies to all channels opened after this option is set, unless overridden for a specific channel opening. Note: If this option is set, any channel opening will fail if the peer does not explicitly advertise support for the upfront-shutdown feature bit."`
540549
}
541550

542551
// GRPCConfig holds the configuration options for the gRPC server.

docs/release-notes/release-notes-0.21.0.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@
4242
# Improvements
4343
## Functional Updates
4444

45+
* [Added support](https://github.com/lightningnetwork/lnd/pull/9432) for the
46+
`upfront-shutdown-address` configuration in `lnd.conf`, allowing users to
47+
specify an address for cooperative channel closures where funds will be sent.
48+
This applies to both funders and fundees, with the ability to override the
49+
value during channel opening or acceptance.
50+
4551
## RPC Updates
4652

4753
## lncli Updates
@@ -71,3 +77,4 @@
7177

7278
* Boris Nagaev
7379
* Elle Mouton
80+
* Nishant Bansal

funding/manager.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,10 @@ type Config struct {
573573
// implementations to inject and process custom records over channel
574574
// related wire messages.
575575
AuxChannelNegotiator fn.Option[lnwallet.AuxChannelNegotiator]
576+
577+
// ShutdownScript is an optional upfront-shutdown script to which our
578+
// funds should be paid on a cooperative close.
579+
ShutdownScript fn.Option[lnwire.DeliveryAddress]
576580
}
577581

578582
// Manager acts as an orchestrator/bridge between the wallet's
@@ -1760,12 +1764,24 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
17601764
return
17611765
}
17621766

1767+
// If the fundee didn't provide an upfront-shutdown address via
1768+
// the channel acceptor, fall back to the configured shutdown
1769+
// script (if any).
1770+
shutdownScript := acceptorResp.UpfrontShutdown
1771+
if len(shutdownScript) == 0 {
1772+
f.cfg.ShutdownScript.WhenSome(
1773+
func(script lnwire.DeliveryAddress) {
1774+
shutdownScript = script
1775+
},
1776+
)
1777+
}
1778+
17631779
// Check whether the peer supports upfront shutdown, and get a new
17641780
// wallet address if our node is configured to set shutdown addresses by
17651781
// default. We use the upfront shutdown script provided by our channel
17661782
// acceptor (if any) in lieu of user input.
17671783
shutdown, err := getUpfrontShutdownScript(
1768-
f.cfg.EnableUpfrontShutdown, peer, acceptorResp.UpfrontShutdown,
1784+
f.cfg.EnableUpfrontShutdown, peer, shutdownScript,
17691785
f.selectShutdownScript,
17701786
)
17711787
if err != nil {
@@ -4849,12 +4865,23 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
48494865
}
48504866
}
48514867

4868+
// If the funder did not provide an upfront-shutdown address, fall back
4869+
// to the configured shutdown script (if any).
4870+
shutdownScript := msg.ShutdownScript
4871+
if len(shutdownScript) == 0 {
4872+
f.cfg.ShutdownScript.WhenSome(
4873+
func(script lnwire.DeliveryAddress) {
4874+
shutdownScript = script
4875+
},
4876+
)
4877+
}
4878+
48524879
// Check whether the peer supports upfront shutdown, and get an address
48534880
// which should be used (either a user specified address or a new
48544881
// address from the wallet if our node is configured to set shutdown
48554882
// address by default).
48564883
shutdown, err := getUpfrontShutdownScript(
4857-
f.cfg.EnableUpfrontShutdown, msg.Peer, msg.ShutdownScript,
4884+
f.cfg.EnableUpfrontShutdown, msg.Peer, shutdownScript,
48584885
f.selectShutdownScript,
48594886
)
48604887
if err != nil {

itest/list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ var allTestCases = []*lntest.TestCase{
286286
Name: "open channel reorg test",
287287
TestFunc: testOpenChannelAfterReorg,
288288
},
289+
{
290+
Name: "open channel with shutdown address",
291+
TestFunc: testOpenChannelWithShutdownAddr,
292+
},
289293
{
290294
Name: "sign psbt",
291295
TestFunc: testSignPsbt,

itest/lnd_open_channel_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,3 +1269,76 @@ func testFundingManagerFundingTimeout(ht *lntest.HarnessTest) {
12691269
// Cleanup the mempool by mining blocks.
12701270
ht.MineBlocksAndAssertNumTxes(6, 1)
12711271
}
1272+
1273+
// testOpenChannelWithShutdownAddr verifies that if the funder or fundee
1274+
// specifies an upfront shutdown address in the config, the funds are correctly
1275+
// transferred to the specified address during channel closure.
1276+
func testOpenChannelWithShutdownAddr(ht *lntest.HarnessTest) {
1277+
const (
1278+
// Channel funding amount in sat.
1279+
channelAmount int64 = 100000
1280+
1281+
// Payment amount in sat.
1282+
paymentAmount int64 = 50000
1283+
)
1284+
1285+
// Create nodes for testing, ensuring Alice has sufficient initial
1286+
// funds.
1287+
alice := ht.NewNodeWithCoins("Alice", nil)
1288+
bob := ht.NewNode("Bob", nil)
1289+
1290+
// Generate upfront shutdown addresses for both nodes.
1291+
aliceShutdownAddr := alice.RPC.NewAddress(&lnrpc.NewAddressRequest{
1292+
Type: lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
1293+
})
1294+
bobShutdownAddr := bob.RPC.NewAddress(&lnrpc.NewAddressRequest{
1295+
Type: lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
1296+
})
1297+
1298+
// Update nodes with upfront shutdown addresses and restart them.
1299+
aliceNodeArgs := []string{
1300+
fmt.Sprintf(
1301+
"--upfront-shutdown-address=%s",
1302+
aliceShutdownAddr.Address,
1303+
),
1304+
}
1305+
ht.RestartNodeWithExtraArgs(alice, aliceNodeArgs)
1306+
1307+
bobNodeArgs := []string{
1308+
fmt.Sprintf(
1309+
"--upfront-shutdown-address=%s",
1310+
bobShutdownAddr.Address,
1311+
),
1312+
}
1313+
ht.RestartNodeWithExtraArgs(bob, bobNodeArgs)
1314+
1315+
// Connect Alice and Bob.
1316+
ht.ConnectNodes(alice, bob)
1317+
1318+
// Open a channel between Alice and Bob.
1319+
openChannelParams := lntest.OpenChannelParams{
1320+
Amt: btcutil.Amount(channelAmount),
1321+
PushAmt: btcutil.Amount(paymentAmount),
1322+
}
1323+
channelPoint := ht.OpenChannel(alice, bob, openChannelParams)
1324+
1325+
// Now close out the channel and obtain the raw closing TX.
1326+
closingTxid := ht.CloseChannel(alice, channelPoint)
1327+
closingTx := ht.GetRawTransaction(closingTxid).MsgTx()
1328+
1329+
// Calculate Alice's updated balance.
1330+
aliceFee := ht.CalculateTxFee(closingTx)
1331+
aliceExpectedBalance := channelAmount - paymentAmount - int64(aliceFee)
1332+
1333+
// Ensure Alice sees the change output in the list of unspent outputs.
1334+
// We expect 6 confirmed UTXOs, as 5 UTXOs of 1 BTC each were sent to
1335+
// the node during NewNodeWithCoins.
1336+
aliceUTXOConfirmed := ht.AssertNumUTXOsConfirmed(alice, 6)[0]
1337+
require.Equal(ht, aliceShutdownAddr.Address, aliceUTXOConfirmed.Address)
1338+
require.Equal(ht, aliceExpectedBalance, aliceUTXOConfirmed.AmountSat)
1339+
1340+
// Ensure Bob see the change output in the list of unspent outputs.
1341+
bobUTXOConfirmed := ht.AssertNumUTXOsConfirmed(bob, 1)[0]
1342+
require.Equal(ht, bobShutdownAddr.Address, bobUTXOConfirmed.Address)
1343+
require.Equal(ht, paymentAmount, bobUTXOConfirmed.AmountSat)
1344+
}

peer/brontide.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3589,9 +3589,9 @@ func (p *Brontide) initNegotiateChanCloser(req *htlcswitch.ChanClose,
35893589
return nil
35903590
}
35913591

3592-
// chooseAddr returns the provided address if it is non-zero length, otherwise
3592+
// ChooseAddr returns the provided address if it is non-zero length, otherwise
35933593
// None.
3594-
func chooseAddr(addr lnwire.DeliveryAddress) fn.Option[lnwire.DeliveryAddress] {
3594+
func ChooseAddr(addr lnwire.DeliveryAddress) fn.Option[lnwire.DeliveryAddress] {
35953595
if len(addr) == 0 {
35963596
return fn.None[lnwire.DeliveryAddress]()
35973597
}
@@ -3930,10 +3930,10 @@ func (p *Brontide) initRbfChanCloser(
39303930
ChanType: channel.ChanType(),
39313931
DefaultFeeRate: defaultFeePerKw.FeePerVByte(),
39323932
ThawHeight: fn.Some(thawHeight),
3933-
RemoteUpfrontShutdown: chooseAddr(
3933+
RemoteUpfrontShutdown: ChooseAddr(
39343934
channel.RemoteUpfrontShutdownScript(),
39353935
),
3936-
LocalUpfrontShutdown: chooseAddr(
3936+
LocalUpfrontShutdown: ChooseAddr(
39373937
channel.LocalUpfrontShutdownScript(),
39383938
),
39393939
NewDeliveryScript: func() (lnwire.DeliveryAddress, error) {

sample-lnd.conf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,15 @@
589589
; pong failure.
590590
; no-disconnect-on-pong-failure=false
591591

592+
; The address to which funds will be paid out during a cooperative channel
593+
; close. This applies to all channels opened after this option is set, unless
594+
; overridden for a specific channel opening.
595+
;
596+
; Note: If this option is set, any channel opening will fail if the peer does
597+
; not explicitly advertise support for the upfront-shutdown feature bit.
598+
; upfront-shutdown-address=
599+
600+
592601
[fee]
593602

594603
; Optional URL for external fee estimation. If no URL is specified, the method

server.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import (
6161
"github.com/lightningnetwork/lnd/lnutils"
6262
"github.com/lightningnetwork/lnd/lnwallet"
6363
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
64+
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
6465
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
6566
"github.com/lightningnetwork/lnd/lnwallet/rpcwallet"
6667
"github.com/lightningnetwork/lnd/lnwire"
@@ -1445,6 +1446,15 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr,
14451446
devCfg, reservationTimeout, zombieSweeperInterval)
14461447
}
14471448

1449+
// Attempt to parse the provided upfront-shutdown address (if any).
1450+
script, err := chancloser.ParseUpfrontShutdownAddress(
1451+
cfg.UpfrontShutdownAddr, cfg.ActiveNetParams.Params,
1452+
)
1453+
if err != nil {
1454+
return nil, fmt.Errorf("error parsing upfront shutdown: %w",
1455+
err)
1456+
}
1457+
14481458
//nolint:ll
14491459
s.fundingMgr, err = funding.NewFundingManager(funding.Config{
14501460
Dev: devCfg,
@@ -1623,6 +1633,7 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr,
16231633
AuxSigner: implCfg.AuxSigner,
16241634
AuxResolver: implCfg.AuxContractResolver,
16251635
AuxChannelNegotiator: implCfg.AuxChannelNegotiator,
1636+
ShutdownScript: peer.ChooseAddr(script),
16261637
})
16271638
if err != nil {
16281639
return nil, err

0 commit comments

Comments
 (0)