Skip to content

Commit

Permalink
Handle zero conf requests
Browse files Browse the repository at this point in the history
  • Loading branch information
aftermath2 committed Dec 18, 2023
1 parent 852cc28 commit da906bd
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 63 deletions.
28 changes: 17 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ func handleChannelRequests(config config.Config, client lightning.Client) error
}
slog.Debug("Channel opening request", slog.Any("request", req))

resp := &lnrpc.ChannelAcceptResponse{Accept: false, PendingChanId: req.PendingChanId}
if err := processRequest(config, client, req); err != nil {
resp, err := handleRequest(config, client, req)
if err != nil {
resp.Error = err.Error()
} else {
resp.Accept = true
Expand All @@ -95,35 +95,41 @@ func handleChannelRequests(config config.Config, client lightning.Client) error
}
}

func processRequest(
func handleRequest(
config config.Config,
client lightning.Client,
req *lnrpc.ChannelAcceptRequest,
) error {
) (*lnrpc.ChannelAcceptResponse, error) {
ctx := context.Background()
resp := &lnrpc.ChannelAcceptResponse{Accept: false, PendingChanId: req.PendingChanId}

node, err := client.GetInfo(ctx, &lnrpc.GetInfoRequest{})
if err != nil {
return errors.Wrap(err, "getting node information")
return resp, errors.Wrap(err, "getting node information")
}

getPeerInfoReq := &lnrpc.NodeInfoRequest{
PubKey: hex.EncodeToString(req.NodePubkey),
IncludeChannels: true,
}
peerNode, err := client.GetNodeInfo(ctx, getPeerInfoReq)
peer, err := client.GetNodeInfo(ctx, getPeerInfoReq)
if err != nil {
return errors.New("Internal server error")
return resp, errors.New("Internal server error")
}
slog.Debug("Peer node information", slog.Any("node", peerNode))
slog.Debug("Peer node information", slog.Any("node", peer))

for _, policy := range config.Policies {
if err := policy.Evaluate(req, node, peerNode); err != nil {
return err
if err := policy.Evaluate(req, node, peer); err != nil {
return resp, err
}
}

return nil
if req.WantsZeroConf {
resp.ZeroConf = true
resp.MinAcceptDepth = 0
}

return resp, nil
}

type response struct {
Expand Down
40 changes: 28 additions & 12 deletions policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,47 @@ type Policy struct {
Node *Node `yaml:"node,omitempty"`
Whitelist *[]string `yaml:"whitelist,omitempty"`
Blacklist *[]string `yaml:"blacklist,omitempty"`
ZeroConfList *[]string `yaml:"zero_conf_list,omitempty"`
RejectAll *bool `yaml:"reject_all,omitempty"`
RejectPrivateChannels *bool `yaml:"reject_private_channels,omitempty"`
RejectZeroConfChannels *bool `yaml:"reject_zero_conf_channels,omitempty"`
AcceptZeroConfChannels *bool `yaml:"accept_zero_conf_channels,omitempty"`
}

// Evaluate set of policies.
func (p *Policy) Evaluate(
req *lnrpc.ChannelAcceptRequest,
node *lnrpc.GetInfoResponse,
peerNode *lnrpc.NodeInfo,
peer *lnrpc.NodeInfo,
) error {
if p.Conditions != nil && !p.Conditions.Match(req, node, peerNode) {
if p.Conditions != nil && !p.Conditions.Match(req, node, peer) {
return nil
}

if !p.checkRejectAll() {
return errors.New("No new channels are accepted")
}

if p.checkWhitelist(peerNode.Node.PubKey) {
return nil
if !p.checkWhitelist(peer.Node.PubKey) {
return errors.New("Node is not whitelisted")
}

if !p.checkBlacklist(peerNode.Node.PubKey) {
if !p.checkBlacklist(peer.Node.PubKey) {
return errors.New("Node is blacklisted")
}

if !p.checkPrivate(req.ChannelFlags != uint32(lnwire.FFAnnounceChannel)) {
return errors.New("Private channels are not accepted")
}

if !p.checkZeroConf(req.WantsZeroConf) {
if !p.checkZeroConf(peer.Node.PubKey, req.WantsZeroConf) {
return errors.New("Zero conf channels are not accepted")
}

if err := p.Request.evaluate(req); err != nil {
return err
}

return p.Node.evaluate(node, peerNode)
return p.Node.evaluate(node, peer)
}

func (p *Policy) checkRejectAll() bool {
Expand All @@ -68,7 +69,7 @@ func (p *Policy) checkRejectAll() bool {

func (p *Policy) checkWhitelist(publicKey string) bool {
if p.Whitelist == nil {
return false
return true
}

for _, pubKey := range *p.Whitelist {
Expand Down Expand Up @@ -99,9 +100,24 @@ func (p *Policy) checkPrivate(private bool) bool {
return private && !*p.RejectPrivateChannels
}

func (p *Policy) checkZeroConf(wantsZeroConf bool) bool {
if p.RejectZeroConfChannels == nil || !wantsZeroConf {
func (p *Policy) checkZeroConf(publicKey string, wantsZeroConf bool) bool {
if !wantsZeroConf {
return true
}
return wantsZeroConf && !*p.RejectZeroConfChannels

if p.AcceptZeroConfChannels == nil || !*p.AcceptZeroConfChannels {
return false
}

if p.ZeroConfList != nil {
for _, pubKey := range *p.ZeroConfList {
if publicKey == pubKey {
return true
}
}

return false
}

return true
}
103 changes: 63 additions & 40 deletions policy/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func TestEvaluatePolicy(t *testing.T) {
},
}
tru := true
fals := false
max := uint64(1)

cases := []struct {
Expand Down Expand Up @@ -58,11 +59,11 @@ func TestEvaluatePolicy(t *testing.T) {
{
desc: "Whitelist",
policy: Policy{
Whitelist: &[]string{peerPublicKey},
Whitelist: &[]string{"other_public_key"},
},
req: defaultReq,
peer: defaultPeer,
fail: false,
fail: true,
},
{
desc: "Blacklist",
Expand Down Expand Up @@ -94,9 +95,9 @@ func TestEvaluatePolicy(t *testing.T) {
fail: true,
},
{
desc: "Reject wants zero conf",
desc: "Accept wants zero conf",
policy: Policy{
RejectZeroConfChannels: &tru,
AcceptZeroConfChannels: &fals,
},
req: &lnrpc.ChannelAcceptRequest{
WantsZeroConf: true,
Expand Down Expand Up @@ -190,80 +191,80 @@ func TestCheckWhitelist(t *testing.T) {
publicKey := "key"

cases := []struct {
whitelist *[]string
desc string
publicKey string
whitelist []string
expected bool
}{
{
desc: "Whitelisted",
publicKey: publicKey,
whitelist: []string{publicKey},
whitelist: &[]string{publicKey},
expected: true,
},
{
desc: "Not whitelisted",
publicKey: "not key",
whitelist: []string{publicKey},
whitelist: &[]string{publicKey},
expected: false,
},
{
desc: "Nil",
whitelist: nil,
expected: true,
},
}

for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
policy := Policy{
Whitelist: &tc.whitelist,
Whitelist: tc.whitelist,
}

actual := policy.checkWhitelist(tc.publicKey)
assert.Equal(t, tc.expected, actual)
})
}

t.Run("Nil", func(t *testing.T) {
policy := Policy{}
assert.False(t, policy.checkWhitelist(""))
})
}

func TestCheckBlacklist(t *testing.T) {
publicKey := "key"

cases := []struct {
blacklist *[]string
desc string
publicKey string
blacklist []string
expected bool
}{
{
desc: "Blacklisted",
publicKey: publicKey,
blacklist: []string{publicKey},
blacklist: &[]string{publicKey},
expected: false,
},
{
desc: "Not blacklisted",
publicKey: "not key",
blacklist: []string{publicKey},
blacklist: &[]string{publicKey},
expected: true,
},
{
desc: "Nil",
blacklist: nil,
expected: true,
},
}

for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
policy := Policy{
Blacklist: &tc.blacklist,
Blacklist: tc.blacklist,
}

actual := policy.checkBlacklist(tc.publicKey)
assert.Equal(t, tc.expected, actual)
})
}

t.Run("Nil", func(t *testing.T) {
policy := Policy{}
assert.True(t, policy.checkBlacklist(""))
})
}

func TestCheckPrivate(t *testing.T) {
Expand Down Expand Up @@ -312,46 +313,68 @@ func TestCheckPrivate(t *testing.T) {
}

func TestCheckZeroConf(t *testing.T) {
publicKey := "public_key"

cases := []struct {
zeroConfList *[]string
desc string
rejectZeroConf bool
publicKey string
acceptZeroConf bool
wantsZeroConf bool
expected bool
}{
{
desc: "Reject",
rejectZeroConf: true,
wantsZeroConf: true,
expected: false,
desc: "No zero conf",
wantsZeroConf: false,
expected: true,
},
{
desc: "Accept",
rejectZeroConf: true,
wantsZeroConf: false,
desc: "Accept all",
acceptZeroConf: true,
wantsZeroConf: true,
expected: true,
},
{
desc: "Accept 2",
rejectZeroConf: false,
desc: "Accept in list",
publicKey: publicKey,
zeroConfList: &[]string{publicKey},
acceptZeroConf: true,
wantsZeroConf: true,
expected: true,
},
{
desc: "Reject all",
acceptZeroConf: false,
wantsZeroConf: true,
expected: false,
},
{
desc: "Reject even if in list",
publicKey: publicKey,
zeroConfList: &[]string{publicKey},
acceptZeroConf: false,
wantsZeroConf: true,
expected: false,
},
{
desc: "Reject not in list",
publicKey: publicKey,
zeroConfList: &[]string{"other_public_key"},
acceptZeroConf: true,
wantsZeroConf: true,
expected: false,
},
}

for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
policy := Policy{
RejectZeroConfChannels: &tc.rejectZeroConf,
AcceptZeroConfChannels: &tc.acceptZeroConf,
ZeroConfList: tc.zeroConfList,
}

actual := policy.checkZeroConf(tc.wantsZeroConf)
actual := policy.checkZeroConf(tc.publicKey, tc.wantsZeroConf)
assert.Equal(t, tc.expected, actual)
})
}

t.Run("Empty", func(t *testing.T) {
policy := Policy{}
actual := policy.checkZeroConf(true)
assert.True(t, actual)
})
}

0 comments on commit da906bd

Please sign in to comment.