multi: add blinded path TLVs to onion payload / hops
This commit adds the encrypted_data, blinding_point and total_amt_msat tlvs to the known set of even tlvs for the onion payload. These TLVs are added in two places (the onion payload and hop struct) because lnd uses the same set of TLV types for both structs (and they inherently represent the same thing). Note: in some places, unit tests intentionally mimic the style of older tests, so as to be more consistently readable.
This commit is contained in:
1 parent
539a275faa
commit
fee0e05708
7 files changed
+392
-23
No files matched your search
@@ -9,6 +9,7 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
@@ -1143,10 +1144,30 @@ func serializeHop(w io.Writer, h *route.Hop) error {
|
||||
records = append(records, h.MPP.Record())
|
||||
}
|
||||
|
||||
// Add blinding point and encrypted data if present.
|
||||
if h.EncryptedData != nil {
|
||||
records = append(records, record.NewEncryptedDataRecord(
|
||||
&h.EncryptedData,
|
||||
))
|
||||
}
|
||||
|
||||
if h.BlindingPoint != nil {
|
||||
records = append(records, record.NewBlindingPointRecord(
|
||||
&h.BlindingPoint,
|
||||
))
|
||||
}
|
||||
|
||||
if h.Metadata != nil {
|
||||
records = append(records, record.NewMetadataRecord(&h.Metadata))
|
||||
}
|
||||
|
||||
if h.TotalAmtMsat != 0 {
|
||||
totalMsatInt := uint64(h.TotalAmtMsat)
|
||||
records = append(
|
||||
records, record.NewTotalAmtMsatBlinded(&totalMsatInt),
|
||||
)
|
||||
}
|
||||
|
||||
// Final sanity check to absolutely rule out custom records that are not
|
||||
// custom and write into the standard range.
|
||||
if err := h.CustomRecords.Validate(); err != nil {
|
||||
@@ -1261,6 +1282,27 @@ func deserializeHop(r io.Reader) (*route.Hop, error) {
|
||||
h.MPP = mpp
|
||||
}
|
||||
|
||||
// If encrypted data or blinding key are present, remove them from
|
||||
// the TLV map and parse into proper types.
|
||||
encryptedDataType := uint64(record.EncryptedDataOnionType)
|
||||
if data, ok := tlvMap[encryptedDataType]; ok {
|
||||
delete(tlvMap, encryptedDataType)
|
||||
h.EncryptedData = data
|
||||
}
|
||||
|
||||
blindingType := uint64(record.BlindingPointOnionType)
|
||||
if blindingPoint, ok := tlvMap[blindingType]; ok {
|
||||
delete(tlvMap, blindingType)
|
||||
|
||||
h.BlindingPoint, err = btcec.ParsePubKey(blindingPoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid blinding point: %w",
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
// If the metatdata type is present, remove it from the tlv map and
|
||||
// populate directly on the hop.
|
||||
metadataType := uint64(record.MetadataOnionType)
|
||||
if metadata, ok := tlvMap[metadataType]; ok {
|
||||
delete(tlvMap, metadataType)
|
||||
@@ -1268,6 +1310,26 @@ func deserializeHop(r io.Reader) (*route.Hop, error) {
|
||||
h.Metadata = metadata
|
||||
}
|
||||
|
||||
totalAmtMsatType := uint64(record.TotalAmtMsatBlindedType)
|
||||
if totalAmtMsat, ok := tlvMap[totalAmtMsatType]; ok {
|
||||
delete(tlvMap, totalAmtMsatType)
|
||||
|
||||
var (
|
||||
totalAmtMsatInt uint64
|
||||
buf [8]byte
|
||||
)
|
||||
if err := tlv.DTUint64(
|
||||
bytes.NewReader(totalAmtMsat),
|
||||
&totalAmtMsatInt,
|
||||
&buf,
|
||||
uint64(len(totalAmtMsat)),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h.TotalAmtMsat = lnwire.MilliSatoshi(totalAmtMsatInt)
|
||||
}
|
||||
|
||||
h.CustomRecords = tlvMap
|
||||
|
||||
return h, nil
|
||||
|
||||
+41
-16
@@ -21,9 +21,10 @@ import (
|
||||
var (
|
||||
priv, _ = btcec.NewPrivateKey()
|
||||
pub = priv.PubKey()
|
||||
vertex = route.NewVertex(pub)
|
||||
|
||||
testHop1 = &route.Hop{
|
||||
PubKeyBytes: route.NewVertex(pub),
|
||||
PubKeyBytes: vertex,
|
||||
ChannelID: 12345,
|
||||
OutgoingTimeLock: 111,
|
||||
AmtToForward: 555,
|
||||
@@ -36,7 +37,7 @@ var (
|
||||
}
|
||||
|
||||
testHop2 = &route.Hop{
|
||||
PubKeyBytes: route.NewVertex(pub),
|
||||
PubKeyBytes: vertex,
|
||||
ChannelID: 12345,
|
||||
OutgoingTimeLock: 111,
|
||||
AmtToForward: 555,
|
||||
@@ -46,12 +47,39 @@ var (
|
||||
testRoute = route.Route{
|
||||
TotalTimeLock: 123,
|
||||
TotalAmount: 1234567,
|
||||
SourcePubKey: route.NewVertex(pub),
|
||||
SourcePubKey: vertex,
|
||||
Hops: []*route.Hop{
|
||||
testHop2,
|
||||
testHop1,
|
||||
},
|
||||
}
|
||||
|
||||
testBlindedRoute = route.Route{
|
||||
TotalTimeLock: 150,
|
||||
TotalAmount: 1000,
|
||||
SourcePubKey: vertex,
|
||||
Hops: []*route.Hop{
|
||||
{
|
||||
PubKeyBytes: vertex,
|
||||
ChannelID: 9876,
|
||||
OutgoingTimeLock: 120,
|
||||
AmtToForward: 900,
|
||||
EncryptedData: []byte{1, 3, 3},
|
||||
BlindingPoint: pub,
|
||||
},
|
||||
{
|
||||
PubKeyBytes: vertex,
|
||||
EncryptedData: []byte{3, 2, 1},
|
||||
},
|
||||
{
|
||||
PubKeyBytes: vertex,
|
||||
Metadata: []byte{4, 5, 6},
|
||||
AmtToForward: 500,
|
||||
OutgoingTimeLock: 100,
|
||||
TotalAmtMsat: 500,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func makeFakeInfo() (*PaymentCreationInfo, *HTLCAttemptInfo) {
|
||||
@@ -140,27 +168,24 @@ func assertRouteEqual(a, b *route.Route) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestRouteSerialization tests serialization of a regular and blinded route.
|
||||
func TestRouteSerialization(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSerializeRoute(t, testRoute)
|
||||
testSerializeRoute(t, testBlindedRoute)
|
||||
}
|
||||
|
||||
func testSerializeRoute(t *testing.T, route route.Route) {
|
||||
var b bytes.Buffer
|
||||
if err := SerializeRoute(&b, testRoute); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := SerializeRoute(&b, route)
|
||||
require.NoError(t, err)
|
||||
|
||||
r := bytes.NewReader(b.Bytes())
|
||||
route2, err := DeserializeRoute(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// First we verify all the records match up porperly, as they aren't
|
||||
// able to be properly compared using reflect.DeepEqual.
|
||||
err = assertRouteEqual(&testRoute, &route2)
|
||||
if err != nil {
|
||||
t.Fatalf("routes not equal: \n%v vs \n%v",
|
||||
spew.Sdump(testRoute), spew.Sdump(route2))
|
||||
}
|
||||
reflect.DeepEqual(route, route2)
|
||||
}
|
||||
|
||||
// deletePayment removes a payment with paymentHash from the payments database.
|
||||
|
||||
Reference in new issue
Block a user