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

Connect and listen to BOLT compatible nodes #437

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
72 changes: 45 additions & 27 deletions cmd/lit-af/lit-af.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"encoding/hex"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -65,7 +66,7 @@ func newConfigParser(conf *litAfConfig, options flags.Options) *flags.Parser {
return parser
}

func (lc *litAfClient) litAfSetup(conf litAfConfig) {
func (lc *litAfClient) litAfSetup(conf litAfConfig) error {

var err error
// create home directory if it does not exist
Expand All @@ -89,42 +90,55 @@ func (lc *litAfClient) litAfSetup(conf litAfConfig) {
}
logging.SetLogLevel(logLevel) // defaults to zero

// we don't know whether the passed address is a remotePKH or a remotePK
// so we need to detect that here and then take steps accordingly
adr, host, port := lnutil.ParseAdrStringWithPort(conf.Con)
logging.Infof("Adr: %s, Host: %s, Port: %d", adr, host, port)
if litrpc.LndcRpcCanConnectLocallyWithHomeDir(defaultDir) && adr == "" && (host == "localhost" || host == "127.0.0.1") {
// now we've split the address, check if pkh, if not, route straight to noise_xk

if len(adr) == 0 {
// so the user didn't provide us with an address to connect to and
// we need to connect to the locally running lit-af instance
lc.RPCClient, err = litrpc.NewLocalLndcRpcClientWithHomeDirAndPort(defaultDir, port)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make a way to specify a homedir too? Because without that it kinda breaks my workflow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm.. yeah, I think that would be possible, was possible earlier as well iirc. Will push an update.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to work right now (./lit-af --dir=blah), was this the use case you were looking at?

if err != nil {
logging.Fatal(err.Error())
}
} else {
if !lnutil.LitAdrOK(adr) {
logging.Fatal("lit address passed in -con parameter is not valid")
}
return nil
}

keyFilePath := filepath.Join(defaultDir, "lit-af-key.hex")
privKey, err := lnutil.ReadKeyFile(keyFilePath)
if err != nil {
logging.Fatal(err.Error())
}
key, _ := koblitz.PrivKeyFromBytes(koblitz.S256(), privKey[:])

if adr != "" && strings.HasPrefix(adr, "ln1") && host == "" {
ipv4, _, err := lnutil.Lookup(adr, conf.Tracker, "")
if err != nil {
logging.Fatalf("Error looking up address on the tracker: %s", err)
} else {
adr = fmt.Sprintf("%s@%s", adr, ipv4)
}
} else {
adr = fmt.Sprintf("%s@%s:%d", adr, host, port)
}
keyFilePath := filepath.Join(defaultDir, "lit-af-key.hex")
privKey, err := lnutil.ReadKeyFile(keyFilePath)
if err != nil {
logging.Fatal(err.Error())
}
key, _ := koblitz.PrivKeyFromBytes(koblitz.S256(), privKey[:])
pubkey := key.PubKey().SerializeCompressed() // this is in bytes
fmt.Printf("The pubkey of this lit-af instance is: %s\n", hex.EncodeToString(pubkey))
var temp [33]byte
copy(temp[:], pubkey[:33])
fmt.Printf("The pkh of this lit-af instance is: %s\n", lnutil.LitAdrFromPubkey(temp))

if len(adr) == 44 && !lnutil.LitAdrOK(adr) {
logging.Fatal("lit address passed in -con parameter is not valid")
}

lc.RPCClient, err = litrpc.NewLndcRpcClient(adr, key)
if host == "" {
ipv4, _, err := lnutil.Lookup(adr, conf.Tracker, "")
if err != nil {
logging.Fatal(err.Error())
logging.Fatalf("Error looking up address on the tracker: %s", err)
}
adr = fmt.Sprintf("%s@%s", adr, ipv4)
} else {
// host is non empty or address is remotePK, doesn't matter since NewLndcRpcClient will take acre of it for us
adr = fmt.Sprintf("%s@%s:%d", adr, host, port)
}

fmt.Printf("Remote Host: %s, Port: %d\n", host, port)
lc.RPCClient, err = litrpc.NewLndcRpcClient(adr, key)
if err != nil {
logging.Fatal(err.Error())
}

return nil
}

// for now just testing how to connect and get messages back and forth
Expand All @@ -137,7 +151,11 @@ func main() {
Dir: defaultDir,
Tracker: defaultTracker,
}
lc.litAfSetup(conf) // setup lit-af to start
err = lc.litAfSetup(conf) // setup lit-af to start
if err != nil {
logging.Error(err)
return
}

rl, err := readline.NewEx(&readline.Config{
Prompt: lnutil.Prompt("lit-af") + lnutil.White("# "),
Expand Down
14 changes: 2 additions & 12 deletions db/lnbolt/peerdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,7 @@ func (pdb *peerboltdb) GetPeerAddrs() ([]lncore.LnAddr, error) {
if k == nil {
break
}
lnaddr, err := lncore.ParseLnAddr(string(k))
if err != nil {
logging.Warnf("lnbolt/peerdb: found invalid key in DB as lnaddr: %s (error: %s)", string(k), err.Error())
continue
}

atmp = append(atmp, lnaddr)
atmp = append(atmp, lncore.LnAddr(string(k)))
}

// Now that we have the final array return it.
Expand Down Expand Up @@ -132,11 +126,7 @@ func (pdb *peerboltdb) GetPeerInfos() (map[lncore.LnAddr]lncore.PeerInfo, error)
return err2
}

ka, err2 := lncore.ParseLnAddr(string(k))
if err2 != nil {
logging.Warnf("lnbolt/peerdb: found invalid key in DB as lnaddr: %s (error: %s)", string(k), err.Error())
continue
}
ka := lncore.LnAddr(string(k))
mtmp[ka] = pi

}
Expand Down
35 changes: 29 additions & 6 deletions lit.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"runtime"
"syscall"
"time"
"encoding/hex"

"github.com/mit-dci/lit/logging"

Expand Down Expand Up @@ -55,11 +56,12 @@ type litConfig struct { // define a struct for usage with go-flags
Rpcport uint16 `short:"p" long:"rpcport" description:"Set RPC port to connect to"`
Rpchost string `long:"rpchost" description:"Set RPC host to listen to"`
// auto config
AutoReconnect bool `long:"autoReconnect" description:"Attempts to automatically reconnect to known peers periodically."`
AutoReconnectInterval int64 `long:"autoReconnectInterval" description:"The interval (in seconds) the reconnect logic should be executed"`
AutoReconnectOnlyConnectedCoins bool `long:"autoReconnectOnlyConnectedCoins" description:"Only reconnect to peers that we have channels with in a coin whose coin daemon is available"`
AutoListenPort int `long:"autoListenPort" description:"When auto reconnect enabled, starts listening on this port"`
NoAutoListen bool `long:"noautolisten" description:"Don't automatically listen on any ports."`
AutoReconnect bool `long:"autoReconnect" description:"Attempts to automatically reconnect to known peers periodically."`
AutoReconnectInterval int64 `long:"autoReconnectInterval" description:"The interval (in seconds) the reconnect logic should be executed"`
AutoReconnectOnlyConnectedCoins bool `long:"autoReconnectOnlyConnectedCoins" description:"Only reconnect to peers that we have channels with in a coin whose coin daemon is available"`
AutoListenPort int `long:"autoListenPort" description:"When auto reconnect enabled, starts listening on this port"`
NoAutoListen bool `long:"noautolisten" description:"Don't automatically listen on any ports."`
Whitelist string `long:"whitelist" description:"Whitelist a single address so that you can enable a remote peer to login for the first time and authenticate others"`
Params *coinparam.Params
}

Expand Down Expand Up @@ -293,12 +295,33 @@ func main() {
// if we don't link wallet, we can still continue, no worries.
logging.Error(err)
}

logging.Info("Starting lit node")
rpcl := new(litrpc.LitRPC)
rpcl.Node = node
rpcl.OffButton = make(chan bool, 1)
node.RPC = rpcl

Authorization := new(qln.RemoteControlAuthorization)
Authorization.UnansweredRequest = false
Authorization.Allowed = true

// check for whitelisted addresses here
if conf.Whitelist != "" && len(conf.Whitelist) == 66 { // the length of a standard LNAddr
// pass the pubkey here, which is ugly
// we could pass the pkh, have the peer dial us and we could get
// the pubkey during the second round of noise, but maybe overkill?
// we need to decode this hex string into a byte slice
addr, _ := hex.DecodeString(conf.Whitelist)
var temp [33]byte
copy(temp[:33], addr)
logging.Info("Whitelisting address as requested: ",addr)
err = rpcl.Node.SaveRemoteControlAuthorization(temp, Authorization)
if err != nil {
logging.Errorf("Error whitelisting address: %s", err.Error())
// don't fatal since this doesn't affect program flow
}
}

if conf.UnauthRPC {
go litrpc.RPCListen(rpcl, conf.Rpchost, conf.Rpcport)
}
Expand Down
13 changes: 5 additions & 8 deletions litrpc/netcmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/mit-dci/lit/bech32"
"github.com/mit-dci/lit/crypto/koblitz"
"github.com/mit-dci/lit/lncore"
"github.com/mit-dci/lit/lnp2p"
"github.com/mit-dci/lit/lnutil"
"github.com/mit-dci/lit/logging"
"github.com/mit-dci/lit/qln"
Expand Down Expand Up @@ -65,6 +66,8 @@ func (r *LitRPC) Connect(args ConnectArgs, reply *ConnectReply) error {
// first, see if the peer to connect to is referenced by peer index.
var connectAdr string
// check if a peer number was supplied instead of a pubkeyhash
// accept either an string or a pubkey (raw)
// so args.LNAddr passed here contains blah@host:ip
peerIdxint, err := strconv.Atoi(args.LNAddr)
// number will mean no error
if err == nil {
Expand All @@ -81,7 +84,6 @@ func (r *LitRPC) Connect(args ConnectArgs, reply *ConnectReply) error {
// use string as is, try to convert to ln address
connectAdr = args.LNAddr
}

err = r.Node.DialPeer(connectAdr)
if err != nil {
return err
Expand All @@ -94,13 +96,8 @@ func (r *LitRPC) Connect(args ConnectArgs, reply *ConnectReply) error {
paddr = strings.SplitN(paddr, "@", 2)[0]
}

pm := r.Node.PeerMan
lnaddr, err := lncore.ParseLnAddr(paddr)
if err != nil {
return err
}

p := pm.GetPeer(lnaddr)
var pm *lnp2p.PeerManager = r.Node.PeerMan
p := pm.GetPeer(lncore.LnAddr(paddr))
if p == nil {
return fmt.Errorf("couldn't find peer in manager after connecting")
}
Expand Down
38 changes: 1 addition & 37 deletions lncore/peers.go
Original file line number Diff line number Diff line change
@@ -1,46 +1,9 @@
package lncore

import (
"fmt"

"github.com/mit-dci/lit/bech32"
)

// LnAddr is just a bech32-encoded pubkey.
// TODO Move this to another package so it's more obviously not *just* IO-related.
type LnAddr string

// ParseLnAddr will verify that the string passed is a valid LN address, as in
// ln1pmclh89haeswrw0unf8awuyqeu4t2uell58nea.
func ParseLnAddr(m string) (LnAddr, error) {

prefix, raw, err := bech32.Decode(m)

// Check it's valid bech32.
if err != nil {
return "", err
}

// Check it has the right prefix.
if prefix != "ln" {
return "", fmt.Errorf("prefix is not 'ln'")
}

// Check the length of the content bytes is right.
if len(raw) > 20 {
return "", fmt.Errorf("address too long to be pubkey")
}

return LnAddr(m), nil // should be the only place we cast to this type

}

// ToString returns the LnAddr as a string. Right now it just unwraps it but it
// might do something more eventually.
func (lnaddr LnAddr) ToString() string {
return string(lnaddr)
}

// LitPeerStorage is storage for peer data.
type LitPeerStorage interface {
GetPeerAddrs() ([]LnAddr, error)
Expand All @@ -59,6 +22,7 @@ type PeerInfo struct {
LnAddr *LnAddr `json:"lnaddr"`
Nickname *string `json:"name"`
NetAddr *string `json:"netaddr"` // ip address, port, I guess
Pubkey *string `json:pubkey`

// TEMP This is again, for adapting to the old system.
PeerIdx uint32 `json:"hint_peeridx"`
Expand Down
Loading