1
0
mirror of https://github.com/ACINQ/eclair.git synced 2024-11-20 02:27:32 +01:00

Allow to disable route randomization via configuration (#851)

* Allow to enable/disable the route randomization feature from the configuration

* Move router related configuration keys in router block.
This commit is contained in:
araspitzu 2019-02-05 17:35:47 +01:00 committed by GitHub
parent 3165f5dc36
commit 968961248e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 24 additions and 16 deletions

View File

@ -79,11 +79,6 @@ eclair {
revocation-timeout = 20 seconds // after sending a commit_sig, we will wait for at most that duration before disconnecting
channel-exclude-duration = 60 seconds // when a temporary channel failure is returned, we exclude the channel from our payment routes for this duration
router-broadcast-interval = 60 seconds // see BOLT #7
router-init-timeout = 5 minutes
ping-interval = 30 seconds
ping-timeout = 10 seconds // will disconnect if peer takes longer than that to respond
ping-disconnect = true // disconnect if no answer to our pings
@ -96,4 +91,11 @@ eclair {
min-funding-satoshis = 100000
autoprobe-count = 0 // number of parallel tasks that send test payments to detect invalid channels
router {
randomize-route-selection = true // when computing a route for a payment we randomize the final selection
channel-exclude-duration = 60 seconds // when a temporary channel failure is returned, we exclude the channel from our payment routes for this duration
broadcast-interval = 60 seconds // see BOLT #7
init-timeout = 5 minutes
}
}

View File

@ -80,7 +80,9 @@ case class NodeParams(keyManager: KeyManager,
paymentRequestExpiry: FiniteDuration,
maxPendingPaymentRequests: Int,
maxPaymentFee: Double,
minFundingSatoshis: Long) {
minFundingSatoshis: Long,
randomizeRouteSelection: Boolean
) {
val privateKey = keyManager.nodeKey.privateKey
val nodeId = keyManager.nodeId
@ -209,7 +211,7 @@ object NodeParams {
paymentsDb = paymentsDb,
auditDb = auditDb,
revocationTimeout = FiniteDuration(config.getDuration("revocation-timeout").getSeconds, TimeUnit.SECONDS),
routerBroadcastInterval = FiniteDuration(config.getDuration("router-broadcast-interval").getSeconds, TimeUnit.SECONDS),
routerBroadcastInterval = FiniteDuration(config.getDuration("router.broadcast-interval").getSeconds, TimeUnit.SECONDS),
pingInterval = FiniteDuration(config.getDuration("ping-interval").getSeconds, TimeUnit.SECONDS),
pingTimeout = FiniteDuration(config.getDuration("ping-timeout").getSeconds, TimeUnit.SECONDS),
pingDisconnect = config.getBoolean("ping-disconnect"),
@ -218,12 +220,13 @@ object NodeParams {
autoReconnect = config.getBoolean("auto-reconnect"),
chainHash = chainHash,
channelFlags = config.getInt("channel-flags").toByte,
channelExcludeDuration = FiniteDuration(config.getDuration("channel-exclude-duration").getSeconds, TimeUnit.SECONDS),
channelExcludeDuration = FiniteDuration(config.getDuration("router.channel-exclude-duration").getSeconds, TimeUnit.SECONDS),
watcherType = watcherType,
paymentRequestExpiry = FiniteDuration(config.getDuration("payment-request-expiry").getSeconds, TimeUnit.SECONDS),
maxPendingPaymentRequests = config.getInt("max-pending-payment-requests"),
maxPaymentFee = config.getDouble("max-payment-fee"),
minFundingSatoshis = config.getLong("min-funding-satoshis")
minFundingSatoshis = config.getLong("min-funding-satoshis"),
randomizeRouteSelection = config.getBoolean("router.randomize-route-selection")
)
}
}

View File

@ -201,7 +201,7 @@ class Setup(datadir: File,
}
router = system.actorOf(SimpleSupervisor.props(Router.props(nodeParams, watcher, Some(routerInitialized)), "router", SupervisorStrategy.Resume))
routerTimeout = after(FiniteDuration(config.getDuration("router-init-timeout").getSeconds, TimeUnit.SECONDS), using = system.scheduler)(Future.failed(new RuntimeException("Router initialization timed out")))
routerTimeout = after(FiniteDuration(config.getDuration("router.init-timeout").getSeconds, TimeUnit.SECONDS), using = system.scheduler)(Future.failed(new RuntimeException("Router initialization timed out")))
_ <- Future.firstCompletedOf(routerInitialized.future :: routerTimeout :: Nil)
wallet = bitcoin match {

View File

@ -193,7 +193,7 @@ object PaymentLifecycle {
/**
* @param maxFeePct set by default to 3% as a safety measure (even if a route is found, if fee is higher than that payment won't be attempted)
*/
case class SendPayment(amountMsat: Long, paymentHash: BinaryData, targetNodeId: PublicKey, assistedRoutes: Seq[Seq[ExtraHop]] = Nil, finalCltvExpiry: Long = Channel.MIN_CLTV_EXPIRY, maxAttempts: Int = 5, maxFeePct: Double = 0.03, randomize: Boolean = true) {
case class SendPayment(amountMsat: Long, paymentHash: BinaryData, targetNodeId: PublicKey, assistedRoutes: Seq[Seq[ExtraHop]] = Nil, finalCltvExpiry: Long = Channel.MIN_CLTV_EXPIRY, maxAttempts: Int = 5, maxFeePct: Double = 0.03, randomize: Option[Boolean] = None) {
require(amountMsat > 0, s"amountMsat must be > 0")
}
case class CheckPayment(paymentHash: BinaryData)

View File

@ -46,7 +46,7 @@ import scala.util.{Random, Try}
case class ChannelDesc(shortChannelId: ShortChannelId, a: PublicKey, b: PublicKey)
case class Hop(nodeId: PublicKey, nextNodeId: PublicKey, lastUpdate: ChannelUpdate)
case class RouteRequest(source: PublicKey, target: PublicKey, amountMsat: Long, assistedRoutes: Seq[Seq[ExtraHop]] = Nil, ignoreNodes: Set[PublicKey] = Set.empty, ignoreChannels: Set[ChannelDesc] = Set.empty, randomize: Boolean = true)
case class RouteRequest(source: PublicKey, target: PublicKey, amountMsat: Long, assistedRoutes: Seq[Seq[ExtraHop]] = Nil, ignoreNodes: Set[PublicKey] = Set.empty, ignoreChannels: Set[ChannelDesc] = Set.empty, randomize: Option[Boolean] = None)
case class RouteResponse(hops: Seq[Hop], ignoreNodes: Set[PublicKey], ignoreChannels: Set[ChannelDesc]) {
require(hops.size > 0, "route cannot be empty")
}
@ -384,7 +384,7 @@ class Router(nodeParams: NodeParams, watcher: ActorRef, initialized: Option[Prom
log.info(s"finding a route $start->$end with assistedChannels={} ignoreNodes={} ignoreChannels={} excludedChannels={}", assistedUpdates.keys.mkString(","), ignoreNodes.map(_.toBin).mkString(","), ignoreChannels.mkString(","), d.excludedChannels.mkString(","))
val extraEdges = assistedUpdates.map { case (c, u) => GraphEdge(c, u) }.toSet
// if we want to randomize we ask the router to make a random selection among the three best routes
val routesToFind = if(randomize) DEFAULT_ROUTES_COUNT else 1
val routesToFind = if(randomize.getOrElse(nodeParams.randomizeRouteSelection)) DEFAULT_ROUTES_COUNT else 1
findRoute(d.graph, start, end, amount, numRoutes = routesToFind, extraEdges = extraEdges, ignoredEdges = ignoredUpdates.toSet)
.map(r => sender ! RouteResponse(r, ignoreNodes, ignoreChannels))
.recover { case t => sender ! Status.Failure(t) }

View File

@ -86,7 +86,9 @@ object TestConstants {
paymentRequestExpiry = 1 hour,
maxPendingPaymentRequests = 10000000,
maxPaymentFee = 0.03,
minFundingSatoshis = 1000L)
minFundingSatoshis = 1000L,
randomizeRouteSelection = true
)
def channelParams = Peer.makeChannelParams(
nodeParams = nodeParams,
@ -145,7 +147,8 @@ object TestConstants {
paymentRequestExpiry = 1 hour,
maxPendingPaymentRequests = 10000000,
maxPaymentFee = 0.03,
minFundingSatoshis = 1000L)
minFundingSatoshis = 1000L,
randomizeRouteSelection = true)
def channelParams = Peer.makeChannelParams(
nodeParams = nodeParams,

View File

@ -251,7 +251,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 coffee"))
val pr = sender.expectMsgType[PaymentRequest]
// then we make the actual payment, do not randomize the route to make sure we route through node B
val sendReq = SendPayment(amountMsat.amount, pr.paymentHash, nodes("D").nodeParams.nodeId, randomize = false)
val sendReq = SendPayment(amountMsat.amount, pr.paymentHash, nodes("D").nodeParams.nodeId, randomize = Some(false))
sender.send(nodes("A").paymentInitiator, sendReq)
// A will receive an error from B that include the updated channel update, then will retry the payment
sender.expectMsgType[PaymentSucceeded](5 seconds)