Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route Blinding Error Handling #9

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
13ebb14
gomod/replace: point to lightning-onion with blinded paths
carlaKC Oct 20, 2022
1b71eb9
multi: add representation of blinded paths
carlaKC Jan 31, 2023
2c2db1b
multi: add encrypted data and metadata to onion payload / hops
carlaKC Oct 26, 2022
ee48aa1
multi/refactor: add RouteRequest to hold FindRoute parameters
carlaKC Dec 19, 2022
806b938
multi: add blinded route to route requests expressed as hints
carlaKC Dec 15, 2022
bc053ec
routing: account for blinded routes in fee calculation
carlaKC Dec 20, 2022
b5874cb
routing: only pack amount and cltv if populated
carlaKC Dec 20, 2022
c97c8b8
routing: include route blinding fields in blinded portion of path
carlaKC Dec 20, 2022
4e56578
lnrpc: surface blinding point and encrypted data in hops
carlaKC Dec 19, 2022
22009c0
lnrpc/refactor: move cltv delta calculation into function
carlaKC Dec 15, 2022
9fe7207
lnrpc/refactor: move query routes request parsing into method
carlaKC Dec 16, 2022
4cbc1cd
lnrpc: add blinded payment to QueryRoutes request
carlaKC Dec 16, 2022
1d6b902
lntest/itest: add coverage for querying routes to blinded paths
carlaKC Oct 31, 2022
dc4ed28
lntest: add coverage for single hop blinded route query routes
carlaKC Jan 19, 2023
67bfc14
lncli: add blinded route cli flags to query routes
carlaKC Jan 25, 2023
8e84019
htlcswitch: remove unused decode hop iterator
carlaKC Nov 21, 2022
5128a7a
lnwire: create common encoder/decoder for raw feature vectors
carlaKC Feb 1, 2023
a016fdb
lnwire: add TLV encoding/decoding for blinded route data blobs
carlaKC Jun 14, 2022
e0aa73c
lnwire: add blinding point to update_add_htlc TLVs
carlaKC Jun 10, 2022
0516082
multi: add blinding point to payment descriptor / use in hop decryption
carlaKC Nov 18, 2022
bcc0147
lnwallet: set remote update log blinding point from pending
carlaKC Jan 27, 2023
9f41db0
htlcswitch: add incoming amount and to decode hop iterator request
carlaKC Jan 27, 2023
0da4e52
hop: add function for calculating forwarding amount
carlaKC Dec 14, 2022
3cc2baa
multi: add validation of blinded route encrypted data
carlaKC Feb 1, 2023
591826a
htlcswitch: add blinding kit to handle encrypted data in blinded routes
carlaKC Dec 14, 2022
cdb55b9
Htlcswitch: add NextBlinding to ForwardingInfo and set in UpdateAddHtlc
carlaKC Dec 21, 2022
e3ac09c
htlcswitch: pass blinding kit to payload creation
carlaKC Jan 27, 2023
ad61996
htlcswitch: add validation for blinded route payloads
carlaKC Nov 18, 2022
249d83d
htlcswitch: set forwarding information from encrypted data
carlaKC Nov 21, 2022
8516df1
multi: advertise route blinding feature bit
carlaKC Jan 25, 2023
051ba8d
lntest: add setup for blinded route forwarding itest
carlaKC Dec 13, 2022
508b90e
lntest: add helper to create blinded route
carlaKC Dec 13, 2022
27144e1
lntest: add route construction to blinded forwarding test
carlaKC Dec 13, 2022
d08d9a5
lntest: dispatch payment to blinded route
carlaKC Dec 14, 2022
918ac69
lntest: add interceptor to blinded forwarding test for workaround
carlaKC Dec 14, 2022
6461181
record: add support for route blinding path_id
calvinrzachman Feb 6, 2023
58fa7f2
record+htlcswitch/hop: add validation of route blinding payload fields
calvinrzachman Feb 6, 2023
91536f6
lntest/itest: add path_id to final hop in blinded route
calvinrzachman Feb 6, 2023
8026d7a
htlcswitch/hop: add validation of required fields for blind hops
calvinrzachman Dec 30, 2022
d704587
htlcswitch/hop: provide slightly more descriptive message for errors …
calvinrzachman Jan 23, 2023
f3c104d
htlcswitch/hop: add cross payload validation tests
calvinrzachman Jan 26, 2023
6e32fd2
htlcswitch/hop: allow MPP record for final blind hop.
calvinrzachman Jan 26, 2023
0b2e6b7
lntest: update blinded forwarding to settle with receiver
calvinrzachman Dec 29, 2022
76d722c
temp: port over HTLC retransmit/recover tests
calvinrzachman Mar 30, 2023
e61e90a
temp: demonstrate we can recover blinding point from persisted pendin…
calvinrzachman Nov 28, 2022
c155dad
temp: demonstrate we can recover blinding point from persisted fwdpkg…
calvinrzachman Mar 30, 2023
e1f7378
lnwire: define `InvalidOnionBlinding` failure code onion error
calvinrzachman Sep 22, 2022
cfc450b
multi: add error handling for blinded routes
calvinrzachman Apr 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions channeldb/payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1172,6 +1173,19 @@ 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))
}
Expand Down Expand Up @@ -1290,6 +1304,28 @@ 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)
Expand Down
6 changes: 4 additions & 2 deletions channeldb/payments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ var (
65536: []byte{},
80001: []byte{},
},
MPP: record.NewMPP(32, [32]byte{0x42}),
Metadata: []byte{1, 2, 3},
MPP: record.NewMPP(32, [32]byte{0x42}),
Metadata: []byte{1, 2, 3},
EncryptedData: []byte{3, 2, 1},
BlindingPoint: pub,
}

