From ba00590172152e775a0623b1439bef7bc2e9a4c1 Mon Sep 17 00:00:00 2001 From: rorp Date: Mon, 14 Nov 2022 14:22:40 -0800 Subject: [PATCH 1/4] Add pagination on Audit API --- .../main/scala/fr/acinq/eclair/Eclair.scala | 10 ++--- .../scala/fr/acinq/eclair/db/AuditDb.scala | 8 ++-- .../fr/acinq/eclair/db/DualDatabases.scala | 18 ++++---- .../fr/acinq/eclair/db/pg/PgAuditDb.scala | 28 +++++++++---- .../eclair/db/sqlite/SqliteAuditDb.scala | 28 +++++++++---- .../fr/acinq/eclair/db/AuditDbSpec.scala | 42 ++++++++++++------- .../integration/PaymentIntegrationSpec.scala | 20 ++++----- .../fr/acinq/eclair/api/handlers/Node.scala | 6 ++- .../fr/acinq/eclair/api/ApiServiceSpec.scala | 18 ++++++-- 9 files changed, 113 insertions(+), 65 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala index 820f06ef9a..c985d0e932 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala @@ -127,7 +127,7 @@ trait Eclair { def sendToRoute(amount: MilliSatoshi, recipientAmount_opt: Option[MilliSatoshi], externalId_opt: Option[String], parentId_opt: Option[UUID], invoice: Bolt11Invoice, route: PredefinedRoute, trampolineSecret_opt: Option[ByteVector32] = None, trampolineFees_opt: Option[MilliSatoshi] = None, trampolineExpiryDelta_opt: Option[CltvExpiryDelta] = None, trampolineNodes_opt: Seq[PublicKey] = Nil)(implicit timeout: Timeout): Future[SendPaymentToRouteResponse] - def audit(from: TimestampSecond, to: TimestampSecond)(implicit timeout: Timeout): Future[AuditResponse] + def audit(from: TimestampSecond, to: TimestampSecond, paginated_opt: Option[Paginated])(implicit timeout: Timeout): Future[AuditResponse] def networkFees(from: TimestampSecond, to: TimestampSecond)(implicit timeout: Timeout): Future[Seq[NetworkFee]] @@ -419,11 +419,11 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging { appKit.nodeParams.db.payments.getIncomingPayment(paymentHash) } - override def audit(from: TimestampSecond, to: TimestampSecond)(implicit timeout: Timeout): Future[AuditResponse] = { + override def audit(from: TimestampSecond, to: TimestampSecond, paginated_opt: Option[Paginated])(implicit timeout: Timeout): Future[AuditResponse] = { Future(AuditResponse( - sent = appKit.nodeParams.db.audit.listSent(from.toTimestampMilli, to.toTimestampMilli), - received = appKit.nodeParams.db.audit.listReceived(from.toTimestampMilli, to.toTimestampMilli), - relayed = appKit.nodeParams.db.audit.listRelayed(from.toTimestampMilli, to.toTimestampMilli) + sent = appKit.nodeParams.db.audit.listSent(from.toTimestampMilli, to.toTimestampMilli, paginated_opt), + received = appKit.nodeParams.db.audit.listReceived(from.toTimestampMilli, to.toTimestampMilli, paginated_opt), + relayed = appKit.nodeParams.db.audit.listRelayed(from.toTimestampMilli, to.toTimestampMilli, paginated_opt) )) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala index 2105278cb4..dba762c3ad 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.db import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} -import fr.acinq.eclair.TimestampMilli +import fr.acinq.eclair.{Paginated, TimestampMilli} import fr.acinq.eclair.channel._ import fr.acinq.eclair.db.AuditDb.{NetworkFee, Stats} import fr.acinq.eclair.db.DbEventHandler.ChannelEvent @@ -44,11 +44,11 @@ trait AuditDb { def addPathFindingExperimentMetrics(metrics: PathFindingExperimentMetrics): Unit - def listSent(from: TimestampMilli, to: TimestampMilli): Seq[PaymentSent] + def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentSent] - def listReceived(from: TimestampMilli, to: TimestampMilli): Seq[PaymentReceived] + def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentReceived] - def listRelayed(from: TimestampMilli, to: TimestampMilli): Seq[PaymentRelayed] + def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentRelayed] def listNetworkFees(from: TimestampMilli, to: TimestampMilli): Seq[NetworkFee] diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala index 92bec058cb..cb0e5dd068 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/DualDatabases.scala @@ -176,19 +176,19 @@ case class DualAuditDb(primary: AuditDb, secondary: AuditDb) extends AuditDb { primary.addPathFindingExperimentMetrics(metrics) } - override def listSent(from: TimestampMilli, to: TimestampMilli): Seq[PaymentSent] = { - runAsync(secondary.listSent(from, to)) - primary.listSent(from, to) + override def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentSent] = { + runAsync(secondary.listSent(from, to, paginated_opt)) + primary.listSent(from, to, paginated_opt) } - override def listReceived(from: TimestampMilli, to: TimestampMilli): Seq[PaymentReceived] = { - runAsync(secondary.listReceived(from, to)) - primary.listReceived(from, to) + override def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentReceived] = { + runAsync(secondary.listReceived(from, to, paginated_opt)) + primary.listReceived(from, to, paginated_opt) } - override def listRelayed(from: TimestampMilli, to: TimestampMilli): Seq[PaymentRelayed] = { - runAsync(secondary.listRelayed(from, to)) - primary.listRelayed(from, to) + override def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentRelayed] = { + runAsync(secondary.listRelayed(from, to, paginated_opt)) + primary.listRelayed(from, to, paginated_opt) } override def listNetworkFees(from: TimestampMilli, to: TimestampMilli): Seq[AuditDb.NetworkFee] = { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala index 6ad3e25de7..1f682fa5c8 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala @@ -26,7 +26,7 @@ import fr.acinq.eclair.db.Monitoring.Tags.DbBackends import fr.acinq.eclair.db._ import fr.acinq.eclair.payment._ import fr.acinq.eclair.transactions.Transactions.PlaceHolderPubKey -import fr.acinq.eclair.{MilliSatoshi, MilliSatoshiLong, TimestampMilli} +import fr.acinq.eclair.{MilliSatoshi, MilliSatoshiLong, Paginated, TimestampMilli} import grizzled.slf4j.Logging import java.sql.{Statement, Timestamp} @@ -334,12 +334,12 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { } } - override def listSent(from: TimestampMilli, to: TimestampMilli): Seq[PaymentSent] = + override def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentSent] = inTransaction { pg => using(pg.prepareStatement("SELECT * FROM audit.sent WHERE timestamp BETWEEN ? AND ?")) { statement => statement.setTimestamp(1, from.toSqlTimestamp) statement.setTimestamp(2, to.toSqlTimestamp) - statement.executeQuery() + val result = statement.executeQuery() .foldLeft(Map.empty[UUID, PaymentSent]) { (sentByParentId, rs) => val parentId = UUID.fromString(rs.getString("parent_payment_id")) val part = PaymentSent.PartialPayment( @@ -361,15 +361,19 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { } sentByParentId + (parentId -> sent) }.values.toSeq.sortBy(_.timestamp) + paginated_opt match { + case Some(paginated) => result.slice(paginated.skip, paginated.skip + paginated.count) + case None => result + } } } - override def listReceived(from: TimestampMilli, to: TimestampMilli): Seq[PaymentReceived] = + override def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentReceived] = inTransaction { pg => using(pg.prepareStatement("SELECT * FROM audit.received WHERE timestamp BETWEEN ? AND ?")) { statement => statement.setTimestamp(1, from.toSqlTimestamp) statement.setTimestamp(2, to.toSqlTimestamp) - statement.executeQuery() + val result = statement.executeQuery() .foldLeft(Map.empty[ByteVector32, PaymentReceived]) { (receivedByHash, rs) => val paymentHash = rs.getByteVector32FromHex("payment_hash") val part = PaymentReceived.PartialPayment( @@ -382,10 +386,14 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { } receivedByHash + (paymentHash -> received) }.values.toSeq.sortBy(_.timestamp) + paginated_opt match { + case Some(paginated) => result.slice(paginated.skip, paginated.skip + paginated.count) + case None => result + } } } - override def listRelayed(from: TimestampMilli, to: TimestampMilli): Seq[PaymentRelayed] = + override def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentRelayed] = inTransaction { pg => val trampolineByHash = using(pg.prepareStatement("SELECT * FROM audit.relayed_trampoline WHERE timestamp BETWEEN ? and ?")) { statement => statement.setTimestamp(1, from.toSqlTimestamp) @@ -413,7 +421,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { relayedByHash + (paymentHash -> (relayedByHash.getOrElse(paymentHash, Nil) :+ part)) } } - relayedByHash.flatMap { + val result = relayedByHash.flatMap { case (paymentHash, parts) => // We may have been routing multiple payments for the same payment_hash (MPP) in both cases (trampoline and channel). // NB: we may link the wrong in-out parts, but the overall sum will be correct: we sort by amounts to minimize the risk of mismatch. @@ -429,6 +437,10 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { case _ => Nil } }.toSeq.sortBy(_.timestamp) + paginated_opt match { + case Some(paginated) => result.slice(paginated.skip, paginated.skip + paginated.count) + case None => result + } } override def listNetworkFees(from: TimestampMilli, to: TimestampMilli): Seq[NetworkFee] = @@ -453,7 +465,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { feeByChannelId + (f.channelId -> (feeByChannelId.getOrElse(f.channelId, 0 sat) + f.fee)) } case class Relayed(amount: MilliSatoshi, fee: MilliSatoshi, direction: String) - val relayed = listRelayed(from, to).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => + val relayed = listRelayed(from, to, None).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => // NB: we must avoid counting the fee twice: we associate it to the outgoing channels rather than the incoming ones. val current = e match { case c: ChannelPaymentRelayed => Map( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala index 2b90dd219b..f33ec02767 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala @@ -26,7 +26,7 @@ import fr.acinq.eclair.db.Monitoring.Tags.DbBackends import fr.acinq.eclair.db._ import fr.acinq.eclair.payment._ import fr.acinq.eclair.transactions.Transactions.PlaceHolderPubKey -import fr.acinq.eclair.{MilliSatoshi, MilliSatoshiLong, TimestampMilli} +import fr.acinq.eclair.{MilliSatoshi, MilliSatoshiLong, Paginated, TimestampMilli} import grizzled.slf4j.Logging import java.sql.{Connection, Statement} @@ -310,11 +310,11 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { } } - override def listSent(from: TimestampMilli, to: TimestampMilli): Seq[PaymentSent] = + override def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentSent] = using(sqlite.prepareStatement("SELECT * FROM sent WHERE timestamp >= ? AND timestamp < ?")) { statement => statement.setLong(1, from.toLong) statement.setLong(2, to.toLong) - statement.executeQuery() + val result = statement.executeQuery() .foldLeft(Map.empty[UUID, PaymentSent]) { (sentByParentId, rs) => val parentId = UUID.fromString(rs.getString("parent_payment_id")) val part = PaymentSent.PartialPayment( @@ -336,13 +336,17 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { } sentByParentId + (parentId -> sent) }.values.toSeq.sortBy(_.timestamp) + paginated_opt match { + case Some(paginated) => result.slice(paginated.skip, paginated.skip + paginated.count) + case None => result + } } - override def listReceived(from: TimestampMilli, to: TimestampMilli): Seq[PaymentReceived] = + override def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentReceived] = using(sqlite.prepareStatement("SELECT * FROM received WHERE timestamp >= ? AND timestamp < ?")) { statement => statement.setLong(1, from.toLong) statement.setLong(2, to.toLong) - statement.executeQuery() + val result = statement.executeQuery() .foldLeft(Map.empty[ByteVector32, PaymentReceived]) { (receivedByHash, rs) => val paymentHash = rs.getByteVector32("payment_hash") val part = PaymentReceived.PartialPayment( @@ -355,9 +359,13 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { } receivedByHash + (paymentHash -> received) }.values.toSeq.sortBy(_.timestamp) + paginated_opt match { + case Some(paginated) => result.slice(paginated.skip, paginated.skip + paginated.count) + case None => result + } } - override def listRelayed(from: TimestampMilli, to: TimestampMilli): Seq[PaymentRelayed] = { + override def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentRelayed] = { val trampolineByHash = using(sqlite.prepareStatement("SELECT * FROM relayed_trampoline WHERE timestamp >= ? AND timestamp < ?")) { statement => statement.setLong(1, from.toLong) statement.setLong(2, to.toLong) @@ -385,7 +393,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { relayedByHash + (paymentHash -> (relayedByHash.getOrElse(paymentHash, Nil) :+ part)) } } - relayedByHash.flatMap { + val result = relayedByHash.flatMap { case (paymentHash, parts) => // We may have been routing multiple payments for the same payment_hash (MPP) in both cases (trampoline and channel). // NB: we may link the wrong in-out parts, but the overall sum will be correct: we sort by amounts to minimize the risk of mismatch. @@ -401,6 +409,10 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { case _ => Nil } }.toSeq.sortBy(_.timestamp) + paginated_opt match { + case Some(paginated) => result.slice(paginated.skip, paginated.skip + paginated.count) + case None => result + } } override def listNetworkFees(from: TimestampMilli, to: TimestampMilli): Seq[NetworkFee] = @@ -424,7 +436,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { feeByChannelId + (f.channelId -> (feeByChannelId.getOrElse(f.channelId, 0 sat) + f.fee)) } case class Relayed(amount: MilliSatoshi, fee: MilliSatoshi, direction: String) - val relayed = listRelayed(from, to).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => + val relayed = listRelayed(from, to, None).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => // NB: we must avoid counting the fee twice: we associate it to the outgoing channels rather than the incoming ones. val current = e match { case c: ChannelPaymentRelayed => Map( diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala index f422d9faec..2ce0b6c679 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala @@ -101,10 +101,22 @@ class AuditDbSpec extends AnyFunSuite { db.add(e11) db.add(e12) - assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute).toSet == Set(e1, e5, e6)) - assert(db.listSent(from = TimestampMilli(100000L), to = TimestampMilli.now() + 1.minute).toList == List(e1)) - assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute).toList == List(e2)) - assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute).toList == List(e3, e10, e11, e12)) + assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, None).toList == List(e5, e1, e6)) + assert(db.listSent(from = TimestampMilli(100000L), to = TimestampMilli.now() + 1.minute, None).toList == List(e1)) + assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 0, skip = 0))).toList == List()) + assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 0))).toList == List(e5, e1)) + assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 1))).toList == List(e1, e6)) + assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 2))).toList == List(e6)) + assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 3))).toList == List()) + assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, None).toList == List(e2)) + assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 0, skip = 0))).toList == List()) + assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 0))).toList == List(e2)) + assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 1))).toList == List()) + assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, None).toList == List(e3, e10, e11, e12)) + assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 0, skip = 0))).toList == List()) + assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 0))).toList == List(e3, e10)) + assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 1))).toList == List(e10, e11)) + assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 4))).toList == List()) assert(db.listNetworkFees(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute).size == 1) assert(db.listNetworkFees(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute).head.txType == "mutual") } @@ -249,7 +261,7 @@ class AuditDbSpec extends AnyFunSuite { targetVersion = SqliteAuditDb.CURRENT_VERSION, postCheck = connection => { // existing rows in the 'sent' table will use id=00000000-0000-0000-0000-000000000000 as default - assert(dbs.audit.listSent(0 unixms, TimestampMilli.now() + 1.minute) == Seq(ps.copy(id = ZERO_UUID, parts = Seq(ps.parts.head.copy(id = ZERO_UUID))))) + assert(dbs.audit.listSent(0 unixms, TimestampMilli.now() + 1.minute, None) == Seq(ps.copy(id = ZERO_UUID, parts = Seq(ps.parts.head.copy(id = ZERO_UUID))))) val postMigrationDb = new SqliteAuditDb(connection) @@ -263,7 +275,7 @@ class AuditDbSpec extends AnyFunSuite { // the old record will have the UNKNOWN_UUID but the new ones will have their actual id val expected = Seq(ps.copy(id = ZERO_UUID, parts = Seq(ps.parts.head.copy(id = ZERO_UUID))), ps1) - assert(postMigrationDb.listSent(0 unixms, TimestampMilli.now() + 1.minute) == expected) + assert(postMigrationDb.listSent(0 unixms, TimestampMilli.now() + 1.minute, None) == expected) } ) } @@ -381,11 +393,11 @@ class AuditDbSpec extends AnyFunSuite { using(connection.createStatement()) { statement => assert(getVersion(statement, "audit").contains(SqliteAuditDb.CURRENT_VERSION)) } - assert(migratedDb.listSent(50 unixms, 150 unixms).toSet == Set( + assert(migratedDb.listSent(50 unixms, 150 unixms, None).toSet == Set( ps1.copy(id = pp1.id, recipientAmount = pp1.amount, parts = pp1 :: Nil), ps1.copy(id = pp2.id, recipientAmount = pp2.amount, parts = pp2 :: Nil) )) - assert(migratedDb.listRelayed(100 unixms, 120 unixms) == Seq(relayed1, relayed2)) + assert(migratedDb.listRelayed(100 unixms, 120 unixms, None) == Seq(relayed1, relayed2)) val postMigrationDb = new SqliteAuditDb(connection) using(connection.createStatement()) { statement => @@ -397,9 +409,9 @@ class AuditDbSpec extends AnyFunSuite { )) val relayed3 = TrampolinePaymentRelayed(randomBytes32(), Seq(PaymentRelayed.Part(450 msat, randomBytes32()), PaymentRelayed.Part(500 msat, randomBytes32())), Seq(PaymentRelayed.Part(800 msat, randomBytes32())), randomKey().publicKey, 700 msat, 150 unixms) postMigrationDb.add(ps2) - assert(postMigrationDb.listSent(155 unixms, 200 unixms) == Seq(ps2)) + assert(postMigrationDb.listSent(155 unixms, 200 unixms, None) == Seq(ps2)) postMigrationDb.add(relayed3) - assert(postMigrationDb.listRelayed(100 unixms, 160 unixms) == Seq(relayed1, relayed2, relayed3)) + assert(postMigrationDb.listRelayed(100 unixms, 160 unixms, None) == Seq(relayed1, relayed2, relayed3)) } ) } @@ -480,7 +492,7 @@ class AuditDbSpec extends AnyFunSuite { postCheck = connection => { val migratedDb = dbs.audit - assert(migratedDb.listRelayed(100 unixms, 120 unixms) == Seq(relayed1, relayed2)) + assert(migratedDb.listRelayed(100 unixms, 120 unixms, None) == Seq(relayed1, relayed2)) val postMigrationDb = new PgAuditDb()(dbs.datasource) using(connection.createStatement()) { statement => @@ -488,7 +500,7 @@ class AuditDbSpec extends AnyFunSuite { } val relayed3 = TrampolinePaymentRelayed(randomBytes32(), Seq(PaymentRelayed.Part(450 msat, randomBytes32()), PaymentRelayed.Part(500 msat, randomBytes32())), Seq(PaymentRelayed.Part(800 msat, randomBytes32())), randomKey().publicKey, 700 msat, 150 unixms) postMigrationDb.add(relayed3) - assert(postMigrationDb.listRelayed(100 unixms, 160 unixms) == Seq(relayed1, relayed2, relayed3)) + assert(postMigrationDb.listRelayed(100 unixms, 160 unixms, None) == Seq(relayed1, relayed2, relayed3)) } ) case dbs: TestSqliteDatabases => @@ -563,7 +575,7 @@ class AuditDbSpec extends AnyFunSuite { using(connection.createStatement()) { statement => assert(getVersion(statement, "audit").contains(SqliteAuditDb.CURRENT_VERSION)) } - assert(migratedDb.listRelayed(100 unixms, 120 unixms) == Seq(relayed1, relayed2)) + assert(migratedDb.listRelayed(100 unixms, 120 unixms, None) == Seq(relayed1, relayed2)) val postMigrationDb = new SqliteAuditDb(connection) using(connection.createStatement()) { statement => @@ -571,7 +583,7 @@ class AuditDbSpec extends AnyFunSuite { } val relayed3 = TrampolinePaymentRelayed(randomBytes32(), Seq(PaymentRelayed.Part(450 msat, randomBytes32()), PaymentRelayed.Part(500 msat, randomBytes32())), Seq(PaymentRelayed.Part(800 msat, randomBytes32())), randomKey().publicKey, 700 msat, 150 unixms) postMigrationDb.add(relayed3) - assert(postMigrationDb.listRelayed(100 unixms, 160 unixms) == Seq(relayed1, relayed2, relayed3)) + assert(postMigrationDb.listRelayed(100 unixms, 160 unixms, None) == Seq(relayed1, relayed2, relayed3)) } ) } @@ -835,7 +847,7 @@ class AuditDbSpec extends AnyFunSuite { statement.executeUpdate() } - assert(db.listRelayed(0 unixms, 40 unixms) == Nil) + assert(db.listRelayed(0 unixms, 40 unixms, None) == Nil) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala index e4a3e0a2a7..5e1edf0fb9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala @@ -362,8 +362,8 @@ class PaymentIntegrationSpec extends IntegrationSpec { assert(paymentParts.forall(p => p.parentId != p.id), paymentParts) assert(paymentParts.forall(p => p.status.asInstanceOf[OutgoingPaymentStatus.Succeeded].feesPaid > 0.msat), paymentParts) - awaitCond(nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now()).nonEmpty) - val sent = nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now()) + awaitCond(nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None).nonEmpty) + val sent = nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None) assert(sent.length == 1, sent) assert(sent.head.copy(parts = sent.head.parts.sortBy(_.timestamp)) == paymentSent.copy(parts = paymentSent.parts.map(_.copy(route = None)).sortBy(_.timestamp)), sent) @@ -485,10 +485,10 @@ class PaymentIntegrationSpec extends IntegrationSpec { assert(receivedAmount == amount) awaitCond({ - val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash) + val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash) relayed.nonEmpty && relayed.head.amountOut >= amount }) - val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash).head + val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash).head assert(relayed.amountIn - relayed.amountOut > 0.msat, relayed) assert(relayed.amountIn - relayed.amountOut < 1210100.msat, relayed) @@ -531,10 +531,10 @@ class PaymentIntegrationSpec extends IntegrationSpec { eventListener.expectMsg(PaymentMetadataReceived(invoice.paymentHash, invoice.paymentMetadata.get)) awaitCond({ - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash) + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash) relayed.nonEmpty && relayed.head.amountOut >= amount }) - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash).head + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash).head assert(relayed.amountIn - relayed.amountOut > 0.msat, relayed) assert(relayed.amountIn - relayed.amountOut < 750000.msat, relayed) @@ -545,8 +545,8 @@ class PaymentIntegrationSpec extends IntegrationSpec { } assert(outgoingSuccess.map(_.amount).sum == amount + 750000.msat, outgoingSuccess) - awaitCond(nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now()).nonEmpty) - val sent = nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now()) + awaitCond(nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None).nonEmpty) + val sent = nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None) assert(sent.length == 1, sent) assert(sent.head.copy(parts = sent.head.parts.sortBy(_.timestamp)) == paymentSent.copy(parts = paymentSent.parts.map(_.copy(route = None)).sortBy(_.timestamp)), sent) } @@ -582,10 +582,10 @@ class PaymentIntegrationSpec extends IntegrationSpec { eventListener.expectMsg(PaymentMetadataReceived(invoice.paymentHash, invoice.paymentMetadata.get)) awaitCond({ - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash) + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash) relayed.nonEmpty && relayed.head.amountOut >= amount }) - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash).head + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash).head assert(relayed.amountIn - relayed.amountOut > 0.msat, relayed) assert(relayed.amountIn - relayed.amountOut < 1500000.msat, relayed) diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Node.scala b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Node.scala index 286c71e903..72a7bed7f3 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Node.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Node.scala @@ -57,8 +57,10 @@ trait Node { } val audit: Route = postRequest("audit") { implicit t => - formFields(fromFormParam(), toFormParam()) { (from, to) => - complete(eclairApi.audit(from, to)) + withPaginated { paginated_opt => + formFields(fromFormParam(), toFormParam()) { (from, to) => + complete(eclairApi.audit(from, to, paginated_opt)) + } } } diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala index f811f89d30..8b5cbc2336 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala @@ -1089,7 +1089,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM val eclair = mock[Eclair] val mockService = new MockService(eclair) val auditResponse = AuditResponse(Seq.empty, Seq.empty, Seq.empty) - eclair.audit(any, any)(any[Timeout]) returns Future.successful(auditResponse) + eclair.audit(any, any, any)(any[Timeout]) returns Future.successful(auditResponse) Post("/audit") ~> addCredentials(BasicHttpCredentials("", mockApi().password)) ~> @@ -1100,7 +1100,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM // The default is to get data for the last day. val from = TimestampSecond.now() - 1.day val to = TimestampSecond.now() - eclair.audit(argThat[TimestampSecond](t => from - 1.minute <= t && t <= from + 1.minute), argThat[TimestampSecond](t => to - 1.minute <= t && t <= to + 1.minute))(any[Timeout]).wasCalled(once) + eclair.audit(argThat[TimestampSecond](t => from - 1.minute <= t && t <= from + 1.minute), argThat[TimestampSecond](t => to - 1.minute <= t && t <= to + 1.minute), None)(any[Timeout]).wasCalled(once) } Post("/audit", FormData("from" -> TimestampSecond.min.toLong.toString, "to" -> TimestampSecond.max.toLong.toString)) ~> @@ -1109,7 +1109,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM check { assert(handled) assert(status == OK) - eclair.audit(TimestampSecond.min, TimestampSecond.max)(any[Timeout]).wasCalled(once) + eclair.audit(TimestampSecond.min, TimestampSecond.max, None)(any[Timeout]).wasCalled(once) } Post("/audit", FormData("from" -> 123456.toString, "to" -> 654321.toString)) ~> @@ -1118,8 +1118,18 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM check { assert(handled) assert(status == OK) - eclair.audit(123456 unixsec, 654321 unixsec)(any[Timeout]).wasCalled(once) + eclair.audit(123456 unixsec, 654321 unixsec, None)(any[Timeout]).wasCalled(once) } + + Post("/audit", FormData("from" -> 123456.toString, "to" -> 654321.toString, "count" -> 1.toString, "skip" -> 2.toString)) ~> + addCredentials(BasicHttpCredentials("", mockApi().password)) ~> + Route.seal(mockService.audit) ~> + check { + assert(handled) + assert(status == OK) + eclair.audit(123456 unixsec, 654321 unixsec, Some(Paginated(count = 1, skip = 2)))(any[Timeout]).wasCalled(once) + } + } test("the websocket should return typed objects") { From c5fd36187670960437ecc90b9f9a97248f516ff7 Mon Sep 17 00:00:00 2001 From: rorp Date: Mon, 14 Nov 2022 14:24:58 -0800 Subject: [PATCH 2/4] update the release notes --- docs/release-notes/eclair-vnext.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/eclair-vnext.md b/docs/release-notes/eclair-vnext.md index c186471b87..dcba9c35f9 100644 --- a/docs/release-notes/eclair-vnext.md +++ b/docs/release-notes/eclair-vnext.md @@ -117,7 +117,7 @@ upgrading to this release. - `channelbalances` and `usablebalances` return a `shortIds` object instead of a single `shortChannelId` (#2323) - `stop` stops eclair: please note that the recommended way of stopping eclair is simply to kill its process (#2233) - `rbfopen` lets the initiator of a dual-funded channel RBF the funding transaction (#2275) -- `listinvoices` now accepts `--count` and `--skip` parameters to limit the number of retrieved items (#2474) +- `listinvoices` and `audit` now accepts `--count` and `--skip` parameters to limit the number of retrieved items (#2474, #2487) ### Miscellaneous improvements and bug fixes From 45b0758fb16712afb9eeebb8dc806dec413b4994 Mon Sep 17 00:00:00 2001 From: rorp Date: Thu, 8 Dec 2022 10:47:17 -0800 Subject: [PATCH 3/4] default value for paginated_opt --- .../scala/fr/acinq/eclair/db/AuditDb.scala | 6 ++--- .../fr/acinq/eclair/db/AuditDbSpec.scala | 22 +++++++++---------- .../integration/PaymentIntegrationSpec.scala | 20 ++++++++--------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala index dba762c3ad..261ef1f9e7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/AuditDb.scala @@ -44,11 +44,11 @@ trait AuditDb { def addPathFindingExperimentMetrics(metrics: PathFindingExperimentMetrics): Unit - def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentSent] + def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentSent] - def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentReceived] + def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentReceived] - def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentRelayed] + def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentRelayed] def listNetworkFees(from: TimestampMilli, to: TimestampMilli): Seq[NetworkFee] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala index 2ce0b6c679..85d4dd5c76 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala @@ -101,18 +101,18 @@ class AuditDbSpec extends AnyFunSuite { db.add(e11) db.add(e12) - assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, None).toList == List(e5, e1, e6)) - assert(db.listSent(from = TimestampMilli(100000L), to = TimestampMilli.now() + 1.minute, None).toList == List(e1)) + assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute).toList == List(e5, e1, e6)) + assert(db.listSent(from = TimestampMilli(100000L), to = TimestampMilli.now() + 1.minute).toList == List(e1)) assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 0, skip = 0))).toList == List()) assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 0))).toList == List(e5, e1)) assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 1))).toList == List(e1, e6)) assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 2))).toList == List(e6)) assert(db.listSent(from = TimestampMilli(0L), to = TimestampMilli.now() + 15.minute, Some(Paginated(count = 2, skip = 3))).toList == List()) - assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, None).toList == List(e2)) + assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute).toList == List(e2)) assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 0, skip = 0))).toList == List()) assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 0))).toList == List(e2)) assert(db.listReceived(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 1))).toList == List()) - assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, None).toList == List(e3, e10, e11, e12)) + assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute).toList == List(e3, e10, e11, e12)) assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 0, skip = 0))).toList == List()) assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 0))).toList == List(e3, e10)) assert(db.listRelayed(from = TimestampMilli(0L), to = TimestampMilli.now() + 1.minute, Some(Paginated(count = 2, skip = 1))).toList == List(e10, e11)) @@ -261,7 +261,7 @@ class AuditDbSpec extends AnyFunSuite { targetVersion = SqliteAuditDb.CURRENT_VERSION, postCheck = connection => { // existing rows in the 'sent' table will use id=00000000-0000-0000-0000-000000000000 as default - assert(dbs.audit.listSent(0 unixms, TimestampMilli.now() + 1.minute, None) == Seq(ps.copy(id = ZERO_UUID, parts = Seq(ps.parts.head.copy(id = ZERO_UUID))))) + assert(dbs.audit.listSent(0 unixms, TimestampMilli.now() + 1.minute) == Seq(ps.copy(id = ZERO_UUID, parts = Seq(ps.parts.head.copy(id = ZERO_UUID))))) val postMigrationDb = new SqliteAuditDb(connection) @@ -393,11 +393,11 @@ class AuditDbSpec extends AnyFunSuite { using(connection.createStatement()) { statement => assert(getVersion(statement, "audit").contains(SqliteAuditDb.CURRENT_VERSION)) } - assert(migratedDb.listSent(50 unixms, 150 unixms, None).toSet == Set( + assert(migratedDb.listSent(50 unixms, 150 unixms).toSet == Set( ps1.copy(id = pp1.id, recipientAmount = pp1.amount, parts = pp1 :: Nil), ps1.copy(id = pp2.id, recipientAmount = pp2.amount, parts = pp2 :: Nil) )) - assert(migratedDb.listRelayed(100 unixms, 120 unixms, None) == Seq(relayed1, relayed2)) + assert(migratedDb.listRelayed(100 unixms, 120 unixms) == Seq(relayed1, relayed2)) val postMigrationDb = new SqliteAuditDb(connection) using(connection.createStatement()) { statement => @@ -492,7 +492,7 @@ class AuditDbSpec extends AnyFunSuite { postCheck = connection => { val migratedDb = dbs.audit - assert(migratedDb.listRelayed(100 unixms, 120 unixms, None) == Seq(relayed1, relayed2)) + assert(migratedDb.listRelayed(100 unixms, 120 unixms) == Seq(relayed1, relayed2)) val postMigrationDb = new PgAuditDb()(dbs.datasource) using(connection.createStatement()) { statement => @@ -500,7 +500,7 @@ class AuditDbSpec extends AnyFunSuite { } val relayed3 = TrampolinePaymentRelayed(randomBytes32(), Seq(PaymentRelayed.Part(450 msat, randomBytes32()), PaymentRelayed.Part(500 msat, randomBytes32())), Seq(PaymentRelayed.Part(800 msat, randomBytes32())), randomKey().publicKey, 700 msat, 150 unixms) postMigrationDb.add(relayed3) - assert(postMigrationDb.listRelayed(100 unixms, 160 unixms, None) == Seq(relayed1, relayed2, relayed3)) + assert(postMigrationDb.listRelayed(100 unixms, 160 unixms) == Seq(relayed1, relayed2, relayed3)) } ) case dbs: TestSqliteDatabases => @@ -575,7 +575,7 @@ class AuditDbSpec extends AnyFunSuite { using(connection.createStatement()) { statement => assert(getVersion(statement, "audit").contains(SqliteAuditDb.CURRENT_VERSION)) } - assert(migratedDb.listRelayed(100 unixms, 120 unixms, None) == Seq(relayed1, relayed2)) + assert(migratedDb.listRelayed(100 unixms, 120 unixms) == Seq(relayed1, relayed2)) val postMigrationDb = new SqliteAuditDb(connection) using(connection.createStatement()) { statement => @@ -583,7 +583,7 @@ class AuditDbSpec extends AnyFunSuite { } val relayed3 = TrampolinePaymentRelayed(randomBytes32(), Seq(PaymentRelayed.Part(450 msat, randomBytes32()), PaymentRelayed.Part(500 msat, randomBytes32())), Seq(PaymentRelayed.Part(800 msat, randomBytes32())), randomKey().publicKey, 700 msat, 150 unixms) postMigrationDb.add(relayed3) - assert(postMigrationDb.listRelayed(100 unixms, 160 unixms, None) == Seq(relayed1, relayed2, relayed3)) + assert(postMigrationDb.listRelayed(100 unixms, 160 unixms) == Seq(relayed1, relayed2, relayed3)) } ) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala index 5e1edf0fb9..e4a3e0a2a7 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/PaymentIntegrationSpec.scala @@ -362,8 +362,8 @@ class PaymentIntegrationSpec extends IntegrationSpec { assert(paymentParts.forall(p => p.parentId != p.id), paymentParts) assert(paymentParts.forall(p => p.status.asInstanceOf[OutgoingPaymentStatus.Succeeded].feesPaid > 0.msat), paymentParts) - awaitCond(nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None).nonEmpty) - val sent = nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None) + awaitCond(nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now()).nonEmpty) + val sent = nodes("B").nodeParams.db.audit.listSent(start, TimestampMilli.now()) assert(sent.length == 1, sent) assert(sent.head.copy(parts = sent.head.parts.sortBy(_.timestamp)) == paymentSent.copy(parts = paymentSent.parts.map(_.copy(route = None)).sortBy(_.timestamp)), sent) @@ -485,10 +485,10 @@ class PaymentIntegrationSpec extends IntegrationSpec { assert(receivedAmount == amount) awaitCond({ - val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash) + val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash) relayed.nonEmpty && relayed.head.amountOut >= amount }) - val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash).head + val relayed = nodes("G").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash).head assert(relayed.amountIn - relayed.amountOut > 0.msat, relayed) assert(relayed.amountIn - relayed.amountOut < 1210100.msat, relayed) @@ -531,10 +531,10 @@ class PaymentIntegrationSpec extends IntegrationSpec { eventListener.expectMsg(PaymentMetadataReceived(invoice.paymentHash, invoice.paymentMetadata.get)) awaitCond({ - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash) + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash) relayed.nonEmpty && relayed.head.amountOut >= amount }) - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash).head + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash).head assert(relayed.amountIn - relayed.amountOut > 0.msat, relayed) assert(relayed.amountIn - relayed.amountOut < 750000.msat, relayed) @@ -545,8 +545,8 @@ class PaymentIntegrationSpec extends IntegrationSpec { } assert(outgoingSuccess.map(_.amount).sum == amount + 750000.msat, outgoingSuccess) - awaitCond(nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None).nonEmpty) - val sent = nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now(), None) + awaitCond(nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now()).nonEmpty) + val sent = nodes("D").nodeParams.db.audit.listSent(start, TimestampMilli.now()) assert(sent.length == 1, sent) assert(sent.head.copy(parts = sent.head.parts.sortBy(_.timestamp)) == paymentSent.copy(parts = paymentSent.parts.map(_.copy(route = None)).sortBy(_.timestamp)), sent) } @@ -582,10 +582,10 @@ class PaymentIntegrationSpec extends IntegrationSpec { eventListener.expectMsg(PaymentMetadataReceived(invoice.paymentHash, invoice.paymentMetadata.get)) awaitCond({ - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash) + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash) relayed.nonEmpty && relayed.head.amountOut >= amount }) - val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now(), None).filter(_.paymentHash == invoice.paymentHash).head + val relayed = nodes("C").nodeParams.db.audit.listRelayed(start, TimestampMilli.now()).filter(_.paymentHash == invoice.paymentHash).head assert(relayed.amountIn - relayed.amountOut > 0.msat, relayed) assert(relayed.amountIn - relayed.amountOut < 1500000.msat, relayed) From a4be029a4f5945c395aeea860c1c938d79e3d5e7 Mon Sep 17 00:00:00 2001 From: rorp Date: Thu, 8 Dec 2022 11:05:52 -0800 Subject: [PATCH 4/4] more default values --- .../src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala | 8 ++++---- .../scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala | 8 ++++---- .../src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala index 1f682fa5c8..1d6b1b5622 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala @@ -334,7 +334,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { } } - override def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentSent] = + override def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentSent] = inTransaction { pg => using(pg.prepareStatement("SELECT * FROM audit.sent WHERE timestamp BETWEEN ? AND ?")) { statement => statement.setTimestamp(1, from.toSqlTimestamp) @@ -368,7 +368,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { } } - override def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentReceived] = + override def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentReceived] = inTransaction { pg => using(pg.prepareStatement("SELECT * FROM audit.received WHERE timestamp BETWEEN ? AND ?")) { statement => statement.setTimestamp(1, from.toSqlTimestamp) @@ -393,7 +393,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { } } - override def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentRelayed] = + override def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentRelayed] = inTransaction { pg => val trampolineByHash = using(pg.prepareStatement("SELECT * FROM audit.relayed_trampoline WHERE timestamp BETWEEN ? and ?")) { statement => statement.setTimestamp(1, from.toSqlTimestamp) @@ -465,7 +465,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { feeByChannelId + (f.channelId -> (feeByChannelId.getOrElse(f.channelId, 0 sat) + f.fee)) } case class Relayed(amount: MilliSatoshi, fee: MilliSatoshi, direction: String) - val relayed = listRelayed(from, to, None).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => + val relayed = listRelayed(from, to).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => // NB: we must avoid counting the fee twice: we associate it to the outgoing channels rather than the incoming ones. val current = e match { case c: ChannelPaymentRelayed => Map( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala index f33ec02767..955a8638e6 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala @@ -310,7 +310,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { } } - override def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentSent] = + override def listSent(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentSent] = using(sqlite.prepareStatement("SELECT * FROM sent WHERE timestamp >= ? AND timestamp < ?")) { statement => statement.setLong(1, from.toLong) statement.setLong(2, to.toLong) @@ -342,7 +342,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { } } - override def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentReceived] = + override def listReceived(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentReceived] = using(sqlite.prepareStatement("SELECT * FROM received WHERE timestamp >= ? AND timestamp < ?")) { statement => statement.setLong(1, from.toLong) statement.setLong(2, to.toLong) @@ -365,7 +365,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { } } - override def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated]): Seq[PaymentRelayed] = { + override def listRelayed(from: TimestampMilli, to: TimestampMilli, paginated_opt: Option[Paginated] = None): Seq[PaymentRelayed] = { val trampolineByHash = using(sqlite.prepareStatement("SELECT * FROM relayed_trampoline WHERE timestamp >= ? AND timestamp < ?")) { statement => statement.setLong(1, from.toLong) statement.setLong(2, to.toLong) @@ -436,7 +436,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { feeByChannelId + (f.channelId -> (feeByChannelId.getOrElse(f.channelId, 0 sat) + f.fee)) } case class Relayed(amount: MilliSatoshi, fee: MilliSatoshi, direction: String) - val relayed = listRelayed(from, to, None).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => + val relayed = listRelayed(from, to).foldLeft(Map.empty[ByteVector32, Seq[Relayed]]) { (previous, e) => // NB: we must avoid counting the fee twice: we associate it to the outgoing channels rather than the incoming ones. val current = e match { case c: ChannelPaymentRelayed => Map( diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala index 85d4dd5c76..92446779ee 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala @@ -275,7 +275,7 @@ class AuditDbSpec extends AnyFunSuite { // the old record will have the UNKNOWN_UUID but the new ones will have their actual id val expected = Seq(ps.copy(id = ZERO_UUID, parts = Seq(ps.parts.head.copy(id = ZERO_UUID))), ps1) - assert(postMigrationDb.listSent(0 unixms, TimestampMilli.now() + 1.minute, None) == expected) + assert(postMigrationDb.listSent(0 unixms, TimestampMilli.now() + 1.minute) == expected) } ) } @@ -409,9 +409,9 @@ class AuditDbSpec extends AnyFunSuite { )) val relayed3 = TrampolinePaymentRelayed(randomBytes32(), Seq(PaymentRelayed.Part(450 msat, randomBytes32()), PaymentRelayed.Part(500 msat, randomBytes32())), Seq(PaymentRelayed.Part(800 msat, randomBytes32())), randomKey().publicKey, 700 msat, 150 unixms) postMigrationDb.add(ps2) - assert(postMigrationDb.listSent(155 unixms, 200 unixms, None) == Seq(ps2)) + assert(postMigrationDb.listSent(155 unixms, 200 unixms) == Seq(ps2)) postMigrationDb.add(relayed3) - assert(postMigrationDb.listRelayed(100 unixms, 160 unixms, None) == Seq(relayed1, relayed2, relayed3)) + assert(postMigrationDb.listRelayed(100 unixms, 160 unixms) == Seq(relayed1, relayed2, relayed3)) } ) }