Skip to content

Commit 0c1760d

Browse files
committed
Add new heuristics in addition to weight ratios
1 parent a94076c commit 0c1760d

File tree

13 files changed

+223
-104
lines changed

13 files changed

+223
-104
lines changed

eclair-core/src/main/resources/reference.conf

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,10 @@ eclair {
219219

220220
// Virtual fee for additional hops
221221
// Corresponds to how much you are willing to pay to get one less hop in the payment path
222-
hop-cost-base-msat = 500
223-
hop-cost-millionths = 200
222+
hop-cost {
223+
fee-base-msat = 500
224+
fee-proportional-millionths = 200
225+
}
224226

225227
mpp {
226228
min-amount-satoshis = 15000 // minimum amount sent via partial HTLCs
@@ -235,6 +237,18 @@ eclair {
235237
percentage = 100 // All traffic use the default configuration
236238
}
237239

240+
// alternative routing heuristics (replaces ratios)
241+
test-failure-cost = ${eclair.router.path-finding.default} {
242+
locked-funds-risk = 1e-15 // msat per msat locked per block. It should be your expected interest rate per block multiplied by the probability that something goes wrong and your funds stay locked.
243+
244+
// Virtual fee for failed payments
245+
// Corresponds to how much you are willing to pay to get one less failed payment attempt
246+
failure-cost {
247+
fee-base-msat = 2000
248+
fee-proportional-millionths = 500
249+
}
250+
}
251+
238252
// Examples of other configs as 0% experiments:
239253

240254
// To optimize for fees only:

eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import fr.acinq.eclair.crypto.keymanager.{ChannelKeyManager, NodeKeyManager}
2727
import fr.acinq.eclair.db._
2828
import fr.acinq.eclair.io.PeerConnection
2929
import fr.acinq.eclair.payment.relay.Relayer.{RelayFees, RelayParams}
30-
import fr.acinq.eclair.router.Graph.WeightRatios
30+
import fr.acinq.eclair.router.Graph.{HeuristicsConstants, WeightRatios}
3131
import fr.acinq.eclair.router.PathFindingExperimentConf
3232
import fr.acinq.eclair.router.Router.{MultiPartParams, PathFindingConf, RouterConf, SearchBoundaries}
3333
import fr.acinq.eclair.tor.Socks5ProxyParams
@@ -210,8 +210,8 @@ object NodeParams extends Logging {
210210
"router.path-finding.ratio-cltv" -> "router.path-finding.default.ratios.cltv",
211211
"router.path-finding.ratio-channel-age" -> "router.path-finding.default.ratios.channel-age",
212212
"router.path-finding.ratio-channel-capacity" -> "router.path-finding.default.ratios.channel-capacity",
213-
"router.path-finding.hop-cost-base-msat" -> "router.path-finding.default.hop-cost-base-msat",
214-
"router.path-finding.hop-cost-millionths" -> "router.path-finding.default.hop-cost-millionths",
213+
"router.path-finding.hop-cost-base-msat" -> "router.path-finding.default.hop-cost.fee-base-msat",
214+
"router.path-finding.hop-cost-millionths" -> "router.path-finding.default.hop-cost.fee-proportional-millionths",
215215
)
216216
deprecatedKeyPaths.foreach {
217217
case (old, new_) => require(!config.hasPath(old), s"configuration key '$old' has been replaced by '$new_'")
@@ -317,6 +317,18 @@ object NodeParams extends Logging {
317317
RelayFees(feeBase, relayFeesConfig.getInt("fee-proportional-millionths"))
318318
}
319319

320+
def getHeuristicsConstants(config: Config): Option[HeuristicsConstants] = {
321+
if (config.hasPath("locked-funds-risk") || config.hasPath("failure-cost")) {
322+
Some(HeuristicsConstants(
323+
lockedFundsRisk = config.getDouble("locked-funds-risk"),
324+
failureCost = getRelayFees(config.getConfig("failure-cost")),
325+
hopCost = getRelayFees(config.getConfig("hop-cost")),
326+
))
327+
} else {
328+
None
329+
}
330+
}
331+
320332
def getPathFindingConf(config: Config, name: String): PathFindingConf = PathFindingConf(
321333
randomize = config.getBoolean("randomize-route-selection"),
322334
boundaries = SearchBoundaries(
@@ -329,9 +341,9 @@ object NodeParams extends Logging {
329341
cltvDeltaFactor = config.getDouble("ratios.cltv"),
330342
ageFactor = config.getDouble("ratios.channel-age"),
331343
capacityFactor = config.getDouble("ratios.channel-capacity"),
332-
hopCostBase = MilliSatoshi(config.getLong("hop-cost-base-msat")),
333-
hopCostMillionths = config.getLong("hop-cost-millionths")
344+
hopCost = getRelayFees(config.getConfig("hop-cost")),
334345
),
346+
heuristicsConstants_opt = getHeuristicsConstants(config),
335347
mpp = MultiPartParams(
336348
Satoshi(config.getLong("mpp.min-amount-satoshis")).toMilliSatoshi,
337349
config.getInt("mpp.max-parts")),

eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/Relayer.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ object Relayer extends Logging {
112112
Props(new Relayer(nodeParams, router, register, paymentHandler, initialized))
113113

114114
// @formatter:off
115-
case class RelayFees(feeBase: MilliSatoshi, feeProportionalMillionths: Long)
115+
case class RelayFees(feeBase: MilliSatoshi, feeProportionalMillionths: Long) {
116+
require(feeBase.toLong >= 0.0, "feeBase must be nonnegative")
117+
require(feeProportionalMillionths >= 0.0, "feeProportionalMillionths must be nonnegative")
118+
}
116119

117120
case class RelayParams(publicChannelFees: RelayFees,
118121
privateChannelFees: RelayFees,

eclair-core/src/main/scala/fr/acinq/eclair/remote/EclairInternalsSerializer.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ import fr.acinq.eclair.crypto.TransportHandler
2323
import fr.acinq.eclair.io.Peer.PeerRoutingMessage
2424
import fr.acinq.eclair.io.Switchboard.RouterPeerConf
2525
import fr.acinq.eclair.io.{ClientSpawner, Peer, PeerConnection, Switchboard}
26-
import fr.acinq.eclair.router.Graph.WeightRatios
27-
import fr.acinq.eclair.router.Router.{GossipDecision, MultiPartParams, PathFindingConf, RouteParams, RouterConf, SearchBoundaries, SendChannelQuery}
26+
import fr.acinq.eclair.payment.relay.Relayer.RelayFees
27+
import fr.acinq.eclair.router.Graph.{HeuristicsConstants, WeightRatios}
28+
import fr.acinq.eclair.router.Router.{GossipDecision, MultiPartParams, PathFindingConf, RouterConf, SearchBoundaries, SendChannelQuery}
2829
import fr.acinq.eclair.router._
2930
import fr.acinq.eclair.wire.protocol.CommonCodecs._
3031
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs._
@@ -49,17 +50,20 @@ object EclairInternalsSerializer {
4950

5051
val searchBoundariesCodec: Codec[SearchBoundaries] = (
5152
("maxFee" | millisatoshi) ::
52-
("maxFeeProportional" | double) ::
53-
("maxRouteLength" | int32) ::
54-
("maxCltv" | int32.as[CltvExpiryDelta])).as[SearchBoundaries]
53+
("maxFeeProportional" | double) ::
54+
("maxRouteLength" | int32) ::
55+
("maxCltv" | int32.as[CltvExpiryDelta])).as[SearchBoundaries]
56+
57+
val relayFeesCodec: Codec[RelayFees] = (
58+
("feeBase" | millisatoshi) ::
59+
("feeProportionalMillionths" | int64)).as[RelayFees]
5560

5661
val weightRatiosCodec: Codec[WeightRatios] = (
5762
("baseFactor" | double) ::
5863
("cltvDeltaFactor" | double) ::
5964
("ageFactor" | double) ::
6065
("capacityFactor" | double) ::
61-
("hopCostBase" | millisatoshi) ::
62-
("hopCostMillionths" | int64)).as[WeightRatios]
66+
("hopCost" | relayFeesCodec)).as[WeightRatios]
6367

6468
val multiPartParamsCodec: Codec[MultiPartParams] = (
6569
("minPartAmount" | millisatoshi) ::
@@ -69,6 +73,7 @@ object EclairInternalsSerializer {
6973
("randomize" | bool(8)) ::
7074
("boundaries" | searchBoundariesCodec) ::
7175
("ratios" | weightRatiosCodec) ::
76+
("heuristicsConstants_opt" | provide[Option[HeuristicsConstants]](None)) ::
7277
("mpp" | multiPartParamsCodec) ::
7378
("experimentName" | utf8_32) ::
7479
("experimentPercentage" | int32)).as[PathFindingConf]

0 commit comments

Comments
 (0)