testHop2 = &route.Hop{
Expand Down
143 changes: 143 additions & 0 deletions cmd/lncli/cmd_payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,45 @@ var (
Name: "time_pref",
Usage: "(optional) expresses time preference (range -1 to 1)",
}

introductionNodeFlag = cli.StringFlag{
Name: "introduction_point",
Usage: "the hex encoded, cleartext node ID of the node to " +
"use for queries to a blinded route",
}

blindingPointFlag = cli.StringFlag{
Name: "blinding_point",
Usage: "the hex encoded blinding point to use if querying a " +
"route to a blinded path, this value *must* be set " +
"for queries to a blinded path",
}

blindedHopsFlag = cli.StringSliceFlag{
Name: "blinded_hops",
Usage: "the blinded hops to include in the query, formatted " +
"as <blinded_node_id>:<hex_encrypted_data>. These " +
"hops must be provided *in order* starting with the " +
"introduction point and ending with the receiving node",
}

blindedBaseFlag = cli.Uint64Flag{
Name: "blinded_base_fee",
Usage: "the aggregate base fee for the blinded portion of " +
"the route, expressed in msat",
}

blindedPPMFlag = cli.Uint64Flag{
Name: "blinded_ppm_fee",
Usage: "the aggregate proportional fee for the blinded " +
"portion of the route, expressed in parts per million",
}

blindedCLTVFlag = cli.Uint64Flag{
Name: "blinded_cltv",
Usage: "the total cltv delay for the blinded portion of the " +
"route",
}
)

// paymentFlags returns common flags for sendpayment and payinvoice.
Expand Down Expand Up @@ -1050,6 +1089,12 @@ var queryRoutesCommand = cli.Command{
},
timePrefFlag,
cltvLimitFlag,
introductionNodeFlag,
blindingPointFlag,
blindedHopsFlag,
blindedBaseFlag,
blindedPPMFlag,
blindedCLTVFlag,
},
Action: actionDecorator(queryRoutes),
}
Expand All @@ -1070,9 +1115,15 @@ func queryRoutes(ctx *cli.Context) error {
switch {
case ctx.IsSet("dest"):
dest = ctx.String("dest")

case args.Present():
dest = args.First()
args = args.Tail()

// If we have a blinded path set, we don't have to specify a
// destination.
case ctx.IsSet(introductionNodeFlag.Name):

default:
return fmt.Errorf("dest argument missing")
}
Expand Down Expand Up @@ -1119,6 +1170,11 @@ func queryRoutes(ctx *cli.Context) error {
}
}

blindedRoute, err := parseBlindedPaymentParameters(ctx)
if err != nil {
return err
}

