routing: extract timestamp from applying payment result

This commit prepares for timestamps being supplied from the database for
processing of historical payment results.
This commit is contained in:
Joost Jager 2019-07-02 11:29:44 +02:00
parent b4a7665bae
commit 1507ff6590
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7

@ -284,21 +284,21 @@ func (m *MissionControl) createHistoryIfNotExists(vertex route.Vertex) *nodeHist
} }
// reportVertexFailure reports a node level failure. // reportVertexFailure reports a node level failure.
func (m *MissionControl) reportVertexFailure(v route.Vertex) { func (m *MissionControl) reportVertexFailure(timestamp time.Time,
log.Debugf("Reporting vertex %v failure to Mission Control", v) v route.Vertex) {
now := m.now() log.Debugf("Reporting vertex %v failure to Mission Control", v)
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
history := m.createHistoryIfNotExists(v) history := m.createHistoryIfNotExists(v)
history.lastFail = &now history.lastFail = &timestamp
} }
// reportEdgePolicyFailure reports a policy related failure. // reportEdgePolicyFailure reports a policy related failure.
func (m *MissionControl) reportEdgePolicyFailure(failedEdge edge) { func (m *MissionControl) reportEdgePolicyFailure(timestamp time.Time,
now := m.now() failedEdge edge) {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
@ -307,32 +307,30 @@ func (m *MissionControl) reportEdgePolicyFailure(failedEdge edge) {
// immediately. If some time has passed since the last policy failure, // immediately. If some time has passed since the last policy failure,
// we grant the node a second chance at forwarding the payment. // we grant the node a second chance at forwarding the payment.
if m.requestSecondChance( if m.requestSecondChance(
now, failedEdge.from, failedEdge.to, timestamp, failedEdge.from, failedEdge.to,
) { ) {
return return
} }
history := m.createHistoryIfNotExists(failedEdge.from) history := m.createHistoryIfNotExists(failedEdge.from)
history.lastFail = &now history.lastFail = &timestamp
} }
// reportEdgeFailure reports a channel level failure. // reportEdgeFailure reports a channel level failure.
// //
// TODO(roasbeef): also add value attempted to send and capacity of channel // TODO(roasbeef): also add value attempted to send and capacity of channel
func (m *MissionControl) reportEdgeFailure(failedEdge edge, func (m *MissionControl) reportEdgeFailure(timestamp time.Time, failedEdge edge,
minPenalizeAmt lnwire.MilliSatoshi) { minPenalizeAmt lnwire.MilliSatoshi) {
log.Debugf("Reporting channel %v failure to Mission Control", log.Debugf("Reporting channel %v failure to Mission Control",
failedEdge.channel) failedEdge.channel)
now := m.now()
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
history := m.createHistoryIfNotExists(failedEdge.from) history := m.createHistoryIfNotExists(failedEdge.from)
history.channelLastFail[failedEdge.channel] = &channelHistory{ history.channelLastFail[failedEdge.channel] = &channelHistory{
lastFail: now, lastFail: timestamp,
minPenalizeAmt: minPenalizeAmt, minPenalizeAmt: minPenalizeAmt,
} }
} }
@ -399,7 +397,26 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
failureSourceIdx *int, failure lnwire.FailureMessage) (bool, failureSourceIdx *int, failure lnwire.FailureMessage) (bool,
channeldb.FailureReason) { channeldb.FailureReason) {
var failureSourceIdxInt int timestamp := m.now()
// Apply result to update mission control state.
return m.applyPaymentResult(
timestamp, paymentID, rt, failureSourceIdx, failure,
)
}
// applyPaymentResult applies a payment result as input for future probability
// estimates. It returns a bool indicating whether this error is a final error
// and no further payment attempts need to be made.
func (m *MissionControl) applyPaymentResult(timeReply time.Time,
paymentID uint64, rt *route.Route, failureSourceIdx *int,
failureMessage lnwire.FailureMessage) (bool, channeldb.FailureReason) {
var (
failureSourceIdxInt int
failure lnwire.FailureMessage
)
if failureSourceIdx == nil { if failureSourceIdx == nil {
// If the failure message could not be decrypted, attribute the // If the failure message could not be decrypted, attribute the
// failure to our own outgoing channel. // failure to our own outgoing channel.
@ -409,6 +426,7 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
failure = lnwire.NewTemporaryChannelFailure(nil) failure = lnwire.NewTemporaryChannelFailure(nil)
} else { } else {
failureSourceIdxInt = *failureSourceIdx failureSourceIdxInt = *failureSourceIdx
failure = failureMessage
} }
var failureVertex route.Vertex var failureVertex route.Vertex
@ -423,7 +441,9 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
// Always determine chan id ourselves, because a channel update with id // Always determine chan id ourselves, because a channel update with id
// may not be available. // may not be available.
failedEdge, failedAmt := getFailedEdge(rt, failureSourceIdxInt) failedEdge, failedAmt := getFailedEdge(
rt, failureSourceIdxInt,
)
switch failure.(type) { switch failure.(type) {
@ -481,7 +501,7 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
// that sent us this error, as it doesn't now what the // that sent us this error, as it doesn't now what the
// correct block height is. // correct block height is.
case *lnwire.FailExpiryTooSoon: case *lnwire.FailExpiryTooSoon:
m.reportVertexFailure(failureVertex) m.reportVertexFailure(timeReply, failureVertex)
return false, 0 return false, 0
// If we hit an instance of onion payload corruption or an invalid // If we hit an instance of onion payload corruption or an invalid
@ -501,49 +521,49 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
// amount, we'll apply the new minimum amount and retry // amount, we'll apply the new minimum amount and retry
// routing. // routing.
case *lnwire.FailAmountBelowMinimum: case *lnwire.FailAmountBelowMinimum:
m.reportEdgePolicyFailure(failedEdge) m.reportEdgePolicyFailure(timeReply, failedEdge)
return false, 0 return false, 0
// If we get a failure due to a fee, we'll apply the // If we get a failure due to a fee, we'll apply the
// new fee update, and retry our attempt using the // new fee update, and retry our attempt using the
// newly updated fees. // newly updated fees.
case *lnwire.FailFeeInsufficient: case *lnwire.FailFeeInsufficient:
m.reportEdgePolicyFailure(failedEdge) m.reportEdgePolicyFailure(timeReply, failedEdge)
return false, 0 return false, 0
// If we get the failure for an intermediate node that // If we get the failure for an intermediate node that
// disagrees with our time lock values, then we'll // disagrees with our time lock values, then we'll
// apply the new delta value and try it once more. // apply the new delta value and try it once more.
case *lnwire.FailIncorrectCltvExpiry: case *lnwire.FailIncorrectCltvExpiry:
m.reportEdgePolicyFailure(failedEdge) m.reportEdgePolicyFailure(timeReply, failedEdge)
return false, 0 return false, 0
// The outgoing channel that this node was meant to // The outgoing channel that this node was meant to
// forward one is currently disabled, so we'll apply // forward one is currently disabled, so we'll apply
// the update and continue. // the update and continue.
case *lnwire.FailChannelDisabled: case *lnwire.FailChannelDisabled:
m.reportEdgeFailure(failedEdge, 0) m.reportEdgeFailure(timeReply, failedEdge, 0)
return false, 0 return false, 0
// It's likely that the outgoing channel didn't have // It's likely that the outgoing channel didn't have
// sufficient capacity, so we'll prune this edge for // sufficient capacity, so we'll prune this edge for
// now, and continue onwards with our path finding. // now, and continue onwards with our path finding.
case *lnwire.FailTemporaryChannelFailure: case *lnwire.FailTemporaryChannelFailure:
m.reportEdgeFailure(failedEdge, failedAmt) m.reportEdgeFailure(timeReply, failedEdge, failedAmt)
return false, 0 return false, 0
// If the send fail due to a node not having the // If the send fail due to a node not having the
// required features, then we'll note this error and // required features, then we'll note this error and
// continue. // continue.
case *lnwire.FailRequiredNodeFeatureMissing: case *lnwire.FailRequiredNodeFeatureMissing:
m.reportVertexFailure(failureVertex) m.reportVertexFailure(timeReply, failureVertex)
return false, 0 return false, 0
// If the send fail due to a node not having the // If the send fail due to a node not having the
// required features, then we'll note this error and // required features, then we'll note this error and
// continue. // continue.
case *lnwire.FailRequiredChannelFeatureMissing: case *lnwire.FailRequiredChannelFeatureMissing:
m.reportVertexFailure(failureVertex) m.reportVertexFailure(timeReply, failureVertex)
return false, 0 return false, 0
// If the next hop in the route wasn't known or // If the next hop in the route wasn't known or
@ -554,18 +574,18 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
// returning errors in order to attempt to black list // returning errors in order to attempt to black list
// another node. // another node.
case *lnwire.FailUnknownNextPeer: case *lnwire.FailUnknownNextPeer:
m.reportEdgeFailure(failedEdge, 0) m.reportEdgeFailure(timeReply, failedEdge, 0)
return false, 0 return false, 0
// If the node wasn't able to forward for which ever // If the node wasn't able to forward for which ever
// reason, then we'll note this and continue with the // reason, then we'll note this and continue with the
// routes. // routes.
case *lnwire.FailTemporaryNodeFailure: case *lnwire.FailTemporaryNodeFailure:
m.reportVertexFailure(failureVertex) m.reportVertexFailure(timeReply, failureVertex)
return false, 0 return false, 0
case *lnwire.FailPermanentNodeFailure: case *lnwire.FailPermanentNodeFailure:
m.reportVertexFailure(failureVertex) m.reportVertexFailure(timeReply, failureVertex)
return false, 0 return false, 0
// If we crafted a route that contains a too long time // If we crafted a route that contains a too long time
@ -578,15 +598,15 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
// that as a hint during future path finding through // that as a hint during future path finding through
// that node. // that node.
case *lnwire.FailExpiryTooFar: case *lnwire.FailExpiryTooFar:
m.reportVertexFailure(failureVertex) m.reportVertexFailure(timeReply, failureVertex)
return false, 0 return false, 0
// If we get a permanent channel or node failure, then // If we get a permanent channel or node failure, then
// we'll prune the channel in both directions and // we'll prune the channel in both directions and
// continue with the rest of the routes. // continue with the rest of the routes.
case *lnwire.FailPermanentChannelFailure: case *lnwire.FailPermanentChannelFailure:
m.reportEdgeFailure(failedEdge, 0) m.reportEdgeFailure(timeReply, failedEdge, 0)
m.reportEdgeFailure(edge{ m.reportEdgeFailure(timeReply, edge{
from: failedEdge.to, from: failedEdge.to,
to: failedEdge.from, to: failedEdge.from,
channel: failedEdge.channel, channel: failedEdge.channel,
@ -595,7 +615,7 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
// Any other failure or an empty failure will get the node pruned. // Any other failure or an empty failure will get the node pruned.
default: default:
m.reportVertexFailure(failureVertex) m.reportVertexFailure(timeReply, failureVertex)
return false, 0 return false, 0
} }
} }