-
Notifications
You must be signed in to change notification settings - Fork 276
Endorse htlc and local reputation #2716
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
Conversation
Codecov Report
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. @@ Coverage Diff @@
## master #2716 +/- ##
==========================================
+ Coverage 85.82% 85.86% +0.04%
==========================================
Files 216 218 +2
Lines 18126 18209 +83
Branches 771 749 -22
==========================================
+ Hits 15556 15636 +80
- Misses 2570 2573 +3
|
7d53a40 to
525f547
Compare
525f547 to
14b6dd1
Compare
14b6dd1 to
deab085
Compare
deab085 to
b8b5cb1
Compare
b8b5cb1 to
3b4b506
Compare
3b4b506 to
7ae571d
Compare
ff97580 to
73efca3
Compare
755ba80 to
fa2e536
Compare
870796d to
b79b298
Compare
eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/HtlcTlv.scala
Outdated
Show resolved
Hide resolved
b79b298 to
83a5627
Compare
t-bast
left a comment
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.
Thanks, it's now more clear to me how we assign reputation to our peers. I've made a few comments on the code itself, some of which (the easy ones) I fixed in #2893.
The reputation algorithm itself looks good to me, let's try it out and see what results we get in practice and during simulations.
However, I don't think the way we interact with the reputation recorder makes the most sense.
You are storing a relay attempt as soon as we start relaying, before we know whether we actually send HTLCs out or not.
This leads to the weird CancelRelay command and an inconsistency between channel relay and trampoline relay.
In the trampoline case, if we can't find a route or can't send outgoing HTLCs, we will treat this as a failure, which is incorrect.
This can probably even be used to skew our reputation algorithm.
It's also pretty invasive, especially in the NodeRelay component...
It seems to me that it would make more sense if we implemented the following flow:
- Once we start relaying (
ChannelRelay/NodeRelay), we obtain the confidence value withGetConfidenceand will include it inCMD_ADD_HTLC. - At that point, we DON'T update the reputation to take this payment into account, because we don't know yet if it will be relayed.
- In
Channel.scala, when we actually send an outgoingUpdateAddHtlc, we emit anOutgoingHtlcAddedevent to the event stream, that contains the outgoing HTLC and itsOrigin.Hot. - In
Channel.scala, when an outgoing HTLC is failed or fulfilled, we emit anOutgoingHtlcFailed/OutgoingHtlcFulfilledevent to the event stream. - The reputation recorder listens to those events, and updates the internal reputation state accordingly.
- We don't use the
relayIdbut rather the outgoingchannel_idandhtlc_id, combined with the origin to group HTLCs. - For trampoline payments, since the reputation recorder has the
Origininformation, it can wait for all outgoing HTLCs to be settled to correctly account for the fees / timestamps.
I believe this better matches what we're trying to accomplish: the only thing the reputation recorder actually needs to know to update reputation is when outgoing HTLCs are sent and when they're settled.
It also provides more accurate relay data to ensure we're updating the reputation correctly, and has much less impact on the ChannelRelay / NodeRelay actors (which should simplify testing).
Can you try that, or let me know if you think that it wouldn't be as good as the currently implemented flow?
eclair-core/src/main/scala/fr/acinq/eclair/reputation/Reputation.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/ChannelRelay.scala
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/reputation/ReputationRecorder.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala
Outdated
Show resolved
Hide resolved
|
The reason for the weird |
But you're not doing this for trampoline relay, so that race can already be exploited anyway? I don't think this matters much in practice though, because:
|
I've tried doing that in #2897.
It seems to me that solving this would require adding more complexity than this refactoring was removing. |
It seems to me that we're trying to make trampoline fit into a box where it actually doesn't fit. One important aspect to trampoline is that the sender does not choose the outgoing channels and does not choose the fees, they allocate a total fee budget for the trampoline node which tries to relay within that fee budget. The trampoline node will ensure that it earns at least its usual channel routing fees, otherwise it won't relay the payment. If the trampoline node is well connected, or the sender over-allocated fees, the trampoline node earns more fees than its usual routing fees: but I'm not sure that this extra fee should count in the reputation? So I think we could handle trampoline relays in a simplified way that gets rid of those issues, by using the channel routing fees instead of trying to take the extra trampoline fees into account: when sending an outgoing HTLC with a trampoline origin, the fees we allocate to it in the reputation algorithm should just be this outgoing channel's routing fees (which can be included in the relay event since we have access to our channel update in the channel data). If the payment succeeds, if we want to give a bonus reputation if we earned more fees than our channel routing fees, this should be easy to do as well, by splitting the extra fee between all the outgoing channels? But I'm not sure we should do this, because we can't really match an outgoing HTLC to a specific incoming channel 1-to-1, so it's probably better to just count our channel routing fees? Do you think that model would make sense, or am I missing something? |
|
It seems like a good solution indeed, I'll try it. |
527cc06 to
59d312b
Compare
59d312b to
a4d9560
Compare
t-bast
left a comment
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 haven't looked at the logic inside Reputation.scala and ReputationRecorder.scala yet, but I've reviewed the interaction with the existing actors and this is nicely non-invasive, looks mostly good to me 👍
eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/reputation/package.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/RelayerSpec.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/ChannelRelayerSpec.scala
Outdated
Show resolved
Hide resolved
t-bast
left a comment
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 on the concept, comments are mostly about code and architecture. During yesterday's spec meeting, Carla asked that you write a gist detailing the steps of your reputation tracking algorithm in english/pseudo-code, which will let them compare it to what they're doing and verify that the implementation correctly matches the high-level algorithm. Can you create a public gist for this?
We do not yet drop HTLCs, the purpose is to collect data first.
We add
UpdateAddHtlc. This follows blip-0004: experimental endorsement signaling in update_add_htlc lightning/blips#27.