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,
|
// 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
|
// and ensure we're able to make upgrades to the network in a forwards
|
||||||
// compatible manner.
|
// compatible manner.
|
||||||
ExtraOpaqueData []byte
|
ExtraOpaqueData lnwire.ExtraOpaqueData
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signature is a channel announcement signature, which is needed for proper
|
// Signature is a channel announcement signature, which is needed for proper
|
||||||
|
@ -217,6 +217,14 @@
|
|||||||
"format": "byte"
|
"format": "byte"
|
||||||
},
|
},
|
||||||
"description": "Custom channel update tlv records."
|
"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.
|
// Custom channel update tlv records.
|
||||||
map<uint64, bytes> custom_records = 8;
|
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"
|
"format": "byte"
|
||||||
},
|
},
|
||||||
"description": "Custom channel update tlv records."
|
"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,
|
MaxHTLC: msg.HtlcMaximumMsat,
|
||||||
FeeBaseMSat: lnwire.MilliSatoshi(msg.BaseFee),
|
FeeBaseMSat: lnwire.MilliSatoshi(msg.BaseFee),
|
||||||
FeeProportionalMillionths: lnwire.MilliSatoshi(msg.FeeRate),
|
FeeProportionalMillionths: lnwire.MilliSatoshi(msg.FeeRate),
|
||||||
|
ExtraOpaqueData: msg.ExtraOpaqueData,
|
||||||
})
|
})
|
||||||
if err != nil && !IsError(err, ErrIgnored, ErrOutdated) {
|
if err != nil && !IsError(err, ErrIgnored, ErrOutdated) {
|
||||||
log.Errorf("Unable to apply channel update: %v", err)
|
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
|
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,
|
func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo,
|
||||||
c1, c2 *models.ChannelEdgePolicy) *lnrpc.ChannelEdge {
|
c1, c2 *models.ChannelEdgePolicy) *lnrpc.ChannelEdge {
|
||||||
|
|
||||||
@ -6108,6 +6125,7 @@ func marshalDBRoutingPolicy(
|
|||||||
disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0
|
disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0
|
||||||
|
|
||||||
customRecords := marshalExtraOpaqueData(policy.ExtraOpaqueData)
|
customRecords := marshalExtraOpaqueData(policy.ExtraOpaqueData)
|
||||||
|
inboundFee := extractInboundFeeSafe(policy.ExtraOpaqueData)
|
||||||
|
|
||||||
return &lnrpc.RoutingPolicy{
|
return &lnrpc.RoutingPolicy{
|
||||||
TimeLockDelta: uint32(policy.TimeLockDelta),
|
TimeLockDelta: uint32(policy.TimeLockDelta),
|
||||||
@ -6118,6 +6136,9 @@ func marshalDBRoutingPolicy(
|
|||||||
Disabled: disabled,
|
Disabled: disabled,
|
||||||
LastUpdate: uint32(policy.LastUpdate.Unix()),
|
LastUpdate: uint32(policy.LastUpdate.Unix()),
|
||||||
CustomRecords: customRecords,
|
CustomRecords: customRecords,
|
||||||
|
|
||||||
|
InboundFeeBaseMsat: inboundFee.BaseFee,
|
||||||
|
InboundFeeRateMilliMsat: inboundFee.FeeRate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user