[1/3]: Preparatory work for Forwarding Blinded Routes#8159
[1/3]: Preparatory work for Forwarding Blinded Routes#8159Roasbeef merged 14 commits intolightningnetwork:masterfrom
Conversation
ellemouton
left a comment
There was a problem hiding this comment.
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. |
ellemouton
left a comment
There was a problem hiding this comment.
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
There was a problem hiding this comment.
This can be simplified to c.BlindingPoint.UnwrapOr(nil).
There was a problem hiding this comment.
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.
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
Roasbeef
left a comment
There was a problem hiding this comment.
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.
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.
Can be written as:
blindingPoint := fn.MapOptionz(msg.BlindingPoint, func(b ..) []byte {
return b.Val.SerializeCompressed()
})Non-blocking.
| 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.
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.
| Incoming: false, | ||
| } | ||
| copy(h.OnionBlob[:], htlc.OnionBlob) | ||
| if htlc.BlindingPoint != nil { |
There was a problem hiding this comment.
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.
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.
| theirWitnessScript: theirWitnessScript, | ||
| } | ||
|
|
||
| htlc.BlindingPoint.WhenSome(func(b tlv.RecordT[ |
There was a problem hiding this comment.
WhenSomeV is useful here again as it gives you just *btcec.PublicKey in this case.
| PaymentHash: pd.RHash, | ||
| } | ||
| copy(htlc.OnionBlob[:], pd.OnionBlob) | ||
| if pd.BlindingPoint != nil { |
There was a problem hiding this comment.
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.
| switch pd.EntryType { | ||
| case Add: | ||
| var b lnwire.BlindingPointRecord | ||
| if pd.BlindingPoint != nil { |
There was a problem hiding this comment.
If the pay desc just stores the record directly, then we also don't need to handle this shuffling.
| []byte, error) { | ||
|
|
||
| var blindingPoint *btcec.PublicKey | ||
| h.htlc.BlindingPoint.WhenSome( |
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_datathat is provided for blinded forwards.blinding_pointtoupdate_add_htlcand persist across restarts.Note: the ability to generate/receive payments via blinded routes is out of scope for these PRs.