-
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
rpc+htlcswitch: add htlc transformation capabilities to the interceptor #8633
rpc+htlcswitch: add htlc transformation capabilities to the interceptor #8633
Conversation
Important Auto Review SkippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting 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 (
|
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 how small this turned out. Just did a quick scan out of interest, not a deep review.
60596eb
to
c5d25a8
Compare
There are two things left to do here:
I would be keen on feedback on what I have so far to check that I'm still on the right track. Note that I couldn't include the It seems to me that much of package |
c5d25a8
to
071d8f7
Compare
|
071d8f7
to
2d70c13
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.
Did a first pass. Looks good, mostly nits 🎉
2d70c13
to
c91e771
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.
Getting super close!
5ccbc21
to
f73c885
Compare
New message encode/decode changes are in place. Still need to modify |
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.
Looks very good!
Just a couple of suggestions to remove code duplication, increase clarity and re-usability.
lnwire/custom_records.go
Outdated
|
||
// NewCustomRecordsFromTlvTypeMap creates a new CustomRecords instance from a | ||
// tlv.TypeMap. | ||
func NewCustomRecordsFromTlvTypeMap(tlvMap tlv.TypeMap) (*CustomRecords, |
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.
Why do we need a completely new type? Can't we just create a ValidateCustomTypes(tlvMap tlv.TypeMap)
function that does this? Especially since this is more or less an exact copy of the record.CustomSet
type as well.
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.
We don't need to introduce a new type; however, it aids in specifying permissible values for the type. The tlv.TypeMap
is insufficiently restrictive. By incorporating the lnwire.CustomRecords
type, we can directly annotate valid map keys within the type definition itself, rather than relegating this information to a separate ValidateCustomTypes
function.
I think a new type might also add clarity as a function argument.
(We can't use record.CustomSet
in lnwire
because of an import cycle.)
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.
Why do we frequently choose a more generic type (tlv.TypeMap
) that lacks the necessary restrictiveness, over a more specific type (lnwire.CustomRecords
)? IMO, this practice often results in missed opportunities for documentation. Using overly generic types in function signatures makes them harder to understand and decreases code clarity. Opting for more specific types can enhance both documentation and code readability.
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.
Why do we frequently choose a more generic type (tlv.TypeMap) that lacks the necessary restrictiveness
I think it's generally not the best idea to have too much business/protocol logic in the wire/encoding level, as that reduces the re-usability. I know that shifts the responsibility of validating the content to the caller. But should a wire message really be dictating what its content should be, rather than focusing on how to encode the content?
To me the encoding function as it looks now mostly distracts from what we actually do: merging two sets of TLV records into a single encoded blob.
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.
We have to ensure that the TLV types we're merging from custom records don't mess with any future protocol extensions which might add new TLV types. In other words, we need to make sure that the custom records TLV types are >= 65536
. Are you saying we shouldn't enforce that at the point of encoding in lnwire
?
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.
I've added a method called CustomRecords.ExtendRecordProducers
which moves the protocol logic to the CustomRecords
type away from the UpdateAddHtlc.Encode
method.
264e2cb
to
0f5ec6b
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.
A bit more bike shedding around custom types and validation, but the rest looks good to me!
lnwire/update_add_htlc.go
Outdated
crRecords := tlv.MapToRecords(c.CustomRecords) | ||
for _, record := range crRecords { | ||
r := recordProducer{record} | ||
records = append(records, &r) | ||
} |
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're going with a custom type, then this could be a method on it.
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.
I've moved this to a new method called CustomRecords.ExtendRecordProducers
. Let me know what you think.
lnwire/update_add_htlc.go
Outdated
for _, recordProducer := range records { | ||
record := recordProducer.Record() | ||
recordTlvType := uint64(record.Type()) | ||
|
||
if recordTlvType >= MinCustomRecordsTlvType { | ||
return fmt.Errorf("records contain TLV type that is "+ | ||
"unexpectedly greater than or equal to the "+ | ||
"minimum TLV type of custom records: %d", | ||
recordTlvType) | ||
} | ||
} |
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.
What if we ever want to encode a "known" custom type here? Then this validation would disallow it. I think what we want to check instead is just that we don't get any collisions between the known records and the custom ones added by the interceptor.
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.
I've added a new method called CustomRecords.ExtendRecordProducers
which uses the validation that you suggest. It simply checks for no collisions. The records
slice can contain high TLV types even before extending with records from CustomRecords
.
9e9e4d4
to
9091805
Compare
9091805
to
d89df52
Compare
62f93d9
to
b5a7696
Compare
b5a7696
to
1e0ea65
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.
Looks good once the new unit test failure has been addressed.
01587b2
to
5d3458f
Compare
This commit introduces the `CustomRecords` type in the `lnwire` package, designed to hold arbitrary byte slices. Each entry in this map can associate with TLV type values that are greater than or equal to 65536.
- Add instance constructor `NewExtraOpaqueDataFromTlvTypeMap`. - Add method `Copy`. - Add method `RecordProducers`.
- Introduce the field `CustomRecords` to the type `UpdateAddHtlc`. - Encode and decode the new field into the `ExtraData` field of the `update_add_htlc` wire message.
This commit adds a random `CustomRecords` field to the `UpdateAddHTLC` message encode/decode unit test.
- Introduce the field `CustomRecords` to the type `UpdateFulfillHtlc`. - Encode and decode the new field into the `ExtraData` field of the `update_fulfill_htlc` wire message. - Empty `ExtraData` field is set to `nil`.
This commit defines random fields for the `UpdateFulfillHTLC` message as part of the encode/decode unit tests.
Introduce `ResumeModified` action to resume standard behavior of a p2p message with optional modifications as specified by the client during interception.
This commit extends the forward HTLC intercept response with fields that can be used in conjunction with a `ResumeModified` action to modify the intercepted HTLC p2p message.
Implement an integration test where an HTLC is intercepted and the interception response modifies fields in the resultant p2p message.
5d3458f
to
03dceca
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 🧱
+tACK 🟢
got a few Qs, non-blocking
func (f *interceptedForward) ResumeModified(_, _ fn.Option[lnwire.MilliSatoshi], | ||
_ fn.Option[record.CustomSet]) error { | ||
|
||
return ErrCannotResume |
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.
maybe I'm missing something, why are we defaulting to err here? is this some old/outdated impementation?
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 code relates to the on-chain resolution flow. In the on-chain resolution flow, an intercepted forward can not be resumed. Therefore, it can't be resume modified either.
require.NoError(ht, err, "failed to send request") | ||
|
||
// Check that the modified UpdateAddHTLC message fields were reported in | ||
// Carol's log. |
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.
we used this trick to get the itests running
should we now consider reading these values the "healthy" way? i.e Carol also intercepts and acquires values from htlc message?
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.
I think ideally Carol should intercept as you suggest. But the log lookup should do for this PR, IMO. I'll see if I can put another PR so that Carol can intercept also. That way this test wont be bound to a log message.
a908c57
into
lightningnetwork:0-19-staging
Change Description
Closes #8619
Steps to Test
Steps for reviewers to follow to test the change.
Pull Request Checklist
Testing
Code Style and Documentation
[skip ci]
in the commit message for small changes.📝 Please see our Contribution Guidelines for further guidance.