req := &lnrpc.QueryRoutesRequest{
PubKey: dest,
Amt: amt,
Expand All @@ -1129,6 +1185,7 @@ func queryRoutes(ctx *cli.Context) error {
OutgoingChanId: ctx.Uint64("outgoing_chanid"),
TimePref: ctx.Float64(timePrefFlag.Name),
IgnoredPairs: ignoredPairs,
BlindedPath: blindedRoute,
}

route, err := client.QueryRoutes(ctxc, req)
Expand All @@ -1140,6 +1197,92 @@ func queryRoutes(ctx *cli.Context) error {
return nil
}

func parseBlindedPaymentParameters(ctx *cli.Context) (*lnrpc.BlindedPayment,
error) {

// If none of the blinded route params are set as we expect, then we
// don't need to return anything.
haveBlinded := ctx.IsSet(blindingPointFlag.Name) ||
ctx.IsSet(blindedHopsFlag.Name) ||
ctx.IsSet(introductionNodeFlag.Name) ||
ctx.IsSet(blindedBaseFlag.Name) ||
ctx.IsSet(blindedPPMFlag.Name) ||
ctx.IsSet(blindedCLTVFlag.Name)

if !haveBlinded {
return nil, nil
}

// If any one of our blinding related flags is set, we expect the
// full set to be set and we'll error our accordingly.
introNode, err := route.NewVertexFromStr(
ctx.String(introductionNodeFlag.Name),
)
if err != nil {
return nil, fmt.Errorf("decode introduction node: %w", err)
}

blindingPoint, err := route.NewVertexFromStr(ctx.String(
blindingPointFlag.Name,
))
if err != nil {
return nil, fmt.Errorf("decode blinding point: %w", err)
}

blindedHops := ctx.StringSlice(blindedHopsFlag.Name)

pmt := &lnrpc.BlindedPayment{
Route: &lnrpc.BlindedRoute{
IntroductionNode: introNode[:],
BlindingPoint: blindingPoint[:],
BlindedHops: make(
[]*lnrpc.BlindedHop, len(blindedHops),
),
},
RelayParameters: &lnrpc.BlindedRelay{
AggregateBaseFeeMsat: ctx.Uint64(
blindedBaseFlag.Name,
),
AggregateProportionalFeePpm: ctx.Uint64(
blindedPPMFlag.Name,
),
TotalCltvDelta: uint32(ctx.Uint64(
blindedCLTVFlag.Name,
)),
},
RelayConstraints: &lnrpc.BlindedConstraints{
CltvLimit: uint32(ctx.Uint(cltvLimitFlag.Name)),
},
}

for i, hop := range blindedHops {
parts := strings.Split(hop, ":")
if len(parts) != 2 {
return nil, fmt.Errorf("blinded hops should be "+
"expressed as "+
"blinded_node_id:hex_encrypted_data, got: %v",
hop)
}

hop, err := route.NewVertexFromStr(parts[0])
if err != nil {
return nil, fmt.Errorf("hop: %v node: %w", i, err)
}

data, err := hex.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("hop: %v data: %w", i, err)
}

pmt.Route.BlindedHops[i] = &lnrpc.BlindedHop{
BlindedNode: hop[:],
EncryptedData: data,
}
}

return pmt, nil
}

