1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-23 14:40:34 +01:00

Use the correct extra edges to put in metrics (#2350)

We were using hints from `SendPaymentConfig.invoice` to populate `PathFindingExperimentMetrics`, but the invoice is optional and not populated for trampoline relay.
This commit is contained in:
Thomas HUET 2022-07-22 16:06:41 +02:00 committed by GitHub
parent c20b3c9e8b
commit 214873e4a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 16 additions and 57 deletions

View file

@ -328,7 +328,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging {
statement.setString(7, m.experimentName)
statement.setString(8, m.recipientNodeId.value.toHex)
statement.setString(9, m.paymentHash.toHex)
statement.setString(10, m.routingHints_opt.map(serialization.write(_)).orNull)
statement.setString(10, serialization.write(m.extraEdges))
statement.executeUpdate()
}
}

View file

@ -261,4 +261,4 @@ case class PathFindingExperimentMetrics(paymentHash: ByteVector32,
isMultiPart: Boolean,
experimentName: String,
recipientNodeId: PublicKey,
routingHints_opt: Option[Seq[Seq[Bolt11Invoice.ExtraHop]]])
extraEdges: Seq[ExtraEdge])

View file

@ -264,11 +264,7 @@ class MultiPartPaymentLifecycle(nodeParams: NodeParams, cfg: SendPaymentConfig,
}
paymentSent.feesPaid + localFees
}
val hints_opt = cfg.invoice.flatMap {
case invoice: Bolt11Invoice if invoice.routingInfo.nonEmpty => Some(invoice.routingInfo)
case _ => None
}
context.system.eventStream.publish(PathFindingExperimentMetrics(cfg.paymentHash, cfg.recipientAmount, fees, status, duration, now, isMultiPart = true, request.routeParams.experimentName, cfg.recipientNodeId, hints_opt))
context.system.eventStream.publish(PathFindingExperimentMetrics(cfg.paymentHash, cfg.recipientAmount, fees, status, duration, now, isMultiPart = true, request.routeParams.experimentName, cfg.recipientNodeId, request.extraEdges))
}
Metrics.SentPaymentDuration
.withTag(Tags.MultiPart, Tags.MultiPartType.Parent)

View file

@ -349,13 +349,9 @@ class PaymentLifecycle(nodeParams: NodeParams, cfg: SendPaymentConfig, router: A
fees
}
request match {
case SendPaymentToNode(_, _, _, _, _, routeParams) =>
val hints_opt = cfg.invoice.flatMap {
case invoice: Bolt11Invoice if invoice.routingInfo.nonEmpty => Some(invoice.routingInfo)
case _ => None
}
context.system.eventStream.publish(PathFindingExperimentMetrics(cfg.paymentHash, request.finalPayload.amount, fees, status, duration, now, isMultiPart = false, routeParams.experimentName, cfg.recipientNodeId, hints_opt))
case SendPaymentToRoute(_, _, _, _) => ()
case request: SendPaymentToNode =>
context.system.eventStream.publish(PathFindingExperimentMetrics(cfg.paymentHash, request.finalPayload.amount, fees, status, duration, now, isMultiPart = false, request.routeParams.experimentName, cfg.recipientNodeId, request.extraEdges))
case _: SendPaymentToRoute => ()
}
}
Metrics.SentPaymentDuration

View file

