routing+refactor: let BlindedEdge carry BlindedPayment
This commit is purely a refactor. In it, we let the `BlindedEdge` struct carry a pointer to the `BlindedPayment` that it was derived from. This is done now because later on in the PR series, we will need more information about the `BlindedPayment` that an edge was derived from. Since we now pass in the whole BlindedPayment, we swap out the `cipherText` member for a `hopIndex` member so that we dont carry around two sources of truth in the same struct.
This commit is contained in:
6 files changed
+109
-60
No files matched your search
@@ -2,8 +2,8 @@ package routing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
@@ -61,11 +61,42 @@ func (p *PrivateEdge) IntermediatePayloadSize(amount lnwire.MilliSatoshi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BlindedEdge implements the AdditionalEdge interface. Blinded hops are viewed
|
// BlindedEdge implements the AdditionalEdge interface. Blinded hops are viewed
|
||||||
// as additional edges because they are appened at the end of a normal route.
|
// as additional edges because they are appended at the end of a normal route.
|
||||||
type BlindedEdge struct {
|
type BlindedEdge struct {
|
||||||
policy *models.CachedEdgePolicy
|
policy *models.CachedEdgePolicy
|
||||||
cipherText []byte
|
|
||||||
blindingPoint *btcec.PublicKey
|
// 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.
|
// EdgePolicy return the policy of the BlindedEdge.
|
||||||
@@ -78,9 +109,11 @@ func (b *BlindedEdge) EdgePolicy() *models.CachedEdgePolicy {
|
|||||||
func (b *BlindedEdge) IntermediatePayloadSize(_ lnwire.MilliSatoshi, _ uint32,
|
func (b *BlindedEdge) IntermediatePayloadSize(_ lnwire.MilliSatoshi, _ uint32,
|
||||||
_ uint64) uint64 {
|
_ uint64) uint64 {
|
||||||
|
|
||||||
|
blindedPath := b.blindedPayment.BlindedPath
|
||||||
|
|
||||||
hop := route.Hop{
|
hop := route.Hop{
|
||||||
BlindingPoint: b.blindingPoint,
|
BlindingPoint: blindedPath.BlindingPoint,
|
||||||
EncryptedData: b.cipherText,
|
EncryptedData: blindedPath.BlindedHops[b.hopIndex].CipherText,
|
||||||
}
|
}
|
||||||
|
|
||||||
// For blinded paths the next chanID is in the encrypted data tlv.
|
// For blinded paths the next chanID is in the encrypted data tlv.
|
||||||
|
|||||||
@@ -42,9 +42,13 @@ func TestIntermediatePayloadSize(t *testing.T) {
|
|||||||
hop: route.Hop{
|
hop: route.Hop{
|
||||||
EncryptedData: []byte{12, 13},
|
EncryptedData: []byte{12, 13},
|
||||||
},
|
},
|
||||||
edge: &BlindedEdge{
|
edge: &BlindedEdge{blindedPayment: &BlindedPayment{
|
||||||
cipherText: []byte{12, 13},
|
BlindedPath: &sphinx.BlindedPath{
|
||||||
},
|
BlindedHops: []*sphinx.BlindedHopInfo{
|
||||||
|
{CipherText: []byte{12, 13}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Blinded edge - introduction point",
|
name: "Blinded edge - introduction point",
|
||||||
@@ -52,10 +56,14 @@ func TestIntermediatePayloadSize(t *testing.T) {
|
|||||||
EncryptedData: []byte{12, 13},
|
EncryptedData: []byte{12, 13},
|
||||||
BlindingPoint: blindedPoint,
|
BlindingPoint: blindedPoint,
|
||||||
},
|
},
|
||||||
edge: &BlindedEdge{
|
edge: &BlindedEdge{blindedPayment: &BlindedPayment{
|
||||||
cipherText: []byte{12, 13},
|
BlindedPath: &sphinx.BlindedPath{
|
||||||
blindingPoint: blindedPoint,
|
BlindingPoint: blindedPoint,
|
||||||
},
|
BlindedHops: []*sphinx.BlindedHopInfo{
|
||||||
|
{CipherText: []byte{12, 13}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-15
@@ -88,13 +88,13 @@ func (b *BlindedPayment) Validate() error {
|
|||||||
// the case of multiple blinded hops, CLTV delta is fully accounted for in the
|
// the case of multiple blinded hops, CLTV delta is fully accounted for in the
|
||||||
// hints (both for intermediate hops and the final_cltv_delta for the receiving
|
// hints (both for intermediate hops and the final_cltv_delta for the receiving
|
||||||
// node).
|
// node).
|
||||||
func (b *BlindedPayment) toRouteHints() RouteHints {
|
func (b *BlindedPayment) toRouteHints() (RouteHints, error) {
|
||||||
// If we just have a single hop in our blinded route, it just contains
|
// If we just have a single hop in our blinded route, it just contains
|
||||||
// an introduction node (this is a valid path according to the spec).
|
// an introduction node (this is a valid path according to the spec).
|
||||||
// Since we have the un-blinded node ID for the introduction node, we
|
// Since we have the un-blinded node ID for the introduction node, we
|
||||||
// don't need to add any route hints.
|
// don't need to add any route hints.
|
||||||
if len(b.BlindedPath.BlindedHops) == 1 {
|
if len(b.BlindedPath.BlindedHops) == 1 {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
hintCount := len(b.BlindedPath.BlindedHops) - 1
|
hintCount := len(b.BlindedPath.BlindedHops) - 1
|
||||||
@@ -136,14 +136,13 @@ func (b *BlindedPayment) toRouteHints() RouteHints {
|
|||||||
ToNodeFeatures: features,
|
ToNodeFeatures: features,
|
||||||
}
|
}
|
||||||
|
|
||||||
hints[fromNode] = []AdditionalEdge{
|
edge, err := NewBlindedEdge(edgePolicy, b, 0)
|
||||||
&BlindedEdge{
|
if err != nil {
|
||||||
policy: edgePolicy,
|
return nil, err
|
||||||
cipherText: b.BlindedPath.BlindedHops[0].CipherText,
|
|
||||||
blindingPoint: b.BlindedPath.BlindingPoint,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hints[fromNode] = []AdditionalEdge{edge}
|
||||||
|
|
||||||
// Start at an offset of 1 because the first node in our blinded hops
|
// Start at an offset of 1 because the first node in our blinded hops
|
||||||
// is the introduction node and terminate at the second-last node
|
// is the introduction node and terminate at the second-last node
|
||||||
// because we're dealing with hops as pairs.
|
// because we're dealing with hops as pairs.
|
||||||
@@ -169,14 +168,13 @@ func (b *BlindedPayment) toRouteHints() RouteHints {
|
|||||||
ToNodeFeatures: features,
|
ToNodeFeatures: features,
|
||||||
}
|
}
|
||||||
|
|
||||||
hints[fromNode] = []AdditionalEdge{
|
edge, err := NewBlindedEdge(edgePolicy, b, i)
|
||||||
&BlindedEdge{
|
if err != nil {
|
||||||
policy: edgePolicy,
|
return nil, err
|
||||||
cipherText: b.BlindedPath.BlindedHops[i].
|
|
||||||
CipherText,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hints[fromNode] = []AdditionalEdge{edge}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hints
|
return hints, nil
|
||||||
}
|
}
|
||||||
+33
-29
@@ -128,7 +128,9 @@ func TestBlindedPaymentToHints(t *testing.T) {
|
|||||||
HtlcMaximum: htlcMax,
|
HtlcMaximum: htlcMax,
|
||||||
Features: features,
|
Features: features,
|
||||||
}
|
}
|
||||||
require.Nil(t, blindedPayment.toRouteHints())
|
hints, err := blindedPayment.toRouteHints()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, hints)
|
||||||
|
|
||||||
// Populate the blinded payment with hops.
|
// Populate the blinded payment with hops.
|
||||||
blindedPayment.BlindedPath.BlindedHops = []*sphinx.BlindedHopInfo{
|
blindedPayment.BlindedPath.BlindedHops = []*sphinx.BlindedHopInfo{
|
||||||
@@ -146,41 +148,43 @@ func TestBlindedPaymentToHints(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
policy1 := &models.CachedEdgePolicy{
|
||||||
|
TimeLockDelta: cltvDelta,
|
||||||
|
MinHTLC: lnwire.MilliSatoshi(htlcMin),
|
||||||
|
MaxHTLC: lnwire.MilliSatoshi(htlcMax),
|
||||||
|
FeeBaseMSat: lnwire.MilliSatoshi(baseFee),
|
||||||
|
FeeProportionalMillionths: lnwire.MilliSatoshi(
|
||||||
|
ppmFee,
|
||||||
|
),
|
||||||
|
ToNodePubKey: func() route.Vertex {
|
||||||
|
return vb2
|
||||||
|
},
|
||||||
|
ToNodeFeatures: features,
|
||||||
|
}
|
||||||
|
policy2 := &models.CachedEdgePolicy{
|
||||||
|
ToNodePubKey: func() route.Vertex {
|
||||||
|
return vb3
|
||||||
|
},
|
||||||
|
ToNodeFeatures: features,
|
||||||
|
}
|
||||||
|
|
||||||
|
blindedEdge1, err := NewBlindedEdge(policy1, blindedPayment, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
blindedEdge2, err := NewBlindedEdge(policy2, blindedPayment, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
expected := RouteHints{
|
expected := RouteHints{
|
||||||
v1: {
|
v1: {
|
||||||
//nolint:lll
|
blindedEdge1,
|
||||||
&BlindedEdge{
|
|
||||||
policy: &models.CachedEdgePolicy{
|
|
||||||
TimeLockDelta: cltvDelta,
|
|
||||||
MinHTLC: lnwire.MilliSatoshi(htlcMin),
|
|
||||||
MaxHTLC: lnwire.MilliSatoshi(htlcMax),
|
|
||||||
FeeBaseMSat: lnwire.MilliSatoshi(baseFee),
|
|
||||||
FeeProportionalMillionths: lnwire.MilliSatoshi(
|
|
||||||
ppmFee,
|
|
||||||
),
|
|
||||||
ToNodePubKey: func() route.Vertex {
|
|
||||||
return vb2
|
|
||||||
},
|
|
||||||
ToNodeFeatures: features,
|
|
||||||
},
|
|
||||||
blindingPoint: blindedPoint,
|
|
||||||
cipherText: cipherText,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
vb2: {
|
vb2: {
|
||||||
&BlindedEdge{
|
blindedEdge2,
|
||||||
policy: &models.CachedEdgePolicy{
|
|
||||||
ToNodePubKey: func() route.Vertex {
|
|
||||||
return vb3
|
|
||||||
},
|
|
||||||
ToNodeFeatures: features,
|
|
||||||
},
|
|
||||||
cipherText: cipherText,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := blindedPayment.toRouteHints()
|
actual, err := blindedPayment.toRouteHints()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, len(expected), len(actual))
|
require.Equal(t, len(expected), len(actual))
|
||||||
for vertex, expectedHint := range expected {
|
for vertex, expectedHint := range expected {
|
||||||
|
|||||||
@@ -3341,7 +3341,9 @@ func TestBlindedRouteConstruction(t *testing.T) {
|
|||||||
// that make up the graph we'll give to route construction. The hints
|
// that make up the graph we'll give to route construction. The hints
|
||||||
// map is keyed by source node, so we can retrieve our blinded edges
|
// map is keyed by source node, so we can retrieve our blinded edges
|
||||||
// accordingly.
|
// accordingly.
|
||||||
blindedEdges := blindedPayment.toRouteHints()
|
blindedEdges, err := blindedPayment.toRouteHints()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
carolDaveEdge := blindedEdges[carolVertex][0]
|
carolDaveEdge := blindedEdges[carolVertex][0]
|
||||||
daveEveEdge := blindedEdges[daveBlindedVertex][0]
|
daveEveEdge := blindedEdges[daveBlindedVertex][0]
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -2001,6 +2001,7 @@ func NewRouteRequest(source route.Vertex, target *route.Vertex,
|
|||||||
// Assume that we're starting off with a regular payment.
|
// Assume that we're starting off with a regular payment.
|
||||||
requestHints = routeHints
|
requestHints = routeHints
|
||||||
requestExpiry = finalExpiry
|
requestExpiry = finalExpiry
|
||||||
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if blindedPayment != nil {
|
if blindedPayment != nil {
|
||||||
@@ -2038,7 +2039,10 @@ func NewRouteRequest(source route.Vertex, target *route.Vertex,
|
|||||||
requestExpiry = blindedPayment.CltvExpiryDelta
|
requestExpiry = blindedPayment.CltvExpiryDelta
|
||||||
}
|
}
|
||||||
|
|
||||||
requestHints = blindedPayment.toRouteHints()
|
requestHints, err = blindedPayment.toRouteHints()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requestTarget, err := getTargetNode(target, blindedPayment)
|
requestTarget, err := getTargetNode(target, blindedPayment)
|
||||||
|
|||||||
Reference in new issue
Block a user