// retrieveFeeLimitLegacy retrieves the fee limit based on the different fee
// limit flags passed. This function will eventually disappear in favor of
// retrieveFeeLimit and the new payment rpc.
Expand Down
7 changes: 7 additions & 0 deletions feature/default_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ var defaultSetDesc = setDesc{
SetInit: {}, // I
SetNodeAnn: {}, // N
},
// Note: we set route blinding optionally in our init and announcement,
// but not yet in invoices (9) as the spec instructs because we do not
// yet support receiving payments to blinded routes, only relaying them.
lnwire.RouteBlindingOptional: {
SetInit: {}, // I
SetNodeAnn: {}, // N
},
lnwire.WumboChannelsOptional: {
SetInit: {}, // I
SetNodeAnn: {}, // N
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ replace github.com/ulikunitz/xz => github.com/ulikunitz/xz v0.5.8
// https://deps.dev/advisory/OSV/GO-2021-0053?from=%2Fgo%2Fgithub.com%252Fgogo%252Fprotobuf%2Fv1.3.1
replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2

// This replace points us to a version of lightning-onion that supports
// route blinding (PR #57).
replace github.com/lightningnetwork/lightning-onion => github.com/ellemouton/lightning-onion v1.2.1-0.20230126071019-d0b521d925bc

// If you change this please also update .github/pull_request_template.md and
// docs/INSTALL.md.
go 1.18
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5Jflh
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/ellemouton/lightning-onion v1.2.1-0.20230126071019-d0b521d925bc h1:xoaOgdPBeiNDqbAQ12JzAA6WYettqXTvuOh4Urz+uOA=
github.com/ellemouton/lightning-onion v1.2.1-0.20230126071019-d0b521d925bc/go.mod h1:IpXmxKG482HAQC/aCn0Sd+DYmKlkfaNF/iUz298HhC0=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
Expand Down Expand Up @@ -404,8 +406,6 @@ github.com/lightninglabs/neutrino v0.14.2 h1:yrnZUCYMZ5ECtXhgDrzqPq2oX8awoAN2D/c
github.com/lightninglabs/neutrino v0.14.2/go.mod h1:OICUeTCn+4Tu27YRJIpWvvqySxx4oH4vgdP33Sw9RDc=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display h1:RZJ8H4ueU/aQ9pFtx5wqsuD3B/DezrewJeVwDKKYY8E=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display/go.mod h1:2oKOBU042GKFHrdbgGiKax4xVrFiZu51lhacUZQ9MnE=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20221202012345-ca23184850a1 h1:Wm0g70gkcAu2pGpNZwfWPSVOY21j8IyYsNewwK4OkT4=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20221202012345-ca23184850a1/go.mod h1:7dDx73ApjEZA0kcknI799m2O5kkpfg4/gr7N092ojNo=
github.com/lightningnetwork/lnd/cert v1.2.0 h1:IWfjHNMI5JgQZU5fdvDptF3DkVI38f4jO/s3tYgWFbE=
github.com/lightningnetwork/lnd/cert v1.2.0/go.mod h1:04JhIEodoR6usBN5+XBRtLEEmEHsclLi0tEyxZQNP+w=
github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg=
Expand Down Expand Up @@ -553,6 +553,7 @@ github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02 h1:tcJ6OjwOMvExLlzrAV
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY=
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
Expand Down
5 changes: 5 additions & 0 deletions htlcswitch/circuit.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ func newPaymentCircuit(hash *[32]byte, pkt *htlcPacket) *PaymentCircuit {
PaymentHash: *hash,
IncomingAmount: pkt.incomingAmount,
OutgoingAmount: pkt.amount,
// NOTE(4/1/23): this payment circuit will be constructed with
// an obfuscator (key) built using the blinding point.
// It does not mean that we can recover the blinding point.
// Only, that we should be using the correct key for
// error encryption for both normal and blind hops.
ErrorEncrypter: pkt.obfuscator,
}
}
Expand Down
4 changes: 4 additions & 0 deletions htlcswitch/circuit_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,10 @@ func (cm *circuitMap) decodeCircuit(v []byte) (*PaymentCircuit, error) {

// Otherwise, we need to reextract the encrypter, so that the shared
// secret is rederived from what was decoded.
//
// NOTE(4/1/23): The CircuitMap is configured with the method by which
// it extracts error encryptors. The method is not pinned to the implementation
// and as a result is more easily changeable?
err := circuit.ErrorEncrypter.Reextract(
cm.cfg.ExtractErrorEncrypter,
)
Expand Down
11 changes: 10 additions & 1 deletion htlcswitch/circuit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,15 @@ func initTestExtracter() {
onionProcessor := newOnionProcessor(nil)
defer onionProcessor.Stop()

// NOTE(4/1/23): Done this way, we have to have the blinding point
// We have an aspect of the error encryptor which does NOT change
// depending on whether the HTLC is normal or blind (our node ID key),
// and we have an aspect which DOES change depending on whether the HTLC
// is normal or blind (the blinding point). When do we want the mixing of
// blinding with node ID key pair to take place in the context of error
// encryption?
obfuscator, _ := onionProcessor.ExtractErrorEncrypter(
testEphemeralKey,
testEphemeralKey, nil,
)

sphinxExtracter, ok := obfuscator.(*hop.SphinxErrorEncrypter)
Expand Down Expand Up @@ -215,6 +222,8 @@ func TestHalfCircuitSerialization(t *testing.T) {
// reextract it from it's decoded state, as this requires an
// ECDH with the onion processor's private key. For mock error
// encrypters, this will be a NOP.
//
// NOTE(4/1/23): Consider this comment.
if circuit2.ErrorEncrypter != nil {
err := circuit2.ErrorEncrypter.Reextract(
onionProcessor.ExtractErrorEncrypter,
Expand Down
9 changes: 6 additions & 3 deletions htlcswitch/hop/error_encryptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ const (

// ErrorEncrypterExtracter defines a function signature that extracts an
// ErrorEncrypter from an sphinx OnionPacket.
type ErrorEncrypterExtracter func(*btcec.PublicKey) (ErrorEncrypter,
lnwire.FailCode)
//
// NOTE(4/1/23): We have updated this to take a second public key
// representing the ephemeral blinding point for blinded routes.
type ErrorEncrypterExtracter func(*btcec.PublicKey,
*btcec.PublicKey) (ErrorEncrypter, lnwire.FailCode)

// ErrorEncrypter is an interface that is used to encrypt HTLC related errors
// at the source of the error, and also at each intermediate hop all the way
Expand Down Expand Up @@ -179,7 +182,7 @@ func (s *SphinxErrorEncrypter) Decode(r io.Reader) error {
func (s *SphinxErrorEncrypter) Reextract(
extract ErrorEncrypterExtracter) error {

obfuscator, failcode := extract(s.EphemeralKey)
obfuscator, failcode := extract(s.EphemeralKey, nil)
if failcode != lnwire.CodeNone {
// This should never happen, since we already validated that
// this obfuscator can be extracted when it was received in the
Expand Down
6 changes: 6 additions & 0 deletions htlcswitch/hop/forwarding_info.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package hop

import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightningnetwork/lnd/lnwire"
)

Expand All @@ -26,4 +27,9 @@ type ForwardingInfo struct {
// OutgoingCTLV is the specified value of the CTLV timelock to be used
// in the outgoing HTLC.
OutgoingCTLV uint32

// NextBlinding is an optional blinding point to be passed to the next
// node in UpdateAddHtlc. This field is set if the htlc is part of a
// blinded route.
NextBlinding *btcec.PublicKey
}
Loading