mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-22 06:31:55 +01:00
Reduce number of requests we send to eclair in testkits, add commandN… (#343)
* Reduce number of requests we send to eclair in testkits, add commandName param to parseResult in EclairRpcClient * Factor our EclairRpcClient error message * Make jvm opts more sane, refactor error message code again * Add error message on EclairRpcTestUtil.sendPayments, scalafmt
This commit is contained in:
parent
abc6f55a08
commit
88e6450c5a
4 changed files with 293 additions and 226 deletions
1
.jvmopts
1
.jvmopts
|
@ -1,2 +1 @@
|
||||||
-Xmx1024m
|
-Xmx1024m
|
||||||
-Xms1024m
|
|
||||||
|
|
|
@ -7,7 +7,11 @@ import org.bitcoins.core.config.RegTest
|
||||||
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits, Satoshis}
|
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits, Satoshis}
|
||||||
import org.bitcoins.core.number.Int64
|
import org.bitcoins.core.number.Int64
|
||||||
import org.bitcoins.core.protocol.ln.LnParams.LnBitcoinRegTest
|
import org.bitcoins.core.protocol.ln.LnParams.LnBitcoinRegTest
|
||||||
import org.bitcoins.core.protocol.ln.channel.{ChannelId, ChannelState, FundedChannelId}
|
import org.bitcoins.core.protocol.ln.channel.{
|
||||||
|
ChannelId,
|
||||||
|
ChannelState,
|
||||||
|
FundedChannelId
|
||||||
|
}
|
||||||
import org.bitcoins.core.protocol.ln.currency._
|
import org.bitcoins.core.protocol.ln.currency._
|
||||||
import org.bitcoins.core.protocol.ln.node.NodeId
|
import org.bitcoins.core.protocol.ln.node.NodeId
|
||||||
import org.bitcoins.core.util.BitcoinSLogger
|
import org.bitcoins.core.util.BitcoinSLogger
|
||||||
|
@ -41,7 +45,6 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
blocksF.flatMap(_ => cliF)
|
blocksF.flatMap(_ => cliF)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val eclairNodesF: Future[EclairNodes4] = {
|
val eclairNodesF: Future[EclairNodes4] = {
|
||||||
bitcoindRpcClientF.flatMap { bitcoindRpcClient =>
|
bitcoindRpcClientF.flatMap { bitcoindRpcClient =>
|
||||||
val nodesF = EclairRpcTestUtil.createNodeLink(bitcoindRpcClient)
|
val nodesF = EclairRpcTestUtil.createNodeLink(bitcoindRpcClient)
|
||||||
|
@ -62,7 +65,6 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
lazy val fourthClientF = eclairNodesF.map(_.c4)
|
lazy val fourthClientF = eclairNodesF.map(_.c4)
|
||||||
|
|
||||||
|
|
||||||
/** There is specific cases where we just need two clients,
|
/** There is specific cases where we just need two clients,
|
||||||
* so this is a helper val that pairs two connected
|
* so this is a helper val that pairs two connected
|
||||||
* clients together with an open channel
|
* clients together with an open channel
|
||||||
|
@ -71,7 +73,7 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
//use second and third client above since they
|
//use second and third client above since they
|
||||||
//aren't really being used in the tests that use eclairNodesF
|
//aren't really being used in the tests that use eclairNodesF
|
||||||
secondClientF.flatMap(s => thirdClientF.map(t => (s,t)))
|
secondClientF.flatMap(s => thirdClientF.map(t => (s, t)))
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val clientF = clientOtherClientF.map(_._1)
|
lazy val clientF = clientOtherClientF.map(_._1)
|
||||||
|
@ -86,21 +88,22 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
* @tparam T
|
* @tparam T
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def executeWithClientOtherClient[T](test: (EclairRpcClient,EclairRpcClient) => Future[T]): Future[T] = {
|
def executeWithClientOtherClient[T](
|
||||||
|
test: (EclairRpcClient, EclairRpcClient) => Future[T]): Future[T] = {
|
||||||
|
|
||||||
executeSpecificClients(clientF = clientF,
|
executeSpecificClients(clientF = clientF,
|
||||||
otherClientF = otherClientF,
|
otherClientF = otherClientF,
|
||||||
test = test)
|
test = test)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Executes the test with the clients passed as a parameter */
|
/** Executes the test with the clients passed as a parameter */
|
||||||
def executeSpecificClients[T](clientF: Future[EclairRpcClient],
|
def executeSpecificClients[T](
|
||||||
otherClientF: Future[EclairRpcClient],
|
clientF: Future[EclairRpcClient],
|
||||||
test: (EclairRpcClient,EclairRpcClient) => Future[T]): Future[T] = {
|
otherClientF: Future[EclairRpcClient],
|
||||||
|
test: (EclairRpcClient, EclairRpcClient) => Future[T]): Future[T] = {
|
||||||
clientF.flatMap { c1 =>
|
clientF.flatMap { c1 =>
|
||||||
otherClientF.flatMap { other =>
|
otherClientF.flatMap { other =>
|
||||||
test(c1,other)
|
test(c1, other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,43 +115,43 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
val changeAddrF = bitcoindRpcClientF.flatMap(_.getNewAddress())
|
val changeAddrF = bitcoindRpcClientF.flatMap(_.getNewAddress())
|
||||||
val result: Future[Assertion] = {
|
val result: Future[Assertion] = {
|
||||||
val isOpenedF: Future[(ChannelId, Assertion)] = {
|
val isOpenedF: Future[(ChannelId, Assertion)] = {
|
||||||
val getChannelId = (client: EclairRpcClient, otherClient: EclairRpcClient) => {
|
val getChannelId =
|
||||||
otherClient.getInfo.flatMap { info =>
|
(client: EclairRpcClient, otherClient: EclairRpcClient) => {
|
||||||
val amt = Satoshis(Int64(100000))
|
otherClient.getInfo.flatMap { info =>
|
||||||
val openedChanF = clientF.flatMap(_.open(info.nodeId, amt))
|
val amt = Satoshis(Int64(100000))
|
||||||
|
val openedChanF = clientF.flatMap(_.open(info.nodeId, amt))
|
||||||
|
|
||||||
openedChanF.flatMap { channelId =>
|
openedChanF.flatMap { channelId =>
|
||||||
val exists = hasChannel(client, channelId)
|
val exists = hasChannel(client, channelId)
|
||||||
exists.map(e => (channelId, e))
|
exists.map(e => (channelId, e))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
executeWithClientOtherClient[(ChannelId, Assertion)](getChannelId)
|
||||||
executeWithClientOtherClient[(ChannelId,Assertion)](getChannelId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val isConfirmedF: Future[(ChannelId, Assertion)] = {
|
val isConfirmedF: Future[(ChannelId, Assertion)] = {
|
||||||
val getIsConfirmed = {
|
val getIsConfirmed = { (client: EclairRpcClient, _: EclairRpcClient) =>
|
||||||
(client: EclairRpcClient, _: EclairRpcClient) =>
|
isOpenedF.flatMap {
|
||||||
isOpenedF.flatMap {
|
case (chanId, assertion) =>
|
||||||
case (chanId, assertion) =>
|
val generatedF = bitcoindRpcClientF.flatMap(_.generate(6))
|
||||||
val generatedF = bitcoindRpcClientF.flatMap(_.generate(6))
|
val normalF = generatedF.flatMap { _ =>
|
||||||
val normalF = generatedF.flatMap { _ =>
|
EclairRpcTestUtil.awaitUntilChannelNormal(
|
||||||
EclairRpcTestUtil.awaitUntilChannelNormal(
|
client = client,
|
||||||
client = client,
|
chanId = chanId
|
||||||
chanId = chanId
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
normalF.map(_ => (chanId, assertion))
|
normalF.map(_ => (chanId, assertion))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
executeWithClientOtherClient(getIsConfirmed)
|
executeWithClientOtherClient(getIsConfirmed)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isClosedF = {
|
val isClosedF = {
|
||||||
val getIsClosed = {
|
val getIsClosed = { (client: EclairRpcClient, _: EclairRpcClient) =>
|
||||||
(client: EclairRpcClient, _: EclairRpcClient) => isConfirmedF.flatMap {
|
isConfirmedF.flatMap {
|
||||||
case (chanId, assertion) =>
|
case (chanId, assertion) =>
|
||||||
val closedF = changeAddrF.flatMap { addr =>
|
val closedF = changeAddrF.flatMap { addr =>
|
||||||
val closedF = client.close(chanId, addr.scriptPubKey)
|
val closedF = client.close(chanId, addr.scriptPubKey)
|
||||||
|
@ -159,7 +162,6 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
}
|
}
|
||||||
|
|
||||||
closedF.flatMap { _ =>
|
closedF.flatMap { _ =>
|
||||||
|
|
||||||
val chanF = client.channel(chanId)
|
val chanF = client.channel(chanId)
|
||||||
chanF.map { chan =>
|
chanF.map { chan =>
|
||||||
assert(chan.state == ChannelState.CLOSING)
|
assert(chan.state == ChannelState.CLOSING)
|
||||||
|
@ -177,7 +179,7 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
val amountF =
|
val amountF =
|
||||||
bitcoindRpcClientF.flatMap { bitcoindRpcClient =>
|
bitcoindRpcClientF.flatMap { bitcoindRpcClient =>
|
||||||
bitcoindRpcClient.getReceivedByAddress(address = addr,
|
bitcoindRpcClient.getReceivedByAddress(address = addr,
|
||||||
minConfirmations = 0)
|
minConfirmations = 0)
|
||||||
}
|
}
|
||||||
amountF.map(amt => assert(amt > CurrencyUnits.zero))
|
amountF.map(amt => assert(amt > CurrencyUnits.zero))
|
||||||
}
|
}
|
||||||
|
@ -199,28 +201,23 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
executeWithClientOtherClient[EclairAuthCredentials](getAuthCredentials)
|
executeWithClientOtherClient[EclairAuthCredentials](getAuthCredentials)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val badCredentialsF = goodCredentialsF.map { good =>
|
val badCredentialsF = goodCredentialsF.map { good =>
|
||||||
EclairAuthCredentials("bad_password",
|
EclairAuthCredentials("bad_password", good.bitcoinAuthOpt, good.port)
|
||||||
good.bitcoinAuthOpt,
|
|
||||||
good.port)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val badInstanceF = badCredentialsF.flatMap { badCredentials =>
|
val badInstanceF = badCredentialsF.flatMap { badCredentials =>
|
||||||
val getBadInstance = (client: EclairRpcClient, _: EclairRpcClient) => {
|
val getBadInstance = (client: EclairRpcClient, _: EclairRpcClient) => {
|
||||||
val instance = EclairInstance(network = client.instance.network,
|
val instance = EclairInstance(network = client.instance.network,
|
||||||
uri = client.instance.uri,
|
uri = client.instance.uri,
|
||||||
rpcUri = client.instance.rpcUri,
|
rpcUri = client.instance.rpcUri,
|
||||||
authCredentials = badCredentials)
|
authCredentials = badCredentials)
|
||||||
|
|
||||||
Future.successful(instance)
|
Future.successful(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
executeWithClientOtherClient(getBadInstance)
|
executeWithClientOtherClient(getBadInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val badClientF = badInstanceF.map(new EclairRpcClient(_))
|
val badClientF = badInstanceF.map(new EclairRpcClient(_))
|
||||||
|
|
||||||
badClientF.flatMap { badClient =>
|
badClientF.flatMap { badClient =>
|
||||||
|
@ -228,13 +225,11 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it should "be able to list an existing peer and isConnected must be true" in {
|
it should "be able to list an existing peer and isConnected must be true" in {
|
||||||
//test assumes that a connection to a peer was made in `beforeAll`
|
//test assumes that a connection to a peer was made in `beforeAll`
|
||||||
val otherClientNodeIdF = {
|
val otherClientNodeIdF = {
|
||||||
val getOtherClientNodeId = {
|
val getOtherClientNodeId = {
|
||||||
(_:EclairRpcClient, otherClient: EclairRpcClient) =>
|
(_: EclairRpcClient, otherClient: EclairRpcClient) =>
|
||||||
otherClient.getInfo.map(_.nodeId)
|
otherClient.getInfo.map(_.nodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,26 +242,28 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
it should "ble able to pay to a hash" in {
|
it should "ble able to pay to a hash" in {
|
||||||
val amt = MilliSatoshis(50)
|
val amt = MilliSatoshis(50)
|
||||||
val getPayment = {
|
val getPayment = {
|
||||||
(client: EclairRpcClient,otherClient: EclairRpcClient) => {
|
(client: EclairRpcClient, otherClient: EclairRpcClient) =>
|
||||||
for {
|
{
|
||||||
channelId <- openAndConfirmChannel(clientF, otherClientF)
|
for {
|
||||||
otherClientNodeId <- otherClient.getInfo.map(_.nodeId)
|
channelId <- openAndConfirmChannel(clientF, otherClientF)
|
||||||
channels <- client.channels(otherClientNodeId)
|
otherClientNodeId <- otherClient.getInfo.map(_.nodeId)
|
||||||
// without this we've been getting "route not found"
|
channels <- client.channels(otherClientNodeId)
|
||||||
// probably an async issue, this is more elegant than Thread.sleep
|
// without this we've been getting "route not found"
|
||||||
_ = assert(channels.exists(_.state == ChannelState.NORMAL), "Nodes did not have open channel!")
|
// probably an async issue, this is more elegant than Thread.sleep
|
||||||
invoice <- otherClient.receive(amt.toLnCurrencyUnit)
|
_ = assert(channels.exists(_.state == ChannelState.NORMAL),
|
||||||
payment <- client.send(amt.toLnCurrencyUnit,
|
"Nodes did not have open channel!")
|
||||||
invoice.lnTags.paymentHash.hash,
|
invoice <- otherClient.receive(amt.toLnCurrencyUnit)
|
||||||
otherClientNodeId)
|
payment <- client.send(amt.toLnCurrencyUnit,
|
||||||
_ <- client.close(channelId)
|
invoice.lnTags.paymentHash.hash,
|
||||||
_ <- bitcoindRpcClientF.flatMap(_.generate(6))
|
otherClientNodeId)
|
||||||
} yield {
|
_ <- client.close(channelId)
|
||||||
assert(payment.isInstanceOf[PaymentSucceeded])
|
_ <- bitcoindRpcClientF.flatMap(_.generate(6))
|
||||||
val succeeded = payment.asInstanceOf[PaymentSucceeded]
|
} yield {
|
||||||
assert(succeeded.amountMsat == amt)
|
assert(payment.isInstanceOf[PaymentSucceeded])
|
||||||
|
val succeeded = payment.asInstanceOf[PaymentSucceeded]
|
||||||
|
assert(succeeded.amountMsat == amt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executeWithClientOtherClient(getPayment)
|
executeWithClientOtherClient(getPayment)
|
||||||
|
@ -277,19 +274,20 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
val amt = MilliSatoshis(50)
|
val amt = MilliSatoshis(50)
|
||||||
|
|
||||||
val getPaymentWithAmount = {
|
val getPaymentWithAmount = {
|
||||||
(client: EclairRpcClient, otherClient: EclairRpcClient) => {
|
(client: EclairRpcClient, otherClient: EclairRpcClient) =>
|
||||||
for {
|
{
|
||||||
channelId <- openAndConfirmChannel(clientF, otherClientF)
|
for {
|
||||||
invoice <- otherClient.receive(amt.toLnCurrencyUnit)
|
channelId <- openAndConfirmChannel(clientF, otherClientF)
|
||||||
payment <- client.send(invoice)
|
invoice <- otherClient.receive(amt.toLnCurrencyUnit)
|
||||||
_ <- client.close(channelId)
|
payment <- client.send(invoice)
|
||||||
_ <- bitcoindRpcClientF.flatMap(_.generate(6))
|
_ <- client.close(channelId)
|
||||||
} yield {
|
_ <- bitcoindRpcClientF.flatMap(_.generate(6))
|
||||||
assert(payment.isInstanceOf[PaymentSucceeded])
|
} yield {
|
||||||
val succeeded = payment.asInstanceOf[PaymentSucceeded]
|
assert(payment.isInstanceOf[PaymentSucceeded])
|
||||||
assert(succeeded.amountMsat == amt)
|
val succeeded = payment.asInstanceOf[PaymentSucceeded]
|
||||||
|
assert(succeeded.amountMsat == amt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executeWithClientOtherClient(getPaymentWithAmount)
|
executeWithClientOtherClient(getPaymentWithAmount)
|
||||||
|
@ -298,19 +296,20 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
it should "be able to generate an invoice without amount and pay it" in {
|
it should "be able to generate an invoice without amount and pay it" in {
|
||||||
val amt = MilliSatoshis(50)
|
val amt = MilliSatoshis(50)
|
||||||
val getPaymentNoAmount = {
|
val getPaymentNoAmount = {
|
||||||
(client: EclairRpcClient, otherClient: EclairRpcClient) => {
|
(client: EclairRpcClient, otherClient: EclairRpcClient) =>
|
||||||
for {
|
{
|
||||||
channelId <- openAndConfirmChannel(clientF, otherClientF)
|
for {
|
||||||
invoice <- otherClient.receive("no amount")
|
channelId <- openAndConfirmChannel(clientF, otherClientF)
|
||||||
payment <- client.send(invoice, amt.toLnCurrencyUnit)
|
invoice <- otherClient.receive("no amount")
|
||||||
_ <- client.close(channelId)
|
payment <- client.send(invoice, amt.toLnCurrencyUnit)
|
||||||
_ <- bitcoindRpcClientF.flatMap(_.generate(6))
|
_ <- client.close(channelId)
|
||||||
} yield {
|
_ <- bitcoindRpcClientF.flatMap(_.generate(6))
|
||||||
assert(payment.isInstanceOf[PaymentSucceeded])
|
} yield {
|
||||||
val succeeded = payment.asInstanceOf[PaymentSucceeded]
|
assert(payment.isInstanceOf[PaymentSucceeded])
|
||||||
assert(succeeded.amountMsat == amt)
|
val succeeded = payment.asInstanceOf[PaymentSucceeded]
|
||||||
|
assert(succeeded.amountMsat == amt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executeWithClientOtherClient(getPaymentNoAmount)
|
executeWithClientOtherClient(getPaymentNoAmount)
|
||||||
|
@ -321,9 +320,10 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
val description = "bitcoin-s test case"
|
val description = "bitcoin-s test case"
|
||||||
val expiry = (System.currentTimeMillis() / 1000)
|
val expiry = (System.currentTimeMillis() / 1000)
|
||||||
|
|
||||||
val invoiceF = clientF.flatMap(_.receive(description = description,
|
val invoiceF = clientF.flatMap(
|
||||||
amountMsat = amt,
|
_.receive(description = description,
|
||||||
expirySeconds = expiry))
|
amountMsat = amt,
|
||||||
|
expirySeconds = expiry))
|
||||||
|
|
||||||
val assert0: Future[Assertion] = {
|
val assert0: Future[Assertion] = {
|
||||||
invoiceF.map { i =>
|
invoiceF.map { i =>
|
||||||
|
@ -334,9 +334,10 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
}
|
}
|
||||||
|
|
||||||
val amt1 = NanoBitcoins.one
|
val amt1 = NanoBitcoins.one
|
||||||
val invoice1F = clientF.flatMap(_.receive(description = description,
|
val invoice1F = clientF.flatMap(
|
||||||
amountMsat = amt1,
|
_.receive(description = description,
|
||||||
expirySeconds = expiry))
|
amountMsat = amt1,
|
||||||
|
expirySeconds = expiry))
|
||||||
|
|
||||||
val assert1 = {
|
val assert1 = {
|
||||||
invoice1F.map { i =>
|
invoice1F.map { i =>
|
||||||
|
@ -347,9 +348,10 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
}
|
}
|
||||||
|
|
||||||
val amt2 = MicroBitcoins.one
|
val amt2 = MicroBitcoins.one
|
||||||
val invoice2F = clientF.flatMap(_.receive(description = description,
|
val invoice2F = clientF.flatMap(
|
||||||
amountMsat = amt2,
|
_.receive(description = description,
|
||||||
expirySeconds = expiry))
|
amountMsat = amt2,
|
||||||
|
expirySeconds = expiry))
|
||||||
|
|
||||||
val assert2 = {
|
val assert2 = {
|
||||||
invoice2F.map { i =>
|
invoice2F.map { i =>
|
||||||
|
@ -362,9 +364,10 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
val amt3 = MilliBitcoins.one
|
val amt3 = MilliBitcoins.one
|
||||||
|
|
||||||
val invoice3F = clientF.flatMap(_.receive(description = description,
|
val invoice3F = clientF.flatMap(
|
||||||
amountMsat = amt3,
|
_.receive(description = description,
|
||||||
expirySeconds = expiry))
|
amountMsat = amt3,
|
||||||
|
expirySeconds = expiry))
|
||||||
|
|
||||||
val assert3 = {
|
val assert3 = {
|
||||||
invoice3F.map { i =>
|
invoice3F.map { i =>
|
||||||
|
@ -385,9 +388,10 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
val description = "bitcoin-s test case"
|
val description = "bitcoin-s test case"
|
||||||
val expiry = (System.currentTimeMillis() / 1000)
|
val expiry = (System.currentTimeMillis() / 1000)
|
||||||
|
|
||||||
val invoiceF = clientF.flatMap(_.receive(description = description,
|
val invoiceF = clientF.flatMap(
|
||||||
amountMsat = amt,
|
_.receive(description = description,
|
||||||
expirySeconds = expiry))
|
amountMsat = amt,
|
||||||
|
expirySeconds = expiry))
|
||||||
|
|
||||||
val paymentRequestF: Future[PaymentRequest] = invoiceF.flatMap { i =>
|
val paymentRequestF: Future[PaymentRequest] = invoiceF.flatMap { i =>
|
||||||
clientF.flatMap(_.checkInvoice(i))
|
clientF.flatMap(_.checkInvoice(i))
|
||||||
|
@ -404,7 +408,8 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
val paymentAmount = NanoBitcoins(100000)
|
val paymentAmount = NanoBitcoins(100000)
|
||||||
val invoiceF =
|
val invoiceF =
|
||||||
openChannelIdF.flatMap(_ => otherClientF.flatMap(_.receive(paymentAmount)))
|
openChannelIdF.flatMap(_ =>
|
||||||
|
otherClientF.flatMap(_.receive(paymentAmount)))
|
||||||
|
|
||||||
val paymentF = invoiceF.flatMap(i => clientF.flatMap(_.send(i)))
|
val paymentF = invoiceF.flatMap(i => clientF.flatMap(_.send(i)))
|
||||||
|
|
||||||
|
@ -451,14 +456,17 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
val paymentAmount = NanoBitcoins(100000)
|
val paymentAmount = NanoBitcoins(100000)
|
||||||
val invoiceF =
|
val invoiceF =
|
||||||
openChannelIdF.flatMap(_ => otherClientF.flatMap(_.receive(paymentAmount)))
|
openChannelIdF.flatMap(_ =>
|
||||||
|
otherClientF.flatMap(_.receive(paymentAmount)))
|
||||||
|
|
||||||
val isPaid1F = invoiceF.flatMap(i => otherClientF.flatMap(_.checkPayment(Left(i))))
|
val isPaid1F =
|
||||||
|
invoiceF.flatMap(i => otherClientF.flatMap(_.checkPayment(Left(i))))
|
||||||
|
|
||||||
val isNotPaidAssertF = isPaid1F.map(isPaid => assert(!isPaid))
|
val isNotPaidAssertF = isPaid1F.map(isPaid => assert(!isPaid))
|
||||||
|
|
||||||
//send the payment now
|
//send the payment now
|
||||||
val paidF: Future[PaymentResult] = invoiceF.flatMap(i => clientF.flatMap(_.send(i)))
|
val paidF: Future[PaymentResult] =
|
||||||
|
invoiceF.flatMap(i => clientF.flatMap(_.send(i)))
|
||||||
|
|
||||||
val isPaid2F: Future[Boolean] = paidF.flatMap { p =>
|
val isPaid2F: Future[Boolean] = paidF.flatMap { p =>
|
||||||
val succeed = p.asInstanceOf[PaymentSucceeded]
|
val succeed = p.asInstanceOf[PaymentSucceeded]
|
||||||
|
@ -481,9 +489,11 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
val paymentAmount = NanoBitcoins(100000)
|
val paymentAmount = NanoBitcoins(100000)
|
||||||
val invoiceF =
|
val invoiceF =
|
||||||
openChannelIdF.flatMap(_ => otherClientF.flatMap(_.receive(paymentAmount)))
|
openChannelIdF.flatMap(_ =>
|
||||||
|
otherClientF.flatMap(_.receive(paymentAmount)))
|
||||||
//send the payment now
|
//send the payment now
|
||||||
val paidF: Future[PaymentResult] = invoiceF.flatMap(i => clientF.flatMap(_.send(i)))
|
val paidF: Future[PaymentResult] =
|
||||||
|
invoiceF.flatMap(i => clientF.flatMap(_.send(i)))
|
||||||
|
|
||||||
val isPaidF: Future[Boolean] = paidF.flatMap { p =>
|
val isPaidF: Future[Boolean] = paidF.flatMap { p =>
|
||||||
val succeed = p.asInstanceOf[PaymentSucceeded]
|
val succeed = p.asInstanceOf[PaymentSucceeded]
|
||||||
|
@ -493,7 +503,8 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
val isPaidAssertF = isPaidF.map(isPaid => assert(isPaid))
|
val isPaidAssertF = isPaidF.map(isPaid => assert(isPaid))
|
||||||
|
|
||||||
isPaidAssertF.flatMap { isPaid =>
|
isPaidAssertF.flatMap { isPaid =>
|
||||||
val invoice2F = openChannelIdF.flatMap(_ => clientF.flatMap(_.receive(paymentAmount)))
|
val invoice2F =
|
||||||
|
openChannelIdF.flatMap(_ => clientF.flatMap(_.receive(paymentAmount)))
|
||||||
//send the payment now
|
//send the payment now
|
||||||
val paid2F: Future[PaymentResult] =
|
val paid2F: Future[PaymentResult] =
|
||||||
invoice2F.flatMap((i => otherClientF.flatMap(_.send(i))))
|
invoice2F.flatMap((i => otherClientF.flatMap(_.send(i))))
|
||||||
|
@ -520,7 +531,8 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
(channel, oldFee) <- channelAndFeeF
|
(channel, oldFee) <- channelAndFeeF
|
||||||
_ <- clientF.flatMap(_.updateRelayFee(channel, MilliSatoshis(oldFee.toLong * 2), 1))
|
_ <- clientF.flatMap(
|
||||||
|
_.updateRelayFee(channel, MilliSatoshis(oldFee.toLong * 2), 1))
|
||||||
newFeeOpt <- clientF.flatMap(_.channel(channel).map(_.feeBaseMsat))
|
newFeeOpt <- clientF.flatMap(_.channel(channel).map(_.feeBaseMsat))
|
||||||
} yield {
|
} yield {
|
||||||
assert(newFeeOpt.isDefined)
|
assert(newFeeOpt.isDefined)
|
||||||
|
@ -540,7 +552,8 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
it should "get a route to a node ID" in {
|
it should "get a route to a node ID" in {
|
||||||
val hasRoute = () => {
|
val hasRoute = () => {
|
||||||
fourthClientF.flatMap(_.getInfo)
|
fourthClientF
|
||||||
|
.flatMap(_.getInfo)
|
||||||
.flatMap(info => firstClientF.flatMap(_.findRoute(info.nodeId)))
|
.flatMap(info => firstClientF.flatMap(_.findRoute(info.nodeId)))
|
||||||
.map(route => route.length == 4)
|
.map(route => route.length == 4)
|
||||||
.recover {
|
.recover {
|
||||||
|
@ -559,14 +572,15 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
it should "get a route to an invoice" in {
|
it should "get a route to an invoice" in {
|
||||||
val hasRoute = () => {
|
val hasRoute = () => {
|
||||||
fourthClientF.flatMap { fourthClient =>
|
fourthClientF.flatMap { fourthClient =>
|
||||||
fourthClient.receive("foo")
|
fourthClient
|
||||||
|
.receive("foo")
|
||||||
.flatMap { invoice =>
|
.flatMap { invoice =>
|
||||||
firstClientF.flatMap(_.findRoute(invoice))
|
firstClientF.flatMap(_.findRoute(invoice))
|
||||||
}
|
}
|
||||||
.map(route => route.length == 4)
|
.map(route => route.length == 4)
|
||||||
.recover {
|
.recover {
|
||||||
case err: RuntimeException
|
case err: RuntimeException
|
||||||
if err.getMessage.contains("route not found") =>
|
if err.getMessage.contains("route not found") =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -581,14 +595,21 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
|
|
||||||
it should "send some payments and get the audit info" in {
|
it should "send some payments and get the audit info" in {
|
||||||
for {
|
for {
|
||||||
invoice <- fourthClientF.flatMap(_.receive(MilliSatoshis(50000).toLnCurrencyUnit))
|
invoice <- fourthClientF.flatMap(
|
||||||
_ <- firstClientF.flatMap(_.send(invoice)
|
_.receive(MilliSatoshis(50000).toLnCurrencyUnit))
|
||||||
.map(payment => assert(payment.isInstanceOf[PaymentSucceeded])))
|
_ <- firstClientF.flatMap(
|
||||||
|
_.send(invoice)
|
||||||
|
.map(payment => assert(payment.isInstanceOf[PaymentSucceeded])))
|
||||||
|
|
||||||
received <- fourthClientF.flatMap(_.audit())
|
received <- fourthClientF
|
||||||
|
.flatMap(_.audit())
|
||||||
.map(_.received) // check for received payments
|
.map(_.received) // check for received payments
|
||||||
relayed <- secondClientF.flatMap(_.audit()).map(_.relayed) // check for relayed payments
|
relayed <- secondClientF
|
||||||
sent <- firstClientF.flatMap(_.audit()).map(_.sent) // check for sent payments
|
.flatMap(_.audit())
|
||||||
|
.map(_.relayed) // check for relayed payments
|
||||||
|
sent <- firstClientF
|
||||||
|
.flatMap(_.audit())
|
||||||
|
.map(_.sent) // check for sent payments
|
||||||
} yield {
|
} yield {
|
||||||
assert(received.nonEmpty)
|
assert(received.nonEmpty)
|
||||||
assert(relayed.nonEmpty)
|
assert(relayed.nonEmpty)
|
||||||
|
@ -601,57 +622,66 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
// to them
|
// to them
|
||||||
it should "get all channel updates for a given node ID" in {
|
it should "get all channel updates for a given node ID" in {
|
||||||
val freshClients1F = bitcoindRpcClientF.flatMap { bitcoindRpcClient =>
|
val freshClients1F = bitcoindRpcClientF.flatMap { bitcoindRpcClient =>
|
||||||
EclairRpcTestUtil.createNodePair(Some(bitcoindRpcClient))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val freshClients2F = bitcoindRpcClientF.flatMap { bitcoindRpcClient =>
|
|
||||||
EclairRpcTestUtil.createNodePair(Some(bitcoindRpcClient))
|
EclairRpcTestUtil.createNodePair(Some(bitcoindRpcClient))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val freshClients2F = bitcoindRpcClientF.flatMap { _ =>
|
||||||
|
thirdClientF.flatMap(t => fourthClientF.map(f => (t, f)))
|
||||||
|
}
|
||||||
|
|
||||||
val connectedClientsF: Future[EclairNodes4] = {
|
val connectedClientsF: Future[EclairNodes4] = {
|
||||||
freshClients1F.flatMap { case (freshClient1, freshClient2) =>
|
freshClients1F.flatMap {
|
||||||
freshClients2F.flatMap { case (freshClient3,freshClient4) =>
|
case (freshClient1, freshClient2) =>
|
||||||
|
freshClients2F.flatMap {
|
||||||
|
case (freshClient3, freshClient4) =>
|
||||||
|
clients ++= List(freshClient1,
|
||||||
|
freshClient2,
|
||||||
|
freshClient3,
|
||||||
|
freshClient4)
|
||||||
|
|
||||||
clients ++= List(freshClient1,
|
val connect1And3 =
|
||||||
freshClient2,
|
EclairRpcTestUtil.connectLNNodes(freshClient1, freshClient3)
|
||||||
freshClient3,
|
val connect1And4 = connect1And3.flatMap(_ =>
|
||||||
freshClient4)
|
EclairRpcTestUtil.connectLNNodes(freshClient1, freshClient4))
|
||||||
|
connect1And3.flatMap { _ =>
|
||||||
val connect1And3 = EclairRpcTestUtil.connectLNNodes(freshClient1, freshClient3)
|
connect1And4.map { _ =>
|
||||||
val connect1And4 = EclairRpcTestUtil.connectLNNodes(freshClient1, freshClient4)
|
EclairNodes4(freshClient1,
|
||||||
connect1And3.flatMap { _ =>
|
freshClient2,
|
||||||
connect1And4.map { _ =>
|
freshClient3,
|
||||||
EclairNodes4(freshClient1, freshClient2, freshClient3, freshClient4)
|
freshClient4)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def openChannel(c1: EclairRpcClient, c2: EclairRpcClient): Future[FundedChannelId] = {
|
def openChannel(
|
||||||
|
c1: EclairRpcClient,
|
||||||
|
c2: EclairRpcClient): Future[FundedChannelId] = {
|
||||||
EclairRpcTestUtil
|
EclairRpcTestUtil
|
||||||
.openChannel(c1, c2, Satoshis(Int64(500000)), MilliSatoshis(500000))
|
.openChannel(c1, c2, Satoshis(Int64(500000)), MilliSatoshis(500000))
|
||||||
}
|
}
|
||||||
|
|
||||||
val openedChannelsF: Future[(ChannelId, ChannelId)] = {
|
val openedChannelsF: Future[(ChannelId, ChannelId)] = {
|
||||||
connectedClientsF.flatMap { case nodes4: EclairNodes4 =>
|
connectedClientsF.flatMap {
|
||||||
val chan1F = openChannel(nodes4.c1, nodes4.c2)
|
case nodes4: EclairNodes4 =>
|
||||||
val chan2F = openChannel(nodes4.c3, nodes4.c4)
|
val chan1F = openChannel(nodes4.c1, nodes4.c2)
|
||||||
chan1F.flatMap(chanId1 => chan2F.map(chanId2 => (chanId1,chanId2)))
|
val chan2F = openChannel(nodes4.c3, nodes4.c4)
|
||||||
|
chan1F.flatMap(chanId1 => chan2F.map(chanId2 => (chanId1, chanId2)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val gen10F = openedChannelsF.flatMap(_ => bitcoindRpcClientF.flatMap(_.generate(10)))
|
val gen10F =
|
||||||
|
openedChannelsF.flatMap(_ => bitcoindRpcClientF.flatMap(_.generate(10)))
|
||||||
|
|
||||||
val nodesReadyForPayments = gen10F.flatMap(_ => connectedClientsF)
|
val nodesReadyForPayments = gen10F.flatMap(_ => connectedClientsF)
|
||||||
|
|
||||||
val sendPaymentsF = nodesReadyForPayments.flatMap { n4 =>
|
val sendPaymentsF = nodesReadyForPayments.flatMap { n4 =>
|
||||||
|
val p1F =
|
||||||
|
EclairRpcTestUtil.sendPayments(c1 = n4.c1, c2 = n4.c2, numPayments = 2)
|
||||||
|
val p2F =
|
||||||
|
EclairRpcTestUtil.sendPayments(c1 = n4.c3, c2 = n4.c4, numPayments = 2)
|
||||||
|
|
||||||
val p1F = EclairRpcTestUtil.sendPayments(n4.c1, n4.c2)
|
|
||||||
val p2F = EclairRpcTestUtil.sendPayments(n4.c3, n4.c4)
|
|
||||||
p1F.flatMap(_ => p2F)
|
p1F.flatMap(_ => p2F)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,10 +707,9 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
val client2F = connectedClientsF.map(_.c2)
|
val client2F = connectedClientsF.map(_.c2)
|
||||||
|
|
||||||
sendPaymentsF.flatMap { _ =>
|
sendPaymentsF.flatMap { _ =>
|
||||||
|
|
||||||
executeSpecificClients(clientF = client1F,
|
executeSpecificClients(clientF = client1F,
|
||||||
otherClientF = client2F,
|
otherClientF = client2F,
|
||||||
test = getChannelUpdates)
|
test = getChannelUpdates)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -692,29 +721,27 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
//about the channels for future fee calculations
|
//about the channels for future fee calculations
|
||||||
val sentPaymentF = secondClientF.flatMap { c1 =>
|
val sentPaymentF = secondClientF.flatMap { c1 =>
|
||||||
thirdClientF.flatMap { c2 =>
|
thirdClientF.flatMap { c2 =>
|
||||||
EclairRpcTestUtil.sendPayments(c1,c2)
|
EclairRpcTestUtil.sendPayments(c1, c2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val gossipFromPeerWithNoChannel = {
|
val gossipFromPeerWithNoChannel = {
|
||||||
(client: EclairRpcClient, nonPeer: EclairRpcClient) =>
|
(client: EclairRpcClient, nonPeer: EclairRpcClient) =>
|
||||||
|
|
||||||
sentPaymentF.flatMap { _ =>
|
sentPaymentF.flatMap { _ =>
|
||||||
val nodeIdF = client.getNodeURI.map(_.nodeId)
|
val nodeIdF = client.getNodeURI.map(_.nodeId)
|
||||||
def ourUpdates = nodeIdF.flatMap(nonPeer.allUpdates(_))
|
def ourUpdates = nodeIdF.flatMap(nonPeer.allUpdates(_))
|
||||||
def allUpdates = nonPeer.allUpdates()
|
def allUpdates = nonPeer.allUpdates()
|
||||||
def checkUpdates() : Future[Boolean] = {
|
def checkUpdates(): Future[Boolean] = {
|
||||||
ourUpdates.flatMap( our =>
|
ourUpdates.flatMap(our =>
|
||||||
allUpdates.map { all =>
|
allUpdates.map { all =>
|
||||||
our != all
|
our != all
|
||||||
}
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val checkedUpatesF: Future[Unit] = AsyncUtil.retryUntilSatisfiedF(
|
val checkedUpatesF: Future[Unit] =
|
||||||
checkUpdates,
|
AsyncUtil.retryUntilSatisfiedF(checkUpdates,
|
||||||
duration = 5.seconds,
|
duration = 5.seconds,
|
||||||
maxTries = 15)
|
maxTries = 15)
|
||||||
|
|
||||||
val hasUpdateP = Promise[Assertion]()
|
val hasUpdateP = Promise[Assertion]()
|
||||||
checkedUpatesF.onComplete { t =>
|
checkedUpatesF.onComplete { t =>
|
||||||
|
@ -795,7 +822,8 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
genF.flatMap { _ =>
|
genF.flatMap { _ =>
|
||||||
//wait until our peer has put the channel in the
|
//wait until our peer has put the channel in the
|
||||||
//NORMAL state so we can route payments to them
|
//NORMAL state so we can route payments to them
|
||||||
val normalF = client2F.flatMap(c2 => EclairRpcTestUtil.awaitUntilChannelNormal(c2, cid))
|
val normalF = client2F.flatMap(c2 =>
|
||||||
|
EclairRpcTestUtil.awaitUntilChannelNormal(c2, cid))
|
||||||
|
|
||||||
normalF.map(_ => cid)
|
normalF.map(_ => cid)
|
||||||
|
|
||||||
|
@ -804,7 +832,7 @@ class EclairRpcClientTest extends AsyncFlatSpec with BeforeAndAfterAll {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def updateIsInChannels(channels: Seq[OpenChannelInfo])(
|
private def updateIsInChannels(channels: Seq[OpenChannelInfo])(
|
||||||
update: ChannelUpdate): Boolean = {
|
update: ChannelUpdate): Boolean = {
|
||||||
channels.exists(_.shortChannelId == update.shortChannelId)
|
channels.exists(_.shortChannelId == update.shortChannelId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -476,7 +476,7 @@ class EclairRpcClient(val instance: EclairInstance)(
|
||||||
val payloadF: Future[JsValue] = responseF.flatMap(getPayload)
|
val payloadF: Future[JsValue] = responseF.flatMap(getPayload)
|
||||||
payloadF.map { payload =>
|
payloadF.map { payload =>
|
||||||
val validated: JsResult[T] = (payload \ resultKey).validate[T]
|
val validated: JsResult[T] = (payload \ resultKey).validate[T]
|
||||||
val parsed: T = parseResult(validated, payload)
|
val parsed: T = parseResult(validated, payload, command)
|
||||||
parsed
|
parsed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -484,16 +484,19 @@ class EclairRpcClient(val instance: EclairInstance)(
|
||||||
case class RpcError(code: Int, message: String)
|
case class RpcError(code: Int, message: String)
|
||||||
implicit val rpcErrorReads: Reads[RpcError] = Json.reads[RpcError]
|
implicit val rpcErrorReads: Reads[RpcError] = Json.reads[RpcError]
|
||||||
|
|
||||||
private def parseResult[T](result: JsResult[T], json: JsValue): T = {
|
private def parseResult[T](result: JsResult[T], json: JsValue, commandName: String): T = {
|
||||||
result match {
|
result match {
|
||||||
case res: JsSuccess[T] =>
|
case res: JsSuccess[T] =>
|
||||||
res.value
|
res.value
|
||||||
case res: JsError =>
|
case res: JsError =>
|
||||||
(json \ errorKey).validate[RpcError] match {
|
(json \ errorKey).validate[RpcError] match {
|
||||||
case err: JsSuccess[RpcError] =>
|
case err: JsSuccess[RpcError] =>
|
||||||
logger.error(s"Error ${err.value.code}: ${err.value.message}")
|
val datadirMsg = instance.authCredentials.datadir
|
||||||
throw new RuntimeException(
|
.map(d => s"datadir=${d}")
|
||||||
s"Error ${err.value.code}: ${err.value.message}")
|
.getOrElse("")
|
||||||
|
val errMsg = s"Error for command=${commandName} ${datadirMsg}, ${err.value.code}=${err.value.message}"
|
||||||
|
logger.error(errMsg)
|
||||||
|
throw new RuntimeException(errMsg)
|
||||||
case _: JsError =>
|
case _: JsError =>
|
||||||
logger.error(JsError.toJson(res).toString())
|
logger.error(JsError.toJson(res).toString())
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|
|
@ -7,8 +7,13 @@ import akka.actor.ActorSystem
|
||||||
import com.typesafe.config.{Config, ConfigFactory}
|
import com.typesafe.config.{Config, ConfigFactory}
|
||||||
import org.bitcoins.core.config.RegTest
|
import org.bitcoins.core.config.RegTest
|
||||||
import org.bitcoins.core.currency.CurrencyUnit
|
import org.bitcoins.core.currency.CurrencyUnit
|
||||||
import org.bitcoins.core.protocol.ln.channel.{ChannelId, ChannelState, FundedChannelId}
|
import org.bitcoins.core.protocol.ln.channel.{
|
||||||
|
ChannelId,
|
||||||
|
ChannelState,
|
||||||
|
FundedChannelId
|
||||||
|
}
|
||||||
import org.bitcoins.core.protocol.ln.currency.MilliSatoshis
|
import org.bitcoins.core.protocol.ln.currency.MilliSatoshis
|
||||||
|
import org.bitcoins.core.protocol.ln.node.NodeId
|
||||||
import org.bitcoins.core.util.BitcoinSLogger
|
import org.bitcoins.core.util.BitcoinSLogger
|
||||||
import org.bitcoins.eclair.rpc.client.EclairRpcClient
|
import org.bitcoins.eclair.rpc.client.EclairRpcClient
|
||||||
import org.bitcoins.eclair.rpc.config.EclairInstance
|
import org.bitcoins.eclair.rpc.config.EclairInstance
|
||||||
|
@ -21,6 +26,7 @@ import org.bitcoins.util.AsyncUtil
|
||||||
|
|
||||||
import scala.concurrent.duration.DurationInt
|
import scala.concurrent.duration.DurationInt
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
import scala.util.{Failure, Success}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @define nodeLinkDoc
|
* @define nodeLinkDoc
|
||||||
|
@ -217,7 +223,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
}(system.dispatcher)
|
}(system.dispatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncUtil.retryUntilSatisfiedF(conditionF = () => isState(), duration = 1.seconds)
|
AsyncUtil.retryUntilSatisfiedF(conditionF = () => isState(),
|
||||||
|
duration = 1.seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def createNodeLink(
|
private def createNodeLink(
|
||||||
|
@ -237,7 +244,7 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
internalBitcoindF.flatMap(b => createNodePair(Some(b)))
|
internalBitcoindF.flatMap(b => createNodePair(Some(b)))
|
||||||
}
|
}
|
||||||
|
|
||||||
val pair2: Future[(EclairRpcClient,EclairRpcClient)] = {
|
val pair2: Future[(EclairRpcClient, EclairRpcClient)] = {
|
||||||
internalBitcoindF.flatMap(b => createNodePair(Some(b)))
|
internalBitcoindF.flatMap(b => createNodePair(Some(b)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,32 +258,30 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
val nodeVecF: Future[Vector[EclairRpcClient]] = {
|
val nodeVecF: Future[Vector[EclairRpcClient]] = {
|
||||||
pair1.flatMap { case (first,second) =>
|
pair1.flatMap {
|
||||||
pair2.flatMap {
|
case (first, second) =>
|
||||||
case (third,fourth) =>
|
pair2.flatMap {
|
||||||
|
case (third, fourth) =>
|
||||||
|
// we need to make sure the second and third nodes are connected
|
||||||
|
val connected = EclairRpcTestUtil.connectLNNodes(second, third)
|
||||||
|
connected.map { _ =>
|
||||||
|
Vector(first, second, third, fourth)
|
||||||
|
}
|
||||||
|
|
||||||
// we need to make sure the second and third nodes are connected
|
}
|
||||||
val connected = EclairRpcTestUtil.connectLNNodes(second, third)
|
|
||||||
connected.map { _ =>
|
|
||||||
Vector(first,second,third,fourth)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val openChannelsFNested: Future[List[Future[FundedChannelId]]] = {
|
val openChannelsFNested: Future[List[Future[FundedChannelId]]] = {
|
||||||
nodeVecF.map { nodeVec =>
|
nodeVecF.map { nodeVec =>
|
||||||
List(open(nodeVec.head, nodeVec(1)),
|
List(open(nodeVec.head, nodeVec(1)),
|
||||||
open(nodeVec(1), nodeVec(2)),
|
open(nodeVec(1), nodeVec(2)),
|
||||||
open(nodeVec(2), nodeVec(3)))
|
open(nodeVec(2), nodeVec(3)))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val openChannelsF :Future[List[FundedChannelId]] = {
|
val openChannelsF: Future[List[FundedChannelId]] = {
|
||||||
openChannelsFNested.flatMap(Future.sequence(_))
|
openChannelsFNested.flatMap(Future.sequence(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +327,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
* @return A 4-tuple of the created nodes' respective
|
* @return A 4-tuple of the created nodes' respective
|
||||||
* [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]]
|
* [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]]
|
||||||
*/
|
*/
|
||||||
def createNodeLink()(implicit actorSystem: ActorSystem): Future[EclairNodes4] = {
|
def createNodeLink()(
|
||||||
|
implicit actorSystem: ActorSystem): Future[EclairNodes4] = {
|
||||||
createNodeLink(None, DEFAULT_CHANNEL_MSAT_AMT)
|
createNodeLink(None, DEFAULT_CHANNEL_MSAT_AMT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +349,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
* respective [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]]s
|
* respective [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]]s
|
||||||
*/
|
*/
|
||||||
def createNodePair(bitcoindRpcClientOpt: Option[BitcoindRpcClient])(
|
def createNodePair(bitcoindRpcClientOpt: Option[BitcoindRpcClient])(
|
||||||
implicit system: ActorSystem): Future[(EclairRpcClient, EclairRpcClient)] = {
|
implicit system: ActorSystem): Future[
|
||||||
|
(EclairRpcClient, EclairRpcClient)] = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
val bitcoindRpcClientF: Future[BitcoindRpcClient] = {
|
val bitcoindRpcClientF: Future[BitcoindRpcClient] = {
|
||||||
|
|
||||||
|
@ -354,8 +361,10 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val e1InstanceF = bitcoindRpcClientF.map(EclairRpcTestUtil.eclairInstance(_))
|
val e1InstanceF =
|
||||||
val e2InstanceF = bitcoindRpcClientF.map(EclairRpcTestUtil.eclairInstance(_))
|
bitcoindRpcClientF.map(EclairRpcTestUtil.eclairInstance(_))
|
||||||
|
val e2InstanceF =
|
||||||
|
bitcoindRpcClientF.map(EclairRpcTestUtil.eclairInstance(_))
|
||||||
|
|
||||||
val clientF = e1InstanceF.flatMap { e1 =>
|
val clientF = e1InstanceF.flatMap { e1 =>
|
||||||
val e = new EclairRpcClient(e1)
|
val e = new EclairRpcClient(e1)
|
||||||
|
@ -372,14 +381,15 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
|
|
||||||
logger.debug(s"Both clients started")
|
logger.debug(s"Both clients started")
|
||||||
|
|
||||||
val connectedLnF: Future[(EclairRpcClient, EclairRpcClient)] = clientF.flatMap { c1 =>
|
val connectedLnF: Future[(EclairRpcClient, EclairRpcClient)] =
|
||||||
otherClientF.flatMap { c2 =>
|
clientF.flatMap { c1 =>
|
||||||
val connectedF = connectLNNodes(c1, c2)
|
otherClientF.flatMap { c2 =>
|
||||||
connectedF.map { _ =>
|
val connectedF = connectLNNodes(c1, c2)
|
||||||
(c1,c2)
|
connectedF.map { _ =>
|
||||||
|
(c1, c2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
connectedLnF
|
connectedLnF
|
||||||
}
|
}
|
||||||
|
@ -389,13 +399,13 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
system: ActorSystem): Future[Unit] = {
|
system: ActorSystem): Future[Unit] = {
|
||||||
implicit val dispatcher = system.dispatcher
|
implicit val dispatcher = system.dispatcher
|
||||||
val infoF = otherClient.getInfo
|
val infoF = otherClient.getInfo
|
||||||
|
val nodeIdF = infoF.map(_.nodeId)
|
||||||
val connection: Future[String] = infoF.flatMap { info =>
|
val connection: Future[String] = infoF.flatMap { info =>
|
||||||
client.connect(info.nodeId, "localhost", info.port)
|
client.connect(info.nodeId, "localhost", info.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
def isConnected(): Future[Boolean] = {
|
def isConnected(): Future[Boolean] = {
|
||||||
val nodeIdF = infoF.map(_.nodeId)
|
|
||||||
nodeIdF.flatMap { nodeId =>
|
nodeIdF.flatMap { nodeId =>
|
||||||
connection.flatMap { _ =>
|
connection.flatMap { _ =>
|
||||||
val connected: Future[Boolean] = client.isConnected(nodeId)
|
val connected: Future[Boolean] = client.isConnected(nodeId)
|
||||||
|
@ -405,9 +415,9 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(s"Awaiting connection between clients")
|
logger.debug(s"Awaiting connection between clients")
|
||||||
val connected = RpcUtil.retryUntilSatisfiedF(
|
val connected = RpcUtil.retryUntilSatisfiedF(conditionF =
|
||||||
conditionF = () => isConnected(),
|
() => isConnected(),
|
||||||
duration = 1.second)
|
duration = 1.second)
|
||||||
|
|
||||||
connected.map(_ => logger.debug(s"Successfully connected two clients"))
|
connected.map(_ => logger.debug(s"Successfully connected two clients"))
|
||||||
|
|
||||||
|
@ -424,8 +434,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
def sendPayments(
|
def sendPayments(
|
||||||
c1: EclairRpcClient,
|
c1: EclairRpcClient,
|
||||||
c2: EclairRpcClient,
|
c2: EclairRpcClient,
|
||||||
numPayments: Int = 10)(
|
numPayments: Int = 5)(
|
||||||
implicit ec: ExecutionContext): Future[Seq[PaymentResult]] = {
|
implicit ec: ExecutionContext): Future[Vector[PaymentResult]] = {
|
||||||
val payments = (1 to numPayments)
|
val payments = (1 to numPayments)
|
||||||
.map(MilliSatoshis(_))
|
.map(MilliSatoshis(_))
|
||||||
.map(
|
.map(
|
||||||
|
@ -434,7 +444,22 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
.flatMap(invoice => c2.send(invoice, sats.toLnCurrencyUnit))
|
.flatMap(invoice => c2.send(invoice, sats.toLnCurrencyUnit))
|
||||||
)
|
)
|
||||||
|
|
||||||
Future.sequence(payments)
|
val resultF = Future.sequence(payments).map(_.toVector)
|
||||||
|
|
||||||
|
resultF.onComplete {
|
||||||
|
case Success(_) =>
|
||||||
|
case Failure(_) =>
|
||||||
|
val nodeId1F = c1.nodeId()
|
||||||
|
val nodeId2F = c2.nodeId()
|
||||||
|
nodeId1F.flatMap { nid1 =>
|
||||||
|
nodeId2F.map { nid2 =>
|
||||||
|
logger.error(
|
||||||
|
s"Failed to send payments from ${nid1.hex} -> ${nid2.hex}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultF
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DEFAULT_CHANNEL_MSAT_AMT = MilliSatoshis(500000000L)
|
private val DEFAULT_CHANNEL_MSAT_AMT = MilliSatoshis(500000000L)
|
||||||
|
@ -450,23 +475,30 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
|
|
||||||
val bitcoindRpcClient = getBitcoindRpc(n1)
|
val bitcoindRpcClient = getBitcoindRpc(n1)
|
||||||
implicit val ec = system.dispatcher
|
implicit val ec = system.dispatcher
|
||||||
val fundedChannelIdF: Future[FundedChannelId] = {
|
|
||||||
n2.nodeId.flatMap { nodeId =>
|
|
||||||
n1.getInfo.map { info =>
|
|
||||||
logger.debug(
|
|
||||||
s"Opening a channel from ${info.nodeId} -> ${nodeId} with amount ${amt}")
|
|
||||||
|
|
||||||
}
|
val n1NodeIdF = n1.nodeId()
|
||||||
n1.open(nodeId = nodeId,
|
val n2NodeIdF = n2.nodeId()
|
||||||
fundingSatoshis = amt,
|
|
||||||
pushMsat = Some(pushMSat),
|
val nodeIdsF: Future[(NodeId, NodeId)] = {
|
||||||
feerateSatPerByte = None,
|
n1NodeIdF.flatMap(n1 => n2NodeIdF.map(n2 => (n1, n2)))
|
||||||
channelFlags = None)
|
}
|
||||||
|
|
||||||
|
val fundedChannelIdF: Future[FundedChannelId] = {
|
||||||
|
nodeIdsF.flatMap {
|
||||||
|
case (nodeId1, nodeId2) =>
|
||||||
|
logger.debug(
|
||||||
|
s"Opening a channel from ${nodeId1} -> ${nodeId2} with amount ${amt}")
|
||||||
|
n1.open(nodeId = nodeId2,
|
||||||
|
fundingSatoshis = amt,
|
||||||
|
pushMsat = Some(pushMSat),
|
||||||
|
feerateSatPerByte = None,
|
||||||
|
channelFlags = None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val gen = fundedChannelIdF.flatMap(_ => bitcoindRpcClient.generate(6))
|
val gen = fundedChannelIdF.flatMap(_ => bitcoindRpcClient.generate(6))
|
||||||
|
|
||||||
val opened = {
|
val openedF = {
|
||||||
gen.flatMap { _ =>
|
gen.flatMap { _ =>
|
||||||
fundedChannelIdF.flatMap { fcid =>
|
fundedChannelIdF.flatMap { fcid =>
|
||||||
val chanOpenF = awaitChannelOpened(n1, fcid)
|
val chanOpenF = awaitChannelOpened(n1, fcid)
|
||||||
|
@ -474,12 +506,17 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opened.map {
|
|
||||||
|
openedF.flatMap {
|
||||||
case _ =>
|
case _ =>
|
||||||
logger.debug(
|
nodeIdsF.map {
|
||||||
s"Channel successfully opened ${n1.getNodeURI} -> ${n2.getNodeURI} with amount $amt")
|
case (nodeId1, nodeId2) =>
|
||||||
|
logger.debug(
|
||||||
|
s"Channel successfully opened ${nodeId1} -> ${nodeId2} with amount $amt")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
opened
|
|
||||||
|
openedF
|
||||||
}
|
}
|
||||||
|
|
||||||
def awaitChannelOpened(client1: EclairRpcClient, chanId: ChannelId)(
|
def awaitChannelOpened(client1: EclairRpcClient, chanId: ChannelId)(
|
||||||
|
|
Loading…
Add table
Reference in a new issue