mirror of
https://github.com/callebtc/electronwall.git
synced 2025-12-17 07:04:21 +01:00
234 lines
6.5 KiB
Go
234 lines
6.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/callebtc/electronwall/api"
|
|
"github.com/callebtc/electronwall/config"
|
|
"github.com/callebtc/electronwall/rules"
|
|
"github.com/callebtc/electronwall/types"
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func (app *App) GetChannelAcceptEvent(ctx context.Context, req lnrpc.ChannelAcceptRequest) (types.ChannelAcceptEvent, error) {
|
|
// print the incoming channel request
|
|
alias, err := app.lnd.getNodeAlias(ctx, hex.EncodeToString(req.NodePubkey))
|
|
if err != nil {
|
|
log.Errorf(err.Error())
|
|
}
|
|
|
|
info, err := app.lnd.getNodeInfo(ctx, hex.EncodeToString(req.NodePubkey))
|
|
if err != nil {
|
|
log.Errorf(err.Error())
|
|
}
|
|
|
|
noeInfo, err := api.GetApiNodeinfo(hex.EncodeToString(req.NodePubkey))
|
|
if err != nil {
|
|
log.Errorf(err.Error())
|
|
}
|
|
|
|
return types.ChannelAcceptEvent{
|
|
PubkeyFrom: hex.EncodeToString(req.NodePubkey),
|
|
AliasFrom: alias,
|
|
NodeInfo: info,
|
|
Event: &req,
|
|
OneMl: noeInfo.OneMl,
|
|
Amboss: noeInfo.Amboss,
|
|
}, nil
|
|
}
|
|
|
|
// DispatchChannelAcceptor is the channel acceptor event loop
|
|
func (app *App) DispatchChannelAcceptor(ctx context.Context) {
|
|
// the channel event logger
|
|
go func() {
|
|
err := app.logChannelEvents(ctx)
|
|
if err != nil {
|
|
log.Errorf("channel event logger error: %v", err)
|
|
}
|
|
}()
|
|
|
|
// the channel event interceptor
|
|
go func() {
|
|
err := app.interceptChannelEvents(ctx)
|
|
if err != nil {
|
|
log.Errorf("channel interceptor error: %v", err)
|
|
}
|
|
// release wait group for channel acceptor
|
|
ctx.Value(ctxKeyWaitGroup).(*sync.WaitGroup).Done()
|
|
}()
|
|
|
|
log.Infof("[channel] Listening for incoming channel requests")
|
|
|
|
}
|
|
|
|
func (app *App) interceptChannelEvents(ctx context.Context) error {
|
|
// get the lnd grpc connection
|
|
acceptClient, err := app.lnd.channelAcceptor(ctx)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
for {
|
|
req := lnrpc.ChannelAcceptRequest{}
|
|
err = acceptClient.RecvMsg(&req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
channelAcceptEvent, err := app.GetChannelAcceptEvent(ctx, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var node_info_string string
|
|
if channelAcceptEvent.AliasFrom != "" {
|
|
node_info_string = fmt.Sprintf("%s (%s)", channelAcceptEvent.AliasFrom, hex.EncodeToString(channelAcceptEvent.Event.NodePubkey))
|
|
} else {
|
|
node_info_string = hex.EncodeToString(channelAcceptEvent.Event.NodePubkey)
|
|
}
|
|
log.Debugf("[channel] New channel request from %s", node_info_string)
|
|
|
|
var channel_info_string string
|
|
if channelAcceptEvent.AliasFrom != "" {
|
|
channel_info_string = fmt.Sprintf("(%d sat) from %s (%s, %d sat capacity, %d channels)",
|
|
channelAcceptEvent.Event.FundingAmt,
|
|
channelAcceptEvent.AliasFrom,
|
|
trimPubKey(channelAcceptEvent.Event.NodePubkey),
|
|
channelAcceptEvent.NodeInfo.TotalCapacity,
|
|
channelAcceptEvent.NodeInfo.NumChannels,
|
|
)
|
|
} else {
|
|
channel_info_string = fmt.Sprintf("(%d sat) from %s (%d sat capacity, %d channels)",
|
|
channelAcceptEvent.Event.FundingAmt,
|
|
trimPubKey(channelAcceptEvent.Event.NodePubkey),
|
|
channelAcceptEvent.NodeInfo.TotalCapacity,
|
|
channelAcceptEvent.NodeInfo.NumChannels,
|
|
)
|
|
}
|
|
|
|
contextLogger := log.WithFields(log.Fields{
|
|
"event": "channel_request",
|
|
"amount": channelAcceptEvent.Event.FundingAmt,
|
|
"alias": channelAcceptEvent.AliasFrom,
|
|
"pubkey": hex.EncodeToString(channelAcceptEvent.Event.NodePubkey),
|
|
"pending_chan_id": hex.EncodeToString(channelAcceptEvent.Event.PendingChanId),
|
|
"total_capacity": channelAcceptEvent.NodeInfo.TotalCapacity,
|
|
"num_channels": channelAcceptEvent.NodeInfo.NumChannels,
|
|
})
|
|
|
|
// make decision
|
|
decision_chan := make(chan bool, 1)
|
|
rules_decision, err := rules.Apply(channelAcceptEvent, decision_chan)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// parse list
|
|
list_decision, err := app.channelAcceptListDecision(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
accept := true
|
|
if !rules_decision || !list_decision {
|
|
accept = false
|
|
}
|
|
|
|
res := lnrpc.ChannelAcceptResponse{}
|
|
if accept {
|
|
if config.Configuration.LogJson {
|
|
contextLogger.Infof("allow")
|
|
} else {
|
|
log.Infof("[channel] ✅ Allow channel %s", channel_info_string)
|
|
}
|
|
res = lnrpc.ChannelAcceptResponse{Accept: true,
|
|
PendingChanId: req.PendingChanId,
|
|
CsvDelay: req.CsvDelay,
|
|
MaxHtlcCount: req.MaxAcceptedHtlcs,
|
|
ReserveSat: req.ChannelReserve,
|
|
InFlightMaxMsat: req.MaxValueInFlight,
|
|
MinHtlcIn: req.MinHtlc,
|
|
}
|
|
|
|
} else {
|
|
if config.Configuration.LogJson {
|
|
contextLogger.Infof("deny")
|
|
} else {
|
|
log.Infof("[channel] ❌ Deny channel %s", channel_info_string)
|
|
}
|
|
res = lnrpc.ChannelAcceptResponse{Accept: false,
|
|
Error: config.Configuration.ChannelRejectMessage}
|
|
}
|
|
err = acceptClient.Send(&res)
|
|
if err != nil {
|
|
log.Errorf(err.Error())
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func (app *App) channelAcceptListDecision(req lnrpc.ChannelAcceptRequest) (bool, error) {
|
|
// determine mode and list of channels to parse
|
|
var accept bool
|
|
var listToParse []string
|
|
if config.Configuration.ChannelMode == "allowlist" {
|
|
accept = false
|
|
listToParse = config.Configuration.ChannelAllowlist
|
|
} else if config.Configuration.ChannelMode == "denylist" {
|
|
accept = true
|
|
listToParse = config.Configuration.ChannelDenylist
|
|
}
|
|
|
|
// parse and make decision
|
|
for _, pubkey := range listToParse {
|
|
if hex.EncodeToString(req.NodePubkey) == pubkey || pubkey == "*" {
|
|
accept = !accept
|
|
break
|
|
}
|
|
}
|
|
log.Infof("[list] decision: %t", accept)
|
|
return accept, nil
|
|
|
|
}
|
|
|
|
func (app *App) logChannelEvents(ctx context.Context) error {
|
|
stream, err := app.lnd.subscribeChannelEvents(ctx, &lnrpc.ChannelEventSubscription{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for {
|
|
event, err := stream.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
switch event.Type {
|
|
case lnrpc.ChannelEventUpdate_OPEN_CHANNEL:
|
|
alias, err := app.lnd.getNodeAlias(ctx, event.GetOpenChannel().RemotePubkey)
|
|
if err != nil {
|
|
log.Errorf(err.Error())
|
|
alias = trimPubKey([]byte(event.GetOpenChannel().RemotePubkey))
|
|
}
|
|
channel_info_string := fmt.Sprintf("(%d sat) from %s",
|
|
event.GetOpenChannel().Capacity,
|
|
alias,
|
|
)
|
|
|
|
if config.Configuration.LogJson {
|
|
contextLogger := log.WithFields(log.Fields{
|
|
"event": "channel",
|
|
"capacity": event.GetOpenChannel().Capacity,
|
|
"alias": alias,
|
|
"pubkey": event.GetOpenChannel().RemotePubkey,
|
|
"chan_id": ParseChannelID(event.GetOpenChannel().ChanId),
|
|
})
|
|
contextLogger.Infof("open")
|
|
} else {
|
|
log.Infof("[channel] Opened channel %s %s", ParseChannelID(event.GetOpenChannel().ChanId), channel_info_string)
|
|
}
|
|
}
|
|
log.Tracef("[channel] Event: %s", event.String())
|
|
}
|
|
}
|