-
Notifications
You must be signed in to change notification settings - Fork 0
/
target_tracker.go
138 lines (112 loc) · 3.96 KB
/
target_tracker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package lrc
import (
"errors"
"fmt"
"time"
"github.com/lightningnetwork/lnd/clock"
)
var (
// ErrResolvedNoResources is returned if we try to resolve a htlc on
// the outgoing link that was not supposed to be allocated resources
// in the first place.
ErrResolvedNoResources = errors.New("resolved htlc on outgoing link " +
"that should not have been assigned resources")
)
// Compile time check that targetChannelTracker implements the targetMonitor
// interface.
var _ targetMonitor = (*targetChannelTracker)(nil)
// targetChannelTracker is used to track the revenue and resources of channels
// that are requested as the outgoing link of a forward.
type targetChannelTracker struct {
revenue *decayingAverage
// blockTime is the expected time to find a block, surfaced to account
// for simulation scenarios where this isn't 10 minutes.
blockTime float64
// resolutionPeriod is the amount of time that we reasonably expect
// a htlc to resolve in.
resolutionPeriod time.Duration
resourceBuckets resourceBucketer
log Logger
}
func newTargetChannelTracker(clock clock.Clock, params ManagerParams,
channel *ChannelInfo, log Logger,
startValue *DecayingAverageStart) (*targetChannelTracker, error) {
bucket, err := newBucketResourceManager(
channel.InFlightLiquidity, channel.InFlightHTLC,
params.ProtectedPercentage,
)
if err != nil {
return nil, err
}
return &targetChannelTracker{
revenue: newDecayingAverage(
clock, params.RevenueWindow, startValue,
),
resourceBuckets: bucket,
blockTime: float64(params.BlockTime),
resolutionPeriod: params.ResolutionPeriod,
log: log,
}, nil
}
// AddInFlight adds a proposed htlc to our outgoing channel, considering the
// reputation of the incoming link. This function will return a forwarding
// decision with the details of the reputation decision and the action that
// was taken for this HTLC considering our resources and its endorsement.
func (t *targetChannelTracker) AddInFlight(incomingReputation IncomingReputation,
htlc *ProposedHTLC) ForwardDecision {
// First, assess reputation of the incoming link to decide whether
// the HTLC should be granted access to protected slots.
reputationCheck := ReputationCheck{
IncomingReputation: incomingReputation,
OutgoingRevenue: t.revenue.getValue(),
HTLCRisk: outstandingRisk(
t.blockTime, htlc, t.resolutionPeriod,
),
}
htlcProtected := reputationCheck.SufficientReputation() &&
htlc.IncomingEndorsed == EndorsementTrue
// Try to add the htlc to our bucket, if we can't accommodate it
// return early.
canForward := t.resourceBuckets.addHTLC(
htlcProtected, htlc.OutgoingAmount,
)
var outcome ForwardOutcome
switch {
case !canForward:
outcome = ForwardOutcomeNoResources
case htlcProtected:
outcome = ForwardOutcomeEndorsed
default:
outcome = ForwardOutcomeUnendorsed
}
return ForwardDecision{
ReputationCheck: reputationCheck,
ForwardOutcome: outcome,
}
}
// ResolveInFlight removes a htlc from our internal state, crediting the fees
// to our channel if it was successful.
func (t *targetChannelTracker) ResolveInFlight(htlc *ResolvedHTLC,
inFlight *InFlightHTLC) error {
if inFlight.OutgoingDecision == ForwardOutcomeNoResources {
return fmt.Errorf("%w: %v(%v) -> %v(%v)",
ErrResolvedNoResources, htlc.IncomingChannel.ToUint64(),
htlc.IncomingIndex, htlc.OutgoingChannel.ToUint64(),
htlc.OutgoingIndex)
}
// Add the fees for the forward to the outgoing channel _if_ the
// HTLC was successful.
if htlc.Success {
t.log.Infof("HTLC successful (%v(%v) -> %v(%v)): adding fees "+
"to channel: %v msat", htlc.IncomingChannel.ToUint64(),
htlc.IncomingIndex, htlc.OutgoingChannel.ToUint64(),
htlc.OutgoingIndex, inFlight.ForwardingFee())
t.revenue.add(float64(inFlight.ForwardingFee()))
}
// Clear out the resources in our resource bucket regardless of outcome.
t.resourceBuckets.removeHTLC(
inFlight.OutgoingDecision == ForwardOutcomeEndorsed,
inFlight.OutgoingAmount,
)
return nil
}