mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-18 13:27:56 +01:00
9f54ec90aa
All the structs defined in the `channeldb/models` package are graph related. So once we move all the graph CRUD code to the graph package, it makes sense to have the schema structs there too. So this just moves the `models` package over to `graph/db/models`.
221 lines
5.2 KiB
Go
221 lines
5.2 KiB
Go
package routing
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
sphinx "github.com/lightningnetwork/lightning-onion"
|
|
"github.com/lightningnetwork/lnd/fn"
|
|
"github.com/lightningnetwork/lnd/graph/db/models"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestBlindedPathValidation tests validation of blinded paths.
|
|
func TestBlindedPathValidation(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
payment *BlindedPayment
|
|
err error
|
|
}{
|
|
{
|
|
name: "no path",
|
|
payment: &BlindedPayment{},
|
|
err: ErrNoBlindedPath,
|
|
},
|
|
{
|
|
name: "insufficient hops",
|
|
payment: &BlindedPayment{
|
|
BlindedPath: &sphinx.BlindedPath{
|
|
BlindedHops: []*sphinx.BlindedHopInfo{},
|
|
},
|
|
},
|
|
err: ErrInsufficientBlindedHops,
|
|
},
|
|
{
|
|
name: "maximum < minimum",
|
|
payment: &BlindedPayment{
|
|
BlindedPath: &sphinx.BlindedPath{
|
|
BlindedHops: []*sphinx.BlindedHopInfo{
|
|
{},
|
|
},
|
|
},
|
|
HtlcMaximum: 10,
|
|
HtlcMinimum: 20,
|
|
},
|
|
err: ErrHTLCRestrictions,
|
|
},
|
|
{
|
|
name: "valid",
|
|
payment: &BlindedPayment{
|
|
BlindedPath: &sphinx.BlindedPath{
|
|
BlindedHops: []*sphinx.BlindedHopInfo{
|
|
{},
|
|
},
|
|
},
|
|
HtlcMaximum: 15,
|
|
HtlcMinimum: 5,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range tests {
|
|
testCase := testCase
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
err := testCase.payment.Validate()
|
|
require.ErrorIs(t, err, testCase.err)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestBlindedPaymentToHints tests conversion of a blinded path to a chain of
|
|
// route hints. As our function assumes that the blinded payment has already
|
|
// been validated.
|
|
func TestBlindedPaymentToHints(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
_, pk1 = btcec.PrivKeyFromBytes([]byte{1})
|
|
_, pkb1 = btcec.PrivKeyFromBytes([]byte{2})
|
|
_, pkb2 = btcec.PrivKeyFromBytes([]byte{3})
|
|
_, pkb3 = btcec.PrivKeyFromBytes([]byte{4})
|
|
|
|
v1 = route.NewVertex(pk1)
|
|
vb2 = route.NewVertex(pkb2)
|
|
vb3 = route.NewVertex(pkb3)
|
|
|
|
baseFee uint32 = 1000
|
|
ppmFee uint32 = 500
|
|
cltvDelta uint16 = 140
|
|
htlcMin uint64 = 100
|
|
htlcMax uint64 = 100_000_000
|
|
|
|
sizeEncryptedData = 100
|
|
cipherText = bytes.Repeat(
|
|
[]byte{1}, sizeEncryptedData,
|
|
)
|
|
_, blindedPoint = btcec.PrivKeyFromBytes([]byte{5})
|
|
|
|
rawFeatures = lnwire.NewRawFeatureVector(
|
|
lnwire.AMPOptional,
|
|
)
|
|
|
|
features = lnwire.NewFeatureVector(
|
|
rawFeatures, lnwire.Features,
|
|
)
|
|
)
|
|
|
|
// Create a blinded payment that's just to the introduction node and
|
|
// assert that we get nil hints.
|
|
blindedPayment := &BlindedPayment{
|
|
BlindedPath: &sphinx.BlindedPath{
|
|
IntroductionPoint: pk1,
|
|
BlindingPoint: blindedPoint,
|
|
BlindedHops: []*sphinx.BlindedHopInfo{
|
|
{},
|
|
},
|
|
},
|
|
BaseFee: baseFee,
|
|
ProportionalFeeRate: ppmFee,
|
|
CltvExpiryDelta: cltvDelta,
|
|
HtlcMinimum: htlcMin,
|
|
HtlcMaximum: htlcMax,
|
|
Features: features,
|
|
}
|
|
hints, err := blindedPayment.toRouteHints(fn.None[*btcec.PublicKey]())
|
|
require.NoError(t, err)
|
|
require.Nil(t, hints)
|
|
|
|
// Populate the blinded payment with hops.
|
|
blindedPayment.BlindedPath.BlindedHops = []*sphinx.BlindedHopInfo{
|
|
{
|
|
BlindedNodePub: pkb1,
|
|
CipherText: cipherText,
|
|
},
|
|
{
|
|
BlindedNodePub: pkb2,
|
|
CipherText: cipherText,
|
|
},
|
|
{
|
|
BlindedNodePub: pkb3,
|
|
CipherText: cipherText,
|
|
},
|
|
}
|
|
|
|
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{
|
|
v1: {
|
|
blindedEdge1,
|
|
},
|
|
vb2: {
|
|
blindedEdge2,
|
|
},
|
|
}
|
|
|
|
actual, err := blindedPayment.toRouteHints(fn.None[*btcec.PublicKey]())
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(expected), len(actual))
|
|
for vertex, expectedHint := range expected {
|
|
actualHint, ok := actual[vertex]
|
|
require.True(t, ok, "node not found: %v", vertex)
|
|
|
|
require.Len(t, expectedHint, 1)
|
|
require.Len(t, actualHint, 1)
|
|
|
|
// We can't assert that our functions are equal, so we check
|
|
// their output and then mark them as nil so that we can use
|
|
// require.Equal for all our other fields.
|
|
require.Equal(t, expectedHint[0].EdgePolicy().ToNodePubKey(),
|
|
actualHint[0].EdgePolicy().ToNodePubKey())
|
|
|
|
actualHint[0].EdgePolicy().ToNodePubKey = nil
|
|
expectedHint[0].EdgePolicy().ToNodePubKey = nil
|
|
|
|
// The arguments we use for the payload do not matter as long as
|
|
// both functions return the same payload.
|
|
expectedPayloadSize := expectedHint[0].IntermediatePayloadSize(
|
|
0, 0, 0,
|
|
)
|
|
actualPayloadSize := actualHint[0].IntermediatePayloadSize(
|
|
0, 0, 0,
|
|
)
|
|
|
|
require.Equal(t, expectedPayloadSize, actualPayloadSize)
|
|
|
|
require.Equal(t, expectedHint[0], actualHint[0])
|
|
}
|
|
}
|