rpc: add implementations for UpdateFees and FeeReport
This commit is contained in:
parent
2b411051e1
commit
44cafb01ae
148
rpcserver.go
148
rpcserver.go
@ -2645,3 +2645,151 @@ func (r *rpcServer) DecodePayReq(ctx context.Context,
|
||||
NumSatoshis: int64(payReq.Amount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// feeBase is the fixed point that fee rate computation are performed over.
|
||||
// Nodes on the network advertise their fee rate using this point as a base.
|
||||
// This means that the minimal possible fee rate if 1e-6, or 0.000001, or
|
||||
// 0.0001%.
|
||||
const feeBase = 1000000
|
||||
|
||||
// FeeReport allows the caller to obtain a report detailing the current fee
|
||||
// schedule enforced by the node globally for each channel.
|
||||
func (r *rpcServer) FeeReport(ctx context.Context,
|
||||
_ *lnrpc.FeeReportRequest) (*lnrpc.FeeReportResponse, error) {
|
||||
|
||||
if r.authSvc != nil {
|
||||
if err := macaroons.ValidateMacaroon(ctx, "feereport",
|
||||
r.authSvc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(roasbeef): use UnaryInterceptor to add automated logging
|
||||
|
||||
channelGraph := r.server.chanDB.ChannelGraph()
|
||||
selfNode, err := channelGraph.SourceNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var feeReports []*lnrpc.ChannelFeeReport
|
||||
err = selfNode.ForEachChannel(nil, func(_ *bolt.Tx, chanInfo *channeldb.ChannelEdgeInfo,
|
||||
edgePolicy, _ *channeldb.ChannelEdgePolicy) error {
|
||||
|
||||
// We'll compute the effective fee rate by converting from a
|
||||
// fixed point fee rate to a floating point fee rate. The fee
|
||||
// rate field in the database the amount of mSAT charged per
|
||||
// 1mil mSAT sent, so will divide by this to get the proper fee
|
||||
// rate.
|
||||
feeRateFixedPoint := edgePolicy.FeeProportionalMillionths
|
||||
feeRate := float64(feeRateFixedPoint) / float64(feeBase)
|
||||
|
||||
// TODO(roasbeef): also add stats for revenue for each channel
|
||||
feeReports = append(feeReports, &lnrpc.ChannelFeeReport{
|
||||
ChanPoint: chanInfo.ChannelPoint.String(),
|
||||
BaseFeeMsat: int64(edgePolicy.FeeBaseMSat),
|
||||
FeePerMil: int64(feeRateFixedPoint),
|
||||
FeeRate: feeRate,
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &lnrpc.FeeReportResponse{feeReports}, nil
|
||||
}
|
||||
|
||||
// minFeeRate is the smallest permitted fee rate within the network. This is
|
||||
// dervied by the fact that fee rates are computed using a fixed point of
|
||||
// 1,000,000. As a result, the smallest representable fee rate is 1e-6, or
|
||||
// 0.000001, or 0.0001%.
|
||||
const minFeeRate = 1e-6
|
||||
|
||||
// UpdateFees allows the caller to update the fee schedule for all channels
|
||||
// globally, or a particular channel.
|
||||
func (r *rpcServer) UpdateFees(ctx context.Context,
|
||||
req *lnrpc.FeeUpdateRequest) (*lnrpc.FeeUpdateResponse, error) {
|
||||
|
||||
if r.authSvc != nil {
|
||||
if err := macaroons.ValidateMacaroon(ctx, "udpatefees",
|
||||
r.authSvc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var targetChans []wire.OutPoint
|
||||
switch scope := req.Scope.(type) {
|
||||
// If the request is targeting all active channels, then we don't need
|
||||
// target any channels by their channel point.
|
||||
case *lnrpc.FeeUpdateRequest_Global:
|
||||
|
||||
// Otherwise, we're targeting an individual channel by its channel
|
||||
// point.
|
||||
case *lnrpc.FeeUpdateRequest_ChanPoint:
|
||||
txid, err := chainhash.NewHash(scope.ChanPoint.FundingTxid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
targetChans = append(targetChans, wire.OutPoint{
|
||||
Hash: *txid,
|
||||
Index: scope.ChanPoint.OutputIndex,
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown scope: %v", scope)
|
||||
}
|
||||
|
||||
// As a sanity check, we'll ensure that the passed fee rate is below
|
||||
// 1e-6, or the lowest allowed fee rate.
|
||||
if req.FeeRate < minFeeRate {
|
||||
return nil, fmt.Errorf("fee rate of %v is too small, min fee "+
|
||||
"rate is %v", req.FeeRate, minFeeRate)
|
||||
}
|
||||
|
||||
// We'll also need to convert the floating point fee rate we accept
|
||||
// over RPC to the fixed point rate that we use within the protocol. We
|
||||
// do this by multiplying the passed fee rate by the fee base. This
|
||||
// gives us the fixed point, scaled by 1 million that's used within the
|
||||
// protocol.
|
||||
feeRateFixed := uint32(req.FeeRate * feeBase)
|
||||
baseFeeMsat := lnwire.MilliSatoshi(req.BaseFeeMsat)
|
||||
feeSchema := routing.FeeSchema{
|
||||
BaseFee: baseFeeMsat,
|
||||
FeeRate: feeRateFixed,
|
||||
}
|
||||
|
||||
rpcsLog.Tracef("[updatefees] updating fee schedule base_fee=%v, "+
|
||||
"rate_float=%v, rate_fixed=%v, targets=%v",
|
||||
req.BaseFeeMsat, req.FeeRate, feeRateFixed,
|
||||
spew.Sdump(targetChans))
|
||||
|
||||
// With the scope resolved, we'll now send this to the
|
||||
// AuthenticatedGossiper so it can propagate the new fee schema for out
|
||||
// target channel(s).
|
||||
err := r.server.authGossiper.PropagateFeeUpdate(
|
||||
feeSchema, targetChans...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Finally, we'll apply the set of active links amongst the target
|
||||
// channels.
|
||||
//
|
||||
// We create a partially policy as the logic won't overwrite a valid
|
||||
// sub-policy with a "nil" one.
|
||||
p := htlcswitch.ForwardingPolicy{
|
||||
BaseFee: baseFeeMsat,
|
||||
FeeRate: lnwire.MilliSatoshi(feeRateFixed),
|
||||
}
|
||||
err = r.server.htlcSwitch.UpdateForwardingPolicies(p, targetChans...)
|
||||
if err != nil {
|
||||
// If we're unable update the fees due to the links not being
|
||||
// online, then we don't need to fail the call. We'll simply
|
||||
// log the failure.
|
||||
rpcsLog.Warnf("Unable to update link fees: %v", err)
|
||||
}
|
||||
|
||||
return &lnrpc.FeeUpdateResponse{}, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user