From 747161a1f4c99de13e519a18e0fe006953921675 Mon Sep 17 00:00:00 2001 From: Turtle Date: Wed, 24 Mar 2021 00:03:59 -0400 Subject: [PATCH] lnd: add config option for specifying particular peers to connect to --- config.go | 1 + lncfg/address.go | 70 ++++++++++++++++++++++++++++-------------------- sample-lnd.conf | 3 +++ server.go | 37 +++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 29 deletions(-) diff --git a/config.go b/config.go index 91a42a299..b75d5cabd 100644 --- a/config.go +++ b/config.go @@ -293,6 +293,7 @@ type Config struct { WSPingInterval time.Duration `long:"ws-ping-interval" description:"The ping interval for REST based WebSocket connections, set to 0 to disable sending ping messages from the server side"` WSPongWait time.Duration `long:"ws-pong-wait" description:"The time we wait for a pong response message on REST based WebSocket connections before the connection is closed as inactive"` NAT bool `long:"nat" description:"Toggle NAT traversal support (using either UPnP or NAT-PMP) to automatically advertise your external IP address to the network -- NOTE this does not support devices behind multiple NATs"` + AddPeers []string `long:"addpeer" description:"Specify peers to connect to first"` MinBackoff time.Duration `long:"minbackoff" description:"Shortest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."` MaxBackoff time.Duration `long:"maxbackoff" description:"Longest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."` ConnectionTimeout time.Duration `long:"connectiontimeout" description:"The timeout value for network connections. Valid time units are {ms, s, m, h}."` diff --git a/lncfg/address.go b/lncfg/address.go index 0f7c35761..74bb934e0 100644 --- a/lncfg/address.go +++ b/lncfg/address.go @@ -278,36 +278,9 @@ func ParseAddressString(strAddress string, defaultPort string, func ParseLNAddressString(strAddress string, defaultPort string, tcpResolver TCPResolver) (*lnwire.NetAddress, error) { - // Split the address string around the @ sign. - parts := strings.Split(strAddress, "@") - - // The string is malformed if there are not exactly two parts. - if len(parts) != 2 { - return nil, fmt.Errorf("invalid lightning address %s: "+ - "must be of the form @", strAddress) - } - - // Now, take the first portion as the hex pubkey, and the latter as the - // address string. - parsedPubKey, parsedAddr := parts[0], parts[1] - - // Decode the hex pubkey to get the raw compressed pubkey bytes. - pubKeyBytes, err := hex.DecodeString(parsedPubKey) + pubKey, parsedAddr, err := ParseLNAddressPubkey(strAddress) if err != nil { - return nil, fmt.Errorf("invalid lightning address pubkey: %v", err) - } - - // The compressed pubkey should have a length of exactly 33 bytes. - if len(pubKeyBytes) != 33 { - return nil, fmt.Errorf("invalid lightning address pubkey: "+ - "length must be 33 bytes, found %d", len(pubKeyBytes)) - } - - // Parse the pubkey bytes to verify that it corresponds to valid public - // key on the secp256k1 curve. - pubKey, err := btcec.ParsePubKey(pubKeyBytes) - if err != nil { - return nil, fmt.Errorf("invalid lightning address pubkey: %v", err) + return nil, err } // Finally, parse the address string using our generic address parser. @@ -322,6 +295,45 @@ func ParseLNAddressString(strAddress string, defaultPort string, }, nil } +// ParseLNAddressPubkey converts a string of the form @ into two +// pieces: the pubkey bytes and an addr string. It validates that the pubkey +// is of a valid form. +func ParseLNAddressPubkey(strAddress string) (*btcec.PublicKey, string, error) { + // Split the address string around the @ sign. + parts := strings.Split(strAddress, "@") + + // The string is malformed if there are not exactly two parts. + if len(parts) != 2 { + return nil, "", fmt.Errorf("invalid lightning address %s: "+ + "must be of the form @", strAddress) + } + + // Now, take the first portion as the hex pubkey, and the latter as the + // address string. + parsedPubKey, parsedAddr := parts[0], parts[1] + + // Decode the hex pubkey to get the raw compressed pubkey bytes. + pubKeyBytes, err := hex.DecodeString(parsedPubKey) + if err != nil { + return nil, "", fmt.Errorf("invalid lightning address pubkey: %v", err) + } + + // The compressed pubkey should have a length of exactly 33 bytes. + if len(pubKeyBytes) != 33 { + return nil, "", fmt.Errorf("invalid lightning address pubkey: "+ + "length must be 33 bytes, found %d", len(pubKeyBytes)) + } + + // Parse the pubkey bytes to verify that it corresponds to valid public + // key on the secp256k1 curve. + pubKey, err := btcec.ParsePubKey(pubKeyBytes) + if err != nil { + return nil, "", fmt.Errorf("invalid lightning address pubkey: %v", err) + } + + return pubKey, parsedAddr, nil +} + // verifyPort makes sure that an address string has both a host and a port. If // there is no port found, the default port is appended. If the address is just // a port, then we'll assume that the user is using the short cut to specify a diff --git a/sample-lnd.conf b/sample-lnd.conf index 6c74ade60..42605da7b 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -183,6 +183,9 @@ ; Disable TLS for the REST API. ; no-rest-tls=true +; Specify peer(s) to connect to first. +; addpeer= + ; The ping interval for REST based WebSocket connections, set to 0 to disable ; sending ping messages from the server side. Valid time units are {s, m, h}. ; ws-ping-interval=30s diff --git a/server.go b/server.go index b19720038..7ee149fbb 100644 --- a/server.go +++ b/server.go @@ -1905,6 +1905,43 @@ func (s *server) Start() error { return nil }) + // If peers are specified as a config option, we'll add those + // peers first. + for _, peerAddrCfg := range s.cfg.AddPeers { + parsedPubkey, parsedHost, err := lncfg.ParseLNAddressPubkey( + peerAddrCfg, + ) + if err != nil { + startErr = fmt.Errorf("unable to parse peer "+ + "pubkey from config: %v", err) + return + } + addr, err := parseAddr(parsedHost, s.cfg.net) + if err != nil { + startErr = fmt.Errorf("unable to parse peer "+ + "address provided as a config option: "+ + "%v", err) + return + } + + peerAddr := &lnwire.NetAddress{ + IdentityKey: parsedPubkey, + Address: addr, + ChainNet: s.cfg.ActiveNetParams.Net, + } + + err = s.ConnectToPeer( + peerAddr, true, + s.cfg.ConnectionTimeout, + ) + if err != nil { + startErr = fmt.Errorf("unable to connect to "+ + "peer address provided as a config "+ + "option: %v", err) + return + } + } + // Subscribe to NodeAnnouncements that advertise new addresses // our persistent peers. if err := s.updatePersistentPeerAddrs(); err != nil {