Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: add upfront-shutdown-address to lnd.conf. #9432

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions chanacceptor/chainedacceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@ package chanacceptor
import (
"sync"
"sync/atomic"

"github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
)

// ChainedAcceptor represents a conjunction of ChannelAcceptor results.
type ChainedAcceptor struct {
acceptorID uint64 // To be used atomically.

// An address to enforce payout of our funds to on cooperative close.
closeAddress string

// params are our current chain params.
params *chaincfg.Params

// acceptors is a map of ChannelAcceptors that will be evaluated when
// the ChainedAcceptor's Accept method is called.
acceptors map[uint64]ChannelAcceptor
Expand All @@ -22,6 +31,20 @@ func NewChainedAcceptor() *ChainedAcceptor {
}
}

// NewChainedAcceptorWithOpts initializes a ChainedAcceptor with the given
// closeAddress and params.
func NewChainedAcceptorWithOpts(
closeAddress string,
params *chaincfg.Params,
) *ChainedAcceptor {

return &ChainedAcceptor{
acceptors: make(map[uint64]ChannelAcceptor),
closeAddress: closeAddress,
params: params,
}
}

// AddAcceptor adds a ChannelAcceptor to this ChainedAcceptor.
//
// NOTE: Part of the MultiplexAcceptor interface.
Expand Down Expand Up @@ -97,6 +120,23 @@ func (c *ChainedAcceptor) Accept(req *ChannelAcceptRequest) *ChannelAcceptRespon
}
}

// Attempt to parse the upfront shutdown address provided.
if len(finalResp.UpfrontShutdown) == 0 && len(c.closeAddress) != 0 {
upfront, err := chancloser.ParseUpfrontShutdownAddress(
c.closeAddress, c.params,
)
if err != nil {
log.Errorf("Could not parse upfront shutdown for "+
"%x: %v", req.OpenChanMsg.PendingChannelID, err)

return NewChannelAcceptResponse(
false, errChannelRejected, nil, 0, 0,
0, 0, 0, 0, false,
)
}
finalResp.UpfrontShutdown = upfront
}

// If we have gone through all of our acceptors with no objections, we
// can return an acceptor with a nil error.
return &finalResp
Expand Down
74 changes: 74 additions & 0 deletions chanacceptor/chainedacceptor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package chanacceptor

import (
"testing"

"github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require"
)

// TestChainedAcceptorNoOpts verifies that the ChainedAcceptor will
// return nil UpfrontShutdown when not specified.
func TestChainedAcceptorNoOpts(t *testing.T) {
t.Parallel()

// Create the chained acceptor.
chainedAcceptor := NewChainedAcceptor()

// Assert that calling Accept return nil UpfrontShutdown.
req := &ChannelAcceptRequest{
OpenChanMsg: &lnwire.OpenChannel{},
}
resp := chainedAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Nil(t, resp.UpfrontShutdown)

// Add a dummyAcceptor to the chained acceptor. Assert that Accept
// return nil UpfrontShutdown.
dummy := &dummyAcceptor{}
dummyID := chainedAcceptor.AddAcceptor(dummy)
resp = chainedAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Nil(t, resp.UpfrontShutdown)

// Remove the dummyAcceptor from the chained acceptor and assert that
// Accept return nil UpfrontShutdown.
chainedAcceptor.RemoveAcceptor(dummyID)
resp = chainedAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Nil(t, resp.UpfrontShutdown)
}

// TestChainedAcceptorWithOpts verifies that the ChainedAcceptor will
// return valid UpfrontShutdown when specified.
func TestChainedAcceptorWithOpts(t *testing.T) {
t.Parallel()

// Create the chained acceptor.
chainedAcceptor := NewChainedAcceptorWithOpts(testValidAddr,
&chaincfg.RegressionNetParams)

// Assert that calling Accept return valid UpfrontShutdown.
req := &ChannelAcceptRequest{
OpenChanMsg: &lnwire.OpenChannel{},
}
resp := chainedAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Equal(t, testAddr, resp.UpfrontShutdown)

// Add a dummyAcceptor to the chained acceptor. Assert that Accept
// return valid UpfrontShutdown.
dummy := &dummyAcceptor{}
dummyID := chainedAcceptor.AddAcceptor(dummy)
resp = chainedAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Equal(t, testAddr, resp.UpfrontShutdown)

// Remove the dummyAcceptor from the chained acceptor and assert that
// Accept return valid UpfrontShutdown.
chainedAcceptor.RemoveAcceptor(dummyID)
resp = chainedAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Equal(t, testAddr, resp.UpfrontShutdown)
}
18 changes: 17 additions & 1 deletion chanacceptor/zeroconfacceptor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package chanacceptor

import "github.com/lightningnetwork/lnd/lnwire"
import (
"github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/lnwire"
)

// ZeroConfAcceptor wraps a regular ChainedAcceptor. If no acceptors are in the
// ChainedAcceptor, then Accept will reject all channel open requests. This
Expand All @@ -18,6 +21,19 @@ func NewZeroConfAcceptor() *ZeroConfAcceptor {
}
}

