routing: change representation of pair results in mc
This commit changes the in-memory structure of the mission control state. It prepares for calculation of a node probability. For this we need to be able to efficiently look up the last results for all channels of a node.
This commit is contained in:
parent
aefbee78d6
commit
a3f7dbc633
@ -49,6 +49,9 @@ const (
|
|||||||
prevSuccessProbability = 0.95
|
prevSuccessProbability = 0.95
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NodeResults contains previous results from a node to its peers.
|
||||||
|
type NodeResults map[route.Vertex]timedPairResult
|
||||||
|
|
||||||
// MissionControl contains state which summarizes the past attempts of HTLC
|
// MissionControl contains state which summarizes the past attempts of HTLC
|
||||||
// routing by external callers when sending payments throughout the network. It
|
// routing by external callers when sending payments throughout the network. It
|
||||||
// acts as a shared memory during routing attempts with the goal to optimize the
|
// acts as a shared memory during routing attempts with the goal to optimize the
|
||||||
@ -59,8 +62,11 @@ const (
|
|||||||
// since the last failure is used to estimate a success probability that is fed
|
// since the last failure is used to estimate a success probability that is fed
|
||||||
// into the path finding process for subsequent payment attempts.
|
// into the path finding process for subsequent payment attempts.
|
||||||
type MissionControl struct {
|
type MissionControl struct {
|
||||||
// lastPairResult tracks the last payment result per node pair.
|
// lastPairResult tracks the last payment result (on a pair basis) for
|
||||||
lastPairResult map[DirectedNodePair]timedPairResult
|
// each transited node. This is a multi-layer map that allows us to look
|
||||||
|
// up the failure history of all connected channels (node pairs) for a
|
||||||
|
// particular node.
|
||||||
|
lastPairResult map[route.Vertex]NodeResults
|
||||||
|
|
||||||
// lastNodeFailure tracks the last node level failure per node.
|
// lastNodeFailure tracks the last node level failure per node.
|
||||||
lastNodeFailure map[route.Vertex]time.Time
|
lastNodeFailure map[route.Vertex]time.Time
|
||||||
@ -180,7 +186,7 @@ func NewMissionControl(db *bbolt.DB, cfg *MissionControlConfig) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
mc := &MissionControl{
|
mc := &MissionControl{
|
||||||
lastPairResult: make(map[DirectedNodePair]timedPairResult),
|
lastPairResult: make(map[route.Vertex]NodeResults),
|
||||||
lastNodeFailure: make(map[route.Vertex]time.Time),
|
lastNodeFailure: make(map[route.Vertex]time.Time),
|
||||||
lastSecondChance: make(map[DirectedNodePair]time.Time),
|
lastSecondChance: make(map[DirectedNodePair]time.Time),
|
||||||
now: time.Now,
|
now: time.Now,
|
||||||
@ -226,7 +232,7 @@ func (m *MissionControl) ResetHistory() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.lastPairResult = make(map[DirectedNodePair]timedPairResult)
|
m.lastPairResult = make(map[route.Vertex]NodeResults)
|
||||||
m.lastNodeFailure = make(map[route.Vertex]time.Time)
|
m.lastNodeFailure = make(map[route.Vertex]time.Time)
|
||||||
m.lastSecondChance = make(map[DirectedNodePair]time.Time)
|
m.lastSecondChance = make(map[DirectedNodePair]time.Time)
|
||||||
|
|
||||||
@ -264,6 +270,36 @@ func (m *MissionControl) getProbAfterFail(lastFailure time.Time) float64 {
|
|||||||
return probability
|
return probability
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getLastPairResult gets the last recorded result for a node pair.
|
||||||
|
func (m *MissionControl) getLastPairResult(fromNode,
|
||||||
|
toNode route.Vertex) *timedPairResult {
|
||||||
|
|
||||||
|
nodePairs, ok := m.lastPairResult[fromNode]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lastResult, ok := nodePairs[toNode]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &lastResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// setLastPairResult stores a result for a node pair.
|
||||||
|
func (m *MissionControl) setLastPairResult(fromNode,
|
||||||
|
toNode route.Vertex, result *timedPairResult) {
|
||||||
|
|
||||||
|
nodePairs, ok := m.lastPairResult[fromNode]
|
||||||
|
if !ok {
|
||||||
|
nodePairs = make(NodeResults)
|
||||||
|
m.lastPairResult[fromNode] = nodePairs
|
||||||
|
}
|
||||||
|
|
||||||
|
nodePairs[toNode] = *result
|
||||||
|
}
|
||||||
|
|
||||||
// getPairProbability estimates the probability of successfully
|
// getPairProbability estimates the probability of successfully
|
||||||
// traversing from fromNode to toNode based on historical payment outcomes.
|
// traversing from fromNode to toNode based on historical payment outcomes.
|
||||||
func (m *MissionControl) getPairProbability(fromNode,
|
func (m *MissionControl) getPairProbability(fromNode,
|
||||||
@ -276,13 +312,12 @@ func (m *MissionControl) getPairProbability(fromNode,
|
|||||||
lastFail := m.lastNodeFailure[fromNode]
|
lastFail := m.lastNodeFailure[fromNode]
|
||||||
|
|
||||||
// Retrieve the last pair outcome.
|
// Retrieve the last pair outcome.
|
||||||
pair := NewDirectedNodePair(fromNode, toNode)
|
lastPairResult := m.getLastPairResult(fromNode, toNode)
|
||||||
lastPairResult, ok := m.lastPairResult[pair]
|
|
||||||
|
|
||||||
// Only look at the last pair outcome if it happened after the last node
|
// Only look at the last pair outcome if it happened after the last node
|
||||||
// level failure. Otherwise the node level failure is the most recent
|
// level failure. Otherwise the node level failure is the most recent
|
||||||
// and used as the basis for calculation of the probability.
|
// and used as the basis for calculation of the probability.
|
||||||
if ok && lastPairResult.timestamp.After(lastFail) {
|
if lastPairResult != nil && lastPairResult.timestamp.After(lastFail) {
|
||||||
if lastPairResult.success {
|
if lastPairResult.success {
|
||||||
return prevSuccessProbability
|
return prevSuccessProbability
|
||||||
}
|
}
|
||||||
@ -355,20 +390,26 @@ func (m *MissionControl) GetHistorySnapshot() *MissionControlSnapshot {
|
|||||||
|
|
||||||
pairs := make([]MissionControlPairSnapshot, 0, len(m.lastPairResult))
|
pairs := make([]MissionControlPairSnapshot, 0, len(m.lastPairResult))
|
||||||
|
|
||||||
for v, h := range m.lastPairResult {
|
for fromNode, fromPairs := range m.lastPairResult {
|
||||||
// Show probability assuming amount meets min
|
for toNode, result := range fromPairs {
|
||||||
// penalization amount.
|
// Show probability assuming amount meets min
|
||||||
prob := m.getPairProbability(v.From, v.To, h.minPenalizeAmt)
|
// penalization amount.
|
||||||
|
prob := m.getPairProbability(
|
||||||
|
fromNode, toNode, result.minPenalizeAmt,
|
||||||
|
)
|
||||||
|
|
||||||
pair := MissionControlPairSnapshot{
|
pair := NewDirectedNodePair(fromNode, toNode)
|
||||||
Pair: v,
|
|
||||||
MinPenalizeAmt: h.minPenalizeAmt,
|
pairSnapshot := MissionControlPairSnapshot{
|
||||||
Timestamp: h.timestamp,
|
Pair: pair,
|
||||||
SuccessProb: prob,
|
MinPenalizeAmt: result.minPenalizeAmt,
|
||||||
LastAttemptSuccessful: h.success,
|
Timestamp: result.timestamp,
|
||||||
|
SuccessProb: prob,
|
||||||
|
LastAttemptSuccessful: result.success,
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs = append(pairs, pairSnapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pairs = append(pairs, pair)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot := MissionControlSnapshot{
|
snapshot := MissionControlSnapshot{
|
||||||
@ -480,10 +521,10 @@ func (m *MissionControl) applyPaymentResult(
|
|||||||
pair, pairResult.minPenalizeAmt)
|
pair, pairResult.minPenalizeAmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.lastPairResult[pair] = timedPairResult{
|
m.setLastPairResult(pair.From, pair.To, &timedPairResult{
|
||||||
timestamp: result.timeReply,
|
timestamp: result.timeReply,
|
||||||
pairResult: pairResult,
|
pairResult: pairResult,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return i.finalFailureReason
|
return i.finalFailureReason
|
||||||
|
Loading…
Reference in New Issue
Block a user