-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
[1/3]: Preparatory work for Forwarding Blinded Routes #8159
[1/3]: Preparatory work for Forwarding Blinded Routes #8159
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice & clean! First pass done. Basically LGTM . Main comment is re potentially using the new tlv.RecordT
and tlv.OptionalRecordT
types for the various new tlv fields.
df54ade
to
3a492b2
Compare
Important Auto Review SkippedAuto reviews are limited to the following labels: llm-review. Please add one of these labels to enable auto reviews. Please check the settings in the CodeRabbit UI or the To trigger a single review, invoke the Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
Just pushed rebase + small fixups, looking into moving TLVs over to generics! |
@bitromortac: review reminder |
Just following up on my previous comment: I personally think it's fine for us to move ahead with the current structure of the new TLV fields. Better to stick to the current "standard" way and then leave the big re-hall of all TLV fields to another PR. Else we will need to reason about 2 different ways of doing the same thing. Let me know if you agree with this @carlaKC - then i'll re-request myself here for final review which I will prio asap 🚀 |
Started working on switching over to generics here, and I agree that It may not be worth trying to make this jump now. From what I can tell generics work isn't totally there, so it's a bit patchwork adding it in this PR IMO.
I'll rebase then re-request you, thanks!! |
3a492b2
to
221c533
Compare
221c533
to
8a37386
Compare
Nope, you can just serialize into a normal blob. Look at this commit where I encoded things into a normal blob: 784d236. It's just like before, you make a stream form the records, but now the attributes themselves are records.
You can make it from anything that implements record producer: Lines 34 to 44 in b0552da
Record() method, then that single struct can be re-used across any other attributes.
It's what we have right now, but doesn't at all appear to be a fundamental barrier. You can either revert back to using plain pointers, then be extra diligent about nil checks, use the existing utilities, or make your own along the way to mske things more egonomic. You can use In short, nothing you've mentioned appear to be a significant barrier. Particularly given that many of PRs and newly introduce sub-systems have started to use the new TLV records. I've pointed out areas where we can delete entire files, and also make |
a7e2c2a
to
b79ad5b
Compare
While I absolutely could have updated the PR to use generics without full confidence that it was the right decision as the author, I don't really think that's how we want to be writing code. I appreciate the time that you and @ellemouton have taken to point out where I've been wrong about my concerns, and have throughout this discussion made a good faith attempt to maintain a version that uses generics that I feel this comment conveniently handwaves away. I still have my reservations about directly porting rust primitives over to golang implementations, but I recognize that I should have reviewed the PRs in question if I wanted a vote. I have switched the series over to use generics - thanks in advance to reviewers for the extra round / apologies for making it necessary. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update to generics LGTM! Just left one suggestion that would reduce the number of lines changed a bit 👍
b79ad5b
to
116ce04
Compare
e47f0ca
to
b79f5a1
Compare
lnwire/update_add_htlc.go
Outdated
@@ -78,6 +78,19 @@ type UpdateAddHTLC struct { | |||
ExtraData ExtraOpaqueData | |||
} | |||
|
|||
// BlindingPointOrNil returns the blinding point associated with the update, or | |||
// nil. | |||
func (c *UpdateAddHTLC) BlindingPointOrNil() *btcec.PublicKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified to c.BlindingPoint.UnwrapOr(nil)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cannot use nil as tlv.RecordT[*tlv.tlvType0, *secp256k1.PublicKey] value in argument to htlc.BlindingPoint.UnwrapOr
?
iiuc we need two layers of unwrapping here to get the underlying type in the record rather than the type in the option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sure, had just glanced at that. Can also use WhenSomeV
instead here to avoid needing to deref Val
, but non-blocking ofc.
Philosophical point, but generally I like to review the option as sort of lazy evaluation, so you pipe it down all the way until you actually need to obtain the true value. Otherwise, by forcing evaluation sooner than needed, you just end up burdening the caller once again with required nil checks.
b79f5a1
to
3275c13
Compare
We'll need to pack feature vectors for route blinding, so we pull the encoding/decoding out into separate functions (currently contained in ChannelType). Though it's more lines of code, we keep most of the ChannelType assertions so that we strictly enforce use of the alias.
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.
Co-authored-by: Calvin Zachman <calvin.zachman@protonmail.com>
Add blinding points to update_add_htlc. This TLV will be set for nodes that are relaying payments in blinded routes that are _not_ the introduction node.
This commit adds an optional blinding point to payment descriptors and persists them in our HTLC's extra data. A get/set pattern is used to populate the ExtraData on our disk representation of the HTLC so that callers do not need to worry about the underlying storage detail.
When we have payments inside of a blinded route, we need to know the incoming amount to be able to back-calculate the amount that we need to forward using the forwarding parameters provided in the blinded route encrypted data. This commit adds the payment amount to our DecodeHopIteratorRequest so that it can be threaded down to payment forwarding information creation in later commits.
This field is incorrectly suffixed as "msat", when it is actually interpreted as the proportional fee rate. This is the value that we should be using because the sender will calculate proportional fees accordingly. This is a breaking change to the RPC, but on an experimental and unreleased API.
3275c13
to
2130022
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🦋
Nice work!
Left some non-blocking comments re slightly different wayts to use some of the new APIs. The other thing that jumped out is that we can get away with just writing/reading ExtraData
in a few more places to not have to worry about ensuring that all the new HTLC TLVs are properly written/read from disk. One example is when we add the endorsement bit directly or indirectly to lnd
, the logic now also needs to make sure that's passed along vs just passing the TLV
blob then leaving it to the caller at the last moment to unpack things. A similar comment applies to some of the option usage as well.
// Bolt 04 notes that we should enforce payment constraints _if_ they | ||
// are present, so we do not fail if not provided. | ||
var err error | ||
blindedData.Constraints.WhenSome( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Directly returning something here, so can be written as:
err := fn.MapOptionZ(blindedData.Contraints, func(c ...) error {
})
if err != nil {
}
Non-blocking. Similar instances below.
return fmt.Sprintf("chan_id=%v, id=%v, amt=%v, expiry=%v, hash=%x", | ||
msg.ChanID, msg.ID, msg.Amount, msg.Expiry, msg.PaymentHash[:]) | ||
var blindingPoint []byte | ||
msg.BlindingPoint.WhenSome( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be written as:
blindingPoint := fn.MapOptionz(msg.BlindingPoint, func(b ..) []byte {
return b.Val.SerializeCompressed()
})
Non-blocking.
@@ -2340,6 +2393,12 @@ func SerializeHtlcs(b io.Writer, htlcs ...HTLC) error { | |||
} | |||
|
|||
for _, htlc := range htlcs { | |||
// Populate TLV stream for any additional fields contained | |||
// in the TLV. | |||
if err := htlc.serializeExtraData(); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this information already be stored in ExtraData
if you just take the opaque bytes from the update add HTLC message? Since we code, but then keep the blob as is.
@@ -736,6 +744,14 @@ func (c *commitment) toDiskCommit(ourCommit bool) *channeldb.ChannelCommitment { | |||
Incoming: false, | |||
} | |||
copy(h.OnionBlob[:], htlc.OnionBlob) | |||
if htlc.BlindingPoint != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re above (and also related to future changes like storing the endorsement bit in an opaque manner), if we copied the extra records from the pay desc into this HTLC, then it's a more generic way to handle storing any future TLV data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we copied the extra records from the pay desc into this HTLC
def, but iirc from the original PR we wanted to be more intentional about what we store (ie, only things we care about) rather than including the full ExtraBytes
and wasting space if people send us random junk along with the HTLC.
@@ -859,6 +882,12 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight, | |||
theirWitnessScript: theirWitnessScript, | |||
} | |||
|
|||
htlc.BlindingPoint.WhenSome(func(b tlv.RecordT[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WhenSomeV
is useful here again as it gives you just *btcec.PublicKey
in this case.
@@ -3607,6 +3638,14 @@ func (lc *LightningChannel) createCommitDiff( | |||
PaymentHash: pd.RHash, | |||
} | |||
copy(htlc.OnionBlob[:], pd.OnionBlob) | |||
if pd.BlindingPoint != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar point here re just copying over the raw bytes so you don't need to be concerned about the record mapping at this state.
@@ -3736,12 +3775,21 @@ func (lc *LightningChannel) getUnsignedAckedUpdates() []channeldb.LogUpdate { | |||
// four messages that it corresponds to. | |||
switch pd.EntryType { | |||
case Add: | |||
var b lnwire.BlindingPointRecord | |||
if pd.BlindingPoint != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the pay desc just stores the record directly, then we also don't need to handle this shuffling.
@@ -520,9 +522,18 @@ func (h *htlcIncomingContestResolver) Supplement(htlc channeldb.HTLC) { | |||
func (h *htlcIncomingContestResolver) decodePayload() (*hop.Payload, | |||
[]byte, error) { | |||
|
|||
var blindingPoint *btcec.PublicKey | |||
h.htlc.BlindingPoint.WhenSome( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WhenSomeV
This PR is the first in a series to add the ability for LND to forward payments to blinded routes.
It contains a collection of prep work to get the codebase into shape for forwarding functionality:
encrypted_data
that is provided for blinded forwards.blinding_point
toupdate_add_htlc
and persist across restarts.Note: the ability to generate/receive payments via blinded routes is out of scope for these PRs.