lnd/routing/additional_edge.go

156 lines
4.9 KiB
Go
Raw Normal View History

package routing
import (
"errors"
"fmt"
"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,
channelID uint64) uint64
// EdgePolicy returns the policy of the additional edge.
EdgePolicy() *models.CachedEdgePolicy
// 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
}
// PayloadSizeFunc defines the interface for the payload size function.
type PayloadSizeFunc func(amount lnwire.MilliSatoshi, expiry uint32,
channelID uint64) uint64
// 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,
expiry uint32, channelID uint64) uint64 {
hop := route.Hop{
AmtToForward: amount,
OutgoingTimeLock: expiry,
}
return hop.PayloadSize(channelID)
}
// 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
}
// BlindedEdge implements the AdditionalEdge interface. Blinded hops are viewed
// as additional edges because they are appended at the end of a normal route.
type BlindedEdge struct {
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
}
// 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,
_ uint64) uint64 {
blindedPath := b.blindedPayment.BlindedPath
hop := route.Hop{
BlindingPoint: blindedPath.BlindingPoint,
EncryptedData: blindedPath.BlindedHops[b.hopIndex].CipherText,
}
// For blinded paths the next chanID is in the encrypted data tlv.
return hop.PayloadSize(0)
}
// BlindedPayment returns the blinded payment that this edge is associated
// with.
func (b *BlindedEdge) BlindedPayment() *BlindedPayment {
return b.blindedPayment
}
// 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,
channelID uint64) uint64 {
// 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{}
return edge.IntermediatePayloadSize(amount, expiry, channelID)
}