mirror of
https://github.com/aljazceru/lspd.git
synced 2025-12-19 23:04:22 +01:00
separate node logic
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/breez/lspd/interceptor"
|
"github.com/breez/lspd/interceptor"
|
||||||
"github.com/breez/lspd/lightning"
|
"github.com/breez/lspd/lightning"
|
||||||
lspdrpc "github.com/breez/lspd/rpc"
|
lspdrpc "github.com/breez/lspd/rpc"
|
||||||
|
"github.com/breez/lspd/shared"
|
||||||
ecies "github.com/ecies/go/v2"
|
ecies "github.com/ecies/go/v2"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
@@ -54,26 +55,26 @@ func (s *channelOpenerServer) ChannelInformation(ctx context.Context, in *lspdrp
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &lspdrpc.ChannelInformationReply{
|
return &lspdrpc.ChannelInformationReply{
|
||||||
Name: node.nodeConfig.Name,
|
Name: node.NodeConfig.Name,
|
||||||
Pubkey: node.nodeConfig.NodePubkey,
|
Pubkey: node.NodeConfig.NodePubkey,
|
||||||
Host: node.nodeConfig.Host,
|
Host: node.NodeConfig.Host,
|
||||||
ChannelCapacity: int64(node.nodeConfig.PublicChannelAmount),
|
ChannelCapacity: int64(node.NodeConfig.PublicChannelAmount),
|
||||||
TargetConf: int32(node.nodeConfig.TargetConf),
|
TargetConf: int32(node.NodeConfig.TargetConf),
|
||||||
MinHtlcMsat: int64(node.nodeConfig.MinHtlcMsat),
|
MinHtlcMsat: int64(node.NodeConfig.MinHtlcMsat),
|
||||||
BaseFeeMsat: int64(node.nodeConfig.BaseFeeMsat),
|
BaseFeeMsat: int64(node.NodeConfig.BaseFeeMsat),
|
||||||
FeeRate: node.nodeConfig.FeeRate,
|
FeeRate: node.NodeConfig.FeeRate,
|
||||||
TimeLockDelta: node.nodeConfig.TimeLockDelta,
|
TimeLockDelta: node.NodeConfig.TimeLockDelta,
|
||||||
ChannelFeePermyriad: int64(node.nodeConfig.ChannelFeePermyriad),
|
ChannelFeePermyriad: int64(node.NodeConfig.ChannelFeePermyriad),
|
||||||
ChannelMinimumFeeMsat: int64(node.nodeConfig.ChannelMinimumFeeMsat),
|
ChannelMinimumFeeMsat: int64(node.NodeConfig.ChannelMinimumFeeMsat),
|
||||||
LspPubkey: node.publicKey.SerializeCompressed(), // TODO: Is the publicKey different from the ecies public key?
|
LspPubkey: node.PublicKey.SerializeCompressed(), // TODO: Is the publicKey different from the ecies public key?
|
||||||
MaxInactiveDuration: int64(node.nodeConfig.MaxInactiveDuration),
|
MaxInactiveDuration: int64(node.NodeConfig.MaxInactiveDuration),
|
||||||
OpeningFeeParamsMenu: params,
|
OpeningFeeParamsMenu: params,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *channelOpenerServer) createOpeningParamsMenu(
|
func (s *channelOpenerServer) createOpeningParamsMenu(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
node *node,
|
node *shared.Node,
|
||||||
token string,
|
token string,
|
||||||
) ([]*lspdrpc.OpeningFeeParams, error) {
|
) ([]*lspdrpc.OpeningFeeParams, error) {
|
||||||
var menu []*lspdrpc.OpeningFeeParams
|
var menu []*lspdrpc.OpeningFeeParams
|
||||||
@@ -136,13 +137,13 @@ func paramsHash(params *lspdrpc.OpeningFeeParams) ([]byte, error) {
|
|||||||
return hash[:], nil
|
return hash[:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPromise(node *node, params *lspdrpc.OpeningFeeParams) (*string, error) {
|
func createPromise(node *shared.Node, params *lspdrpc.OpeningFeeParams) (*string, error) {
|
||||||
hash, err := paramsHash(params)
|
hash, err := paramsHash(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Sign the hash with the private key of the LSP id.
|
// Sign the hash with the private key of the LSP id.
|
||||||
sig, err := ecdsa.SignCompact(node.privateKey, hash[:], true)
|
sig, err := ecdsa.SignCompact(node.PrivateKey, hash[:], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("createPromise: SignCompact error: %v", err)
|
log.Printf("createPromise: SignCompact error: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -151,7 +152,7 @@ func createPromise(node *node, params *lspdrpc.OpeningFeeParams) (*string, error
|
|||||||
return &promise, nil
|
return &promise, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyPromise(node *node, params *lspdrpc.OpeningFeeParams) error {
|
func verifyPromise(node *shared.Node, params *lspdrpc.OpeningFeeParams) error {
|
||||||
hash, err := paramsHash(params)
|
hash, err := paramsHash(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -166,14 +167,14 @@ func verifyPromise(node *node, params *lspdrpc.OpeningFeeParams) error {
|
|||||||
log.Printf("verifyPromise: RecoverCompact(%x) error: %v", sig, err)
|
log.Printf("verifyPromise: RecoverCompact(%x) error: %v", sig, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !node.publicKey.IsEqual(pub) {
|
if !node.PublicKey.IsEqual(pub) {
|
||||||
log.Print("verifyPromise: not signed by us", err)
|
log.Print("verifyPromise: not signed by us", err)
|
||||||
return fmt.Errorf("invalid promise")
|
return fmt.Errorf("invalid promise")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateOpeningFeeParams(node *node, params *lspdrpc.OpeningFeeParams) bool {
|
func validateOpeningFeeParams(node *shared.Node, params *lspdrpc.OpeningFeeParams) bool {
|
||||||
if params == nil {
|
if params == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -206,10 +207,10 @@ func (s *channelOpenerServer) RegisterPayment(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := ecies.Decrypt(node.eciesPrivateKey, in.Blob)
|
data, err := ecies.Decrypt(node.EciesPrivateKey, in.Blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ecies.Decrypt(%x) error: %v", in.Blob, err)
|
log.Printf("ecies.Decrypt(%x) error: %v", in.Blob, err)
|
||||||
data, err = btceclegacy.Decrypt(node.privateKey, in.Blob)
|
data, err = btceclegacy.Decrypt(node.PrivateKey, in.Blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("btcec.Decrypt(%x) error: %v", in.Blob, err)
|
log.Printf("btcec.Decrypt(%x) error: %v", in.Blob, err)
|
||||||
return nil, fmt.Errorf("btcec.Decrypt(%x) error: %w", in.Blob, err)
|
return nil, fmt.Errorf("btcec.Decrypt(%x) error: %w", in.Blob, err)
|
||||||
@@ -247,10 +248,10 @@ func (s *channelOpenerServer) RegisterPayment(
|
|||||||
} else {
|
} else {
|
||||||
log.Printf("DEPRECATED: RegisterPayment with deprecated fee mechanism.")
|
log.Printf("DEPRECATED: RegisterPayment with deprecated fee mechanism.")
|
||||||
pi.OpeningFeeParams = &lspdrpc.OpeningFeeParams{
|
pi.OpeningFeeParams = &lspdrpc.OpeningFeeParams{
|
||||||
MinMsat: uint64(node.nodeConfig.ChannelMinimumFeeMsat),
|
MinMsat: uint64(node.NodeConfig.ChannelMinimumFeeMsat),
|
||||||
Proportional: uint32(node.nodeConfig.ChannelFeePermyriad * 100),
|
Proportional: uint32(node.NodeConfig.ChannelFeePermyriad * 100),
|
||||||
ValidUntil: time.Now().UTC().Add(time.Duration(time.Hour * 24)).Format(basetypes.TIME_FORMAT),
|
ValidUntil: time.Now().UTC().Add(time.Duration(time.Hour * 24)).Format(basetypes.TIME_FORMAT),
|
||||||
MaxIdleTime: uint32(node.nodeConfig.MaxInactiveDuration / 600),
|
MaxIdleTime: uint32(node.NodeConfig.MaxInactiveDuration / 600),
|
||||||
MaxClientToSelfDelay: uint32(10000),
|
MaxClientToSelfDelay: uint32(10000),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,25 +283,25 @@ func (s *channelOpenerServer) OpenChannel(ctx context.Context, in *lspdrpc.OpenC
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err, _ := node.openChannelReqGroup.Do(in.Pubkey, func() (interface{}, error) {
|
r, err, _ := node.OpenChannelReqGroup.Do(in.Pubkey, func() (interface{}, error) {
|
||||||
pubkey, err := hex.DecodeString(in.Pubkey)
|
pubkey, err := hex.DecodeString(in.Pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
channelCount, err := node.client.GetNodeChannelCount(pubkey)
|
channelCount, err := node.Client.GetNodeChannelCount(pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var outPoint *wire.OutPoint
|
var outPoint *wire.OutPoint
|
||||||
if channelCount == 0 {
|
if channelCount == 0 {
|
||||||
outPoint, err = node.client.OpenChannel(&lightning.OpenChannelRequest{
|
outPoint, err = node.Client.OpenChannel(&lightning.OpenChannelRequest{
|
||||||
CapacitySat: node.nodeConfig.ChannelAmount,
|
CapacitySat: node.NodeConfig.ChannelAmount,
|
||||||
Destination: pubkey,
|
Destination: pubkey,
|
||||||
TargetConf: &node.nodeConfig.TargetConf,
|
TargetConf: &node.NodeConfig.TargetConf,
|
||||||
MinHtlcMsat: node.nodeConfig.MinHtlcMsat,
|
MinHtlcMsat: node.NodeConfig.MinHtlcMsat,
|
||||||
IsPrivate: node.nodeConfig.ChannelPrivate,
|
IsPrivate: node.NodeConfig.ChannelPrivate,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -320,13 +321,13 @@ func (s *channelOpenerServer) OpenChannel(ctx context.Context, in *lspdrpc.OpenC
|
|||||||
return r.(*lspdrpc.OpenChannelReply), err
|
return r.(*lspdrpc.OpenChannelReply), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) getSignedEncryptedData(in *lspdrpc.Encrypted) (string, []byte, bool, error) {
|
func getSignedEncryptedData(n *shared.Node, in *lspdrpc.Encrypted) (string, []byte, bool, error) {
|
||||||
usedEcies := true
|
usedEcies := true
|
||||||
signedBlob, err := ecies.Decrypt(n.eciesPrivateKey, in.Data)
|
signedBlob, err := ecies.Decrypt(n.EciesPrivateKey, in.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ecies.Decrypt(%x) error: %v", in.Data, err)
|
log.Printf("ecies.Decrypt(%x) error: %v", in.Data, err)
|
||||||
usedEcies = false
|
usedEcies = false
|
||||||
signedBlob, err = btceclegacy.Decrypt(n.privateKey, in.Data)
|
signedBlob, err = btceclegacy.Decrypt(n.PrivateKey, in.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("btcec.Decrypt(%x) error: %v", in.Data, err)
|
log.Printf("btcec.Decrypt(%x) error: %v", in.Data, err)
|
||||||
return "", nil, usedEcies, fmt.Errorf("btcec.Decrypt(%x) error: %w", in.Data, err)
|
return "", nil, usedEcies, fmt.Errorf("btcec.Decrypt(%x) error: %w", in.Data, err)
|
||||||
@@ -366,7 +367,7 @@ func (s *channelOpenerServer) CheckChannels(ctx context.Context, in *lspdrpc.Enc
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeID, data, usedEcies, err := node.getSignedEncryptedData(in)
|
nodeID, data, usedEcies, err := getSignedEncryptedData(node, in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("getSignedEncryptedData error: %v", err)
|
log.Printf("getSignedEncryptedData error: %v", err)
|
||||||
return nil, fmt.Errorf("getSignedEncryptedData error: %v", err)
|
return nil, fmt.Errorf("getSignedEncryptedData error: %v", err)
|
||||||
@@ -377,7 +378,7 @@ func (s *channelOpenerServer) CheckChannels(ctx context.Context, in *lspdrpc.Enc
|
|||||||
log.Printf("proto.Unmarshal(%x) error: %v", data, err)
|
log.Printf("proto.Unmarshal(%x) error: %v", data, err)
|
||||||
return nil, fmt.Errorf("proto.Unmarshal(%x) error: %w", data, err)
|
return nil, fmt.Errorf("proto.Unmarshal(%x) error: %w", data, err)
|
||||||
}
|
}
|
||||||
closedChannels, err := node.client.GetClosedChannels(nodeID, checkChannelsRequest.WaitingCloseChannels)
|
closedChannels, err := node.Client.GetClosedChannels(nodeID, checkChannelsRequest.WaitingCloseChannels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("GetClosedChannels(%v) error: %v", checkChannelsRequest.FakeChannels, err)
|
log.Printf("GetClosedChannels(%v) error: %v", checkChannelsRequest.FakeChannels, err)
|
||||||
return nil, fmt.Errorf("GetClosedChannels(%v) error: %w", checkChannelsRequest.FakeChannels, err)
|
return nil, fmt.Errorf("GetClosedChannels(%v) error: %w", checkChannelsRequest.FakeChannels, err)
|
||||||
@@ -399,7 +400,7 @@ func (s *channelOpenerServer) CheckChannels(ctx context.Context, in *lspdrpc.Enc
|
|||||||
|
|
||||||
var encrypted []byte
|
var encrypted []byte
|
||||||
if usedEcies {
|
if usedEcies {
|
||||||
encrypted, err = ecies.Encrypt(node.eciesPublicKey, dataReply)
|
encrypted, err = ecies.Encrypt(node.EciesPublicKey, dataReply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ecies.Encrypt() error: %v", err)
|
log.Printf("ecies.Encrypt() error: %v", err)
|
||||||
return nil, fmt.Errorf("ecies.Encrypt() error: %w", err)
|
return nil, fmt.Errorf("ecies.Encrypt() error: %w", err)
|
||||||
@@ -415,7 +416,7 @@ func (s *channelOpenerServer) CheckChannels(ctx context.Context, in *lspdrpc.Enc
|
|||||||
return &lspdrpc.Encrypted{Data: encrypted}, nil
|
return &lspdrpc.Encrypted{Data: encrypted}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *channelOpenerServer) getNode(ctx context.Context) (*node, string, error) {
|
func (s *channelOpenerServer) getNode(ctx context.Context) (*shared.Node, string, error) {
|
||||||
nd := ctx.Value(contextKey("node"))
|
nd := ctx.Value(contextKey("node"))
|
||||||
if nd == nil {
|
if nd == nil {
|
||||||
return nil, "", status.Errorf(codes.PermissionDenied, "Not authorized")
|
return nil, "", status.Errorf(codes.PermissionDenied, "Not authorized")
|
||||||
|
|||||||
102
grpc_server.go
102
grpc_server.go
@@ -3,23 +3,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/breez/lspd/cln"
|
|
||||||
"github.com/breez/lspd/config"
|
|
||||||
"github.com/breez/lspd/lightning"
|
|
||||||
"github.com/breez/lspd/lnd"
|
|
||||||
"github.com/breez/lspd/notifications"
|
"github.com/breez/lspd/notifications"
|
||||||
lspdrpc "github.com/breez/lspd/rpc"
|
lspdrpc "github.com/breez/lspd/rpc"
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/breez/lspd/shared"
|
||||||
"github.com/caddyserver/certmagic"
|
"github.com/caddyserver/certmagic"
|
||||||
ecies "github.com/ecies/go/v2"
|
|
||||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||||
"golang.org/x/sync/singleflight"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
@@ -27,119 +20,38 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type grpcServer struct {
|
type grpcServer struct {
|
||||||
|
nodesService shared.NodesService
|
||||||
address string
|
address string
|
||||||
certmagicDomain string
|
certmagicDomain string
|
||||||
lis net.Listener
|
lis net.Listener
|
||||||
s *grpc.Server
|
s *grpc.Server
|
||||||
nodes map[string]*node
|
|
||||||
c lspdrpc.ChannelOpenerServer
|
c lspdrpc.ChannelOpenerServer
|
||||||
n notifications.NotificationsServer
|
n notifications.NotificationsServer
|
||||||
}
|
}
|
||||||
|
|
||||||
type nodeContext struct {
|
type nodeContext struct {
|
||||||
token string
|
token string
|
||||||
node *node
|
node *shared.Node
|
||||||
}
|
|
||||||
|
|
||||||
type node struct {
|
|
||||||
client lightning.Client
|
|
||||||
nodeConfig *config.NodeConfig
|
|
||||||
privateKey *btcec.PrivateKey
|
|
||||||
publicKey *btcec.PublicKey
|
|
||||||
eciesPrivateKey *ecies.PrivateKey
|
|
||||||
eciesPublicKey *ecies.PublicKey
|
|
||||||
openChannelReqGroup singleflight.Group
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGrpcServer(
|
func NewGrpcServer(
|
||||||
configs []*config.NodeConfig,
|
nodesService shared.NodesService,
|
||||||
address string,
|
address string,
|
||||||
certmagicDomain string,
|
certmagicDomain string,
|
||||||
c lspdrpc.ChannelOpenerServer,
|
c lspdrpc.ChannelOpenerServer,
|
||||||
n notifications.NotificationsServer,
|
n notifications.NotificationsServer,
|
||||||
) (*grpcServer, error) {
|
) (*grpcServer, error) {
|
||||||
if len(configs) == 0 {
|
|
||||||
return nil, fmt.Errorf("no nodes supplied")
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes := make(map[string]*node)
|
|
||||||
for _, config := range configs {
|
|
||||||
pk, err := hex.DecodeString(config.LspdPrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("hex.DecodeString(config.lspdPrivateKey=%v) error: %v", config.LspdPrivateKey, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
eciesPrivateKey := ecies.NewPrivateKeyFromBytes(pk)
|
|
||||||
eciesPublicKey := eciesPrivateKey.PublicKey
|
|
||||||
privateKey, publicKey := btcec.PrivKeyFromBytes(pk)
|
|
||||||
|
|
||||||
node := &node{
|
|
||||||
nodeConfig: config,
|
|
||||||
privateKey: privateKey,
|
|
||||||
publicKey: publicKey,
|
|
||||||
eciesPrivateKey: eciesPrivateKey,
|
|
||||||
eciesPublicKey: eciesPublicKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Lnd == nil && config.Cln == nil {
|
|
||||||
return nil, fmt.Errorf("node has to be either cln or lnd")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Lnd != nil && config.Cln != nil {
|
|
||||||
return nil, fmt.Errorf("node cannot be both cln and lnd")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Lnd != nil {
|
|
||||||
node.client, err = lnd.NewLndClient(config.Lnd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Cln != nil {
|
|
||||||
node.client, err = cln.NewClnClient(config.Cln.SocketPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, token := range config.Tokens {
|
|
||||||
_, exists := nodes[token]
|
|
||||||
if exists {
|
|
||||||
return nil, fmt.Errorf("cannot have multiple nodes with the same token")
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes[token] = node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &grpcServer{
|
return &grpcServer{
|
||||||
|
nodesService: nodesService,
|
||||||
address: address,
|
address: address,
|
||||||
certmagicDomain: certmagicDomain,
|
certmagicDomain: certmagicDomain,
|
||||||
nodes: nodes,
|
|
||||||
c: c,
|
c: c,
|
||||||
n: n,
|
n: n,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *grpcServer) Start() error {
|
func (s *grpcServer) Start() error {
|
||||||
// Make sure all nodes are available and set name and pubkey if not set
|
|
||||||
// in config.
|
|
||||||
for _, n := range s.nodes {
|
|
||||||
info, err := n.client.GetInfo()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get info from host %s", n.nodeConfig.Host)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n.nodeConfig.Name == "" {
|
|
||||||
n.nodeConfig.Name = info.Alias
|
|
||||||
}
|
|
||||||
|
|
||||||
if n.nodeConfig.NodePubkey == "" {
|
|
||||||
n.nodeConfig.NodePubkey = info.Pubkey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var lis net.Listener
|
var lis net.Listener
|
||||||
if s.certmagicDomain == "" {
|
if s.certmagicDomain == "" {
|
||||||
var err error
|
var err error
|
||||||
@@ -167,8 +79,8 @@ func (s *grpcServer) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
token := strings.Replace(auth, "Bearer ", "", 1)
|
token := strings.Replace(auth, "Bearer ", "", 1)
|
||||||
node, ok := s.nodes[token]
|
node, err := s.nodesService.GetNode(token)
|
||||||
if !ok {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
main.go
8
main.go
@@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/breez/lspd/mempool"
|
"github.com/breez/lspd/mempool"
|
||||||
"github.com/breez/lspd/notifications"
|
"github.com/breez/lspd/notifications"
|
||||||
"github.com/breez/lspd/postgresql"
|
"github.com/breez/lspd/postgresql"
|
||||||
|
"github.com/breez/lspd/shared"
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,6 +45,11 @@ func main() {
|
|||||||
log.Fatalf("need at least one node configured in NODES.")
|
log.Fatalf("need at least one node configured in NODES.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodesService, err := shared.NewNodesService(nodes)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to create nodes service: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
mempoolUrl := os.Getenv("MEMPOOL_API_BASE_URL")
|
mempoolUrl := os.Getenv("MEMPOOL_API_BASE_URL")
|
||||||
if mempoolUrl == "" {
|
if mempoolUrl == "" {
|
||||||
log.Fatalf("No mempool url configured.")
|
log.Fatalf("No mempool url configured.")
|
||||||
@@ -136,7 +142,7 @@ func main() {
|
|||||||
certMagicDomain := os.Getenv("CERTMAGIC_DOMAIN")
|
certMagicDomain := os.Getenv("CERTMAGIC_DOMAIN")
|
||||||
cs := NewChannelOpenerServer(interceptStore)
|
cs := NewChannelOpenerServer(interceptStore)
|
||||||
ns := notifications.NewNotificationsServer(notificationsStore)
|
ns := notifications.NewNotificationsServer(notificationsStore)
|
||||||
s, err := NewGrpcServer(nodes, address, certMagicDomain, cs, ns)
|
s, err := NewGrpcServer(nodesService, address, certMagicDomain, cs, ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to initialize grpc server: %v", err)
|
log.Fatalf("failed to initialize grpc server: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
118
shared/nodes_service.go
Normal file
118
shared/nodes_service.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package shared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/breez/lspd/cln"
|
||||||
|
"github.com/breez/lspd/config"
|
||||||
|
"github.com/breez/lspd/lightning"
|
||||||
|
"github.com/breez/lspd/lnd"
|
||||||
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
|
ecies "github.com/ecies/go/v2"
|
||||||
|
"golang.org/x/sync/singleflight"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
Client lightning.Client
|
||||||
|
NodeConfig *config.NodeConfig
|
||||||
|
PrivateKey *btcec.PrivateKey
|
||||||
|
PublicKey *btcec.PublicKey
|
||||||
|
EciesPrivateKey *ecies.PrivateKey
|
||||||
|
EciesPublicKey *ecies.PublicKey
|
||||||
|
OpenChannelReqGroup singleflight.Group
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodesService interface {
|
||||||
|
GetNode(token string) (*Node, error)
|
||||||
|
}
|
||||||
|
type nodesService struct {
|
||||||
|
nodes map[string]*Node
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNodesService(configs []*config.NodeConfig) (NodesService, error) {
|
||||||
|
if len(configs) == 0 {
|
||||||
|
return nil, fmt.Errorf("no nodes supplied")
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes := make(map[string]*Node)
|
||||||
|
for _, config := range configs {
|
||||||
|
pk, err := hex.DecodeString(config.LspdPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("hex.DecodeString(config.lspdPrivateKey=%v) error: %v", config.LspdPrivateKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
eciesPrivateKey := ecies.NewPrivateKeyFromBytes(pk)
|
||||||
|
eciesPublicKey := eciesPrivateKey.PublicKey
|
||||||
|
privateKey, publicKey := btcec.PrivKeyFromBytes(pk)
|
||||||
|
node := &Node{
|
||||||
|
NodeConfig: config,
|
||||||
|
PrivateKey: privateKey,
|
||||||
|
PublicKey: publicKey,
|
||||||
|
EciesPrivateKey: eciesPrivateKey,
|
||||||
|
EciesPublicKey: eciesPublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Lnd == nil && config.Cln == nil {
|
||||||
|
return nil, fmt.Errorf("node has to be either cln or lnd")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Lnd != nil && config.Cln != nil {
|
||||||
|
return nil, fmt.Errorf("node cannot be both cln and lnd")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Lnd != nil {
|
||||||
|
node.Client, err = lnd.NewLndClient(config.Lnd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Cln != nil {
|
||||||
|
node.Client, err = cln.NewClnClient(config.Cln.SocketPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the nodes is available and set name and pubkey if not set
|
||||||
|
// in config.
|
||||||
|
info, err := node.Client.GetInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get info from host %s", node.NodeConfig.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.NodeConfig.Name == "" {
|
||||||
|
node.NodeConfig.Name = info.Alias
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.NodeConfig.NodePubkey == "" {
|
||||||
|
node.NodeConfig.NodePubkey = info.Pubkey
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, token := range config.Tokens {
|
||||||
|
_, exists := nodes[token]
|
||||||
|
if exists {
|
||||||
|
return nil, fmt.Errorf("cannot have multiple nodes with the same token")
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes[token] = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &nodesService{
|
||||||
|
nodes: nodes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrNodeNotFound = errors.New("node not found")
|
||||||
|
|
||||||
|
func (s *nodesService) GetNode(token string) (*Node, error) {
|
||||||
|
node, ok := s.nodes[token]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNodeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user