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

draft: forward blinded payments #17

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
79bc0a5
gomod/replace: point to lightning-onion with blinded paths
carlaKC Oct 20, 2022
47402be
multi: add representation of blinded paths
carlaKC Jan 31, 2023
0a861a9
multi: add encrypted data and metadata to onion payload / hops
carlaKC Oct 26, 2022
e97d458
multi/refactor: add RouteRequest to hold FindRoute parameters
carlaKC Dec 19, 2022
5897e4d
multi: add blinded route to route requests expressed as hints
carlaKC Dec 15, 2022
49ee9a2
routing: account for blinded routes in fee calculation
carlaKC Dec 20, 2022
77eacb9
routing: only pack amount and cltv if populated
carlaKC Dec 20, 2022
3201fec
routing: include route blinding fields in blinded portion of path
carlaKC Dec 20, 2022
6e42212
lnrpc: surface blinding point and encrypted data in hops
carlaKC Dec 19, 2022
23f822c
lnrpc/refactor: move cltv delta calculation into function
carlaKC Dec 15, 2022
1e853a6
lnrpc/refactor: move query routes request parsing into method
carlaKC Dec 16, 2022
ac41974
lnrpc: add blinded payment to QueryRoutes request
carlaKC Dec 16, 2022
6aef946
lntest/itest: add coverage for querying routes to blinded paths
carlaKC Oct 31, 2022
03bb9bf
lntest: add coverage for single hop blinded route query routes
carlaKC Jan 19, 2023
47029e2
lncli: add blinded route cli flags to query routes
carlaKC Jan 25, 2023
5acc469
htlcswitch: remove unused decode hop iterator
carlaKC Nov 21, 2022
4e51c65
lnwire: create common encoder/decoder for raw feature vectors
carlaKC Feb 1, 2023
0388134
lnwire: add TLV encoding/decoding for blinded route data blobs
carlaKC Jun 14, 2022
f130b77
lnwire: add blinding point to update_add_htlc TLVs
carlaKC Jun 10, 2022
81a2ce8
multi: add blinding point to payment descriptor / use in hop decryption
carlaKC Nov 18, 2022
c335b86
lnwallet: set remote update log blinding point from pending
carlaKC Jan 27, 2023
88083d8
htlcswitch: add incoming amount and to decode hop iterator request
carlaKC Jan 27, 2023
194ad39
hop: add function for calculating forwarding amount
carlaKC Dec 14, 2022
6dbae85
multi: add validation of blinded route encrypted data
carlaKC Feb 1, 2023
edc6872
htlcswitch: add blinding kit to handle encrypted data in blinded routes
carlaKC Dec 14, 2022
85ec581
Htlcswitch: add NextBlinding to ForwardingInfo and set in UpdateAddHtlc
carlaKC Dec 21, 2022
659e8b5
htlcswitch: pass blinding kit to payload creation
carlaKC Jan 27, 2023
382c8cd
htlcswitch: add validation for blinded route payloads
carlaKC Nov 18, 2022
3c9aca8
htlcswitch: set forwarding information from encrypted data
carlaKC Nov 21, 2022
fa49ef8
multi: advertise route blinding feature bit
carlaKC Jan 25, 2023
32cbfe0
lntest: add setup for blinded route forwarding itest
carlaKC Dec 13, 2022
3280e54
lntest: add helper to create blinded route
carlaKC Dec 13, 2022
ba37cd9
lntest: add route construction to blinded forwarding test
carlaKC Dec 13, 2022
dc1a828
lntest: dispatch payment to blinded route
carlaKC Dec 14, 2022
4fb5e84
lntest: add interceptor to blinded forwarding test for workaround
carlaKC Dec 14, 2022
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%2Fgit.luolix.top%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 @@ -166,6 +166,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 @@ -403,8 +405,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.1.1 h1:Nsav0RlIDRbOnzz2Yu69SQlK939IKya3Q2S0mDviIN8=
github.com/lightningnetwork/lnd/cert v1.1.1/go.mod h1:1P46svkkd73oSoeI4zjkVKgZNwGq8bkGuPR8z+5vQUs=
github.com/lightningnetwork/lnd/cert v1.2.0 h1:IWfjHNMI5JgQZU5fdvDptF3DkVI38f4jO/s3tYgWFbE=
Expand Down Expand Up @@ -554,6 +554,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
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