Skip to content

Commit 54f4041

Browse files
committed
Better explanations
1 parent 83a5627 commit 54f4041

File tree

8 files changed

+35
-29
lines changed

8 files changed

+35
-29
lines changed

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,18 @@ eclair {
237237
// Number of blocks before the incoming HTLC expires that an async payment must be triggered by the receiver
238238
cancel-safety-before-timeout-blocks = 144
239239
}
240+
241+
// We assign reputations to our peers to prioritize HTLCs during congestion.
242+
// The reputation is computed as fees paid divided by what should have been paid if all HTLCs were successful.
243+
peer-reputation {
244+
// Reputation decays with the following half life to emphasize recent behavior.
245+
half-life = 7 days
246+
// HTLCs that stay pending for longer than this get penalized
247+
max-htlc-relay-duration = 12 seconds
248+
// Pending HTLCs are counted as failed, and because they could potentially stay pending for a very long time, the
249+
// following multiplier is applied.
250+
pending-multiplier = 1000 // A pending HTLCs counts as a thousand failed ones.
251+
}
240252
}
241253

242254
on-chain-fees {
@@ -547,15 +559,6 @@ eclair {
547559
enabled = true // enable automatic purges of expired invoices from the database
548560
interval = 24 hours // interval between expired invoice purges
549561
}
550-
551-
local-reputation {
552-
# Reputation decays with the following half life to emphasize recent behavior.
553-
half-life = 7 days
554-
# HTLCs that stay pending for longer than this get penalized
555-
good-htlc-duration = 12 seconds # 95% of successful payments settle in less than 12 seconds, only the slowest 5% will be penalized.
556-
# How much to penalize pending HLTCs. A pending HTLC is considered equivalent to this many fast-failing HTLCs.
557-
pending-multiplier = 1000
558-
}
559562
}
560563

