mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
lnwire+channeldb: parse inbound fees
In this commit, the tlv extension of a channel update message is parsed. If an inbound fee schedule is encountered, it is reported in the graph rpc calls.
This commit is contained in:
parent
1d61de28c0
commit
3e6adbf1c0
@ -70,7 +70,7 @@ type ChannelEdgePolicy struct {
|
||||
// properly validate the set of signatures that cover these new fields,
|
||||
// and ensure we're able to make upgrades to the network in a forwards
|
||||
// compatible manner.
|
||||
ExtraOpaqueData []byte
|
||||
ExtraOpaqueData lnwire.ExtraOpaqueData
|
||||
}
|
||||
|
||||
// Signature is a channel announcement signature, which is needed for proper
|
||||
|
@ -217,6 +217,14 @@
|
||||
"format": "byte"
|
||||
},
|
||||
"description": "Custom channel update tlv records."
|
||||
},
|
||||
"inbound_fee_base_msat": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"inbound_fee_rate_milli_msat": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3330,6 +3330,9 @@ message RoutingPolicy {
|
||||
|
||||
// Custom channel update tlv records.
|
||||
map<uint64, bytes> custom_records = 8;
|
||||
|
||||
int32 inbound_fee_base_msat = 9;
|
||||
int32 inbound_fee_rate_milli_msat = 10;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6840,6 +6840,14 @@
|
||||
"format": "byte"
|
||||
},
|
||||
"description": "Custom channel update tlv records."
|
||||
},
|
||||
"inbound_fee_base_msat": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"inbound_fee_rate_milli_msat": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
60
lnwire/typed_fee.go
Normal file
60
lnwire/typed_fee.go
Normal file
@ -0,0 +1,60 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
const (
|
||||
FeeRecordType tlv.Type = 55555
|
||||
)
|
||||
|
||||
// Fee represents a fee schedule.
|
||||
type Fee struct {
|
||||
BaseFee int32
|
||||
FeeRate int32
|
||||
}
|
||||
|
||||
// Record returns a TLV record that can be used to encode/decode the fee
|
||||
// type from a given TLV stream.
|
||||
func (l *Fee) Record() tlv.Record {
|
||||
return tlv.MakeStaticRecord(
|
||||
FeeRecordType, l, 8, feeEncoder, feeDecoder, //nolint:gomnd
|
||||
)
|
||||
}
|
||||
|
||||
// feeEncoder is a custom TLV encoder for the fee record.
|
||||
func feeEncoder(w io.Writer, val interface{}, buf *[8]byte) error {
|
||||
v, ok := val.(*Fee)
|
||||
if !ok {
|
||||
return tlv.NewTypeForEncodingErr(val, "lnwire.Fee")
|
||||
}
|
||||
|
||||
if err := tlv.EUint32T(w, uint32(v.BaseFee), buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tlv.EUint32T(w, uint32(v.FeeRate), buf)
|
||||
}
|
||||
|
||||
// feeDecoder is a custom TLV decoder for the fee record.
|
||||
func feeDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
|
||||
v, ok := val.(*Fee)
|
||||
if !ok {
|
||||
return tlv.NewTypeForDecodingErr(val, "lnwire.Fee", l, 8)
|
||||
}
|
||||
|
||||
var baseFee, feeRate uint32
|
||||
if err := tlv.DUint32(r, &baseFee, buf, 4); err != nil { //nolint: gomnd,lll
|
||||
return err
|
||||
}
|
||||
if err := tlv.DUint32(r, &feeRate, buf, 4); err != nil { //nolint: gomnd,lll
|
||||
return err
|
||||
}
|
||||
|
||||
v.FeeRate = int32(feeRate)
|
||||
v.BaseFee = int32(baseFee)
|
||||
|
||||
return nil
|
||||
}
|
40
lnwire/typed_fee_test.go
Normal file
40
lnwire/typed_fee_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTypedFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("positive", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testTypedFee(t, Fee{
|
||||
BaseFee: 10,
|
||||
FeeRate: 20,
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("negative", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testTypedFee(t, Fee{
|
||||
BaseFee: -10,
|
||||
FeeRate: -20,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func testTypedFee(t *testing.T, fee Fee) { //nolint: thelper
|
||||
var eob ExtraOpaqueData
|
||||
require.NoError(t, eob.PackRecords(&fee))
|
||||
|
||||
var extractedFee Fee
|
||||
_, err := eob.ExtractRecords(&extractedFee)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, fee, extractedFee)
|
||||
}
|
@ -2763,6 +2763,7 @@ func (r *ChannelRouter) applyChannelUpdate(msg *lnwire.ChannelUpdate) bool {
|
||||
MaxHTLC: msg.HtlcMaximumMsat,
|
||||
FeeBaseMSat: lnwire.MilliSatoshi(msg.BaseFee),
|
||||
FeeProportionalMillionths: lnwire.MilliSatoshi(msg.FeeRate),
|
||||
ExtraOpaqueData: msg.ExtraOpaqueData,
|
||||
})
|
||||
if err != nil && !IsError(err, ErrIgnored, ErrOutdated) {
|
||||
log.Errorf("Unable to apply channel update: %v", err)
|
||||
|
21
rpcserver.go
21
rpcserver.go
@ -6059,6 +6059,23 @@ func marshalExtraOpaqueData(data []byte) map[uint64][]byte {
|
||||
return records
|
||||
}
|
||||
|
||||
// extractInboundFeeSafe tries to extract the inbound fee from the given extra
|
||||
// opaque data tlv block. If parsing fails, a zero inbound fee is returned. This
|
||||
// function is typically used on unvalidated data coming stored in the database.
|
||||
// There is not much we can do other than ignoring errors here.
|
||||
func extractInboundFeeSafe(data lnwire.ExtraOpaqueData) lnwire.Fee {
|
||||
var inboundFee lnwire.Fee
|
||||
|
||||
_, err := data.ExtractRecords(&inboundFee)
|
||||
if err != nil {
|
||||
// Return zero fee. Do not return the inboundFee variable
|
||||
// because it may be undefined.
|
||||
return lnwire.Fee{}
|
||||
}
|
||||
|
||||
return inboundFee
|
||||
}
|
||||
|
||||
func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo,
|
||||
c1, c2 *models.ChannelEdgePolicy) *lnrpc.ChannelEdge {
|
||||
|
||||
@ -6108,6 +6125,7 @@ func marshalDBRoutingPolicy(
|
||||
disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0
|
||||
|
||||
customRecords := marshalExtraOpaqueData(policy.ExtraOpaqueData)
|
||||
inboundFee := extractInboundFeeSafe(policy.ExtraOpaqueData)
|
||||
|
||||
return &lnrpc.RoutingPolicy{
|
||||
TimeLockDelta: uint32(policy.TimeLockDelta),
|
||||
@ -6118,6 +6136,9 @@ func marshalDBRoutingPolicy(
|
||||
Disabled: disabled,
|
||||
LastUpdate: uint32(policy.LastUpdate.Unix()),
|
||||
CustomRecords: customRecords,
|
||||
|
||||
InboundFeeBaseMsat: inboundFee.BaseFee,
|
||||
InboundFeeRateMilliMsat: inboundFee.FeeRate,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user