rules: restrict initial channel fee parameters

Channel policy boundaries are enforced for channel openings.
This commit is contained in:
bitromortac 2024-05-14 12:20:05 +02:00
parent 9911052fd7
commit a36d6c0296
No known key found for this signature in database
GPG key ID: 1965063FC13BEBE2
3 changed files with 162 additions and 0 deletions

View file

@ -175,6 +175,24 @@ func (f *ChanPolicyBounds) checkers() map[string]mid.RoundTripChecker {
return f.checkPolicyUpdate(ctx, r)
},
),
"/lnrpc.Lightning/OpenChannelSync": mid.NewRequestChecker(
&lnrpc.OpenChannelRequest{},
&lnrpc.ChannelPoint{},
func(ctx context.Context,
r *lnrpc.OpenChannelRequest) error {
return f.checkOpenChannelRequestFee(ctx, r)
},
),
"/lnrpc.Lightning/BatchOpenChannel": mid.NewRequestChecker(
&lnrpc.BatchOpenChannelRequest{},
&lnrpc.BatchOpenChannelResponse{},
func(ctx context.Context,
r *lnrpc.BatchOpenChannelRequest) error {
return f.checkBatchOpenChannelRequestFee(ctx, r)
},
),
}
}
@ -221,6 +239,65 @@ func (f *ChanPolicyBounds) checkPolicyUpdate(_ context.Context,
return nil
}
// checkOpenChannelRequest verifies that the given lnrpc.OpenChannelRequest is
// valid given the ChannelConstraint values.
// Note: the onchain fee rate is checked by the onchain budget rule.
func (f *ChanPolicyBounds) checkOpenChannelRequestFee(_ context.Context,
req *lnrpc.OpenChannelRequest) error {
return checkOpenRequestFee(f, req)
}
// checkBatchOpenChannelRequest verifies that the given
// lnrpc.BatchOpenChannelRequest is valid for each individual channel requested
// given the ChannelConstraint values.
// Note: the onchain fee rate is checked by the onchain budget rule.
func (f *ChanPolicyBounds) checkBatchOpenChannelRequestFee(_ context.Context,
req *lnrpc.BatchOpenChannelRequest) error {
// We check that each channel in the batch request is valid.
for _, openReq := range req.Channels {
err := checkOpenRequestFee(f, openReq)
if err != nil {
return err
}
}
return nil
}
// checkOpenRequestFee verifies that the given lnrpc.OpenChannelRequest is valid
// given the ChanPolicyBounds values.
func checkOpenRequestFee(f *ChanPolicyBounds, req ChanOpenReq) error {
if req.GetUseBaseFee() {
if req.GetBaseFee() < f.MinBaseMsat ||
req.GetBaseFee() > f.MaxBaseMsat {
return fmt.Errorf("invalid base fee amount")
}
}
if req.GetUseFeeRate() {
if req.GetFeeRate() > math.MaxUint32 {
return fmt.Errorf("fee rate is too large")
}
if uint32(req.GetFeeRate()) < f.MinRatePPM ||
uint32(req.GetFeeRate()) > f.MaxRatePPM {
return fmt.Errorf("invalid fee rate")
}
}
if req.GetMinHtlcMsat() < int64(f.MinHtlcMsat) ||
req.GetMinHtlcMsat() > int64(f.MaxHtlcMsat) {
return fmt.Errorf("invalid min htlc msat amount")
}
return nil
}
// VerifySane checks that the value of the values is ok given the min and max
// allowed values.
//

View file

@ -368,6 +368,86 @@ func TestChannelPolicyBoundsCheckers(t *testing.T) {
},
expectErr: true,
},
{
name: "channel opening sync in bounds",
uri: "/lnrpc.Lightning/OpenChannelSync",
msg: &lnrpc.OpenChannelRequest{
UseBaseFee: true,
BaseFee: 6,
UseFeeRate: true,
FeeRate: 6000000,
MinHtlcMsat: 20,
},
},
{
name: "channel opening high fee rate",
uri: "/lnrpc.Lightning/OpenChannelSync",
msg: &lnrpc.OpenChannelRequest{
UseBaseFee: true,
BaseFee: 6,
UseFeeRate: true,
FeeRate: 11000000,
MinHtlcMsat: 20,
},
expectErr: true,
},
{
name: "channel opening high base fee",
uri: "/lnrpc.Lightning/OpenChannelSync",
msg: &lnrpc.OpenChannelRequest{
UseBaseFee: true,
BaseFee: 11,
UseFeeRate: true,
FeeRate: 6000000,
MinHtlcMsat: 20,
},
expectErr: true,
},
{
name: "allowed batch channel opening",
uri: "/lnrpc.Lightning/BatchOpenChannel",
msg: &lnrpc.BatchOpenChannelRequest{
Channels: []*lnrpc.BatchOpenChannel{
{
UseBaseFee: true,
BaseFee: 5,
UseFeeRate: true,
FeeRate: 5000000,
MinHtlcMsat: 10,
},
{
UseBaseFee: true,
BaseFee: 10,
UseFeeRate: true,
FeeRate: 10000000,
MinHtlcMsat: 10,
},
},
},
},
{
name: "batch channel opening low min htlc msat",
uri: "/lnrpc.Lightning/BatchOpenChannel",
msg: &lnrpc.BatchOpenChannelRequest{
Channels: []*lnrpc.BatchOpenChannel{
{
UseBaseFee: true,
BaseFee: 6,
UseFeeRate: true,
FeeRate: 6000000,
MinHtlcMsat: 20,
},
{
UseBaseFee: true,
BaseFee: 6,
UseFeeRate: true,
FeeRate: 6000000,
MinHtlcMsat: 9,
},
},
},
expectErr: true,
},
}
for _, test := range tests {

View file

@ -207,6 +207,11 @@ type ChanOpenReq interface {
GetCloseAddress() string
GetPrivate() bool
GetNodePubkey() []byte
GetBaseFee() uint64
GetUseBaseFee() bool
GetFeeRate() uint64
GetUseFeeRate() bool
GetMinHtlcMsat() int64
}
// checkOpenRequest verifies that the given request is valid given the