561564
akka {

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,
8888
blockchainWatchdogSources: Seq[String],
8989
onionMessageConfig: OnionMessageConfig,
9090
purgeInvoicesInterval: Option[FiniteDuration],
91-
revokedHtlcInfoCleanerConfig: RevokedHtlcInfoCleaner.Config,
92-
localReputationConfig: ReputationConfig) {
91+
revokedHtlcInfoCleanerConfig: RevokedHtlcInfoCleaner.Config) {
9392
val privateKey: Crypto.PrivateKey = nodeKeyManager.nodeKey.privateKey
9493

9594
val nodeId: PublicKey = nodeKeyManager.nodeId
@@ -563,7 +562,12 @@ object NodeParams extends Logging {
563562
privateChannelFees = getRelayFees(config.getConfig("relay.fees.private-channels")),
564563
minTrampolineFees = getRelayFees(config.getConfig("relay.fees.min-trampoline")),
565564
enforcementDelay = FiniteDuration(config.getDuration("relay.fees.enforcement-delay").getSeconds, TimeUnit.SECONDS),
566-
asyncPaymentsParams = AsyncPaymentsParams(asyncPaymentHoldTimeoutBlocks, asyncPaymentCancelSafetyBeforeTimeoutBlocks)
565+
asyncPaymentsParams = AsyncPaymentsParams(asyncPaymentHoldTimeoutBlocks, asyncPaymentCancelSafetyBeforeTimeoutBlocks),
566+
peerReputationConfig = ReputationConfig(
567+
FiniteDuration(config.getDuration("relay.peer-reputation.half-life").getSeconds, TimeUnit.SECONDS),
568+
FiniteDuration(config.getDuration("relay.peer-reputation.max-htlc-relay-duration").getSeconds, TimeUnit.SECONDS),
569+
config.getDouble("relay.peer-reputation.pending-multiplier"),
570+
),
567571
),
568572
db = database,
569573
autoReconnect = config.getBoolean("auto-reconnect"),
@@ -613,12 +617,7 @@ object NodeParams extends Logging {
613617
revokedHtlcInfoCleanerConfig = RevokedHtlcInfoCleaner.Config(
614618
batchSize = config.getInt("db.revoked-htlc-info-cleaner.batch-size"),
615619
interval = FiniteDuration(config.getDuration("db.revoked-htlc-info-cleaner.interval").getSeconds, TimeUnit.SECONDS)
616-
),
617-
localReputationConfig = ReputationConfig(
618-
FiniteDuration(config.getDuration("local-reputation.half-life").getSeconds, TimeUnit.SECONDS),
619-
FiniteDuration(config.getDuration("local-reputation.good-htlc-duration").getSeconds, TimeUnit.SECONDS),
620-
config.getDouble("local-reputation.pending-multiplier"),
621-
),
620+
)
622621
)
623622
}
624623
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ class Setup(val datadir: File,
361361
offerManager = system.spawn(Behaviors.supervise(OfferManager(nodeParams, router, paymentTimeout = 1 minute)).onFailure(typed.SupervisorStrategy.resume), name = "offer-manager")
362362
paymentHandler = system.actorOf(SimpleSupervisor.props(PaymentHandler.props(nodeParams, register, offerManager), "payment-handler", SupervisorStrategy.Resume))
363363
triggerer = system.spawn(Behaviors.supervise(AsyncPaymentTriggerer()).onFailure(typed.SupervisorStrategy.resume), name = "async-payment-triggerer")
364-
reputationRecorder = system.spawn(Behaviors.supervise(ReputationRecorder(nodeParams.localReputationConfig, Map.empty)).onFailure(typed.SupervisorStrategy.resume), name = "reputation-recorder")
364+
reputationRecorder = system.spawn(Behaviors.supervise(ReputationRecorder(nodeParams.relayParams.peerReputationConfig, Map.empty)).onFailure(typed.SupervisorStrategy.resume), name = "reputation-recorder")
365365
relayer = system.actorOf(SimpleSupervisor.props(Relayer.props(nodeParams, router, register, paymentHandler, triggerer, reputationRecorder, Some(postRestartCleanUpInitialized)), "relayer", SupervisorStrategy.Resume))
366366
_ = relayer ! PostRestartHtlcCleaner.Init(channels)
367367
// Before initializing the switchboard (which re-connects us to the network) and the user-facing parts of the system,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
2828
import fr.acinq.eclair.channel._
2929
import fr.acinq.eclair.db.PendingCommandsDb
3030
import fr.acinq.eclair.payment._
31+
import fr.acinq.eclair.reputation.Reputation.ReputationConfig
3132
import fr.acinq.eclair.reputation.ReputationRecorder
3233
import fr.acinq.eclair.wire.protocol._
3334
import fr.acinq.eclair.{CltvExpiryDelta, Logs, MilliSatoshi, NodeParams}
@@ -136,7 +137,8 @@ object Relayer extends Logging {
136137
privateChannelFees: RelayFees,
137138
minTrampolineFees: RelayFees,
138139
enforcementDelay: FiniteDuration,
139-
asyncPaymentsParams: AsyncPaymentsParams) {
140+
asyncPaymentsParams: AsyncPaymentsParams,
141+
peerReputationConfig: ReputationConfig) {
140142
def defaultFees(announceChannel: Boolean): RelayFees = {
141143
if (announceChannel) {
142144
publicChannelFees

eclair-core/src/main/scala/fr/acinq/eclair/reputation/Reputation.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ object Reputation {
7676
}
7777
}
7878

79-
case class ReputationConfig(halfLife: FiniteDuration, goodDuration: FiniteDuration, pendingMultiplier: Double)
79+
case class ReputationConfig(halfLife: FiniteDuration, maxHtlcRelayDuration: FiniteDuration, pendingMultiplier: Double)
8080

81-
def init(config: ReputationConfig): Reputation = Reputation(0.0, 0.0, TimestampMilli.min, Map.empty, config.halfLife, config.goodDuration, config.pendingMultiplier)
81+
def init(config: ReputationConfig): Reputation = Reputation(0.0, 0.0, TimestampMilli.min, Map.empty, config.halfLife, config.maxHtlcRelayDuration, config.pendingMultiplier)
8282
}

eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ object TestConstants {
166166
feeBase = 548000 msat,
167167
feeProportionalMillionths = 30),
168168
enforcementDelay = 10 minutes,
169-
asyncPaymentsParams = AsyncPaymentsParams(1008, CltvExpiryDelta(144))),
169+
asyncPaymentsParams = AsyncPaymentsParams(1008, CltvExpiryDelta(144)),
170+
peerReputationConfig = ReputationConfig(1 day, 10 seconds, 100),
171+
),
170172
db = TestDatabases.inMemoryDb(),
171173
autoReconnect = false,
172174
initialRandomReconnectDelay = 5 seconds,
@@ -233,7 +235,6 @@ object TestConstants {
233235
),
234236
purgeInvoicesInterval = None,
235237
revokedHtlcInfoCleanerConfig = RevokedHtlcInfoCleaner.Config(10, 100 millis),
236-
localReputationConfig = ReputationConfig(1 day, 10 seconds, 100),
237238
)
238239

