Files
electronwall/channelAcceptor.go
callebtc edc4152faf works
2022-08-31 14:09:17 +02:00

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())
}
}