-
Notifications
You must be signed in to change notification settings - Fork 516
Outgoing reputation and HTLC Accountability #1280
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
base: master
Are you sure you want to change the base?
Conversation
4c35777
to
1bab2ce
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.
Concept ACK.
This is a big improvement over #1071:
- The inverted reputation scheme protects against sink attacks.
- The inverted reputation scheme enables new nodes to immediately send payments to reputable destinations when the network is under attack (better UX).
- The hash-based general slot assignment provides some discouragement for general jamming attacks.
- The tit-for-tat congestion bucket provides a mechanism to build reputation even when being general-jammed.
We probably also want to tweak the general slot assignment recommendations a bit to improve the strength of the hash-based defense:
- Scale
general_bucket_slot_count
based onmax_accepted_htlcs
instead of the commitment type. - Increase the recommended percentage of total slots allocated to the general bucket.
There's also still an open question about how to address the issues with high payment fanout. For example, LSPs often have high payment fan-out, which would prevent their clients from ever getting a good reputation with the current algorithm.
Reputation relies on the fees charged by the local node rather than the fee | ||
offered by the sender to prevent over-payment of advertised fees from | ||
contributing to reputation. This is unlikely to impact honest senders who will | ||
abide by advertised fee policies, and complicates (but does not prevent) | ||
attempts to artificially inflate reputation through excessive fee payments. |
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 should we care about reputation inflation if it's paid for? Fees paid are sunk costs to an attacker regardless of whether they happen in one payment or many.
Basing reputation on charged rather than offered fees could be good for a different reason though -- to avoid certain reputation destruction attacks. Suppose payments like this: M1 -> A -> B -> M2
, where the attacker is trying to destroy B
's reputation with A
. The attacker could offer insanely high fees to A
and minimal fees to B
, then hold HTLCs until expiry. As a result, B
's reputation would drop way more than M2
's.
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 should we care about reputation inflation if it's paid for?
We generally don't want an attacker to be able to take unusual actions that give them an advantage over honest behaving nodes. This just forces an attacker to align more with the behavior of honest nodes, even if it's trivial for them to do (multiple payments).
to avoid certain reputation destruction attacks
Good point! I'll include this in rationale.
A HTLC is eligible to use the general bucket if for its | ||
`(incoming scid, outgoing scid)`'s assigned resources: | ||
- Currently occupied slots < `general_bucket_slot_count` | ||
- Currently occupied liquidity + `amt_msat` <= `general_bucket_liquidity_allocation` |
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 should explicitly state that the general bucket can only be used when one of the assigned slots for that channel pair is unoccupied.
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 is covered by the general_bucket_slot_count
check above?
It's badly named, I"ll change it to general_bucket_slot_allocation
so that it's clearer.
it difficult for an attacker to crowd out honest traffic. With these defaults, | ||
an attacker will need to open approximately 50 channels in expectation to gain | ||
access to all general resources. |
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.
As noted above, the number of channels required is a lot less with typical values for max_accepted_htlcs
. If we have 16 general slots, we'd expect them to be fully occupied after ~11 or ~3 opened channels for general_bucket_slot_count
s of 5 and 20, respectively (coupon collector expectation).
average, expressed in seconds. | ||
- `decaying_average`: stores the value of the decaying average. | ||
- `decay_rate`: a constant rate of decay based on the rolling window chosen, | ||
calculated as: `((1/2)^(2/window_length_seconds))`. |
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.
Should we provide a recommendation for window_length_seconds
?
It looks like this will decay by 75% every window, so I'm guessing the same size as the fixed window would be reasonable here...
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.
window_length_seconds
is a placeholder for the period that you want a rolling average over - for revenue you'd use revenue_window
and for reputation you'd use revenue_window * reputation_multiplier
, for example.
I'll update the wording - let me know if it clarifies it!
1bab2ce
to
c25f7b1
Compare
Thanks for taking a look @morehouse! Addressed some of your feedback - diff here.
Agreed, this could definitely use some refining! Also interested to see whether we can think about larger default
Now that we look at reputation only in the outgoing direction, a sending LSP wouldn't need to worry about its clients (only the node it is forwarding out to). For a receiving LSP that needs to decide whether the client that they're sending a HTLC to has reputation, I imagine there are some LSP-related heuristics or different set of parameters that they could use? |
- `general_bucket_slot_count`: | ||
- If the channel type allows a maximum of 483 HTLCs: 20 | ||
- If the channel type allows a maximum of 120 HTLCs: 5 |
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.
LND and LDK both have defaults on 483, so most of the network is probably running with this default.
That's true for LND, though it looks like LDK defaults to 50.
Assuming that these values are set to protect nodes from the on-chain cost of resolution, I'm hopeful that other impls will be able to increase the number of slots they allow now that they can't be so trivially filled up.
Good point. Using the suggested defaults with zero-fee commits would put the general bucket size at 120 * .4 = 48
, which is essentially the same as current max_accepted_htlcs
defaults. Usage above that amount would be possible but would require reputation.
1. type: 0 (`blinded_path`) | ||
2. data: | ||
* [`point`:`path_key`] | ||
1. type: 1 (`accountable`) |
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 not allow multiple accountability level instead of it being just a boolean flag? Just as with the endorsement before.
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.
The accountable
signal being set should be interpreted as: "I will hold your reputation responsible for the timely resolution of this HTLC", which is a boolean statement.
By contrast, endorsement signals meant "I think that this HTLC will resolve in a timely manner", which makes more sense to interpret as a range.
The recipient of a payment is ultimately responsible for the fast resolution of a payment (though intermediate node can, of course, slow it down). We add a signal from the final recipient that the sender can use to reason about the amount of time it should take to resolve.
Once we have a signal from the recipient, we need a way to propagate this information throughout the route. Including a signal in the onion provides an uncorruptable way for the sender to propagate this signal. If the sender is dishonest, this will eventually be detected by the final recipient. In the commits that follow we'll add reputation and resource management that will allow nodes to use this signal to protect against jamming attacks.
c25f7b1
to
84ab329
Compare
This PR replaces #1071 with our latest proposal for a reputation scheme and resource management to mitigate slow jamming attacks.
Key differences for the new approach are:
accountable
signal to our outgoing peer to indicate whether we'll hold their reputation accountable because scarce resources have been used (rather than anendorsed
signal that indicates scarce resources may be used).