239240
def channelParams: LocalParams = OpenChannelInterceptor.makeChannelParams(
@@ -337,7 +338,9 @@ object TestConstants {
337338
feeBase = 548000 msat,
338339
feeProportionalMillionths = 30),
339340
enforcementDelay = 10 minutes,
340-
asyncPaymentsParams = AsyncPaymentsParams(1008, CltvExpiryDelta(144))),
341+
asyncPaymentsParams = AsyncPaymentsParams(1008, CltvExpiryDelta(144)),
342+
peerReputationConfig = ReputationConfig(2 day, 20 seconds, 200),
343+
),
341344
db = TestDatabases.inMemoryDb(),
342345
autoReconnect = false,
343346
initialRandomReconnectDelay = 5 seconds,
@@ -404,7 +407,6 @@ object TestConstants {
404407
),
405408
purgeInvoicesInterval = None,
406409
revokedHtlcInfoCleanerConfig = RevokedHtlcInfoCleaner.Config(10, 100 millis),
407-
localReputationConfig = ReputationConfig(2 days, 20 seconds, 200),
408410
)
409411

410412
def channelParams: LocalParams = OpenChannelInterceptor.makeChannelParams(

eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ class FuzzySpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Channe
6767
val bobRegister = system.actorOf(Props(new TestRegister()))
6868
val alicePaymentHandler = system.actorOf(Props(new PaymentHandler(aliceParams, aliceRegister, TestProbe().ref)))
6969
val bobPaymentHandler = system.actorOf(Props(new PaymentHandler(bobParams, bobRegister, TestProbe().ref)))
70-
val aliceReputationRecorder = system.spawnAnonymous(ReputationRecorder(aliceParams.localReputationConfig, Map.empty))
71-
val bobReputationRecorder = system.spawnAnonymous(ReputationRecorder(bobParams.localReputationConfig, Map.empty))
70+
val aliceReputationRecorder = system.spawnAnonymous(ReputationRecorder(aliceParams.relayParams.peerReputationConfig, Map.empty))
71+
val bobReputationRecorder = system.spawnAnonymous(ReputationRecorder(bobParams.relayParams.peerReputationConfig, Map.empty))
7272
val aliceRelayer = system.actorOf(Relayer.props(aliceParams, TestProbe().ref, aliceRegister, alicePaymentHandler, TestProbe().ref, aliceReputationRecorder))
7373
val bobRelayer = system.actorOf(Relayer.props(bobParams, TestProbe().ref, bobRegister, bobPaymentHandler, TestProbe().ref, bobReputationRecorder))
7474
val wallet = new DummyOnChainWallet()

eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ object MinimalNodeFixture extends Assertions with Eventually with IntegrationPat
9797
val router = system.actorOf(Router.props(nodeParams, watcherTyped), "router")
9898
val offerManager = system.spawn(OfferManager(nodeParams, router, 1 minute), "offer-manager")
9999
val paymentHandler = system.actorOf(PaymentHandler.props(nodeParams, register, offerManager), "payment-handler")
100-
val reputationRecorder = system.spawn(ReputationRecorder(nodeParams.localReputationConfig, Map.empty), "reputation-recorder")
100+
val reputationRecorder = system.spawn(ReputationRecorder(nodeParams.relayParams.peerReputationConfig, Map.empty), "reputation-recorder")
101101
val relayer = system.actorOf(Relayer.props(nodeParams, router, register, paymentHandler, triggerer.ref.toTyped, reputationRecorder), "relayer")
102102
val txPublisherFactory = Channel.SimpleTxPublisherFactory(nodeParams, watcherTyped, bitcoinClient)
103103
val channelFactory = Peer.SimpleChannelFactory(nodeParams, watcherTyped, relayer, wallet, txPublisherFactory)

0 commit comments

Comments
 (0)