record: add TLV encoding/decoding for blinded route data blobs
This commit adds encoding and decoding for blinded route data blobs. TLV fields such as path_id (which are only used for the final hop) are omitted to minimize the change size.
This commit is contained in:
3 files changed
+545
No files matched your search
@@ -0,0 +1,197 @@
|
||||
package record
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
//nolint:lll
|
||||
const pubkeyStr = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619"
|
||||
|
||||
func pubkey(t *testing.T) *btcec.PublicKey {
|
||||
t.Helper()
|
||||
|
||||
nodeBytes, err := hex.DecodeString(pubkeyStr)
|
||||
require.NoError(t, err)
|
||||
|
||||
nodePk, err := btcec.ParsePubKey(nodeBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
return nodePk
|
||||
}
|
||||
|
||||
// TestBlindedDataEncoding tests encoding and decoding of blinded data blobs.
|
||||
// These tests specifically cover cases where the variable length encoded
|
||||
// integers values have different numbers of leading zeros trimmed because
|
||||
// these TLVs are the first composite records with variable length tlvs
|
||||
// (previously, a variable length integer would take up the whole record).
|
||||
func TestBlindedDataEncoding(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
baseFee uint32
|
||||
htlcMin lnwire.MilliSatoshi
|
||||
features *lnwire.FeatureVector
|
||||
constraints bool
|
||||
}{
|
||||
{
|
||||
name: "zero variable values",
|
||||
baseFee: 0,
|
||||
htlcMin: 0,
|
||||
},
|
||||
{
|
||||
name: "zeros trimmed",
|
||||
baseFee: math.MaxUint32 / 2,
|
||||
htlcMin: math.MaxUint64 / 2,
|
||||
},
|
||||
{
|
||||
name: "no zeros trimmed",
|
||||
baseFee: math.MaxUint32,
|
||||
htlcMin: math.MaxUint64,
|
||||
},
|
||||
{
|
||||
name: "nil feature vector",
|
||||
features: nil,
|
||||
},
|
||||
{
|
||||
name: "non-nil, but empty feature vector",
|
||||
features: lnwire.EmptyFeatureVector(),
|
||||
},
|
||||
{
|
||||
name: "populated feature vector",
|
||||
features: lnwire.NewFeatureVector(
|
||||
lnwire.NewRawFeatureVector(lnwire.AMPOptional),
|
||||
lnwire.Features,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "no payment constraints",
|
||||
constraints: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range tests {
|
||||
testCase := testCase
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a standard set of blinded route data, using
|
||||
// the values from our test case for the variable
|
||||
// length encoded values.
|
||||
channelID := lnwire.NewShortChanIDFromInt(1)
|
||||
info := PaymentRelayInfo{
|
||||
FeeRate: 2,
|
||||
CltvExpiryDelta: 3,
|
||||
BaseFee: testCase.baseFee,
|
||||
}
|
||||
|
||||
var constraints *PaymentConstraints
|
||||
if testCase.constraints {
|
||||
constraints = &PaymentConstraints{
|
||||
MaxCltvExpiry: 4,
|
||||
HtlcMinimumMsat: testCase.htlcMin,
|
||||
}
|
||||
}
|
||||
|
||||
encodedData := NewBlindedRouteData(
|
||||
channelID, pubkey(t), info, constraints,
|
||||
testCase.features,
|
||||
)
|
||||
|
||||
encoded, err := EncodeBlindedRouteData(encodedData)
|
||||
require.NoError(t, err)
|
||||
|
||||
b := bytes.NewBuffer(encoded)
|
||||
decodedData, err := DecodeBlindedRouteData(b)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, encodedData, decodedData)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestBlindedRouteVectors tests encoding/decoding of the test vectors for
|
||||
// blinded route data provided in the specification.
|
||||
//
|
||||
//nolint:lll
|
||||
func TestBlindingSpecTestVectors(t *testing.T) {
|
||||
nextBlindingOverrideStr, err := hex.DecodeString("031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f")
|
||||
require.NoError(t, err)
|
||||
nextBlindingOverride, err := btcec.ParsePubKey(nextBlindingOverrideStr)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
encoded string
|
||||
expectedPaymentData *BlindedRouteData
|
||||
}{
|
||||
{
|
||||
encoded: "011a0000000000000000000000000000000000000000000000000000020800000000000006c10a0800240000009627100c06000b69e505dc0e00fd023103123456",
|
||||
expectedPaymentData: NewBlindedRouteData(
|
||||
lnwire.ShortChannelID{
|
||||
BlockHeight: 0,
|
||||
TxIndex: 0,
|
||||
TxPosition: 1729,
|
||||
},
|
||||
nil,
|
||||
PaymentRelayInfo{
|
||||
CltvExpiryDelta: 36,
|
||||
FeeRate: 150,
|
||||
BaseFee: 10000,
|
||||
},
|
||||
&PaymentConstraints{
|
||||
MaxCltvExpiry: 748005,
|
||||
HtlcMinimumMsat: 1500,
|
||||
},
|
||||
lnwire.NewFeatureVector(
|
||||
lnwire.NewRawFeatureVector(),
|
||||
lnwire.Features,
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
encoded: "020800000000000004510821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0a0800300000006401f40c06000b69c105dc0e00",
|
||||
expectedPaymentData: NewBlindedRouteData(
|
||||
lnwire.ShortChannelID{
|
||||
TxPosition: 1105,
|
||||
},
|
||||
nextBlindingOverride,
|
||||
PaymentRelayInfo{
|
||||
CltvExpiryDelta: 48,
|
||||
FeeRate: 100,
|
||||
BaseFee: 500,
|
||||
},
|
||||
&PaymentConstraints{
|
||||
MaxCltvExpiry: 747969,
|
||||
HtlcMinimumMsat: 1500,
|
||||
},
|
||||
lnwire.NewFeatureVector(
|
||||
lnwire.NewRawFeatureVector(),
|
||||
lnwire.Features,
|
||||
)),
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
route, err := hex.DecodeString(test.encoded)
|
||||
require.NoError(t, err)
|
||||
|
||||
buff := bytes.NewBuffer(route)
|
||||
|
||||
decodedRoute, err := DecodeBlindedRouteData(buff)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(
|
||||
t, test.expectedPaymentData, decodedRoute,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user