// NewZeroConfAcceptorWithOpts initializes a ZeroConfAcceptor with the given
// closeAddress and params.
func NewZeroConfAcceptorWithOpts(
closeAddress string,
params *chaincfg.Params,
) *ZeroConfAcceptor {

return &ZeroConfAcceptor{
chainedAcceptor: NewChainedAcceptorWithOpts(closeAddress,
params),
}
}

// AddAcceptor adds a sub-ChannelAcceptor to the internal ChainedAcceptor.
func (z *ZeroConfAcceptor) AddAcceptor(acceptor ChannelAcceptor) uint64 {
return z.chainedAcceptor.AddAcceptor(acceptor)
Expand Down
21 changes: 19 additions & 2 deletions chanacceptor/zeroconfacceptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@ package chanacceptor
import (
"testing"

"github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require"
)

var (
testValidAddr = "bcrt1qwrmq9uca0t3dy9t9wtuq5tm4405r7tfzyqn9pp"
testAddr, _ = chancloser.ParseUpfrontShutdownAddress(
testValidAddr, &chaincfg.RegressionNetParams,
)
)

// dummyAcceptor is a ChannelAcceptor that will never return a failure.
type dummyAcceptor struct{}

Expand All @@ -23,27 +32,31 @@ func TestZeroConfAcceptorNormal(t *testing.T) {
t.Parallel()

// Create the zero-conf acceptor.
zeroAcceptor := NewZeroConfAcceptor()
zeroAcceptor := NewZeroConfAcceptorWithOpts(testValidAddr,
&chaincfg.RegressionNetParams)

// Assert that calling Accept won't return a failure.
req := &ChannelAcceptRequest{
OpenChanMsg: &lnwire.OpenChannel{},
}
resp := zeroAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Equal(t, testAddr, resp.UpfrontShutdown)

// Add a dummyAcceptor to the zero-conf acceptor. Assert that Accept
// does not return a failure.
dummy := &dummyAcceptor{}
dummyID := zeroAcceptor.AddAcceptor(dummy)
resp = zeroAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Equal(t, testAddr, resp.UpfrontShutdown)

// Remove the dummyAcceptor from the zero-conf acceptor and assert that
// Accept doesn't return a failure.
zeroAcceptor.RemoveAcceptor(dummyID)
resp = zeroAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Equal(t, testAddr, resp.UpfrontShutdown)
}

// TestZeroConfAcceptorZC verifies that the ZeroConfAcceptor will fail
Expand All @@ -52,7 +65,8 @@ func TestZeroConfAcceptorZC(t *testing.T) {
t.Parallel()

// Create the zero-conf acceptor.
zeroAcceptor := NewZeroConfAcceptor()
zeroAcceptor := NewZeroConfAcceptorWithOpts(testValidAddr,
&chaincfg.RegressionNetParams)

channelType := new(lnwire.ChannelType)
*channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector(
Expand All @@ -67,17 +81,20 @@ func TestZeroConfAcceptorZC(t *testing.T) {
}
resp := zeroAcceptor.Accept(req)
require.True(t, resp.RejectChannel())
require.Nil(t, resp.UpfrontShutdown)

// Add a dummyAcceptor to the zero-conf acceptor. Assert that Accept
// does not return a failure.
dummy := &dummyAcceptor{}
dummyID := zeroAcceptor.AddAcceptor(dummy)
resp = zeroAcceptor.Accept(req)
require.False(t, resp.RejectChannel())
require.Equal(t, testAddr, resp.UpfrontShutdown)

// Remove the dummyAcceptor from the zero-conf acceptor and assert that
// Accept returns a failure.
zeroAcceptor.RemoveAcceptor(dummyID)
resp = zeroAcceptor.Accept(req)
require.True(t, resp.RejectChannel())
require.Nil(t, resp.UpfrontShutdown)
}
3 changes: 3 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,9 @@ type Config struct {
// HTTPHeaderTimeout is the maximum duration that the server will wait
// before timing out reading the headers of an HTTP request.
HTTPHeaderTimeout time.Duration `long:"http-header-timeout" description:"The maximum duration that the server will wait before timing out reading the headers of an HTTP request."`

// An address to enforce payout of our funds to on cooperative close.
CloseAddress string `long:"upfront-shutdown-address" description:"An address to enforce payout of our funds to on cooperative close."`
}

// GRPCConfig holds the configuration options for the gRPC server.
Expand Down
6 changes: 6 additions & 0 deletions docs/release-notes/release-notes-0.19.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@
config is added `disable-backup-archive`, with default set to false, to
determine if previous channel backups should be archived or not.

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

## Functional Enhancements
* [Add ability](https://github.com/lightningnetwork/lnd/pull/8998) to paginate
wallet transactions.
Expand Down
1 change: 1 addition & 0 deletions itest/list_exclude_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var excludedTestsWindows = []string{
"batch channel funding",
"zero conf channel open",
"open channel with unstable utxos",
"open channel with shutdown address",
"funding flow persistence",

// Gives "channel link not found" error.
Expand Down
4 changes: 4 additions & 0 deletions itest/list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ var allTestCases = []*lntest.TestCase{
Name: "open channel reorg test",
TestFunc: testOpenChannelAfterReorg,
},
{
Name: "open channel with shutdown address",
TestFunc: testOpenChannelWithShutdownAddr,
},
{
Name: "sign psbt",
TestFunc: testSignPsbt,
Expand Down
Loading
Loading