record: add NextNodeID type to BlindedRouteData

Add the NextNodeID TLV (tlv type 4) to the BlindedRouteData TLV stream.
This will be used during the dummy hop payload construction.
This commit is contained in:
Elle Mouton 2024-07-10 09:59:47 +02:00
parent 9192c165ff
commit 62a97f86dd
No known key found for this signature in database
GPG key ID: D7D916376026F177
2 changed files with 70 additions and 2 deletions

View file

@ -22,6 +22,11 @@ type BlindedRouteData struct {
// ShortChannelID is the channel ID of the next hop.
ShortChannelID tlv.OptionalRecordT[tlv.TlvType2, lnwire.ShortChannelID]
// NextNodeID is the node ID of the next node on the path. In the
// context of blinded path payments, this is used to indicate the
// presence of dummy hops that need to be peeled from the onion.
NextNodeID tlv.OptionalRecordT[tlv.TlvType4, *btcec.PublicKey]
// PathID is a secret set of bytes that the blinded path creator will
// set so that they can check the value on decryption to ensure that the
// path they created was used for the intended purpose.
@ -98,6 +103,26 @@ func NewFinalHopBlindedRouteData(constraints *PaymentConstraints,
return &data
}
// NewDummyHopRouteData creates the data that's provided for any hop preceding
// a dummy hop. The presence of such a payload indicates to the reader that
// they are the intended recipient and should peel the remainder of the onion.
func NewDummyHopRouteData(ourPubKey *btcec.PublicKey,
relayInfo PaymentRelayInfo,
constraints PaymentConstraints) *BlindedRouteData {
return &BlindedRouteData{
NextNodeID: tlv.SomeRecordT(
tlv.NewPrimitiveRecord[tlv.TlvType4](ourPubKey),
),
RelayInfo: tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType10](relayInfo),
),
Constraints: tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType12](constraints),
),
}
}
// DecodeBlindedRouteData decodes the data provided within a blinded route.
func DecodeBlindedRouteData(r io.Reader) (*BlindedRouteData, error) {
var (
@ -105,6 +130,7 @@ func DecodeBlindedRouteData(r io.Reader) (*BlindedRouteData, error) {
padding = d.Padding.Zero()
scid = d.ShortChannelID.Zero()
nextNodeID = d.NextNodeID.Zero()
pathID = d.PathID.Zero()
blindingOverride = d.NextBlindingOverride.Zero()
relayInfo = d.RelayInfo.Zero()
@ -118,8 +144,8 @@ func DecodeBlindedRouteData(r io.Reader) (*BlindedRouteData, error) {
}
typeMap, err := tlvRecords.ExtractRecords(
&padding, &scid, &pathID, &blindingOverride, &relayInfo,
&constraints, &features,
&padding, &scid, &nextNodeID, &pathID, &blindingOverride,
&relayInfo, &constraints, &features,
)
if err != nil {
return nil, err
@ -134,6 +160,10 @@ func DecodeBlindedRouteData(r io.Reader) (*BlindedRouteData, error) {
d.ShortChannelID = tlv.SomeRecordT(scid)
}
if val, ok := typeMap[d.NextNodeID.TlvType()]; ok && val == nil {
d.NextNodeID = tlv.SomeRecordT(nextNodeID)
}
if val, ok := typeMap[d.PathID.TlvType()]; ok && val == nil {
d.PathID = tlv.SomeRecordT(pathID)
}
@ -175,6 +205,12 @@ func EncodeBlindedRouteData(data *BlindedRouteData) ([]byte, error) {
recordProducers = append(recordProducers, &scid)
})
data.NextNodeID.WhenSome(func(f tlv.RecordT[tlv.TlvType4,
*btcec.PublicKey]) {
recordProducers = append(recordProducers, &f)
})
data.PathID.WhenSome(func(pathID tlv.RecordT[tlv.TlvType6, []byte]) {
recordProducers = append(recordProducers, &pathID)
})

View file

@ -171,6 +171,38 @@ func TestBlindedDataFinalHopEncoding(t *testing.T) {
}
}
// TestDummyHopBlindedDataEncoding tests the encoding and decoding of a blinded
// data blob intended for hops preceding a dummy hop in a blinded path. These
// hops provide the reader with a signal that the next hop may be a dummy hop.
func TestDummyHopBlindedDataEncoding(t *testing.T) {
t.Parallel()
priv, err := btcec.NewPrivateKey()
require.NoError(t, err)
info := PaymentRelayInfo{
FeeRate: 2,
CltvExpiryDelta: 3,
BaseFee: 30,
}
constraints := PaymentConstraints{
MaxCltvExpiry: 4,
HtlcMinimumMsat: 100,
}
routeData := NewDummyHopRouteData(priv.PubKey(), info, constraints)
encoded, err := EncodeBlindedRouteData(routeData)
require.NoError(t, err)
b := bytes.NewBuffer(encoded)
decodedData, err := DecodeBlindedRouteData(b)
require.NoError(t, err)
require.Equal(t, routeData, decodedData)
}
// TestBlindedRouteDataPadding tests the PadBy method of BlindedRouteData.
func TestBlindedRouteDataPadding(t *testing.T) {
newBlindedRouteData := func() *BlindedRouteData {