multi: only allow specifying towers to TowerClient through RPC
With the introduction of the WatchtowerClient RPC subserver, the lnd configuration flag to specify private watchtowers for the client is no longer needed and can lead to confusion upon users. Therefore, we remove the flag completely, and only rely on the watchtower client being active through a new --wtclient.active flag.
This commit is contained in:
parent
359b2049b6
commit
0431701262
12
config.go
12
config.go
@ -33,7 +33,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
"github.com/lightningnetwork/lnd/tor"
|
"github.com/lightningnetwork/lnd/tor"
|
||||||
"github.com/lightningnetwork/lnd/watchtower"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -1091,17 +1090,6 @@ func loadConfig() (*config, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user provided private watchtower addresses, parse them to
|
|
||||||
// obtain the LN addresses.
|
|
||||||
if cfg.WtClient.IsActive() {
|
|
||||||
err := cfg.WtClient.ParsePrivateTowers(
|
|
||||||
watchtower.DefaultPeerPort, cfg.net.ResolveTCPAddr,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, ensure that the user's color is correctly formatted,
|
// Finally, ensure that the user's color is correctly formatted,
|
||||||
// otherwise the server will not be able to start after the unlocking
|
// otherwise the server will not be able to start after the unlocking
|
||||||
// the wallet.
|
// the wallet.
|
||||||
|
@ -1,65 +1,38 @@
|
|||||||
package lncfg
|
package lncfg
|
||||||
|
|
||||||
import (
|
import "errors"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WtClient holds the configuration options for the daemon's watchtower client.
|
// WtClient holds the configuration options for the daemon's watchtower client.
|
||||||
type WtClient struct {
|
type WtClient struct {
|
||||||
|
// Active determines whether a watchtower client should be created to
|
||||||
|
// back up channel states with registered watchtowers.
|
||||||
|
Active bool `long:"active" description:"Whether the daemon should use private watchtowers to back up revoked channel states."`
|
||||||
|
|
||||||
// PrivateTowerURIs specifies the lightning URIs of the towers the
|
// PrivateTowerURIs specifies the lightning URIs of the towers the
|
||||||
// watchtower client should send new backups to.
|
// watchtower client should send new backups to.
|
||||||
PrivateTowerURIs []string `long:"private-tower-uris" description:"Specifies the URIs of private watchtowers to use in backing up revoked states. URIs must be of the form <pubkey>@<addr>. Only 1 URI is supported at this time, if none are provided the tower will not be enabled."`
|
PrivateTowerURIs []string `long:"private-tower-uris" description:"(Deprecated) Specifies the URIs of private watchtowers to use in backing up revoked states. URIs must be of the form <pubkey>@<addr>. Only 1 URI is supported at this time, if none are provided the tower will not be enabled."`
|
||||||
|
|
||||||
// PrivateTowers is the list of towers parsed from the URIs provided in
|
|
||||||
// PrivateTowerURIs.
|
|
||||||
PrivateTowers []*lnwire.NetAddress
|
|
||||||
|
|
||||||
// SweepFeeRate specifies the fee rate in sat/byte to be used when
|
// SweepFeeRate specifies the fee rate in sat/byte to be used when
|
||||||
// constructing justice transactions sent to the tower.
|
// constructing justice transactions sent to the tower.
|
||||||
SweepFeeRate uint64 `long:"sweep-fee-rate" description:"Specifies the fee rate in sat/byte to be used when constructing justice transactions sent to the watchtower."`
|
SweepFeeRate uint64 `long:"sweep-fee-rate" description:"Specifies the fee rate in sat/byte to be used when constructing justice transactions sent to the watchtower."`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate asserts that at most 1 private watchtower is requested.
|
// Validate ensures the user has provided a valid configuration.
|
||||||
//
|
//
|
||||||
// NOTE: Part of the Validator interface.
|
// NOTE: Part of the Validator interface.
|
||||||
func (c *WtClient) Validate() error {
|
func (c *WtClient) Validate() error {
|
||||||
if len(c.PrivateTowerURIs) > 1 {
|
if len(c.PrivateTowerURIs) > 0 {
|
||||||
return fmt.Errorf("at most 1 private watchtower is supported, "+
|
return errors.New("`wtclient.private-tower-uris` is " +
|
||||||
"found %d", len(c.PrivateTowerURIs))
|
"deprecated and will be removed in the v0.8.0 " +
|
||||||
|
"release, to specify watchtowers remove " +
|
||||||
|
"`wtclient.private-tower-uris`, set " +
|
||||||
|
"`wtclient.active`, and check out `lncli wtclient -h` " +
|
||||||
|
"for more information on how to manage towers")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsActive returns true if the watchtower client should be active.
|
|
||||||
func (c *WtClient) IsActive() bool {
|
|
||||||
return len(c.PrivateTowerURIs) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParsePrivateTowers parses any private tower URIs held PrivateTowerURIs. The
|
|
||||||
// value of port should be the default port to use when a URI does not have one.
|
|
||||||
func (c *WtClient) ParsePrivateTowers(port int, resolver TCPResolver) error {
|
|
||||||
towers := make([]*lnwire.NetAddress, 0, len(c.PrivateTowerURIs))
|
|
||||||
for _, uri := range c.PrivateTowerURIs {
|
|
||||||
addr, err := ParseLNAddressString(
|
|
||||||
uri, strconv.Itoa(port), resolver,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to parse private "+
|
|
||||||
"watchtower address: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
towers = append(towers, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.PrivateTowers = towers
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile-time constraint to ensure WtClient implements the Validator
|
// Compile-time constraint to ensure WtClient implements the Validator
|
||||||
// interface.
|
// interface.
|
||||||
var _ Validator = (*WtClient)(nil)
|
var _ Validator = (*WtClient)(nil)
|
||||||
|
2
lnd.go
2
lnd.go
@ -340,7 +340,7 @@ func Main() error {
|
|||||||
// If the watchtower client should be active, open the client database.
|
// If the watchtower client should be active, open the client database.
|
||||||
// This is done here so that Close always executes when lndMain returns.
|
// This is done here so that Close always executes when lndMain returns.
|
||||||
var towerClientDB *wtdb.ClientDB
|
var towerClientDB *wtdb.ClientDB
|
||||||
if cfg.WtClient.IsActive() {
|
if cfg.WtClient.Active {
|
||||||
var err error
|
var err error
|
||||||
towerClientDB, err = wtdb.OpenClientDB(graphDir)
|
towerClientDB, err = wtdb.OpenClientDB(graphDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,6 +35,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
@ -7708,22 +7709,27 @@ func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness,
|
|||||||
externalIP, willyInfo.Uris[0])
|
externalIP, willyInfo.Uris[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a URI from listening port and public key, since aren't
|
|
||||||
// actually connecting remotely.
|
|
||||||
willyTowerURI := fmt.Sprintf("%x@%s", willyInfo.Pubkey, listener)
|
|
||||||
|
|
||||||
// Dave will be the breached party. We set --nolisten to ensure Carol
|
// Dave will be the breached party. We set --nolisten to ensure Carol
|
||||||
// won't be able to connect to him and trigger the channel data
|
// won't be able to connect to him and trigger the channel data
|
||||||
// protection logic automatically.
|
// protection logic automatically.
|
||||||
dave, err := net.NewNode("Dave", []string{
|
dave, err := net.NewNode("Dave", []string{
|
||||||
"--nolisten",
|
"--nolisten",
|
||||||
"--wtclient.private-tower-uris=" + willyTowerURI,
|
"--wtclient.active",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create new node: %v", err)
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
}
|
}
|
||||||
defer shutdownAndAssert(net, t, dave)
|
defer shutdownAndAssert(net, t, dave)
|
||||||
|
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
addTowerReq := &wtclientrpc.AddTowerRequest{
|
||||||
|
Pubkey: willyInfo.Pubkey,
|
||||||
|
Address: listener,
|
||||||
|
}
|
||||||
|
if _, err := dave.WatchtowerClient.AddTower(ctxt, addTowerReq); err != nil {
|
||||||
|
t.Fatalf("unable to add willy's watchtower: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// We must let Dave have an open channel before she can send a node
|
// We must let Dave have an open channel before she can send a node
|
||||||
// announcement, so we open a channel with Carol,
|
// announcement, so we open a channel with Carol,
|
||||||
if err := net.ConnectNodes(ctxb, dave, carol); err != nil {
|
if err := net.ConnectNodes(ctxb, dave, carol); err != nil {
|
||||||
|
@ -1081,7 +1081,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.WtClient.IsActive() {
|
if cfg.WtClient.Active {
|
||||||
policy := wtpolicy.DefaultPolicy()
|
policy := wtpolicy.DefaultPolicy()
|
||||||
|
|
||||||
if cfg.WtClient.SweepFeeRate != 0 {
|
if cfg.WtClient.SweepFeeRate != 0 {
|
||||||
@ -1104,7 +1104,6 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
Dial: cfg.net.Dial,
|
Dial: cfg.net.Dial,
|
||||||
AuthDial: wtclient.AuthDial,
|
AuthDial: wtclient.AuthDial,
|
||||||
DB: towerClientDB,
|
DB: towerClientDB,
|
||||||
PrivateTower: cfg.WtClient.PrivateTowers[0],
|
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
ChainHash: *activeNetParams.GenesisHash,
|
ChainHash: *activeNetParams.GenesisHash,
|
||||||
MinBackoff: 10 * time.Second,
|
MinBackoff: 10 * time.Second,
|
||||||
|
@ -141,10 +141,6 @@ type Config struct {
|
|||||||
// new sessions will be requested immediately.
|
// new sessions will be requested immediately.
|
||||||
Policy wtpolicy.Policy
|
Policy wtpolicy.Policy
|
||||||
|
|
||||||
// PrivateTower is the net address of a private tower. The client will
|
|
||||||
// try to create all sessions with this tower.
|
|
||||||
PrivateTower *lnwire.NetAddress
|
|
||||||
|
|
||||||
// ChainHash identifies the chain that the client is on and for which
|
// ChainHash identifies the chain that the client is on and for which
|
||||||
// the tower must be watching to monitor for breaches.
|
// the tower must be watching to monitor for breaches.
|
||||||
ChainHash chainhash.Hash
|
ChainHash chainhash.Hash
|
||||||
@ -266,13 +262,6 @@ func New(config *Config) (*TowerClient, error) {
|
|||||||
cfg.WriteTimeout = DefaultWriteTimeout
|
cfg.WriteTimeout = DefaultWriteTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the tower in our database, also loading any addresses
|
|
||||||
// previously associated with its public key.
|
|
||||||
tower, err := cfg.DB.CreateTower(cfg.PrivateTower)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, load all candidate sessions and towers from the database into
|
// Next, load all candidate sessions and towers from the database into
|
||||||
// the client. We will use any of these session if their policies match
|
// the client. We will use any of these session if their policies match
|
||||||
// the current policy of the client, otherwise they will be ignored and
|
// the current policy of the client, otherwise they will be ignored and
|
||||||
|
@ -26,7 +26,11 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/watchtower/wtserver"
|
"github.com/lightningnetwork/lnd/watchtower/wtserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const csvDelay uint32 = 144
|
const (
|
||||||
|
csvDelay uint32 = 144
|
||||||
|
|
||||||
|
towerAddrStr = "18.28.243.2:9911"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
revPrivBytes = []byte{
|
revPrivBytes = []byte{
|
||||||
@ -387,7 +391,6 @@ type harnessCfg struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newHarness(t *testing.T, cfg harnessCfg) *testHarness {
|
func newHarness(t *testing.T, cfg harnessCfg) *testHarness {
|
||||||
towerAddrStr := "18.28.243.2:9911"
|
|
||||||
towerTCPAddr, err := net.ResolveTCPAddr("tcp", towerAddrStr)
|
towerTCPAddr, err := net.ResolveTCPAddr("tcp", towerAddrStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to resolve tower TCP addr: %v", err)
|
t.Fatalf("Unable to resolve tower TCP addr: %v", err)
|
||||||
@ -412,6 +415,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness {
|
|||||||
DB: serverDB,
|
DB: serverDB,
|
||||||
ReadTimeout: timeout,
|
ReadTimeout: timeout,
|
||||||
WriteTimeout: timeout,
|
WriteTimeout: timeout,
|
||||||
|
NodePrivKey: privKey,
|
||||||
NewAddress: func() (btcutil.Address, error) {
|
NewAddress: func() (btcutil.Address, error) {
|
||||||
return addr, nil
|
return addr, nil
|
||||||
},
|
},
|
||||||
@ -435,7 +439,6 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness {
|
|||||||
DB: clientDB,
|
DB: clientDB,
|
||||||
AuthDial: mockNet.AuthDial,
|
AuthDial: mockNet.AuthDial,
|
||||||
SecretKeyRing: wtmock.NewSecretKeyRing(),
|
SecretKeyRing: wtmock.NewSecretKeyRing(),
|
||||||
PrivateTower: towerAddr,
|
|
||||||
Policy: cfg.policy,
|
Policy: cfg.policy,
|
||||||
NewAddress: func() ([]byte, error) {
|
NewAddress: func() ([]byte, error) {
|
||||||
return addrScript, nil
|
return addrScript, nil
|
||||||
@ -458,6 +461,10 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness {
|
|||||||
server.Stop()
|
server.Stop()
|
||||||
t.Fatalf("Unable to start wtclient: %v", err)
|
t.Fatalf("Unable to start wtclient: %v", err)
|
||||||
}
|
}
|
||||||
|
if err := client.AddTower(towerAddr); err != nil {
|
||||||
|
server.Stop()
|
||||||
|
t.Fatalf("Unable to add tower to wtclient: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
h := &testHarness{
|
h := &testHarness{
|
||||||
t: t,
|
t: t,
|
||||||
@ -505,7 +512,15 @@ func (h *testHarness) startServer() {
|
|||||||
func (h *testHarness) startClient() {
|
func (h *testHarness) startClient() {
|
||||||
h.t.Helper()
|
h.t.Helper()
|
||||||
|
|
||||||
var err error
|
towerTCPAddr, err := net.ResolveTCPAddr("tcp", towerAddrStr)
|
||||||
|
if err != nil {
|
||||||
|
h.t.Fatalf("Unable to resolve tower TCP addr: %v", err)
|
||||||
|
}
|
||||||
|
towerAddr := &lnwire.NetAddress{
|
||||||
|
IdentityKey: h.serverCfg.NodePrivKey.PubKey(),
|
||||||
|
Address: towerTCPAddr,
|
||||||
|
}
|
||||||
|
|
||||||
h.client, err = wtclient.New(h.clientCfg)
|
h.client, err = wtclient.New(h.clientCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.t.Fatalf("unable to create wtclient: %v", err)
|
h.t.Fatalf("unable to create wtclient: %v", err)
|
||||||
@ -513,6 +528,9 @@ func (h *testHarness) startClient() {
|
|||||||
if err := h.client.Start(); err != nil {
|
if err := h.client.Start(); err != nil {
|
||||||
h.t.Fatalf("unable to start wtclient: %v", err)
|
h.t.Fatalf("unable to start wtclient: %v", err)
|
||||||
}
|
}
|
||||||
|
if err := h.client.AddTower(towerAddr); err != nil {
|
||||||
|
h.t.Fatalf("unable to add tower to wtclient: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// chanIDFromInt creates a unique channel id given a unique integral id.
|
// chanIDFromInt creates a unique channel id given a unique integral id.
|
||||||
|
Loading…
Reference in New Issue
Block a user