@ -31,8 +31,6 @@ import fr.acinq.eclair.channel._
import fr.acinq.eclair.db._
import fr.acinq.eclair.io.Peer
import fr.acinq.eclair.io.Peer.OpenChannel
import fr.acinq.eclair.payment.Bolt11Invoice.ExtraHop
import fr.acinq.eclair.payment.Invoice.BasicEdge
import fr.acinq.eclair.payment.receive.MultiPartHandler.ReceivePayment
import fr.acinq.eclair.payment.receive.PaymentHandler
import fr.acinq.eclair.payment.relay.Relayer.{GetOutgoingChannels, RelayFees}
@ -122,26 +120,6 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I
assert(send.recipientAmount == 123.msat)
assert(send.paymentHash == ByteVector32.Zeroes)
assert(send.invoice == invoice0)
assert(send.invoice.extraEdges == Seq.empty)
// with assisted routes
val externalId1 = "030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87"
val hints = List(ExtraHop(Bob.nodeParams.nodeId, ShortChannelId.fromCoordinates("569178x2331x1").success.value, feeBase = 10 msat, feeProportionalMillionths = 1, cltvExpiryDelta = CltvExpiryDelta(12)))
val invoice1 = Bolt11Invoice(Block.RegtestGenesisBlock.hash, Some(123 msat), ByteVector32.Zeroes, nodePrivKey, Left("description"), CltvExpiryDelta(18), None, None, List(hints))
eclair.send(Some(externalId1), 123 msat, invoice1)
val send1 = paymentInitiator.expectMsgType[SendPaymentToNode]
assert(send1.externalId.contains(externalId1))
assert(send1.recipientNodeId == nodePrivKey.publicKey)
assert(send1.recipientAmount == 123.msat)
assert(send1.paymentHash == ByteVector32.Zeroes)
assert(send1.invoice == invoice1)
assert(send1.invoice.extraEdges.length == 1)
assert(send1.invoice.extraEdges.head.asInstanceOf[BasicEdge].shortChannelId == ShortChannelId.fromCoordinates("569178x2331x1").success.value)
assert(send1.invoice.extraEdges.head.asInstanceOf[BasicEdge].sourceNodeId == Bob.nodeParams.nodeId)
assert(send1.invoice.extraEdges.head.asInstanceOf[BasicEdge].targetNodeId == nodePrivKey.publicKey)
assert(send1.invoice.extraEdges.head.asInstanceOf[BasicEdge].feeBase == 10.msat)
assert(send1.invoice.extraEdges.head.asInstanceOf[BasicEdge].feeProportionalMillionths == 1)
assert(send1.invoice.extraEdges.head.asInstanceOf[BasicEdge].cltvExpiryDelta == CltvExpiryDelta(12))
// with finalCltvExpiry
val externalId2 = "487da196-a4dc-4b1e-92b4-3e5e905e9f3f"

View file

