Adds audit RPC call + test (#314)

This commit is contained in:
Torkel Rogstad 2019-01-29 01:15:02 +01:00 committed by Chris Stewart
parent 9257a53fde
commit 8bbd4e0631
7 changed files with 98 additions and 13 deletions

View File

@ -19,6 +19,18 @@ trait EclairApi {
def allNodes(): Future[Vector[NodeInfo]]
/**
* List all sent/received/relayed payments
*/
def audit(): Future[AuditResult]
/**
* List all sent/received/relayed payments in the given interval
* @param from start timestamp
* @param to end timestamp
*/
def audit(from: Long, to: Long): Future[AuditResult]
def allUpdates(): Future[Vector[ChannelUpdate]]
def allUpdates(nodeId: NodeId): Future[Vector[ChannelUpdate]]

View File

@ -59,6 +59,18 @@ class EclairRpcClient(val instance: EclairInstance)(
eclairCall[Vector[ChannelUpdate]]("allupdates",
List(JsString(nodeId.toString)))
/**
* @inheritdoc
*/
override def audit(): Future[AuditResult] =
eclairCall[AuditResult]("audit", List.empty)
/**
* @inheritdoc
*/
override def audit(from: Long, to: Long): Future[AuditResult] =
eclairCall[AuditResult]("audit", List(JsNumber(from), JsNumber(to)))
override def channel(channelId: ChannelId): Future[ChannelResult] = {
eclairCall[ChannelResult]("channel", List(JsString(channelId.hex)))
}

View File

@ -86,6 +86,37 @@ case class NodeInfo(
case class ChannelDesc(shortChannelId: ShortChannelId, a: NodeId, b: NodeId)
case class AuditResult(
sent: Vector[SentPayment],
relayed: Vector[RelayedPayment],
received: Vector[ReceivedPayment]
)
case class ReceivedPayment(
amount: MilliSatoshis,
paymentHash: Sha256Digest,
fromChannelId: FundedChannelId,
timestamp: Long
)
case class RelayedPayment(
amountIn: MilliSatoshis,
amountOut: MilliSatoshis,
paymentHash: Sha256Digest,
fromChannelId: FundedChannelId,
toChannelId: FundedChannelId,
timestamp: Long
)
case class SentPayment(
amount: MilliSatoshis,
feesPaid: MilliSatoshis,
paymentHash: Sha256Digest,
paymentPreimage: String,
toChannelId: FundedChannelId,
timestamp: Long
)
case class ChannelUpdate(
signature: ECDigitalSignature,
chainHash: DoubleSha256Digest,

View File

@ -222,4 +222,11 @@ object JsonReaders {
JsNull) =>
JsError(s"Invalid type on refund invoice: $bad, expected JsString")
}
implicit val receivedPaymentReads: Reads[ReceivedPayment] =
Json.reads[ReceivedPayment]
implicit val sentPaymentReads: Reads[SentPayment] = Json.reads[SentPayment]
implicit val relayedPaymentReads: Reads[RelayedPayment] =
Json.reads[RelayedPayment]
implicit val auditResultReads: Reads[AuditResult] = Json.reads[AuditResult]
}

View File

@ -36,6 +36,14 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
val bitcoindRpcClient: BitcoindRpcClient =
BitcoindRpcTestUtil.startedBitcoindRpcClient()
lazy val EclairNodes4(firstClient, secondClient, thirdClient, fourthClient) = {
val EclairNodes4(first, second, third, fourth) =
EclairRpcTestUtil.createNodeLink(bitcoindRpcClient)
clients ++= List(first, second, third, fourth)
EclairNodes4(first, second, third, fourth)
}
lazy val (client, otherClient) = {
val (c1, c2) = EclairRpcTestUtil.createNodePair(Some(bitcoindRpcClient))
clients += c1
@ -357,13 +365,9 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
}
it should "get a route to a node ID" in {
val EclairNodes4(first, second, third, fourth) =
EclairRpcTestUtil.createNodeLink(bitcoindRpcClient)
clients ++= List(first, second, third, fourth)
val hasRoute = () => {
fourth.getInfo
.flatMap(info => first.findRoute(info.nodeId))
fourthClient.getInfo
.flatMap(info => firstClient.findRoute(info.nodeId))
.map(route => route.length == 4)
.recover {
case err: RuntimeException
@ -379,14 +383,10 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
}
it should "get a route to an invoice" in {
val EclairNodes4(first, second, third, fourth) =
EclairRpcTestUtil.createNodeLink(bitcoindRpcClient)
clients ++= List(first, second, third, fourth)
val hasRoute = () => {
fourth
fourthClient
.receive("foo")
.flatMap(invoice => first.findRoute(invoice))
.flatMap(invoice => firstClient.findRoute(invoice))
.map(route => route.length == 4)
.recover {
case err: RuntimeException
@ -401,6 +401,28 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
succeed
}
it should "send some payments and get the audit info" in {
for {
invoice <- fourthClient.receive(MilliSatoshis(50000).toLnCurrencyUnit)
_ <- firstClient
.send(invoice)
.map(payment => assert(payment.isInstanceOf[PaymentSucceeded]))
received <- fourthClient
.audit()
.map(_.received) // check for received payments
relayed <- secondClient
.audit()
.map(_.relayed) // check for relayed payments
sent <- firstClient
.audit()
.map(_.sent) // check for sent payments
} yield {
assert(received.nonEmpty)
assert(relayed.nonEmpty)
assert(sent.nonEmpty)
}
}
// We spawn fresh clients in this test because the test
// needs nodes with activity both related and not related
// to them

View File

@ -17,7 +17,7 @@ object Deps {
val nativeLoaderV = "2.3.2"
val typesafeConfigV = "1.3.3"
val bitcoinsV = "0.0.4.1-SNAPSHOT"
val bitcoinsV = "5d3bf4-1548681478579-SNAPSHOT"
}
object Compile {

View File

@ -93,6 +93,7 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
"eclair.auto-reconnect" -> false,
"eclair.db.driver" -> "org.sqlite.JDBC",
"eclair.db.regtest.url" -> "jdbc:sqlite:regtest/",
"eclair.max-payment-fee" -> 10, // avoid complaints about too high fees
"eclair.alias" -> "suredbits"
)
}