routing: add representation of blinded payments

This commit adds a representation of blinded payments, which include a
blinded path and aggregate routing parameters to be used in payment to
the path.
This commit is contained in:
Carla Kirk-Cohen 2023-05-31 15:28:09 -04:00 committed by Olaoluwa Osuntokun
parent 20e7e801c0
commit 539a275faa
2 changed files with 149 additions and 0 deletions

79
routing/blinding.go Normal file
View file

@ -0,0 +1,79 @@
package routing
import (
"errors"
"fmt"
sphinx "github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/lnwire"
)
var (
// ErrNoBlindedPath is returned when the blinded path in a blinded
// payment is missing.
ErrNoBlindedPath = errors.New("blinded path required")
// ErrInsufficientBlindedHops is returned when a blinded path does
// not have enough blinded hops.
ErrInsufficientBlindedHops = errors.New("blinded path requires " +
"at least one hop")
// ErrHTLCRestrictions is returned when a blinded path has invalid
// HTLC maximum and minimum values.
ErrHTLCRestrictions = errors.New("invalid htlc minimum and maximum")
)
// BlindedPayment provides the path and payment parameters required to send a
// payment along a blinded path.
type BlindedPayment struct {
// BlindedPath contains the unblinded introduction point and blinded
// hops for the blinded section of the payment.
BlindedPath *sphinx.BlindedPath
// BaseFee is the total base fee to be paid for payments made over the
// blinded path.
BaseFee uint32
// ProportionalFee is the aggregated proportional fee for payments
// made over the blinded path.
ProportionalFee uint32
// CltvExpiryDelta is the total expiry delta for the blinded path. Note
// this does not include the final cltv delta for the receiving node
// (which should be provided in an invoice).
CltvExpiryDelta uint16
// HtlcMinimum is the highest HLTC minimum supported along the blinded
// path (while some hops may have lower values, we're effectively
// bounded by the highest minimum).
HtlcMinimum uint64
// HtlcMaximum is the lowest HTLC maximum supported along the blinded
// path (while some hops may have higher values, we're effectively
// bounded by the lowest maximum).
HtlcMaximum uint64
// Features is the set of relay features available for the payment.
Features *lnwire.FeatureVector
}
// Validate performs validation on a blinded payment.
func (b *BlindedPayment) Validate() error {
if b.BlindedPath == nil {
return ErrNoBlindedPath
}
// The sphinx library inserts the introduction node as the first hop,
// so we expect at least one hop.
if len(b.BlindedPath.BlindedHops) < 1 {
return fmt.Errorf("%w got: %v", ErrInsufficientBlindedHops,
len(b.BlindedPath.BlindedHops))
}
if b.HtlcMaximum < b.HtlcMinimum {
return fmt.Errorf("%w: %v < %v", ErrHTLCRestrictions,
b.HtlcMaximum, b.HtlcMinimum)
}
return nil
}

70
routing/blinding_test.go Normal file
View file

@ -0,0 +1,70 @@
package routing
import (
"testing"
sphinx "github.com/lightningnetwork/lightning-onion"
"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)
})
}
}