mirror of
https://github.com/callebtc/electronwall.git
synced 2026-02-01 05:14:52 +01:00
190
README.md
190
README.md
@@ -1,7 +1,9 @@
|
||||
# ⚡️🛡 electronwall
|
||||
A tiny firewall for LND that can filter Lightning **channel opening requests** and **HTLC forwards** on your node based on set rules.
|
||||
A tiny firewall for LND that can filter Lightning **channel opening requests** and **HTLC forwards** based on your custom rules.
|
||||
|
||||
Currently, electronwall uses filter lists that either allow (allowlist) or reject (denylist) events from a list of node public keys for channel openings, or channel IDs and channel pairs for payment routings.
|
||||
electronwall uses filter lists that either allow (allowlist) or reject (denylist) events from a list of node public keys for channel openings, or channel IDs and channel pairs for payment routings.
|
||||
|
||||
You can also write [custom rules](#programmable-rules) using a builtin Javascript engine.
|
||||
|
||||

|
||||
|
||||
@@ -21,10 +23,192 @@ go build .
|
||||
You can download a binary for your system [here](https://github.com/callebtc/electronwall/releases). You'll still need a [config file](https://github.com/callebtc/electronwall/blob/main/config.yaml.example).
|
||||
|
||||
## Config
|
||||
Edit `config.yaml.example` and rename to `config.yaml`.
|
||||
Edit `config.yaml.example` and rename to `config.yaml`.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
./electronwall
|
||||
```
|
||||
|
||||
---------------
|
||||
# Rules
|
||||
|
||||
## Allowlist and denylist
|
||||
|
||||
Allowlist and denylist rules are set in `config.yaml` under the appropriate keys. See the [example](config.yaml.example) config.
|
||||
|
||||
## Programmable rules
|
||||
|
||||
electronwall has a Javascript engine called [goja](https://github.com/dop251/goja) that allows you to set custom rules. Note that you can only use pure Javascript (ECMAScript), you can't import a ton of other dependcies like with web applications.
|
||||
|
||||
Rules are saved in the `rules/` directory. There are two files, one for channel open requests `ChannelAccept.js` and one for HTLC forwards `HtlcForward.js`.
|
||||
|
||||
electronwall passes [contextual information](#contextual-information) to the Javascript engine that you can use to create rich rules. See below for a list of objects that are currently supported.
|
||||
|
||||
Here is one rather complex rule for channel accept decisions in `ChannelAccept.js` for demonstration purposes:
|
||||
|
||||
```javascript
|
||||
// only channels > 0.75 Msat
|
||||
ChannelAccept.Event.FundingAmt >= 750000 &&
|
||||
// nodes with high 1ML availability score
|
||||
ChannelAccept.OneMl.Noderank.Availability > 100 &&
|
||||
// nodes with a low enough 1ML age rank
|
||||
ChannelAccept.OneMl.Noderank.Age < 10000 &&
|
||||
(
|
||||
// only nodes with Amboss contact data
|
||||
ChannelAccept.Amboss.Socials.Info.Email ||
|
||||
ChannelAccept.Amboss.Socials.Info.Twitter ||
|
||||
ChannelAccept.Amboss.Socials.Info.Telegram
|
||||
) &&
|
||||
(
|
||||
// elitist: either nodes with amboss prime
|
||||
ChannelAccept.Amboss.Amboss.IsPrime ||
|
||||
// or nodes with high-ranking capacity
|
||||
ChannelAccept.Amboss.GraphInfo.Metrics.CapacityRank < 1000 ||
|
||||
// or nodes with high-ranking channel count
|
||||
ChannelAccept.Amboss.GraphInfo.Metrics.ChannelsRank < 1000
|
||||
)
|
||||
```
|
||||
|
||||
Here is an example `HtlcForward.js`
|
||||
```javascript
|
||||
if (
|
||||
// only forward amounts larger than 100 sat
|
||||
HtlcForward.Event.OutgoingAmountMsat >= 100000
|
||||
) { true } else { false }
|
||||
```
|
||||
|
||||
### Contextual information
|
||||
Here is a list of all objects that are passed to the Javascript engine. You need to look at the structure of these objects in order to use them in a custom rule like the example above.
|
||||
|
||||
#### LND: ChannelAcceptRequest `*.Event`
|
||||
```go
|
||||
type ChannelAcceptRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The pubkey of the node that wishes to open an inbound channel.
|
||||
NodePubkey []byte `protobuf:"bytes,1,opt,name=node_pubkey,json=nodePubkey,proto3" json:"node_pubkey,omitempty"`
|
||||
// The hash of the genesis block that the proposed channel resides in.
|
||||
ChainHash []byte `protobuf:"bytes,2,opt,name=chain_hash,json=chainHash,proto3" json:"chain_hash,omitempty"`
|
||||
// The pending channel id.
|
||||
PendingChanId []byte `protobuf:"bytes,3,opt,name=pending_chan_id,json=pendingChanId,proto3" json:"pending_chan_id,omitempty"`
|
||||
// The funding amount in satoshis that initiator wishes to use in the
|
||||
// channel.
|
||||
FundingAmt uint64 `protobuf:"varint,4,opt,name=funding_amt,json=fundingAmt,proto3" json:"funding_amt,omitempty"`
|
||||
// The push amount of the proposed channel in millisatoshis.
|
||||
PushAmt uint64 `protobuf:"varint,5,opt,name=push_amt,json=pushAmt,proto3" json:"push_amt,omitempty"`
|
||||
// The dust limit of the initiator's commitment tx.
|
||||
DustLimit uint64 `protobuf:"varint,6,opt,name=dust_limit,json=dustLimit,proto3" json:"dust_limit,omitempty"`
|
||||
// The maximum amount of coins in millisatoshis that can be pending in this
|
||||
// channel.
|
||||
MaxValueInFlight uint64 `protobuf:"varint,7,opt,name=max_value_in_flight,json=maxValueInFlight,proto3" json:"max_value_in_flight,omitempty"`
|
||||
// The minimum amount of satoshis the initiator requires us to have at all
|
||||
// times.
|
||||
ChannelReserve uint64 `protobuf:"varint,8,opt,name=channel_reserve,json=channelReserve,proto3" json:"channel_reserve,omitempty"`
|
||||
// The smallest HTLC in millisatoshis that the initiator will accept.
|
||||
MinHtlc uint64 `protobuf:"varint,9,opt,name=min_htlc,json=minHtlc,proto3" json:"min_htlc,omitempty"`
|
||||
// The initial fee rate that the initiator suggests for both commitment
|
||||
// transactions.
|
||||
FeePerKw uint64 `protobuf:"varint,10,opt,name=fee_per_kw,json=feePerKw,proto3" json:"fee_per_kw,omitempty"`
|
||||
//
|
||||
//The number of blocks to use for the relative time lock in the pay-to-self
|
||||
//output of both commitment transactions.
|
||||
CsvDelay uint32 `protobuf:"varint,11,opt,name=csv_delay,json=csvDelay,proto3" json:"csv_delay,omitempty"`
|
||||
// The total number of incoming HTLC's that the initiator will accept.
|
||||
MaxAcceptedHtlcs uint32 `protobuf:"varint,12,opt,name=max_accepted_htlcs,json=maxAcceptedHtlcs,proto3" json:"max_accepted_htlcs,omitempty"`
|
||||
// A bit-field which the initiator uses to specify proposed channel
|
||||
// behavior.
|
||||
ChannelFlags uint32 `protobuf:"varint,13,opt,name=channel_flags,json=channelFlags,proto3" json:"channel_flags,omitempty"`
|
||||
// The commitment type the initiator wishes to use for the proposed channel.
|
||||
CommitmentType CommitmentType `protobuf:"varint,14,opt,name=commitment_type,json=commitmentType,proto3,enum=lnrpc.CommitmentType" json:"commitment_type,omitempty"`
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 1ML node information `*.OneMl`
|
||||
```go
|
||||
type OneML_NodeInfoResponse struct {
|
||||
LastUpdate int `json:"last_update"`
|
||||
PubKey string `json:"pub_key"`
|
||||
Alias string `json:"alias"`
|
||||
Addresses []struct {
|
||||
Network string `json:"network"`
|
||||
Addr string `json:"addr"`
|
||||
} `json:"addresses"`
|
||||
Color string `json:"color"`
|
||||
Capacity int `json:"capacity"`
|
||||
Channelcount int `json:"channelcount"`
|
||||
Noderank struct {
|
||||
Capacity int `json:"capacity"`
|
||||
Channelcount int `json:"channelcount"`
|
||||
Age int `json:"age"`
|
||||
Growth int `json:"growth"`
|
||||
Availability int `json:"availability"`
|
||||
} `json:"noderank"`
|
||||
}
|
||||
```
|
||||
#### Amboss node information `*.Amboss`
|
||||
```go
|
||||
type Amboss_NodeInfoResponse struct {
|
||||
Socials struct {
|
||||
Info struct {
|
||||
Email string `json:"email"`
|
||||
Telegram string `json:"telegram"`
|
||||
Twitter string `json:"twitter"`
|
||||
LightningAddress string `json:"lightning_address"`
|
||||
Website string `json:"website"`
|
||||
Pubkey string `json:"pubkey"`
|
||||
MinChannelSize interface{} `json:"minChannelSize"`
|
||||
Message string `json:"message"`
|
||||
TwitterVerified bool `json:"twitter_verified"`
|
||||
Updated time.Time `json:"updated"`
|
||||
} `json:"info"`
|
||||
} `json:"socials"`
|
||||
GraphInfo struct {
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
Metrics struct {
|
||||
Capacity string `json:"capacity"`
|
||||
CapacityRank int `json:"capacity_rank"`
|
||||
Channels int `json:"channels"`
|
||||
ChannelsRank int `json:"channels_rank"`
|
||||
} `json:"metrics"`
|
||||
Node struct {
|
||||
Addresses []struct {
|
||||
Addr string `json:"addr"`
|
||||
IPInfo struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
CountryCode string `json:"country_code"`
|
||||
} `json:"ip_info"`
|
||||
Network string `json:"network"`
|
||||
} `json:"addresses"`
|
||||
LastUpdate int `json:"last_update"`
|
||||
Color string `json:"color"`
|
||||
Features []struct {
|
||||
FeatureID string `json:"feature_id"`
|
||||
IsKnown bool `json:"is_known"`
|
||||
IsRequired bool `json:"is_required"`
|
||||
Name string `json:"name"`
|
||||
} `json:"features"`
|
||||
} `json:"node"`
|
||||
} `json:"graph_info"`
|
||||
Amboss struct {
|
||||
IsFavorite bool `json:"is_favorite"`
|
||||
IsPrime bool `json:"is_prime"`
|
||||
NumberFavorites int `json:"number_favorites"`
|
||||
NewChannelGossipDelta struct {
|
||||
Mean string `json:"mean"`
|
||||
Sd string `json:"sd"`
|
||||
} `json:"new_channel_gossip_delta"`
|
||||
Notifications struct {
|
||||
NumberSubscribers int `json:"number_subscribers"`
|
||||
} `json:"notifications"`
|
||||
} `json:"amboss"`
|
||||
}
|
||||
```
|
||||
|
||||
#### Network information `*.Network`
|
||||
*TBD*
|
||||
77
api/1ml.go
Normal file
77
api/1ml.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/callebtc/electronwall/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type OneML_NodeInfoResponse struct {
|
||||
LastUpdate int `json:"last_update"`
|
||||
PubKey string `json:"pub_key"`
|
||||
Alias string `json:"alias"`
|
||||
Addresses []struct {
|
||||
Network string `json:"network"`
|
||||
Addr string `json:"addr"`
|
||||
} `json:"addresses"`
|
||||
Color string `json:"color"`
|
||||
Capacity int `json:"capacity"`
|
||||
Channelcount int `json:"channelcount"`
|
||||
Noderank struct {
|
||||
Capacity int `json:"capacity"`
|
||||
Channelcount int `json:"channelcount"`
|
||||
Age int `json:"age"`
|
||||
Growth int `json:"growth"`
|
||||
Availability int `json:"availability"`
|
||||
} `json:"noderank"`
|
||||
}
|
||||
|
||||
type OneMlClient struct {
|
||||
}
|
||||
|
||||
func GetOneMlClient() OneMlClient {
|
||||
return OneMlClient{}
|
||||
}
|
||||
|
||||
func (c *OneMlClient) GetNodeInfo(pubkey string) (OneML_NodeInfoResponse, error) {
|
||||
|
||||
url := fmt.Sprintf("https://1ml.com/node/%s/json", pubkey)
|
||||
|
||||
log.Infof("Getting info from 1ml.com for %s", pubkey)
|
||||
|
||||
client := http.Client{
|
||||
Timeout: time.Second * time.Duration(config.Configuration.ApiRules.OneMl.Timeout),
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
res, getErr := client.Do(req)
|
||||
if getErr != nil {
|
||||
log.Fatal(getErr)
|
||||
}
|
||||
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
body, readErr := ioutil.ReadAll(res.Body)
|
||||
if readErr != nil {
|
||||
log.Fatal(readErr)
|
||||
}
|
||||
|
||||
r := OneML_NodeInfoResponse{}
|
||||
jsonErr := json.Unmarshal(body, &r)
|
||||
if jsonErr != nil {
|
||||
log.Errorf("[1ml] api error: %v", jsonErr)
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
169
api/amboss.go
Normal file
169
api/amboss.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/callebtc/electronwall/config"
|
||||
"github.com/machinebox/graphql"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Amboss_NodeInfoResponse struct {
|
||||
Socials struct {
|
||||
Info struct {
|
||||
Email string `json:"email"`
|
||||
Telegram string `json:"telegram"`
|
||||
Twitter string `json:"twitter"`
|
||||
LightningAddress string `json:"lightning_address"`
|
||||
Website string `json:"website"`
|
||||
Pubkey string `json:"pubkey"`
|
||||
MinChannelSize interface{} `json:"minChannelSize"`
|
||||
Message string `json:"message"`
|
||||
TwitterVerified bool `json:"twitter_verified"`
|
||||
Updated time.Time `json:"updated"`
|
||||
} `json:"info"`
|
||||
} `json:"socials"`
|
||||
GraphInfo struct {
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
Metrics struct {
|
||||
Capacity string `json:"capacity"`
|
||||
CapacityRank int `json:"capacity_rank"`
|
||||
Channels int `json:"channels"`
|
||||
ChannelsRank int `json:"channels_rank"`
|
||||
} `json:"metrics"`
|
||||
Node struct {
|
||||
Addresses []struct {
|
||||
Addr string `json:"addr"`
|
||||
IPInfo struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
CountryCode string `json:"country_code"`
|
||||
} `json:"ip_info"`
|
||||
Network string `json:"network"`
|
||||
} `json:"addresses"`
|
||||
LastUpdate int `json:"last_update"`
|
||||
Color string `json:"color"`
|
||||
Features []struct {
|
||||
FeatureID string `json:"feature_id"`
|
||||
IsKnown bool `json:"is_known"`
|
||||
IsRequired bool `json:"is_required"`
|
||||
Name string `json:"name"`
|
||||
} `json:"features"`
|
||||
} `json:"node"`
|
||||
} `json:"graph_info"`
|
||||
Amboss struct {
|
||||
IsFavorite bool `json:"is_favorite"`
|
||||
IsPrime bool `json:"is_prime"`
|
||||
NumberFavorites int `json:"number_favorites"`
|
||||
NewChannelGossipDelta struct {
|
||||
Mean string `json:"mean"`
|
||||
Sd string `json:"sd"`
|
||||
} `json:"new_channel_gossip_delta"`
|
||||
Notifications struct {
|
||||
NumberSubscribers int `json:"number_subscribers"`
|
||||
} `json:"notifications"`
|
||||
} `json:"amboss"`
|
||||
}
|
||||
|
||||
type Amboss_NodeInfoResponse_Nested struct {
|
||||
Data struct {
|
||||
GetNode struct {
|
||||
Amboss_NodeInfoResponse
|
||||
} `json:"getNode"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
var amboss_graphql_query = `query Info($pubkey: String!) {
|
||||
getNode(pubkey: $pubkey) {
|
||||
socials {
|
||||
info {
|
||||
email
|
||||
telegram
|
||||
twitter
|
||||
lightning_address
|
||||
website
|
||||
pubkey
|
||||
minChannelSize
|
||||
message
|
||||
twitter_verified
|
||||
updated
|
||||
}
|
||||
}
|
||||
graph_info {
|
||||
last_update
|
||||
metrics {
|
||||
capacity
|
||||
capacity_rank
|
||||
channels
|
||||
channels_rank
|
||||
}
|
||||
node {
|
||||
addresses {
|
||||
addr
|
||||
ip_info {
|
||||
city
|
||||
country
|
||||
country_code
|
||||
}
|
||||
network
|
||||
}
|
||||
last_update
|
||||
color
|
||||
features {
|
||||
feature_id
|
||||
is_known
|
||||
is_required
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
amboss {
|
||||
is_favorite
|
||||
is_prime
|
||||
number_favorites
|
||||
new_channel_gossip_delta {
|
||||
mean
|
||||
sd
|
||||
}
|
||||
notifications {
|
||||
number_subscribers
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
var amboss_graphql_variabnes = `{
|
||||
"pubkey": "%s"
|
||||
}
|
||||
`
|
||||
|
||||
type AmbossClient struct {
|
||||
}
|
||||
|
||||
func GetAmbossClient() AmbossClient {
|
||||
return AmbossClient{}
|
||||
}
|
||||
|
||||
func (c *AmbossClient) GetNodeInfo(pubkey string) (Amboss_NodeInfoResponse, error) {
|
||||
url := "https://api.amboss.space/graphql"
|
||||
log.Infof("Getting info from amboss.space for %s", pubkey)
|
||||
|
||||
graphqlClient := graphql.NewClient(url)
|
||||
graphqlRequest := graphql.NewRequest(amboss_graphql_query)
|
||||
graphqlRequest.Var("pubkey", pubkey)
|
||||
// set header fields
|
||||
graphqlRequest.Header.Set("Cache-Control", "no-cache")
|
||||
graphqlRequest.Header.Set("Content-Type", "application/json")
|
||||
|
||||
var r_nested Amboss_NodeInfoResponse_Nested
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(config.Configuration.ApiRules.Amboss.Timeout))
|
||||
defer cancel()
|
||||
|
||||
if err := graphqlClient.Run(ctx, graphqlRequest, &r_nested.Data); err != nil {
|
||||
log.Errorf("[amboss] api error: %v", err)
|
||||
}
|
||||
|
||||
r := r_nested.Data.GetNode.Amboss_NodeInfoResponse
|
||||
return r, nil
|
||||
}
|
||||
45
api/api.go
Normal file
45
api/api.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/callebtc/electronwall/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ApiClient interface {
|
||||
GetNodeInfo(pubkey string) OneML_NodeInfoResponse
|
||||
}
|
||||
|
||||
type ApiNodeInfo struct {
|
||||
OneMl OneML_NodeInfoResponse `json:"1ml"`
|
||||
Amboss Amboss_NodeInfoResponse `json:"amboss"`
|
||||
}
|
||||
|
||||
func GetApiNodeinfo(pubkey string) (ApiNodeInfo, error) {
|
||||
response := ApiNodeInfo{
|
||||
OneMl: OneML_NodeInfoResponse{},
|
||||
Amboss: Amboss_NodeInfoResponse{},
|
||||
}
|
||||
|
||||
if config.Configuration.ApiRules.OneMl.Active {
|
||||
// get info from 1ml
|
||||
OnemlClient := GetOneMlClient()
|
||||
onemlNodeInfo, err := OnemlClient.GetNodeInfo(pubkey)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
onemlNodeInfo = OneML_NodeInfoResponse{}
|
||||
}
|
||||
response.OneMl = onemlNodeInfo
|
||||
}
|
||||
|
||||
if config.Configuration.ApiRules.Amboss.Active {
|
||||
// get info from amboss
|
||||
ambossClient := GetAmbossClient()
|
||||
ambossNodeInfo, err := ambossClient.GetNodeInfo(pubkey)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
ambossNodeInfo = Amboss_NodeInfoResponse{}
|
||||
}
|
||||
response.Amboss = ambossNodeInfo
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
51
api_test/main.go
Normal file
51
api_test/main.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/callebtc/electronwall/api"
|
||||
"github.com/callebtc/electronwall/rules"
|
||||
"github.com/callebtc/electronwall/types"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
log.Errorf("Pass node ID as argument.")
|
||||
return
|
||||
}
|
||||
pubkey := os.Args[1]
|
||||
log.Infof("pubkey: %s", pubkey)
|
||||
pk_byte := []byte(pubkey)
|
||||
decision_chan := make(chan bool, 1)
|
||||
event := types.ChannelAcceptEvent{}
|
||||
|
||||
event.Event = &lnrpc.ChannelAcceptRequest{}
|
||||
|
||||
event.Event.FundingAmt = 1_000_000
|
||||
log.Infof("Funding amount: %d sat", event.Event.FundingAmt)
|
||||
event.Event.NodePubkey = pk_byte
|
||||
|
||||
req := lnrpc.ChannelAcceptRequest{}
|
||||
req.NodePubkey = pk_byte
|
||||
|
||||
nodeInfo, err := api.GetApiNodeinfo(string(req.NodePubkey))
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
// log.Infoln("1ML")
|
||||
// // log.Infoln("%+v", noeInfo.OneMl)
|
||||
// log.Printf("%+v\n", nodeInfo.OneMl)
|
||||
// log.Infoln("Amboss")
|
||||
// log.Printf("%+v\n", nodeInfo.Amboss)
|
||||
|
||||
event.OneMl = nodeInfo.OneMl
|
||||
event.Amboss = nodeInfo.Amboss
|
||||
|
||||
rules_decision, err := rules.Apply(event, decision_chan)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Infof("Decision: %t", rules_decision)
|
||||
}
|
||||
@@ -6,13 +6,15 @@ import (
|
||||
"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) {
|
||||
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 {
|
||||
@@ -23,11 +25,19 @@ func (app *App) getChannelAcceptEvent(ctx context.Context, req lnrpc.ChannelAcce
|
||||
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
|
||||
}
|
||||
|
||||
@@ -68,7 +78,7 @@ func (app *App) interceptChannelEvents(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
channelAcceptEvent, err := app.getChannelAcceptEvent(ctx, req)
|
||||
channelAcceptEvent, err := app.GetChannelAcceptEvent(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -116,7 +126,7 @@ func (app *App) interceptChannelEvents(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
// parse list
|
||||
list_decision, err := app.channelAcceptDecision(req)
|
||||
list_decision, err := app.channelAcceptListDecision(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -128,7 +138,7 @@ func (app *App) interceptChannelEvents(ctx context.Context) error {
|
||||
|
||||
res := lnrpc.ChannelAcceptResponse{}
|
||||
if accept {
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger.Infof("allow")
|
||||
} else {
|
||||
log.Infof("[channel] ✅ Allow channel %s", channel_info_string)
|
||||
@@ -143,13 +153,13 @@ func (app *App) interceptChannelEvents(ctx context.Context) error {
|
||||
}
|
||||
|
||||
} else {
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger.Infof("deny")
|
||||
} else {
|
||||
log.Infof("[channel] ❌ Deny channel %s", channel_info_string)
|
||||
}
|
||||
res = lnrpc.ChannelAcceptResponse{Accept: false,
|
||||
Error: Configuration.ChannelRejectMessage}
|
||||
Error: config.Configuration.ChannelRejectMessage}
|
||||
}
|
||||
err = acceptClient.Send(&res)
|
||||
if err != nil {
|
||||
@@ -159,26 +169,26 @@ func (app *App) interceptChannelEvents(ctx context.Context) error {
|
||||
|
||||
}
|
||||
|
||||
func (app *App) channelAcceptDecision(req lnrpc.ChannelAcceptRequest) (bool, 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 Configuration.ChannelMode == "allowlist" {
|
||||
if config.Configuration.ChannelMode == "allowlist" {
|
||||
accept = false
|
||||
listToParse = Configuration.ChannelAllowlist
|
||||
} else if Configuration.ChannelMode == "denylist" {
|
||||
listToParse = config.Configuration.ChannelAllowlist
|
||||
} else if config.Configuration.ChannelMode == "denylist" {
|
||||
accept = true
|
||||
listToParse = Configuration.ChannelDenylist
|
||||
listToParse = config.Configuration.ChannelDenylist
|
||||
}
|
||||
|
||||
// parse and make decision
|
||||
log.Infof(hex.EncodeToString(req.NodePubkey))
|
||||
for _, pubkey := range listToParse {
|
||||
if hex.EncodeToString(req.NodePubkey) == pubkey || pubkey == "*" {
|
||||
accept = !accept
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Infof("[list] decision: %t", accept)
|
||||
return accept, nil
|
||||
|
||||
}
|
||||
@@ -205,7 +215,7 @@ func (app *App) logChannelEvents(ctx context.Context) error {
|
||||
alias,
|
||||
)
|
||||
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger := log.WithFields(log.Fields{
|
||||
"event": "channel",
|
||||
"capacity": event.GetOpenChannel().Capacity,
|
||||
|
||||
@@ -41,3 +41,13 @@ forward-allowlist:
|
||||
- "*->25328x256x0" # all forwards to this channel
|
||||
forward-denylist:
|
||||
- "9961472x65537x1"
|
||||
|
||||
# ---- Javascript rules ----
|
||||
rules:
|
||||
apply: true # whether to respect the rule decision
|
||||
oneml: # 1ML.com API
|
||||
active: true
|
||||
timeout: 5 # API timeout in seconds
|
||||
amboss: # Amboss.space API
|
||||
active: true
|
||||
timeout: 5 # API timeout in seconds
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -20,6 +20,17 @@ var Configuration = struct {
|
||||
ForwardMode string `yaml:"forward-mode"`
|
||||
ForwardAllowlist []string `yaml:"forward-allowlist"`
|
||||
ForwardDenylist []string `yaml:"forward-denylist"`
|
||||
ApiRules struct {
|
||||
Apply bool `yaml:"apply"`
|
||||
OneMl struct {
|
||||
Active bool `yaml:"active"`
|
||||
Timeout int `yaml:"timeout"`
|
||||
} `yaml:"oneml"`
|
||||
Amboss struct {
|
||||
Active bool `yaml:"active"`
|
||||
Timeout int `yaml:"timeout"`
|
||||
} `yaml:"amboss"`
|
||||
} `yaml:"rules"`
|
||||
}{}
|
||||
|
||||
func init() {
|
||||
@@ -31,8 +42,6 @@ func init() {
|
||||
}
|
||||
|
||||
func checkConfig() {
|
||||
setLogger(Configuration.Debug, Configuration.LogJson)
|
||||
welcome()
|
||||
|
||||
if Configuration.Host == "" {
|
||||
panic(fmt.Errorf("no host specified in config.yaml"))
|
||||
4
go.mod
4
go.mod
@@ -6,8 +6,12 @@ require (
|
||||
github.com/dop251/goja v0.0.0-20220815083517-0c74f9139fd6
|
||||
github.com/jinzhu/configor v1.2.1
|
||||
github.com/lightningnetwork/lnd v0.14.3-beta
|
||||
github.com/machinebox/graphql v0.2.2
|
||||
github.com/matryer/is v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
google.golang.org/grpc v1.46.2
|
||||
gopkg.in/macaroon.v2 v2.1.0
|
||||
)
|
||||
|
||||
16
go.sum
16
go.sum
@@ -527,9 +527,13 @@ github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQ
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
|
||||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
||||
github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo=
|
||||
github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA=
|
||||
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -721,6 +725,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
@@ -842,6 +847,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -887,8 +893,9 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8=
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -968,8 +975,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1052,8 +1061,9 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -20,12 +20,12 @@ func trimPubKey(pubkey []byte) string {
|
||||
}
|
||||
}
|
||||
|
||||
func welcome() {
|
||||
log.Info("---- ⚡️ electronwall 0.3.3 ⚡️ ----")
|
||||
func Welcome() {
|
||||
log.Info("---- ⚡️ electronwall 0.4 ⚡️ ----")
|
||||
}
|
||||
|
||||
// setLogger will initialize the log format
|
||||
func setLogger(debug bool, json bool) {
|
||||
// SetLogger will initialize the log format
|
||||
func SetLogger(debug bool, json bool) {
|
||||
if json {
|
||||
customFormatter := new(log.JSONFormatter)
|
||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/callebtc/electronwall/config"
|
||||
"github.com/callebtc/electronwall/rules"
|
||||
"github.com/callebtc/electronwall/types"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
@@ -144,14 +145,14 @@ func (app *App) interceptHtlcEvents(ctx context.Context) error {
|
||||
}
|
||||
switch accept {
|
||||
case true:
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger.Infof("allow")
|
||||
} else {
|
||||
log.Infof("[forward] ✅ Allow HTLC %s", forward_info_string)
|
||||
}
|
||||
response.Action = routerrpc.ResolveHoldForwardAction_RESUME
|
||||
case false:
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger.Infof("deny")
|
||||
} else {
|
||||
log.Infof("[forward] ❌ Deny HTLC %s", forward_info_string)
|
||||
@@ -181,15 +182,15 @@ func (app *App) htlcInterceptDecision(ctx context.Context, event *routerrpc.Forw
|
||||
// time.Sleep(60 * time.Second)
|
||||
|
||||
// determine filtering mode and list to parse
|
||||
switch Configuration.ForwardMode {
|
||||
switch config.Configuration.ForwardMode {
|
||||
case "allowlist":
|
||||
accept = false
|
||||
listToParse = Configuration.ForwardAllowlist
|
||||
listToParse = config.Configuration.ForwardAllowlist
|
||||
case "denylist":
|
||||
accept = true
|
||||
listToParse = Configuration.ForwardDenylist
|
||||
listToParse = config.Configuration.ForwardDenylist
|
||||
default:
|
||||
return false, fmt.Errorf("unknown forward mode: %s", Configuration.ForwardMode)
|
||||
return false, fmt.Errorf("unknown forward mode: %s", config.Configuration.ForwardMode)
|
||||
}
|
||||
|
||||
// parse list and decide
|
||||
@@ -217,6 +218,7 @@ func (app *App) htlcInterceptDecision(ctx context.Context, event *routerrpc.Forw
|
||||
}
|
||||
}
|
||||
// decision_chan <- accept
|
||||
log.Infof("[list] decision: %t", accept)
|
||||
return accept, nil
|
||||
}
|
||||
|
||||
@@ -251,7 +253,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error {
|
||||
|
||||
switch event.Event.(type) {
|
||||
case *routerrpc.HtlcEvent_SettleEvent:
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger(event).Infof("SettleEvent")
|
||||
// contextLogger.Debugf("[forward] Preimage: %s", hex.EncodeToString(event.GetSettleEvent().Preimage))
|
||||
} else {
|
||||
@@ -262,7 +264,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error {
|
||||
}
|
||||
|
||||
case *routerrpc.HtlcEvent_ForwardFailEvent:
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger(event).Infof("ForwardFailEvent")
|
||||
// contextLogger.Debugf("[forward] Reason: %s", event.GetForwardFailEvent())
|
||||
} else {
|
||||
@@ -271,7 +273,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error {
|
||||
}
|
||||
|
||||
case *routerrpc.HtlcEvent_ForwardEvent:
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger(event).Infof("ForwardEvent")
|
||||
} else {
|
||||
log.Infof("[forward] HTLC ForwardEvent (chan_id:%s, htlc_id:%d)", ParseChannelID(event.IncomingChannelId), event.IncomingHtlcId)
|
||||
@@ -280,7 +282,7 @@ func (app *App) logHtlcEvents(ctx context.Context) error {
|
||||
// log.Debugf("[forward] Details: %s", event.GetForwardEvent().String())
|
||||
|
||||
case *routerrpc.HtlcEvent_LinkFailEvent:
|
||||
if Configuration.LogJson {
|
||||
if config.Configuration.LogJson {
|
||||
contextLogger(event).Infof("LinkFailEvent")
|
||||
// contextLogger(event).Debugf("[forward] Reason: %s", event.GetLinkFailEvent().FailureString)
|
||||
} else {
|
||||
|
||||
11
main.go
11
main.go
@@ -5,6 +5,7 @@ import (
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"github.com/callebtc/electronwall/config"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
@@ -39,11 +40,11 @@ func NewApp(ctx context.Context, lnd lndclient) *App {
|
||||
|
||||
// gets the lnd grpc connection
|
||||
func getClientConnection(ctx context.Context) (*grpc.ClientConn, error) {
|
||||
creds, err := credentials.NewClientTLSFromFile(Configuration.TLSPath, "")
|
||||
creds, err := credentials.NewClientTLSFromFile(config.Configuration.TLSPath, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
macBytes, err := ioutil.ReadFile(Configuration.MacaroonPath)
|
||||
macBytes, err := ioutil.ReadFile(config.Configuration.MacaroonPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -60,8 +61,8 @@ func getClientConnection(ctx context.Context) (*grpc.ClientConn, error) {
|
||||
grpc.WithBlock(),
|
||||
grpc.WithPerRPCCredentials(cred),
|
||||
}
|
||||
log.Infof("Connecting to %s", Configuration.Host)
|
||||
conn, err := grpc.DialContext(ctx, Configuration.Host, opts...)
|
||||
log.Infof("Connecting to %s", config.Configuration.Host)
|
||||
conn, err := grpc.DialContext(ctx, config.Configuration.Host, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -84,6 +85,8 @@ func newLndClient(ctx context.Context) (*LndClient, error) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
SetLogger(config.Configuration.Debug, config.Configuration.LogJson)
|
||||
Welcome()
|
||||
ctx := context.Background()
|
||||
for {
|
||||
lnd, err := newLndClient(ctx)
|
||||
|
||||
124
main_test.go
124
main_test.go
@@ -2,8 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/callebtc/electronwall/config"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -33,8 +35,8 @@ func TestHTLCDenylist_BothMatch(t *testing.T) {
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
Configuration.ForwardMode = "denylist"
|
||||
Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
config.Configuration.ForwardMode = "denylist"
|
||||
config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
@@ -67,8 +69,8 @@ func TestHTLCDenylist_BothNoMatch(t *testing.T) {
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
Configuration.ForwardMode = "denylist"
|
||||
Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
config.Configuration.ForwardMode = "denylist"
|
||||
config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
@@ -101,12 +103,12 @@ func TestHTLCDenylist_WildCardOutBothMatch(t *testing.T) {
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
Configuration.ForwardMode = "denylist"
|
||||
Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
config.Configuration.ForwardMode = "denylist"
|
||||
config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardDenylist = []string{"700762x1327x1->*"}
|
||||
config.Configuration.ForwardDenylist = []string{"700762x1327x1->*"}
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 770495967390531585,
|
||||
@@ -137,14 +139,14 @@ func TestHTLCDenylist_WildCardOutNoMatch(t *testing.T) {
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
Configuration.ForwardMode = "denylist"
|
||||
Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
config.Configuration.ForwardMode = "denylist"
|
||||
config.Configuration.ForwardDenylist = []string{"700762x1327x1->690757x1005x1"}
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
// wildcard out, first key doesn't match: should be allowed
|
||||
|
||||
Configuration.ForwardDenylist = []string{"700762x1327x1->*"}
|
||||
config.Configuration.ForwardDenylist = []string{"700762x1327x1->*"}
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 759495353533530113,
|
||||
@@ -176,11 +178,11 @@ func TestHTLCAllowlist_BothMatch(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
|
||||
// both keys correct: should be allowed
|
||||
Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 770495967390531585,
|
||||
@@ -212,10 +214,10 @@ func TestHTLCAllowlist_BothNonMatch(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
// both keys wrong: should be denied
|
||||
Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"700762x1327x1->690757x1005x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 123456789876543210,
|
||||
@@ -246,10 +248,10 @@ func TestHTLCAllowlist_Wildcard(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
// wildcard: should be allowed
|
||||
Configuration.ForwardAllowlist = []string{"*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 123456789876543210,
|
||||
HtlcId: 1337000,
|
||||
@@ -279,11 +281,11 @@ func TestHTLCAllowlist_WildcardIn(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
// wildcard in: should be allowed
|
||||
|
||||
Configuration.ForwardAllowlist = []string{"*->690757x1005x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"*->690757x1005x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 123456789876543210,
|
||||
@@ -314,10 +316,10 @@ func TestHTLCAllowlist_WildcardOut(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
// wildcard out: should be allowed
|
||||
Configuration.ForwardAllowlist = []string{"700762x1327x1->*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"700762x1327x1->*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 770495967390531585,
|
||||
@@ -348,10 +350,10 @@ func TestHTLCAllowlist_WildcardOutWrongKeyIn(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
// wildcard out but wrong in key: should be denied
|
||||
Configuration.ForwardAllowlist = []string{"700762x1327x1->*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"700762x1327x1->*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 123456789876543210,
|
||||
@@ -382,10 +384,10 @@ func TestHTLCAllowlist_WildcardIn_WrongKeyOut(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
// wildcard in but wrong out key: should be denied
|
||||
Configuration.ForwardAllowlist = []string{"*->700762x1327x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"*->700762x1327x1"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 123456789876543210,
|
||||
@@ -416,10 +418,10 @@ func TestHTLCAllowlist_WildcardBoth(t *testing.T) {
|
||||
|
||||
app.DispatchHTLCAcceptor(ctx)
|
||||
|
||||
Configuration.ForwardMode = "allowlist"
|
||||
config.Configuration.ForwardMode = "allowlist"
|
||||
// wildcard both: should be allowed
|
||||
Configuration.ForwardAllowlist = []string{"*->*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", Configuration.ForwardMode, Configuration.ForwardAllowlist)
|
||||
config.Configuration.ForwardAllowlist = []string{"*->*"}
|
||||
log.Tracef("[test] Mode: %s, Rules: %v", config.Configuration.ForwardMode, config.Configuration.ForwardAllowlist)
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 123456789876543210,
|
||||
@@ -451,16 +453,16 @@ func TestChannelAllowlist_CorrectKey(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
Configuration.ChannelMode = "allowlist"
|
||||
Configuration.ChannelAllowlist = []string{"6d792d7075626b65792d69732d766572792d6c6f6e672d666f722d7472696d6d696e672d7075626b6579"}
|
||||
pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"
|
||||
config.Configuration.ChannelMode = "allowlist"
|
||||
config.Configuration.ChannelAllowlist = []string{pubkey_str}
|
||||
|
||||
app.DispatchChannelAcceptor(ctx)
|
||||
|
||||
// correct key: should be allowed
|
||||
|
||||
pubkey, _ := hex.DecodeString(pubkey_str)
|
||||
client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{
|
||||
NodePubkey: []byte("my-pubkey-is-very-long-for-trimming-pubkey"),
|
||||
NodePubkey: pubkey,
|
||||
FundingAmt: 1337000,
|
||||
PendingChanId: []byte("759495353533530113"),
|
||||
}
|
||||
@@ -468,15 +470,28 @@ func TestChannelAllowlist_CorrectKey(t *testing.T) {
|
||||
resp := <-client.channelAcceptorResponses
|
||||
require.Equal(t, resp.Accept, true)
|
||||
|
||||
}
|
||||
func TestChannelAllowlist_WrongKey(t *testing.T) {
|
||||
client := newLndclientMock()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"
|
||||
config.Configuration.ChannelMode = "allowlist"
|
||||
config.Configuration.ChannelAllowlist = []string{pubkey_str}
|
||||
|
||||
app.DispatchChannelAcceptor(ctx)
|
||||
// wrong key: should be denied
|
||||
|
||||
client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{
|
||||
NodePubkey: []byte("WRONG PUBKEY"),
|
||||
NodePubkey: []byte("WRONG-KEY"),
|
||||
FundingAmt: 1337000,
|
||||
PendingChanId: []byte("759495353533530113"),
|
||||
}
|
||||
|
||||
resp = <-client.channelAcceptorResponses
|
||||
resp := <-client.channelAcceptorResponses
|
||||
require.Equal(t, resp.Accept, false)
|
||||
}
|
||||
func TestChannelAllowlist_Wildcard(t *testing.T) {
|
||||
@@ -488,12 +503,14 @@ func TestChannelAllowlist_Wildcard(t *testing.T) {
|
||||
|
||||
app.DispatchChannelAcceptor(ctx)
|
||||
|
||||
pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"
|
||||
// wildcard: should be allowed
|
||||
Configuration.ChannelMode = "allowlist"
|
||||
Configuration.ChannelAllowlist = []string{"*"}
|
||||
config.Configuration.ChannelMode = "allowlist"
|
||||
config.Configuration.ChannelAllowlist = []string{"*"}
|
||||
|
||||
pubkey, _ := hex.DecodeString(pubkey_str)
|
||||
client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{
|
||||
NodePubkey: []byte("WRONG PUBKEY"),
|
||||
NodePubkey: pubkey,
|
||||
FundingAmt: 1337000,
|
||||
PendingChanId: []byte("759495353533530113"),
|
||||
}
|
||||
@@ -508,16 +525,16 @@ func TestChannelDenylist_Match(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
Configuration.ChannelMode = "denylist"
|
||||
Configuration.ChannelDenylist = []string{"6d792d7075626b65792d69732d766572792d6c6f6e672d666f722d7472696d6d696e672d7075626b6579"}
|
||||
pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"
|
||||
config.Configuration.ChannelMode = "denylist"
|
||||
config.Configuration.ChannelDenylist = []string{pubkey_str}
|
||||
|
||||
app.DispatchChannelAcceptor(ctx)
|
||||
|
||||
// should be denied
|
||||
|
||||
pubkey, _ := hex.DecodeString(pubkey_str)
|
||||
client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{
|
||||
NodePubkey: []byte("my-pubkey-is-very-long-for-trimming-pubkey"),
|
||||
NodePubkey: []byte(pubkey),
|
||||
FundingAmt: 1337000,
|
||||
PendingChanId: []byte("759495353533530113"),
|
||||
}
|
||||
@@ -532,15 +549,16 @@ func TestChannelAllowlist_Match(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
app := NewApp(ctx, client)
|
||||
|
||||
Configuration.ChannelMode = "allowlist"
|
||||
Configuration.ChannelAllowlist = []string{"6d792d7075626b65792d69732d766572792d6c6f6e672d666f722d7472696d6d696e672d7075626b6579"}
|
||||
pubkey_str := "03006fcf3312dae8d068ea297f58e2bd00ec1ffe214b793eda46966b6294a53ce6"
|
||||
config.Configuration.ChannelMode = "allowlist"
|
||||
config.Configuration.ChannelAllowlist = []string{pubkey_str}
|
||||
|
||||
app.DispatchChannelAcceptor(ctx)
|
||||
|
||||
// should be allowed
|
||||
pubkey, _ := hex.DecodeString(pubkey_str)
|
||||
client.channelAcceptorRequests <- &lnrpc.ChannelAcceptRequest{
|
||||
NodePubkey: []byte("my-pubkey-is-very-long-for-trimming-pubkey"),
|
||||
NodePubkey: []byte(pubkey),
|
||||
FundingAmt: 1337000,
|
||||
PendingChanId: []byte("759495353533530113"),
|
||||
}
|
||||
|
||||
@@ -1,2 +1,20 @@
|
||||
ChannelAccept.Event.FundingAmt >= 750000;
|
||||
|
||||
// only channels > 0.75 Msat
|
||||
ChannelAccept.Event.FundingAmt >= 750000 &&
|
||||
// nodes with high 1ML availability score
|
||||
ChannelAccept.OneMl.Noderank.Availability > 100 &&
|
||||
// nodes with a low enough 1ML age rank
|
||||
ChannelAccept.OneMl.Noderank.Age < 10000 &&
|
||||
(
|
||||
// only nodes with Amboss contact data
|
||||
ChannelAccept.Amboss.Socials.Info.Email ||
|
||||
ChannelAccept.Amboss.Socials.Info.Twitter ||
|
||||
ChannelAccept.Amboss.Socials.Info.Telegram
|
||||
) &&
|
||||
(
|
||||
// elitist: either nodes with amboss prime
|
||||
ChannelAccept.Amboss.Amboss.IsPrime ||
|
||||
// or nodes with high-ranking capacity
|
||||
ChannelAccept.Amboss.GraphInfo.Metrics.CapacityRank < 1000 ||
|
||||
// or nodes with high-ranking channel count
|
||||
ChannelAccept.Amboss.GraphInfo.Metrics.ChannelsRank < 1000
|
||||
)
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
HtlcForward.Event.OutgoingAmountMsat >= 100000
|
||||
if (
|
||||
// only forward amounts larger than 100 sat
|
||||
HtlcForward.Event.OutgoingAmountMsat >= 100000
|
||||
) { true } else { false }
|
||||
|
||||
|
||||
@@ -2,14 +2,20 @@ package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/callebtc/electronwall/config"
|
||||
"github.com/callebtc/electronwall/types"
|
||||
"github.com/dop251/goja"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) {
|
||||
|
||||
if !config.Configuration.ApiRules.Apply {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
vm := goja.New()
|
||||
|
||||
var js_script []byte
|
||||
@@ -28,12 +34,6 @@ func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// case *routerrpc.ForwardHtlcInterceptRequest:
|
||||
// vm.Set("HtlcForwardEvent", s)
|
||||
// js_script, err = os.ReadFile("rules/ForwardHtlcInterceptRequest.js")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
default:
|
||||
return false, fmt.Errorf("no rule found for event type")
|
||||
}
|
||||
@@ -41,11 +41,12 @@ func Apply(s interface{}, decision_chan chan bool) (accept bool, err error) {
|
||||
// execute script
|
||||
v, err := vm.RunString(string(js_script))
|
||||
if err != nil {
|
||||
fmt.Print(err.Error())
|
||||
log.Errorf("JS error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
accept = v.Export().(bool)
|
||||
decision_chan <- accept
|
||||
log.Infof("[rules] decision: %t", accept)
|
||||
return accept, nil
|
||||
}
|
||||
|
||||
24
types/types.go
Normal file
24
types/types.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/callebtc/electronwall/api"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
)
|
||||
|
||||
type HtlcForwardEvent struct {
|
||||
PubkeyFrom string
|
||||
AliasFrom string
|
||||
PubkeyTo string
|
||||
AliasTo string
|
||||
Event *routerrpc.ForwardHtlcInterceptRequest
|
||||
}
|
||||
|
||||
type ChannelAcceptEvent struct {
|
||||
PubkeyFrom string
|
||||
AliasFrom string
|
||||
Event *lnrpc.ChannelAcceptRequest
|
||||
NodeInfo *lnrpc.NodeInfo
|
||||
OneMl api.OneML_NodeInfoResponse
|
||||
Amboss api.Amboss_NodeInfoResponse
|
||||
}
|
||||
Reference in New Issue
Block a user