@ -852,7 +852,8 @@ class AuditDbSpec extends AnyFunSuite {
test("add experiment metrics") {
forAllDbs { dbs =>
val isPg = dbs.isInstanceOf[TestPgDatabases]
val hints = Some(Seq(Seq(ExtraHop(
val recipientNodeId = PublicKey(hex"03f5b1f2768140178e1daac0fec11fce2eec6beec3ed64862bfb1114f7bc535b48")
val hints = Seq(Seq(ExtraHop(
PublicKey(hex"033f2d90d6ba1f771e4b3586b35cc9f825cfcb7cdd7edaa2bfd63f0cb81b17580e"),
ShortChannelId(1),
1000 msat,
@ -870,12 +871,13 @@ class AuditDbSpec extends AnyFunSuite {
800 msat,
300,
CltvExpiryDelta(78)
))))
dbs.audit.addPathFindingExperimentMetrics(PathFindingExperimentMetrics(randomBytes32(), 100000000 msat, 3000 msat, status = "SUCCESS", 37 millis, TimestampMilli.now(), isMultiPart = false, "my-test-experiment", randomKey().publicKey, hints))
)))
val extraEdges = hints.flatMap(Bolt11Invoice.toExtraEdges(_, recipientNodeId))
dbs.audit.addPathFindingExperimentMetrics(PathFindingExperimentMetrics(randomBytes32(), 100000000 msat, 3000 msat, status = "SUCCESS", 37 millis, TimestampMilli.now(), isMultiPart = false, "my-test-experiment", recipientNodeId, extraEdges))
val table = if (isPg) "audit.path_finding_metrics" else "path_finding_metrics"
val hint_column = if (isPg) ", routing_hints" else ""
using(dbs.connection.prepareStatement(s"SELECT amount_msat, status, fees_msat, duration_ms, experiment_name $hint_column FROM $table")) { statement =>
using(dbs.connection.prepareStatement(s"SELECT amount_msat, status, fees_msat, duration_ms, experiment_name, recipient_node_id $hint_column FROM $table")) { statement =>
val result = statement.executeQuery()
assert(result.next())
assert(result.getLong(1) == 100000000)
@ -884,7 +886,8 @@ class AuditDbSpec extends AnyFunSuite {
assert(result.getLong(4) == 37)
assert(result.getString(5) == "my-test-experiment")
if (isPg) {
assert(result.getString(6) == "[[{\"nodeId\": \"033f2d90d6ba1f771e4b3586b35cc9f825cfcb7cdd7edaa2bfd63f0cb81b17580e\", \"feeBase\": 1000, \"shortChannelId\": \"0x0x1\", \"cltvExpiryDelta\": 144, \"feeProportionalMillionths\": 100}, {\"nodeId\": \"02c15a88ff263cec5bf79c315b17b7f2e083f71d62a880e30281faaac0898cb2b7\", \"feeBase\": 900, \"shortChannelId\": \"0x0x2\", \"cltvExpiryDelta\": 12, \"feeProportionalMillionths\": 200}], [{\"nodeId\": \"026ec3e3438308519a75ca4496822a6c1e229174fbcaadeeb174704c377112c331\", \"feeBase\": 800, \"shortChannelId\": \"0x0x3\", \"cltvExpiryDelta\": 78, \"feeProportionalMillionths\": 300}]]")
assert(result.getString(6) == recipientNodeId.toHex)
assert(result.getString(7) == "[{\"feeBase\": 1000, \"sourceNodeId\": \"033f2d90d6ba1f771e4b3586b35cc9f825cfcb7cdd7edaa2bfd63f0cb81b17580e\", \"targetNodeId\": \"02c15a88ff263cec5bf79c315b17b7f2e083f71d62a880e30281faaac0898cb2b7\", \"shortChannelId\": \"0x0x1\", \"cltvExpiryDelta\": 144, \"feeProportionalMillionths\": 100}, {\"feeBase\": 900, \"sourceNodeId\": \"02c15a88ff263cec5bf79c315b17b7f2e083f71d62a880e30281faaac0898cb2b7\", \"targetNodeId\": \"03f5b1f2768140178e1daac0fec11fce2eec6beec3ed64862bfb1114f7bc535b48\", \"shortChannelId\": \"0x0x2\", \"cltvExpiryDelta\": 12, \"feeProportionalMillionths\": 200}, {\"feeBase\": 800, \"sourceNodeId\": \"026ec3e3438308519a75ca4496822a6c1e229174fbcaadeeb174704c377112c331\", \"targetNodeId\": \"03f5b1f2768140178e1daac0fec11fce2eec6beec3ed64862bfb1114f7bc535b48\", \"shortChannelId\": \"0x0x3\", \"cltvExpiryDelta\": 78, \"feeProportionalMillionths\": 300}]")
}
assert(!result.next())
}

View file

@ -280,25 +280,11 @@ object MinimalNodeFixture extends Assertions with EitherValues {
def sendPayment(node1: MinimalNodeFixture, node2: MinimalNodeFixture, amount: MilliSatoshi, hints: Seq[Seq[ExtraHop]] = Seq.empty)(implicit system: ActorSystem): Either[PaymentFailed, PaymentSent] = {
val sender = TestProbe("sender")
sender.send(node2.paymentHandler, MultiPartHandler.ReceivePayment(Some(amount), Left("test payment")))
sender.send(node2.paymentHandler, MultiPartHandler.ReceivePayment(Some(amount), Left("test payment"), extraHops = hints.map(_.toList).toList))
val invoice = sender.expectMsgType[Bolt11Invoice]
val invoiceWithHints = Bolt11Invoice(
chainHash = node2.nodeParams.chainHash,
amount = invoice.amount_opt,
paymentHash = invoice.paymentHash,
privateKey = node2.nodeParams.privateKey,
description = invoice.description,
minFinalCltvExpiryDelta = invoice.minFinalCltvExpiryDelta,
fallbackAddress = invoice.fallbackAddress(),
expirySeconds = invoice.tags.collectFirst { case expiry: Bolt11Invoice.Expiry => expiry.toLong },
extraHops = hints.map(_.toList).toList,
timestamp = invoice.createdAt,
paymentSecret = invoice.paymentSecret.get,
paymentMetadata = invoice.paymentMetadata,
features = invoice.features)
val routeParams = node1.nodeParams.routerConf.pathFindingExperimentConf.experiments.values.head.getDefaultRouteParams
sender.send(node1.paymentInitiator, PaymentInitiator.SendPaymentToNode(amount, invoiceWithHints, maxAttempts = 1, routeParams = routeParams, blockUntilComplete = true))
sender.send(node1.paymentInitiator, PaymentInitiator.SendPaymentToNode(amount, invoice, maxAttempts = 1, routeParams = routeParams, blockUntilComplete = true))
sender.expectMsgType[PaymentEvent] match {
case e: PaymentSent => Right(e)
case e: PaymentFailed => Left(e)