2023-11-03 08:29:03 +01:00
|
|
|
package routing
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2024-05-13 13:44:56 +02:00
|
|
|
"fmt"
|
2023-11-03 08:29:03 +01:00
|
|
|
|
|
|
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// ErrNoPayLoadSizeFunc is returned when no payload size function is
|
|
|
|
// definied.
|
|
|
|
ErrNoPayLoadSizeFunc = errors.New("no payloadSizeFunc defined for " +
|
|
|
|
"additional edge")
|
|
|
|
)
|
|
|
|
|
|
|
|
// AdditionalEdge is an interface which specifies additional edges which can
|
|
|
|
// be appended to an existing route. Compared to normal edges of a route they
|
|
|
|
// provide an explicit payload size function and are introduced because blinded
|
|
|
|
// paths differ in their payload structure.
|
|
|
|
type AdditionalEdge interface {
|
|
|
|
// IntermediatePayloadSize returns the size of the payload for the
|
|
|
|
// additional edge when being an intermediate hop in a route NOT the
|
|
|
|
// final hop.
|
|
|
|
IntermediatePayloadSize(amount lnwire.MilliSatoshi, expiry uint32,
|
2024-05-29 22:14:46 +02:00
|
|
|
channelID uint64) uint64
|
2023-11-03 08:29:03 +01:00
|
|
|
|
|
|
|
// EdgePolicy returns the policy of the additional edge.
|
|
|
|
EdgePolicy() *models.CachedEdgePolicy
|
2024-05-14 12:34:33 +02:00
|
|
|
|
|
|
|
// BlindedPayment returns the BlindedPayment that this additional edge
|
|
|
|
// info was derived from. It will return nil if this edge was not
|
|
|
|
// derived from a blinded route.
|
|
|
|
BlindedPayment() *BlindedPayment
|
2023-11-03 08:29:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// PayloadSizeFunc defines the interface for the payload size function.
|
|
|
|
type PayloadSizeFunc func(amount lnwire.MilliSatoshi, expiry uint32,
|
2024-05-29 22:14:46 +02:00
|
|
|
channelID uint64) uint64
|
2023-11-03 08:29:03 +01:00
|
|
|
|
|
|
|
// PrivateEdge implements the AdditionalEdge interface. As the name implies it
|
|
|
|
// is used for private route hints that the receiver adds for example to an
|
|
|
|
// invoice.
|
|
|
|
type PrivateEdge struct {
|
|
|
|
policy *models.CachedEdgePolicy
|
|
|
|
}
|
|
|
|
|
|
|
|
// EdgePolicy return the policy of the PrivateEdge.
|
|
|
|
func (p *PrivateEdge) EdgePolicy() *models.CachedEdgePolicy {
|
|
|
|
return p.policy
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntermediatePayloadSize returns the sphinx payload size defined in BOLT04 if
|
|
|
|
// this edge were to be included in a route.
|
|
|
|
func (p *PrivateEdge) IntermediatePayloadSize(amount lnwire.MilliSatoshi,
|
2024-05-29 22:14:46 +02:00
|
|
|
expiry uint32, channelID uint64) uint64 {
|
2023-11-03 08:29:03 +01:00
|
|
|
|
|
|
|
hop := route.Hop{
|
|
|
|
AmtToForward: amount,
|
|
|
|
OutgoingTimeLock: expiry,
|
|
|
|
}
|
|
|
|
|
|
|
|
return hop.PayloadSize(channelID)
|
|
|
|
}
|
|
|
|
|
2024-05-14 12:34:33 +02:00
|
|
|
// BlindedPayment is a no-op for a PrivateEdge since it is not associated with
|
|
|
|
// a blinded payment. This will thus return nil.
|
|
|
|
func (p *PrivateEdge) BlindedPayment() *BlindedPayment {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-11-03 08:29:03 +01:00
|
|
|
// BlindedEdge implements the AdditionalEdge interface. Blinded hops are viewed
|
2024-05-13 13:44:56 +02:00
|
|
|
// as additional edges because they are appended at the end of a normal route.
|
2023-11-03 08:29:03 +01:00
|
|
|
type BlindedEdge struct {
|
2024-05-13 13:44:56 +02:00
|
|
|
policy *models.CachedEdgePolicy
|
|
|
|
|
|
|
|
// blindedPayment is the BlindedPayment that this blinded edge was
|
|
|
|
// derived from.
|
|
|
|
blindedPayment *BlindedPayment
|
|
|
|
|
|
|
|
// hopIndex is the index of the hop in the blinded payment path that
|
|
|
|
// this edge is associated with.
|
|
|
|
hopIndex int
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBlindedEdge constructs a new BlindedEdge which packages the policy info
|
|
|
|
// for a specific hop within the given blinded payment path. The hop index
|
|
|
|
// should correspond to the hop within the blinded payment that this edge is
|
|
|
|
// associated with.
|
|
|
|
func NewBlindedEdge(policy *models.CachedEdgePolicy, payment *BlindedPayment,
|
|
|
|
hopIndex int) (*BlindedEdge, error) {
|
|
|
|
|
|
|
|
if payment == nil {
|
|
|
|
return nil, fmt.Errorf("blinded payment cannot be nil for " +
|
|
|
|
"blinded edge")
|
|
|
|
}
|
|
|
|
|
|
|
|
if hopIndex < 0 || hopIndex >= len(payment.BlindedPath.BlindedHops) {
|
|
|
|
return nil, fmt.Errorf("the hop index %d is outside the "+
|
|
|
|
"valid range between 0 and %d", hopIndex,
|
|
|
|
len(payment.BlindedPath.BlindedHops)-1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &BlindedEdge{
|
|
|
|
policy: policy,
|
|
|
|
hopIndex: hopIndex,
|
|
|
|
blindedPayment: payment,
|
|
|
|
}, nil
|
2023-11-03 08:29:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// EdgePolicy return the policy of the BlindedEdge.
|
|
|
|
func (b *BlindedEdge) EdgePolicy() *models.CachedEdgePolicy {
|
|
|
|
return b.policy
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntermediatePayloadSize returns the sphinx payload size defined in BOLT04 if
|
|
|
|
// this edge were to be included in a route.
|
|
|
|
func (b *BlindedEdge) IntermediatePayloadSize(_ lnwire.MilliSatoshi, _ uint32,
|
2024-05-29 22:14:46 +02:00
|
|
|
_ uint64) uint64 {
|
2023-11-03 08:29:03 +01:00
|
|
|
|
2024-05-13 13:44:56 +02:00
|
|
|
blindedPath := b.blindedPayment.BlindedPath
|
|
|
|
|
2023-11-03 08:29:03 +01:00
|
|
|
hop := route.Hop{
|
2024-05-13 13:44:56 +02:00
|
|
|
BlindingPoint: blindedPath.BlindingPoint,
|
|
|
|
EncryptedData: blindedPath.BlindedHops[b.hopIndex].CipherText,
|
2023-11-03 08:29:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// For blinded paths the next chanID is in the encrypted data tlv.
|
|
|
|
return hop.PayloadSize(0)
|
|
|
|
}
|
|
|
|
|
2024-05-14 12:34:33 +02:00
|
|
|
// BlindedPayment returns the blinded payment that this edge is associated
|
|
|
|
// with.
|
|
|
|
func (b *BlindedEdge) BlindedPayment() *BlindedPayment {
|
|
|
|
return b.blindedPayment
|
|
|
|
}
|
|
|
|
|
2023-11-03 08:29:03 +01:00
|
|
|
// Compile-time constraints to ensure the PrivateEdge and the BlindedEdge
|
|
|
|
// implement the AdditionalEdge interface.
|
|
|
|
var _ AdditionalEdge = (*PrivateEdge)(nil)
|
|
|
|
var _ AdditionalEdge = (*BlindedEdge)(nil)
|
|
|
|
|
|
|
|
// defaultHopPayloadSize is the default payload size of a normal (not-blinded)
|
|
|
|
// hop in the route.
|
|
|
|
func defaultHopPayloadSize(amount lnwire.MilliSatoshi, expiry uint32,
|
2024-05-29 22:14:46 +02:00
|
|
|
channelID uint64) uint64 {
|
2023-11-03 08:29:03 +01:00
|
|
|
|
|
|
|
// The payload size of a cleartext intermediate hop is equal to the
|
|
|
|
// payload size of a private edge therefore we reuse its size function.
|
|
|
|
edge := PrivateEdge{}
|
|
|
|
|
2024-05-29 22:14:46 +02:00
|
|
|
return edge.IntermediatePayloadSize(amount, expiry, channelID)
|
2023-11-03 08:29:03 +01:00
|
|
|
}
|