-
Notifications
You must be signed in to change notification settings - Fork 2.3k
[1/?] Local reputation: subsystem core, read only #10919
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?
Changes from 4 commits
6d4cedd
a22c0fe
a024bf8
8782054
e57ff3a
c6480fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -279,6 +279,13 @@ type ChannelLink interface { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // policy to govern if it an incoming HTLC should be forwarded or not. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UpdateForwardingPolicy(models.ForwardingPolicy) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // AdvertisedFee returns the fee this link's current forwarding policy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // charges to forward the given outgoing amount (base fee plus the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // proportional fee). It is the fee the node advertised for this link, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // as distinct from the (possibly larger) fee actually offered by the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // incoming HTLC. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AdvertisedFee(amtToForward lnwire.MilliSatoshi) lnwire.MilliSatoshi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // CheckHtlcForward should return a nil error if the passed HTLC details | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // satisfy the current forwarding policy fo the target link. Otherwise, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // a LinkError with a valid protocol failure message should be returned | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -515,6 +522,29 @@ type htlcNotifier interface { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| info channeldb.FinalHtlcInfo) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ReputationManager is the read-only seam through which the switch feeds HTLC | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // forwarding lifecycle events to the (optional) local reputation subsystem. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // It is a black box that only observes events to update internal reputation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // state; it never affects forwarding decisions or the wire (log-only). When no | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // reputation manager is configured this is nil and the hooks are skipped. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type ReputationManager interface { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // OnForward observes a forwarded HTLC at the point the switch | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // commits to forwarding it to the outgoing channel. advertisedFee is | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // the fee the node advertised on the outgoing link for this forward | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // (not the fee offered by the incoming HTLC), height is the switch's | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // current best block height, and accountable is the outgoing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // accountable bit as this node would forward it. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OnForward(incoming, outgoing CircuitKey, incomingAmt, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| outgoingAmt, advertisedFee lnwire.MilliSatoshi, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| incomingCltv, height uint32, accountable bool) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+531
to
+539
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We may want to document that the outgoing
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps just use the outgoing channel (not the circuit key)? We don't have use for the ID anyway iirc |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // OnSettle observes the successful resolution of a forwarded HTLC. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OnSettle(incoming, outgoing CircuitKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // OnFail observes the failed resolution of a forwarded HTLC. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OnFail(incoming, outgoing CircuitKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // AuxHtlcModifier is an interface that allows the sender to modify the outgoing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // HTLC of a payment by changing the amount or the wire message tlv records. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type AuxHtlcModifier interface { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| package htlcswitch | ||
|
|
||
| import ( | ||
| "sync/atomic" | ||
|
|
||
| "github.com/lightningnetwork/lnd/lnwire" | ||
| ) | ||
|
|
||
| // guardedReputationManager wraps a ReputationManager so that a panic in any of | ||
| // its hooks can never propagate into the switch's forwarding goroutine. The | ||
| // reputation subsystem is log-only and MUST NOT be able to degrade forwarding; | ||
| // if a hook panics we log it, permanently disable the subsystem (fail open), | ||
| // and continue forwarding unaffected. | ||
|
Comment on lines
+9
to
+13
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is also a bit code-smelly to me. Is this standard practice for LND to add this type of gating to new features? |
||
| // | ||
| // The hooks run synchronously on the switch's forwarding goroutine, so this | ||
| // boundary keeps a subsystem bug — a nil deref, an arithmetic panic — from | ||
| // taking down the node's HTLC forwarding. | ||
| type guardedReputationManager struct { | ||
| inner ReputationManager | ||
| disabled atomic.Bool | ||
| } | ||
|
|
||
| // NewGuardedReputationManager wraps the given ReputationManager with a panic | ||
| // boundary. It returns nil when inner is nil, so the switch's existing nil | ||
| // check still short-circuits a disabled subsystem with zero overhead. | ||
| func NewGuardedReputationManager(inner ReputationManager) ReputationManager { | ||
| if inner == nil { | ||
| return nil | ||
| } | ||
|
|
||
| return &guardedReputationManager{inner: inner} | ||
| } | ||
|
|
||
| // OnForward forwards the observation to the wrapped manager behind a panic | ||
| // boundary. | ||
| func (g *guardedReputationManager) OnForward(incoming, outgoing CircuitKey, | ||
| incomingAmt, outgoingAmt, advertisedFee lnwire.MilliSatoshi, | ||
| incomingCltv, height uint32, accountable bool) { | ||
|
|
||
| if g.disabled.Load() { | ||
| return | ||
| } | ||
| defer g.recoverHook("OnForward") | ||
|
|
||
| g.inner.OnForward( | ||
| incoming, outgoing, incomingAmt, outgoingAmt, advertisedFee, | ||
| incomingCltv, height, accountable, | ||
| ) | ||
| } | ||
|
|
||
| // OnSettle forwards the observation to the wrapped manager behind a panic | ||
| // boundary. | ||
| func (g *guardedReputationManager) OnSettle(incoming, outgoing CircuitKey) { | ||
| if g.disabled.Load() { | ||
| return | ||
| } | ||
| defer g.recoverHook("OnSettle") | ||
|
|
||
| g.inner.OnSettle(incoming, outgoing) | ||
| } | ||
|
|
||
| // OnFail forwards the observation to the wrapped manager behind a panic | ||
| // boundary. | ||
| func (g *guardedReputationManager) OnFail(incoming, outgoing CircuitKey) { | ||
| if g.disabled.Load() { | ||
| return | ||
| } | ||
| defer g.recoverHook("OnFail") | ||
|
|
||
| g.inner.OnFail(incoming, outgoing) | ||
| } | ||
|
|
||
| // recoverHook recovers from a panic in a reputation hook, logging it and | ||
| // permanently disabling the subsystem so a deterministic bug cannot panic on | ||
| // every forwarded HTLC. Forwarding is never affected. | ||
| func (g *guardedReputationManager) recoverHook(method string) { | ||
| if r := recover(); r != nil { | ||
| log.Errorf("Reputation %s hook panicked; disabling reputation "+ | ||
| "subsystem (forwarding is unaffected): %v", method, r) | ||
| g.disabled.Store(true) | ||
| } | ||
| } | ||
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.
Nice 👌