From b0320d71c20be578a484a7d90ebca8530f474f54 Mon Sep 17 00:00:00 2001 From: pm47 Date: Thu, 5 Sep 2019 21:22:05 +0200 Subject: [PATCH 01/54] removed Globals class --- .../scala/fr/acinq/eclair/CltvExpiry.scala | 2 +- .../main/scala/fr/acinq/eclair/Eclair.scala | 2 +- .../main/scala/fr/acinq/eclair/Globals.scala | 48 ------- .../scala/fr/acinq/eclair/NodeParams.scala | 6 +- .../main/scala/fr/acinq/eclair/Setup.scala | 44 ++++-- .../blockchain/bitcoind/ZmqWatcher.scala | 12 +- .../electrum/ElectrumClientPool.scala | 8 +- .../blockchain/electrum/ElectrumWatcher.scala | 52 ++------ .../fr/acinq/eclair/channel/Channel.scala | 2 +- .../fr/acinq/eclair/channel/Commitments.scala | 13 +- .../eclair/payment/LocalPaymentHandler.scala | 15 ++- .../eclair/payment/PaymentInitiator.scala | 2 +- .../scala/fr/acinq/eclair/router/Router.scala | 17 ++- .../fr/acinq/eclair/CltvExpirySpec.scala | 6 +- .../scala/fr/acinq/eclair/StartupSpec.scala | 7 +- .../scala/fr/acinq/eclair/TestConstants.scala | 3 + .../scala/fr/acinq/eclair/TestUtils.scala | 13 ++ .../fr/acinq/eclair/TestkitBaseClass.scala | 4 - .../bitcoind/BitcoinCoreWalletSpec.scala | 4 +- .../blockchain/bitcoind/BitcoindService.scala | 39 +++++- .../bitcoind/ExtendedBitcoinClientSpec.scala | 4 +- .../electrum/ElectrumClientPoolSpec.scala | 3 +- .../electrum/ElectrumWalletSpec.scala | 3 +- .../electrum/ElectrumWatcherSpec.scala | 16 ++- .../electrum/ElectrumxService.scala | 10 +- .../fee/BitcoinCoreFeeProviderSpec.scala | 4 +- .../eclair/channel/CommitmentsSpec.scala | 20 +-- .../fr/acinq/eclair/channel/FuzzySpec.scala | 125 +++++++++--------- .../acinq/eclair/channel/ThroughputSpec.scala | 3 +- .../states/StateTestsHelperMethods.scala | 11 +- .../channel/states/e/NormalStateSpec.scala | 96 +++++++------- .../channel/states/e/OfflineStateSpec.scala | 4 +- .../channel/states/f/ShutdownStateSpec.scala | 4 +- .../eclair/integration/IntegrationSpec.scala | 26 ++-- .../interop/rustytests/RustyTestsSpec.scala | 11 +- .../eclair/payment/HtlcGenerationSpec.scala | 6 +- .../eclair/payment/PaymentHandlerSpec.scala | 10 +- .../eclair/payment/PaymentLifecycleSpec.scala | 24 ++-- .../eclair/router/RouteCalculationSpec.scala | 99 +++++++------- .../fr/acinq/eclair/router/RouterSpec.scala | 4 +- .../acinq/eclair/router/RoutingSyncSpec.scala | 1 + .../transactions/TransactionsSpec.scala | 7 +- .../scala/fr/acinq/eclair/gui/Handlers.scala | 14 ++ .../controllers/OpenChannelController.scala | 14 +- pom.xml | 3 +- 45 files changed, 413 insertions(+), 408 deletions(-) delete mode 100644 eclair-core/src/main/scala/fr/acinq/eclair/Globals.scala diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/CltvExpiry.scala b/eclair-core/src/main/scala/fr/acinq/eclair/CltvExpiry.scala index 3452df377c..d3249fd461 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/CltvExpiry.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/CltvExpiry.scala @@ -49,7 +49,7 @@ case class CltvExpiryDelta(private val underlying: Int) extends Ordered[CltvExpi /** * Adds the current block height to the given delta to obtain an absolute expiry. */ - def toCltvExpiry = CltvExpiry(Globals.blockCount.get() + underlying) + def toCltvExpiry(blockHeight: Long) = CltvExpiry(blockHeight + underlying) // @formatter:off def +(other: Int): CltvExpiryDelta = CltvExpiryDelta(underlying + other) 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 7b485e0461..fc8e7356c5 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala @@ -272,7 +272,7 @@ class EclairImpl(appKit: Kit) extends Eclair { GetInfoResponse(nodeId = appKit.nodeParams.nodeId, alias = appKit.nodeParams.alias, chainHash = appKit.nodeParams.chainHash, - blockHeight = Globals.blockCount.intValue(), + blockHeight = appKit.nodeParams.currentBlockHeight.toInt, publicAddresses = appKit.nodeParams.publicAddresses) ) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Globals.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Globals.scala deleted file mode 100644 index 5cc3630947..0000000000 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Globals.scala +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2019 ACINQ SAS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package fr.acinq.eclair - -import java.util.concurrent.atomic.{AtomicLong, AtomicReference} - -import fr.acinq.eclair.blockchain.fee.{FeeratesPerKB, FeeratesPerKw} - -/** - * Created by PM on 25/01/2016. - */ -object Globals { - - /** - * This counter holds the current blockchain height. - * It is mainly used to calculate htlc expiries. - * The value is read by all actors, hence it needs to be thread-safe. - */ - val blockCount = new AtomicLong(0) - - /** - * This holds the current feerates, in satoshi-per-kilobytes. - * The value is read by all actors, hence it needs to be thread-safe. - */ - val feeratesPerKB = new AtomicReference[FeeratesPerKB](null) - - /** - * This holds the current feerates, in satoshi-per-kw. - * The value is read by all actors, hence it needs to be thread-safe. - */ - val feeratesPerKw = new AtomicReference[FeeratesPerKw](null) -} - - diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index ecadd9dbc0..6bc3625b17 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -20,6 +20,7 @@ import java.io.File import java.net.InetSocketAddress import java.nio.file.Files import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicLong import com.typesafe.config.{Config, ConfigFactory} import fr.acinq.bitcoin.Crypto.PublicKey @@ -41,6 +42,7 @@ import scala.concurrent.duration.FiniteDuration * Created by PM on 26/02/2017. */ case class NodeParams(keyManager: KeyManager, + private val blockCount: AtomicLong, alias: String, color: Color, publicAddresses: List[NodeAddress], @@ -80,6 +82,7 @@ case class NodeParams(keyManager: KeyManager, maxPaymentAttempts: Int) { val privateKey = keyManager.nodeKey.privateKey val nodeId = keyManager.nodeId + def currentBlockHeight: Long = blockCount.get } object NodeParams { @@ -124,7 +127,7 @@ object NodeParams { } } - def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases, feeEstimator: FeeEstimator): NodeParams = { + def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases, blockCount: AtomicLong, feeEstimator: FeeEstimator): NodeParams = { val chain = config.getString("chain") val chainHash = makeChainHash(chain) @@ -201,6 +204,7 @@ object NodeParams { NodeParams( keyManager = keyManager, + blockCount = blockCount, alias = nodeAlias, color = Color(color(0), color(1), color(2)), publicAddresses = addresses, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala index 4c770f4faf..c7258eb445 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -20,6 +20,7 @@ import java.io.File import java.net.InetSocketAddress import java.sql.DriverManager import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.{AtomicLong, AtomicReference} import akka.Done import akka.actor.{ActorRef, ActorSystem, Props, SupervisorStrategy} @@ -92,12 +93,31 @@ class Setup(datadir: File, case None => Databases.sqliteJDBC(chaindir) } + /** + * This counter holds the current blockchain height. + * It is mainly used to calculate htlc expiries. + * The value is read by all actors, hence it needs to be thread-safe. + */ + val blockCount = new AtomicLong(0) + + /** + * This holds the current feerates, in satoshi-per-kilobytes. + * The value is read by all actors, hence it needs to be thread-safe. + */ + val feeratesPerKB = new AtomicReference[FeeratesPerKB](null) + + /** + * This holds the current feerates, in satoshi-per-kw. + * The value is read by all actors, hence it needs to be thread-safe. + */ + val feeratesPerKw = new AtomicReference[FeeratesPerKw](null) + val feeEstimator = new FeeEstimator { - override def getFeeratePerKb(target: Int): Long = Globals.feeratesPerKB.get().feePerBlock(target) - override def getFeeratePerKw(target: Int): Long = Globals.feeratesPerKw.get().feePerBlock(target) + override def getFeeratePerKb(target: Int): Long = feeratesPerKB.get().feePerBlock(target) + override def getFeeratePerKw(target: Int): Long = feeratesPerKw.get().feePerBlock(target) } - val nodeParams = NodeParams.makeNodeParams(config, keyManager, initTor(), database, feeEstimator) + val nodeParams = NodeParams.makeNodeParams(config, keyManager, initTor(), database, blockCount, feeEstimator) val serverBindingAddress = new InetSocketAddress( config.getString("server.binding-ip"), @@ -169,7 +189,7 @@ class Setup(datadir: File, val stream = classOf[Setup].getResourceAsStream(addressesFile) ElectrumClientPool.readServerAddresses(stream, sslEnabled) } - val electrumClient = system.actorOf(SimpleSupervisor.props(Props(new ElectrumClientPool(addresses)), "electrum-client", SupervisorStrategy.Resume)) + val electrumClient = system.actorOf(SimpleSupervisor.props(Props(new ElectrumClientPool(blockCount, addresses)), "electrum-client", SupervisorStrategy.Resume)) Electrum(electrumClient) } @@ -192,8 +212,8 @@ class Setup(datadir: File, blocks_72 = config.getLong("on-chain-fees.default-feerates.72"), blocks_144 = config.getLong("on-chain-fees.default-feerates.144") ) - Globals.feeratesPerKB.set(confDefaultFeerates) - Globals.feeratesPerKw.set(FeeratesPerKw(confDefaultFeerates)) + feeratesPerKB.set(confDefaultFeerates) + feeratesPerKw.set(FeeratesPerKw(confDefaultFeerates)) confDefaultFeerates } minFeeratePerByte = config.getLong("min-feerate") @@ -207,10 +227,10 @@ class Setup(datadir: File, } _ = system.scheduler.schedule(0 seconds, 10 minutes)(feeProvider.getFeerates.map { case feerates: FeeratesPerKB => - Globals.feeratesPerKB.set(feerates) - Globals.feeratesPerKw.set(FeeratesPerKw(feerates)) - system.eventStream.publish(CurrentFeerates(Globals.feeratesPerKw.get)) - logger.info(s"current feeratesPerKB=${Globals.feeratesPerKB.get()} feeratesPerKw=${Globals.feeratesPerKw.get()}") + feeratesPerKB.set(feerates) + feeratesPerKw.set(FeeratesPerKw(feerates)) + system.eventStream.publish(CurrentFeerates(feeratesPerKw.get)) + logger.info(s"current feeratesPerKB=${feeratesPerKB.get()} feeratesPerKw=${feeratesPerKw.get()}") feeratesRetrieved.trySuccess(Done) }) _ <- feeratesRetrieved.future @@ -219,11 +239,11 @@ class Setup(datadir: File, case Bitcoind(bitcoinClient) => system.actorOf(SimpleSupervisor.props(Props(new ZMQActor(config.getString("bitcoind.zmqblock"), Some(zmqBlockConnected))), "zmqblock", SupervisorStrategy.Restart)) system.actorOf(SimpleSupervisor.props(Props(new ZMQActor(config.getString("bitcoind.zmqtx"), Some(zmqTxConnected))), "zmqtx", SupervisorStrategy.Restart)) - system.actorOf(SimpleSupervisor.props(ZmqWatcher.props(new ExtendedBitcoinClient(new BatchingBitcoinJsonRPCClient(bitcoinClient))), "watcher", SupervisorStrategy.Resume)) + system.actorOf(SimpleSupervisor.props(ZmqWatcher.props(blockCount, new ExtendedBitcoinClient(new BatchingBitcoinJsonRPCClient(bitcoinClient))), "watcher", SupervisorStrategy.Resume)) case Electrum(electrumClient) => zmqBlockConnected.success(Done) zmqTxConnected.success(Done) - system.actorOf(SimpleSupervisor.props(Props(new ElectrumWatcher(electrumClient)), "watcher", SupervisorStrategy.Resume)) + system.actorOf(SimpleSupervisor.props(Props(new ElectrumWatcher(blockCount, electrumClient)), "watcher", SupervisorStrategy.Resume)) } router = system.actorOf(SimpleSupervisor.props(Router.props(nodeParams, watcher, Some(routerInitialized)), "router", SupervisorStrategy.Resume)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala index b6feb4afff..73511db293 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala @@ -17,11 +17,11 @@ package fr.acinq.eclair.blockchain.bitcoind import java.util.concurrent.Executors +import java.util.concurrent.atomic.AtomicLong import akka.actor.{Actor, ActorLogging, Cancellable, Props, Terminated} import akka.pattern.pipe import fr.acinq.bitcoin._ -import fr.acinq.eclair.Globals import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.bitcoind.rpc.ExtendedBitcoinClient import fr.acinq.eclair.channel.BITCOIN_PARENT_TX_CONFIRMED @@ -39,7 +39,7 @@ import scala.util.Try * - also uses bitcoin-core rpc api, most notably for tx confirmation count and blockcount (because reorgs) * Created by PM on 21/02/2016. */ -class ZmqWatcher(client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) extends Actor with ActorLogging { +class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) extends Actor with ActorLogging { import ZmqWatcher._ @@ -80,7 +80,7 @@ class ZmqWatcher(client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = client.getBlockCount.map { case count => log.debug(s"setting blockCount=$count") - Globals.blockCount.set(count) + blockCount.set(count) context.system.eventStream.publish(CurrentBlockCount(count)) } // TODO: beware of the herd effect @@ -151,7 +151,7 @@ class ZmqWatcher(client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = context become watching(watches + w, addWatchedUtxos(watchedUtxos, w), block2tx, nextTick) case PublishAsap(tx) => - val blockCount = Globals.blockCount.get() + val blockCount = this.blockCount.get() val cltvTimeout = Scripts.cltvTimeout(tx) val csvTimeout = Scripts.csvTimeout(tx) if (csvTimeout > 0) { @@ -168,7 +168,7 @@ class ZmqWatcher(client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = case WatchEventConfirmed(BITCOIN_PARENT_TX_CONFIRMED(tx), blockHeight, _, _) => log.info(s"parent tx of txid=${tx.txid} has been confirmed") - val blockCount = Globals.blockCount.get() + val blockCount = this.blockCount.get() val csvTimeout = Scripts.csvTimeout(tx) val absTimeout = blockHeight + csvTimeout if (absTimeout > blockCount) { @@ -226,7 +226,7 @@ class ZmqWatcher(client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = object ZmqWatcher { - def props(client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) = Props(new ZmqWatcher(client)(ec)) + def props(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) = Props(new ZmqWatcher(blockCount, client)(ec)) case object TickNewBlock diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala index b7249d409a..117b204bf1 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala @@ -18,10 +18,10 @@ package fr.acinq.eclair.blockchain.electrum import java.io.InputStream import java.net.InetSocketAddress +import java.util.concurrent.atomic.AtomicLong import akka.actor.{Actor, ActorRef, FSM, OneForOneStrategy, Props, SupervisorStrategy, Terminated} import fr.acinq.bitcoin.BlockHeader -import fr.acinq.eclair.Globals import fr.acinq.eclair.blockchain.CurrentBlockCount import fr.acinq.eclair.blockchain.electrum.ElectrumClient.SSL import fr.acinq.eclair.blockchain.electrum.ElectrumClientPool.ElectrumServerAddress @@ -32,7 +32,7 @@ import scala.concurrent.ExecutionContext import scala.concurrent.duration._ import scala.util.Random -class ElectrumClientPool(serverAddresses: Set[ElectrumServerAddress])(implicit val ec: ExecutionContext) extends Actor with FSM[ElectrumClientPool.State, ElectrumClientPool.Data] { +class ElectrumClientPool(blockCount: AtomicLong, serverAddresses: Set[ElectrumServerAddress])(implicit val ec: ExecutionContext) extends Actor with FSM[ElectrumClientPool.State, ElectrumClientPool.Data] { import ElectrumClientPool._ val statusListeners = collection.mutable.HashSet.empty[ActorRef] @@ -166,10 +166,10 @@ class ElectrumClientPool(serverAddresses: Set[ElectrumServerAddress])(implicit v private def updateBlockCount(blockCount: Long): Unit = { // when synchronizing we don't want to advertise previous blocks - if (Globals.blockCount.get() < blockCount) { + if (this.blockCount.get() < blockCount) { log.debug("current blockchain height={}", blockCount) context.system.eventStream.publish(CurrentBlockCount(blockCount)) - Globals.blockCount.set(blockCount) + this.blockCount.set(blockCount) } } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala index be45eb2b96..48aab4bbe3 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala @@ -16,20 +16,21 @@ package fr.acinq.eclair.blockchain.electrum -import java.net.InetSocketAddress +import java.util.concurrent.atomic.AtomicLong -import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem, Props, Stash, Terminated} +import akka.actor.{Actor, ActorLogging, ActorRef, Stash, Terminated} import fr.acinq.bitcoin.{BlockHeader, ByteVector32, Script, Transaction, TxIn, TxOut} import fr.acinq.eclair.blockchain._ -import fr.acinq.eclair.blockchain.electrum.ElectrumClient.{SSL, computeScriptHash} -import fr.acinq.eclair.channel.{BITCOIN_FUNDING_DEPTHOK, BITCOIN_FUNDING_SPENT, BITCOIN_PARENT_TX_CONFIRMED} +import fr.acinq.eclair.blockchain.electrum.ElectrumClient.computeScriptHash +import fr.acinq.eclair.channel.BITCOIN_PARENT_TX_CONFIRMED import fr.acinq.eclair.transactions.Scripts -import fr.acinq.eclair.{Globals, LongToBtcAmount, ShortChannelId, TxCoordinates} +import fr.acinq.eclair.{LongToBtcAmount, ShortChannelId, TxCoordinates} import scala.collection.SortedMap import scala.collection.immutable.Queue -class ElectrumWatcher(client: ActorRef) extends Actor with Stash with ActorLogging { + +class ElectrumWatcher(blockCount: AtomicLong, client: ActorRef) extends Actor with Stash with ActorLogging { client ! ElectrumClient.AddStatusListener(self) @@ -162,7 +163,7 @@ class ElectrumWatcher(client: ActorRef) extends Actor with Stash with ActorLoggi case ElectrumClient.ServerError(ElectrumClient.GetTransaction(txid, Some(origin: ActorRef)), _) => origin ! GetTxWithMetaResponse(txid, None, tip.time) case PublishAsap(tx) => - val blockCount = Globals.blockCount.get() + val blockCount = this.blockCount.get() val cltvTimeout = Scripts.cltvTimeout(tx) val csvTimeout = Scripts.csvTimeout(tx) if (csvTimeout > 0) { @@ -183,7 +184,7 @@ class ElectrumWatcher(client: ActorRef) extends Actor with Stash with ActorLoggi case WatchEventConfirmed(BITCOIN_PARENT_TX_CONFIRMED(tx), blockHeight, _, _) => log.info(s"parent tx of txid=${tx.txid} has been confirmed") - val blockCount = Globals.blockCount.get() + val blockCount = this.blockCount.get() val csvTimeout = Scripts.csvTimeout(tx) val absTimeout = blockHeight + csvTimeout if (absTimeout > blockCount) { @@ -211,38 +212,3 @@ class ElectrumWatcher(client: ActorRef) extends Actor with Stash with ActorLoggi } } - -object ElectrumWatcher extends App { - - val system = ActorSystem() - - import scala.concurrent.ExecutionContext.Implicits.global - - class Root extends Actor with ActorLogging { - val client = context.actorOf(Props(new ElectrumClient(new InetSocketAddress("localhost", 51000), ssl = SSL.OFF)), "client") - client ! ElectrumClient.AddStatusListener(self) - - override def unhandled(message: Any): Unit = { - super.unhandled(message) - log.warning(s"unhandled message $message") - } - - def receive = { - case ElectrumClient.ElectrumReady(_, _, _) => - log.info(s"starting watcher") - context become running(context.actorOf(Props(new ElectrumWatcher(client)), "watcher")) - } - - def running(watcher: ActorRef): Receive = { - case watch: Watch => watcher forward watch - } - } - - val root = system.actorOf(Props[Root], "root") - val scanner = new java.util.Scanner(System.in) - while (true) { - val tx = Transaction.read(scanner.nextLine()) - root ! WatchSpent(root, tx.txid, 0, tx.txOut(0).publicKeyScript, BITCOIN_FUNDING_SPENT) - root ! WatchConfirmed(root, tx.txid, tx.txOut(0).publicKeyScript, 4L, BITCOIN_FUNDING_DEPTHOK) - } -} diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala index 239dfa1c4c..e8df996ffd 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala @@ -601,7 +601,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId handleCommandError(AddHtlcFailed(d.channelId, c.paymentHash, error, origin(c), Some(d.channelUpdate), Some(c)), c) case Event(c: CMD_ADD_HTLC, d: DATA_NORMAL) => - Try(Commitments.sendAdd(d.commitments, c, origin(c))) match { + Try(Commitments.sendAdd(d.commitments, c, origin(c), nodeParams.currentBlockHeight)) match { case Success(Right((commitments1, add))) => if (c.commit) self ! CMD_SIGN handleCommandSuccess(sender, d.copy(commitments = commitments1)) sending add diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 35eed22370..4bbc5940de 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -26,7 +26,7 @@ import fr.acinq.eclair.payment._ import fr.acinq.eclair.transactions.Transactions._ import fr.acinq.eclair.transactions._ import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{Globals, MilliSatoshi, UInt64, _} +import fr.acinq.eclair.{MilliSatoshi, UInt64, _} // @formatter:off case class LocalChanges(proposed: List[UpdateMessage], signed: List[UpdateMessage], acked: List[UpdateMessage]) { @@ -121,17 +121,16 @@ object Commitments { * @param cmd add HTLC command * @return either Left(failure, error message) where failure is a failure message (see BOLT #4 and the Failure Message class) or Right((new commitments, updateAddHtlc) */ - def sendAdd(commitments: Commitments, cmd: CMD_ADD_HTLC, origin: Origin): Either[ChannelException, (Commitments, UpdateAddHtlc)] = { - val blockCount = Globals.blockCount.get() + def sendAdd(commitments: Commitments, cmd: CMD_ADD_HTLC, origin: Origin, blockHeight: Long): Either[ChannelException, (Commitments, UpdateAddHtlc)] = { // our counterparty needs a reasonable amount of time to pull the funds from downstream before we can get refunded (see BOLT 2 and BOLT 11 for a calculation and rationale) - val minExpiry = Channel.MIN_CLTV_EXPIRY_DELTA.toCltvExpiry + val minExpiry = Channel.MIN_CLTV_EXPIRY_DELTA.toCltvExpiry(blockHeight) if (cmd.cltvExpiry < minExpiry) { - return Left(ExpiryTooSmall(commitments.channelId, minimum = minExpiry, actual = cmd.cltvExpiry, blockCount = blockCount)) + return Left(ExpiryTooSmall(commitments.channelId, minimum = minExpiry, actual = cmd.cltvExpiry, blockCount = blockHeight)) } - val maxExpiry = Channel.MAX_CLTV_EXPIRY_DELTA.toCltvExpiry + val maxExpiry = Channel.MAX_CLTV_EXPIRY_DELTA.toCltvExpiry(blockHeight) // we don't want to use too high a refund timeout, because our funds will be locked during that time if the payment is never fulfilled if (cmd.cltvExpiry >= maxExpiry) { - return Left(ExpiryTooBig(commitments.channelId, maximum = maxExpiry, actual = cmd.cltvExpiry, blockCount = blockCount)) + return Left(ExpiryTooBig(commitments.channelId, maximum = maxExpiry, actual = cmd.cltvExpiry, blockCount = blockHeight)) } if (cmd.amount < commitments.remoteParams.htlcMinimum) { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala index 1e43a04392..9d3cea6cbc 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/LocalPaymentHandler.scala @@ -22,7 +22,7 @@ import fr.acinq.eclair.channel.{CMD_FAIL_HTLC, CMD_FULFILL_HTLC, Channel} import fr.acinq.eclair.db.IncomingPayment import fr.acinq.eclair.payment.PaymentLifecycle.ReceivePayment import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{Globals, NodeParams, randomBytes32} +import fr.acinq.eclair.{NodeParams, randomBytes32} import scala.compat.Platform import scala.concurrent.ExecutionContext @@ -59,30 +59,31 @@ class LocalPaymentHandler(nodeParams: NodeParams) extends Actor with ActorLoggin case htlc: UpdateAddHtlc => paymentDb.getPendingPaymentRequestAndPreimage(htlc.paymentHash) match { case Some((paymentPreimage, paymentRequest)) => - val minFinalExpiry = paymentRequest.minFinalCltvExpiryDelta.getOrElse(Channel.MIN_CLTV_EXPIRY_DELTA).toCltvExpiry + val minFinalExpiry = paymentRequest.minFinalCltvExpiryDelta.getOrElse(Channel.MIN_CLTV_EXPIRY_DELTA).toCltvExpiry(nodeParams.currentBlockHeight) // The htlc amount must be equal or greater than the requested amount. A slight overpaying is permitted, however // it must not be greater than two times the requested amount. // see https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#failure-messages paymentRequest.amount match { case _ if paymentRequest.isExpired => - sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, Globals.blockCount.get())), commit = true) + sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, nodeParams.currentBlockHeight)), commit = true) case _ if htlc.cltvExpiry < minFinalExpiry => - sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, Globals.blockCount.get())), commit = true) + sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, nodeParams.currentBlockHeight)), commit = true) case Some(amount) if htlc.amountMsat < amount => log.warning(s"received payment with amount too small for paymentHash=${htlc.paymentHash} amount=${htlc.amountMsat}") - sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, Globals.blockCount.get())), commit = true) + sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, nodeParams.currentBlockHeight)), commit = true) case Some(amount) if htlc.amountMsat > amount * 2 => log.warning(s"received payment with amount too large for paymentHash=${htlc.paymentHash} amount=${htlc.amountMsat}") - sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, Globals.blockCount.get())), commit = true) + sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, nodeParams.currentBlockHeight)), commit = true) case _ => log.info(s"received payment for paymentHash=${htlc.paymentHash} amount=${htlc.amountMsat}") // amount is correct or was not specified in the payment request nodeParams.db.payments.addIncomingPayment(IncomingPayment(htlc.paymentHash, htlc.amountMsat, Platform.currentTime)) sender ! CMD_FULFILL_HTLC(htlc.id, paymentPreimage, commit = true) context.system.eventStream.publish(PaymentReceived(htlc.amountMsat, htlc.paymentHash, htlc.channelId)) + } case None => - sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, Globals.blockCount.get())), commit = true) + sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat, nodeParams.currentBlockHeight)), commit = true) } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala index a3db9e6dc8..4238ad10ec 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala @@ -37,7 +37,7 @@ class PaymentInitiator(nodeParams: NodeParams, router: ActorRef, register: Actor case p: PaymentInitiator.SendPaymentRequest => val paymentId = UUID.randomUUID() // We add one block in order to not have our htlc fail when a new block has just been found. - val finalExpiry = (p.finalExpiryDelta + 1).toCltvExpiry + val finalExpiry = (p.finalExpiryDelta + 1).toCltvExpiry(nodeParams.currentBlockHeight) val payFsm = context.actorOf(PaymentLifecycle.props(nodeParams, paymentId, router, register)) // NB: we only generate legacy payment onions for now for maximum compatibility. p.predefinedRoute match { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala index 7e0bf08f8d..7303b7fc69 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala @@ -375,7 +375,7 @@ class Router(val nodeParams: NodeParams, watcher: ActorRef, initialized: Option[ case Event(TickPruneStaleChannels, d) => // first we select channels that we will prune - val staleChannels = getStaleChannels(d.channels.values) + val staleChannels = getStaleChannels(d.channels.values, nodeParams.currentBlockHeight) val staleChannelIds = staleChannels.map(_.ann.shortChannelId) // then we remove nodes that aren't tied to any channels anymore (and deduplicate them) val potentialStaleNodes = staleChannels.flatMap(c => Set(c.ann.nodeId1, c.ann.nodeId2)).toSet @@ -456,7 +456,7 @@ class Router(val nodeParams: NodeParams, watcher: ActorRef, initialized: Option[ log.info(s"finding a route $start->$end with assistedChannels={} ignoreNodes={} ignoreChannels={} excludedChannels={}", assistedChannels.keys.mkString(","), ignoreNodes.map(_.value).mkString(","), ignoreChannels.mkString(","), d.excludedChannels.mkString(",")) log.info(s"finding a route with randomize={} params={}", routesToFind > 1, params) - findRoute(d.graph, start, end, amount, numRoutes = routesToFind, extraEdges = extraEdges, ignoredEdges = ignoredEdges, ignoredVertices = ignoreNodes, routeParams = params) + findRoute(d.graph, start, end, amount, numRoutes = routesToFind, extraEdges = extraEdges, ignoredEdges = ignoredEdges, ignoredVertices = ignoreNodes, routeParams = params, nodeParams.currentBlockHeight) .map(r => sender ! RouteResponse(r, ignoreNodes, ignoreChannels)) .recover { case t => sender ! Status.Failure(t) } stay @@ -863,15 +863,15 @@ object Router { * @param update2_opt update corresponding to the other side of the channel, if we have it * @return */ - def isStale(channel: ChannelAnnouncement, update1_opt: Option[ChannelUpdate], update2_opt: Option[ChannelUpdate]): Boolean = { + def isStale(channel: ChannelAnnouncement, update1_opt: Option[ChannelUpdate], update2_opt: Option[ChannelUpdate], currentBlockHeight: Long): Boolean = { // BOLT 7: "nodes MAY prune channels should the timestamp of the latest channel_update be older than 2 weeks (1209600 seconds)" // but we don't want to prune brand new channels for which we didn't yet receive a channel update, so we keep them as long as they are less than 2 weeks (2016 blocks) old - val staleThresholdBlocks = Globals.blockCount.get() - 2016 + val staleThresholdBlocks = currentBlockHeight - 2016 val TxCoordinates(blockHeight, _, _) = ShortChannelId.coordinates(channel.shortChannelId) blockHeight < staleThresholdBlocks && update1_opt.map(isStale).getOrElse(true) && update2_opt.map(isStale).getOrElse(true) } - def getStaleChannels(channels: Iterable[PublicChannel]): Iterable[PublicChannel] = channels.filter(data => isStale(data.ann, data.update_1_opt, data.update_2_opt)) + def getStaleChannels(channels: Iterable[PublicChannel], currentBlockHeight: Long): Iterable[PublicChannel] = channels.filter(data => isStale(data.ann, data.update_1_opt, data.update_2_opt, currentBlockHeight)) /** * Filters channels that we want to send to nodes asking for a channel range @@ -1155,12 +1155,11 @@ object Router { extraEdges: Set[GraphEdge] = Set.empty, ignoredEdges: Set[ChannelDesc] = Set.empty, ignoredVertices: Set[PublicKey] = Set.empty, - routeParams: RouteParams): Try[Seq[Hop]] = Try { + routeParams: RouteParams, + currentBlockHeight: Long): Try[Seq[Hop]] = Try { if (localNodeId == targetNodeId) throw CannotRouteToSelf - val currentBlockHeight = Globals.blockCount.get() - def feeBaseOk(fee: MilliSatoshi): Boolean = fee <= routeParams.maxFeeBase def feePctOk(fee: MilliSatoshi, amount: MilliSatoshi): Boolean = { @@ -1180,7 +1179,7 @@ object Router { val foundRoutes = Graph.yenKshortestPaths(g, localNodeId, targetNodeId, amount, ignoredEdges, ignoredVertices, extraEdges, numRoutes, routeParams.ratios, currentBlockHeight, boundaries).toList match { case Nil if routeParams.routeMaxLength < ROUTE_MAX_LENGTH => // if not found within the constraints we relax and repeat the search - return findRoute(g, localNodeId, targetNodeId, amount, numRoutes, extraEdges, ignoredEdges, ignoredVertices, routeParams.copy(routeMaxLength = ROUTE_MAX_LENGTH, routeMaxCltv = DEFAULT_ROUTE_MAX_CLTV)) + return findRoute(g, localNodeId, targetNodeId, amount, numRoutes, extraEdges, ignoredEdges, ignoredVertices, routeParams.copy(routeMaxLength = ROUTE_MAX_LENGTH, routeMaxCltv = DEFAULT_ROUTE_MAX_CLTV), currentBlockHeight) case Nil => throw RouteNotFound case routes => routes.find(_.path.size == 1) match { case Some(directRoute) => directRoute :: Nil diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/CltvExpirySpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/CltvExpirySpec.scala index 779c58a999..76c1ca0922 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/CltvExpirySpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/CltvExpirySpec.scala @@ -39,10 +39,8 @@ class CltvExpirySpec extends FunSuite { assert(d > CltvExpiryDelta(560)) // convert to cltv expiry - Globals.blockCount.set(1105) - assert(d.toCltvExpiry === CltvExpiry(1666)) - Globals.blockCount.set(1106) - assert(d.toCltvExpiry === CltvExpiry(1667)) + assert(d.toCltvExpiry(blockHeight = 1105) === CltvExpiry(1666)) + assert(d.toCltvExpiry(blockHeight = 1106) === CltvExpiry(1667)) } test("cltv expiry") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala index da1edf35f7..e0931dba52 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala @@ -16,10 +16,13 @@ package fr.acinq.eclair +import java.util.concurrent.atomic.AtomicLong + import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.Block import fr.acinq.eclair.crypto.LocalKeyManager import org.scalatest.FunSuite + import scala.util.Try class StartupSpec extends FunSuite { @@ -42,8 +45,10 @@ class StartupSpec extends FunSuite { val conf = illegalAliasConf.withFallback(ConfigFactory.parseResources("reference.conf").getConfig("eclair")) val keyManager = new LocalKeyManager(seed = randomBytes32, chainHash = Block.TestnetGenesisBlock.hash) + val blockCount = new AtomicLong(0) + // try to create a NodeParams instance with a conf that contains an illegal alias - val nodeParamsAttempt = Try(NodeParams.makeNodeParams(conf, keyManager, None, TestConstants.inMemoryDb(), new TestConstants.TestFeeEstimator)) + val nodeParamsAttempt = Try(NodeParams.makeNodeParams(conf, keyManager, None, TestConstants.inMemoryDb(), blockCount, new TestConstants.TestFeeEstimator)) assert(nodeParamsAttempt.isFailure && nodeParamsAttempt.failed.get.getMessage.contains("alias, too long")) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index fb4838d4fa..e954684ce6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -17,6 +17,7 @@ package fr.acinq.eclair import java.sql.{Connection, DriverManager} +import java.util.concurrent.atomic.AtomicLong import fr.acinq.bitcoin.Crypto.PrivateKey import fr.acinq.bitcoin.{Block, ByteVector32, Script} @@ -65,6 +66,7 @@ object TestConstants { // This is a function, and not a val! When called will return a new NodeParams def nodeParams = NodeParams( keyManager = keyManager, + blockCount = new AtomicLong(400000), alias = "alice", color = Color(1, 2, 3), publicAddresses = NodeAddress.fromParts("localhost", 9731).get :: Nil, @@ -140,6 +142,7 @@ object TestConstants { def nodeParams = NodeParams( keyManager = keyManager, + blockCount = new AtomicLong(400000), alias = "bob", color = Color(4, 5, 6), publicAddresses = NodeAddress.fromParts("localhost", 9732).get :: Nil, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala index 4f5ecdcb6f..862621b040 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala @@ -17,6 +17,7 @@ package fr.acinq.eclair import java.io.File +import java.net.ServerSocket object TestUtils { @@ -27,4 +28,16 @@ object TestUtils { .props .get("buildDirectory") // this is defined if we run from maven .getOrElse(new File(sys.props("user.dir"), "target").getAbsolutePath) // otherwise we probably are in intellij, so we build it manually assuming that user.dir == path to the module + + def availablePort: Int = synchronized { + var serverSocket: ServerSocket = null + try { + serverSocket = new ServerSocket(0) + serverSocket.getLocalPort + } finally { + if (serverSocket != null) { + serverSocket.close() + } + } + } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestkitBaseClass.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestkitBaseClass.scala index 0aaa6fd811..ca88758426 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestkitBaseClass.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestkitBaseClass.scala @@ -30,10 +30,6 @@ import scala.concurrent.Await */ abstract class TestkitBaseClass extends TestKit(ActorSystem("test")) with fixture.FunSuiteLike with BeforeAndAfterEach with BeforeAndAfterAll { - override def beforeAll { - Globals.blockCount.set(400000) - } - override def afterEach() { system.actorSelection(system / "*") ! PoisonPill intercept[ActorNotFound] { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala index c16c1d6e7d..136e09822e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala @@ -45,8 +45,8 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala index 518e6ed1a7..359d6f88e0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala @@ -28,10 +28,11 @@ import fr.acinq.eclair.TestUtils import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, BitcoinJsonRPCClient} import fr.acinq.eclair.integration.IntegrationSpec import grizzled.slf4j.Logging -import org.json4s.JsonAST.JValue +import org.json4s.JsonAST.{JArray, JDecimal, JInt, JString, JValue} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ +import scala.io.Source trait BitcoindService extends Logging { self: TestKitBase => @@ -39,6 +40,14 @@ trait BitcoindService extends Logging { implicit val system: ActorSystem implicit val sttpBackend = OkHttpFutureBackend() + val bitcoindPort: Int = TestUtils.availablePort + + val bitcoindRpcPort: Int = TestUtils.availablePort + + val bitcoindZmqBlockPort: Int = TestUtils.availablePort + + val bitcoindZmqTxPort: Int = TestUtils.availablePort + import scala.sys.process._ val INTEGRATION_TMP_DIR = new File(TestUtils.BUILD_DIRECTORY, s"integration-${UUID.randomUUID()}") @@ -56,11 +65,17 @@ trait BitcoindService extends Logging { def startBitcoind(): Unit = { Files.createDirectories(PATH_BITCOIND_DATADIR.toPath) if (!Files.exists(new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath)) { - Files.copy(classOf[IntegrationSpec].getResourceAsStream("/integration/bitcoin.conf"), new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath, StandardCopyOption.REPLACE_EXISTING) + val is = classOf[IntegrationSpec].getResourceAsStream("/integration/bitcoin.conf") + val conf = Source.fromInputStream(is).mkString + .replace("28333", bitcoindPort.toString) + .replace("28332", bitcoindRpcPort.toString) + .replace("28334", bitcoindZmqBlockPort.toString) + .replace("28335", bitcoindZmqTxPort.toString) + Files.writeString(new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath, conf) } bitcoind = s"$PATH_BITCOIND -datadir=$PATH_BITCOIND_DATADIR".run() - bitcoinrpcclient = new BasicBitcoinJsonRPCClient(user = "foo", password = "bar", host = "localhost", port = 28332) + bitcoinrpcclient = new BasicBitcoinJsonRPCClient(user = "foo", password = "bar", host = "localhost", port = bitcoindRpcPort) bitcoincli = system.actorOf(Props(new Actor { override def receive: Receive = { case BitcoinReq(method) => bitcoinrpcclient.invoke(method) pipeTo sender @@ -83,11 +98,23 @@ trait BitcoindService extends Logging { logger.info(s"waiting for bitcoind to initialize...") awaitCond({ sender.send(bitcoincli, BitcoinReq("getnetworkinfo")) - sender.receiveOne(5 second).isInstanceOf[JValue] - }, max = 30 seconds, interval = 500 millis) + sender.expectMsgType[Any](5 second) match { + case j: JValue => j \ "version" match { + case JInt(_) => true + case _ => false + } + case _ => false + } + }, max = 3 minutes, interval = 2 seconds) logger.info(s"generating initial blocks...") sender.send(bitcoincli, BitcoinReq("generate", 150)) - sender.expectMsgType[JValue](30 seconds) + val JArray(res) = sender.expectMsgType[JValue](3 minutes) + assert(res.size == 150) + awaitCond({ + sender.send(bitcoincli, BitcoinReq("getbalance")) + val JDecimal(balance) = sender.expectMsgType[JDecimal](30 seconds) + balance > 100 + }, max = 3 minutes, interval = 2 second) } } \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala index 945c6db054..86e139e54c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala @@ -38,8 +38,8 @@ class ExtendedBitcoinClientSpec extends TestKit(ActorSystem("test")) with Bitcoi "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala index 7227c5f59d..0aca5ca3ee 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala @@ -17,6 +17,7 @@ package fr.acinq.eclair.blockchain.electrum import java.net.InetSocketAddress +import java.util.concurrent.atomic.AtomicLong import akka.actor.{ActorRef, ActorSystem, Props} import akka.testkit.{TestKit, TestProbe} @@ -66,7 +67,7 @@ class ElectrumClientPoolSpec extends TestKit(ActorSystem("test")) with FunSuiteL val addresses = random.shuffle(serverAddresses.toSeq).take(2).toSet + ElectrumClientPool.ElectrumServerAddress(new InetSocketAddress("electrum.acinq.co", 50002), SSL.STRICT) stream.close() assert(addresses.nonEmpty) - pool = system.actorOf(Props(new ElectrumClientPool(addresses)), "electrum-client") + pool = system.actorOf(Props(new ElectrumClientPool(new AtomicLong(), addresses)), "electrum-client") } test("connect to an electrumx mainnet server") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala index b7e26e7b98..ee18f3e7ce 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala @@ -18,6 +18,7 @@ package fr.acinq.eclair.blockchain.electrum import java.net.InetSocketAddress import java.sql.DriverManager +import java.util.concurrent.atomic.AtomicLong import akka.actor.{ActorRef, ActorSystem, Props} import akka.testkit.{TestKit, TestProbe} @@ -87,7 +88,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike } test("wait until wallet is ready") { - electrumClient = system.actorOf(Props(new ElectrumClientPool(Set(ElectrumServerAddress(new InetSocketAddress("localhost", electrumPort), SSL.OFF))))) + electrumClient = system.actorOf(Props(new ElectrumClientPool(new AtomicLong(), Set(ElectrumServerAddress(new InetSocketAddress("localhost", electrumPort), SSL.OFF))))) wallet = system.actorOf(Props(new ElectrumWallet(seed, electrumClient, WalletParameters(Block.RegtestGenesisBlock.hash, new SqliteWalletDb(DriverManager.getConnection("jdbc:sqlite::memory:")), minimumFee = 5000 sat))), "wallet") val probe = TestProbe() awaitCond({ diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala index 09c7ce7af5..38d0f92476 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala @@ -17,6 +17,7 @@ package fr.acinq.eclair.blockchain.electrum import java.net.InetSocketAddress +import java.util.concurrent.atomic.AtomicLong import akka.actor.{ActorSystem, Props} import akka.testkit.{TestKit, TestProbe} @@ -55,8 +56,9 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("watch for confirmed transactions") { val probe = TestProbe() - val electrumClient = system.actorOf(Props(new ElectrumClientPool(Set(electrumAddress)))) - val watcher = system.actorOf(Props(new ElectrumWatcher(electrumClient))) + val blockCount = new AtomicLong() + val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(electrumAddress)))) + val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) probe.send(bitcoincli, BitcoinReq("getnewaddress")) val JString(address) = probe.expectMsgType[JValue] @@ -80,8 +82,9 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("watch for spent transactions") { val probe = TestProbe() - val electrumClient = system.actorOf(Props(new ElectrumClientPool(Set(electrumAddress)))) - val watcher = system.actorOf(Props(new ElectrumWatcher(electrumClient))) + val blockCount = new AtomicLong() + val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(electrumAddress)))) + val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) probe.send(bitcoincli, BitcoinReq("getnewaddress")) val JString(address) = probe.expectMsgType[JValue] @@ -124,9 +127,10 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike } test("get transaction") { + val blockCount = new AtomicLong() val mainnetAddress = ElectrumServerAddress(new InetSocketAddress("electrum.acinq.co", 50002), SSL.STRICT) - val electrumClient = system.actorOf(Props(new ElectrumClientPool(Set(mainnetAddress)))) - val watcher = system.actorOf(Props(new ElectrumWatcher(electrumClient))) + val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(mainnetAddress)))) + val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) //Thread.sleep(10000) val probe = TestProbe() diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala index ba1266f04a..71b487f3e8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala @@ -20,26 +20,28 @@ import com.spotify.docker.client.{DefaultDockerClient, DockerClient} import com.whisk.docker.impl.spotify.SpotifyDockerFactory import com.whisk.docker.scalatest.DockerTestKit import com.whisk.docker.{DockerContainer, DockerFactory} +import fr.acinq.eclair.TestUtils +import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import org.scalatest.Suite trait ElectrumxService extends DockerTestKit { - self: Suite => + self: Suite with BitcoindService => - val electrumPort = 47000 + val electrumPort = TestUtils.availablePort val electrumxContainer = if (System.getProperty("os.name").startsWith("Linux")) { // "host" mode will let the container access the host network on linux // we use our own docker image because other images on Docker lag behind and don't yet support 1.4 DockerContainer("acinq/electrumx") .withNetworkMode("host") - .withEnv("DAEMON_URL=http://foo:bar@localhost:28332", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") + .withEnv(s"DAEMON_URL=http://foo:bar@localhost:$bitcoindRpcPort", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") //.withLogLineReceiver(LogLineReceiver(true, println)) } else { // on windows or oxs, host mode is not available, but from docker 18.03 on host.docker.internal can be used instead // host.docker.internal is not (yet ?) available on linux though DockerContainer("acinq/electrumx") .withPorts(electrumPort -> Some(electrumPort)) - .withEnv("DAEMON_URL=http://foo:bar@host.docker.internal:28332", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") + .withEnv(s"DAEMON_URL=http://foo:bar@host.docker.internal:$bitcoindRpcPort", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") //.withLogLineReceiver(LogLineReceiver(true, println)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala index 126218bab9..1ad9f555ff 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala @@ -42,8 +42,8 @@ class BitcoinCoreFeeProviderSpec extends TestKit(ActorSystem("test")) with Bitco "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala index e96e86e21f..eb23739a34 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala @@ -61,8 +61,8 @@ class CommitmentsSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(bc0.availableBalanceForSend == b) assert(bc0.availableBalanceForReceive == a) - val (payment_preimage, cmdAdd) = makeCmdAdd(p, bob.underlyingActor.nodeParams.nodeId) - val Right((ac1, add)) = sendAdd(ac0, cmdAdd, Local(UUID.randomUUID, None)) + val (payment_preimage, cmdAdd) = makeCmdAdd(p, bob.underlyingActor.nodeParams.nodeId, currentBlockHeight) + val Right((ac1, add)) = sendAdd(ac0, cmdAdd, Local(UUID.randomUUID, None), currentBlockHeight) assert(ac1.availableBalanceForSend == a - p - fee) // as soon as htlc is sent, alice sees its balance decrease (more than the payment amount because of the commitment fees) assert(ac1.availableBalanceForReceive == b) @@ -145,8 +145,8 @@ class CommitmentsSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(bc0.availableBalanceForSend == b) assert(bc0.availableBalanceForReceive == a) - val (_, cmdAdd) = makeCmdAdd(p, bob.underlyingActor.nodeParams.nodeId) - val Right((ac1, add)) = sendAdd(ac0, cmdAdd, Local(UUID.randomUUID, None)) + val (_, cmdAdd) = makeCmdAdd(p, bob.underlyingActor.nodeParams.nodeId, currentBlockHeight) + val Right((ac1, add)) = sendAdd(ac0, cmdAdd, Local(UUID.randomUUID, None), currentBlockHeight) assert(ac1.availableBalanceForSend == a - p - fee) // as soon as htlc is sent, alice sees its balance decrease (more than the payment amount because of the commitment fees) assert(ac1.availableBalanceForReceive == b) @@ -232,18 +232,18 @@ class CommitmentsSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(bc0.availableBalanceForSend == b) assert(bc0.availableBalanceForReceive == a) - val (payment_preimage1, cmdAdd1) = makeCmdAdd(p1, bob.underlyingActor.nodeParams.nodeId) - val Right((ac1, add1)) = sendAdd(ac0, cmdAdd1, Local(UUID.randomUUID, None)) + val (payment_preimage1, cmdAdd1) = makeCmdAdd(p1, bob.underlyingActor.nodeParams.nodeId, currentBlockHeight) + val Right((ac1, add1)) = sendAdd(ac0, cmdAdd1, Local(UUID.randomUUID, None), currentBlockHeight) assert(ac1.availableBalanceForSend == a - p1 - fee) // as soon as htlc is sent, alice sees its balance decrease (more than the payment amount because of the commitment fees) assert(ac1.availableBalanceForReceive == b) - val (_, cmdAdd2) = makeCmdAdd(p2, bob.underlyingActor.nodeParams.nodeId) - val Right((ac2, add2)) = sendAdd(ac1, cmdAdd2, Local(UUID.randomUUID, None)) + val (_, cmdAdd2) = makeCmdAdd(p2, bob.underlyingActor.nodeParams.nodeId, currentBlockHeight) + val Right((ac2, add2)) = sendAdd(ac1, cmdAdd2, Local(UUID.randomUUID, None), currentBlockHeight) assert(ac2.availableBalanceForSend == a - p1 - fee - p2 - fee) // as soon as htlc is sent, alice sees its balance decrease (more than the payment amount because of the commitment fees) assert(ac2.availableBalanceForReceive == b) - val (payment_preimage3, cmdAdd3) = makeCmdAdd(p3, alice.underlyingActor.nodeParams.nodeId) - val Right((bc1, add3)) = sendAdd(bc0, cmdAdd3, Local(UUID.randomUUID, None)) + val (payment_preimage3, cmdAdd3) = makeCmdAdd(p3, alice.underlyingActor.nodeParams.nodeId, currentBlockHeight) + val Right((bc1, add3)) = sendAdd(bc0, cmdAdd3, Local(UUID.randomUUID, None), currentBlockHeight) assert(bc1.availableBalanceForSend == b - p3) // bob doesn't pay the fee assert(bc1.availableBalanceForReceive == a) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala index f1f464ee1c..a28b6c3b79 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala @@ -40,8 +40,8 @@ import scala.concurrent.duration._ import scala.util.Random /** - * Created by PM on 05/07/2016. - */ + * Created by PM on 05/07/2016. + */ class FuzzySpec extends TestkitBaseClass with StateTestsHelperMethods with Logging { @@ -81,107 +81,101 @@ class FuzzySpec extends TestkitBaseClass with StateTestsHelperMethods with Loggi bob ! WatchEventConfirmed(BITCOIN_FUNDING_DEPTHOK, 400000, 42, fundingTx) alice2blockchain.expectMsgType[WatchLost] bob2blockchain.expectMsgType[WatchLost] - awaitCond(alice.stateName == NORMAL) - awaitCond(bob.stateName == NORMAL) + awaitCond(alice.stateName == NORMAL, 1 minute) + awaitCond(bob.stateName == NORMAL, 1 minute) } withFixture(test.toNoArgTest(FixtureParam(alice, bob, pipe, relayerA, relayerB, paymentHandlerA, paymentHandlerB))) } - class SenderActor(channel: TestFSMRef[State, Data, Channel], paymentHandler: ActorRef, latch: CountDownLatch) extends Actor with ActorLogging { + class SenderActor(sendChannel: TestFSMRef[State, Data, Channel], paymentHandler: ActorRef, latch: CountDownLatch, count: Int) extends Actor with ActorLogging { // we don't want to be below htlcMinimumMsat - val requiredAmount = 1000000 + val requiredAmount = 1000000 msat def buildCmdAdd(paymentHash: ByteVector32, dest: PublicKey) = { // allow overpaying (no more than 2 times the required amount) - val amount = MilliSatoshi(requiredAmount + Random.nextInt(requiredAmount)) - val expiry = (Channel.MIN_CLTV_EXPIRY_DELTA + 1).toCltvExpiry + val amount = requiredAmount + Random.nextInt(requiredAmount.toLong.toInt).msat + val expiry = (Channel.MIN_CLTV_EXPIRY_DELTA + 1).toCltvExpiry(blockHeight = 400000) PaymentLifecycle.buildCommand(UUID.randomUUID(), paymentHash, Hop(null, dest, null) :: Nil, FinalLegacyPayload(amount, expiry))._1 } - def initiatePayment(stopping: Boolean): Unit = - if (stopping) { - context stop self + def initiatePaymentOrStop(remaining: Int): Unit = + if (remaining > 0) { + paymentHandler ! ReceivePayment(Some(requiredAmount), "One coffee") + context become { + case req: PaymentRequest => + sendChannel ! buildCmdAdd(req.paymentHash, req.nodeId) + context become { + case u: UpdateFulfillHtlc => + log.info(s"successfully sent htlc #${u.id}") + initiatePaymentOrStop(remaining - 1) + case u: UpdateFailHtlc => + log.warning(s"htlc failed: ${u.id}") + initiatePaymentOrStop(remaining - 1) + case Status.Failure(t) => + log.error(s"htlc error: ${t.getMessage}") + initiatePaymentOrStop(remaining - 1) + } + } } else { - paymentHandler ! ReceivePayment(Some(MilliSatoshi(requiredAmount)), "One coffee") - context become waitingForPaymentRequest + context stop self + latch.countDown() } - initiatePayment(false) + initiatePaymentOrStop(count) override def receive: Receive = ??? - def waitingForPaymentRequest: Receive = { - case req: PaymentRequest => - channel ! buildCmdAdd(req.paymentHash, req.nodeId) - context become waitingForFulfill(false) - } - - def waitingForFulfill(stopping: Boolean): Receive = { - case u: UpdateFulfillHtlc => - log.info(s"successfully sent htlc #${u.id}") - latch.countDown() - initiatePayment(stopping) - case u: UpdateFailHtlc => - log.warning(s"htlc failed: ${u.id}") - initiatePayment(stopping) - case Status.Failure(t) => - log.error(s"htlc error: ${t.getMessage}") - initiatePayment(stopping) - case 'stop => - log.warning(s"stopping...") - context become waitingForFulfill(true) - } - } test("fuzzy test with only one party sending HTLCs", Tag("fuzzy")) { f => import f._ - val latch = new CountDownLatch(100) - system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) - system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) + val senders = 2 + val totalMessages = 100 + val latch = new CountDownLatch(senders) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch, totalMessages / senders))) awaitCond(latch.getCount == 0, max = 2 minutes) - assert(alice.stateName == NORMAL || alice.stateName == OFFLINE) - assert(bob.stateName == NORMAL || alice.stateName == OFFLINE) + assert(List(NORMAL, OFFLINE, SYNCING).contains(alice.stateName)) + assert(List(NORMAL, OFFLINE, SYNCING).contains(bob.stateName)) } test("fuzzy test with both parties sending HTLCs", Tag("fuzzy")) { f => import f._ - val latch = new CountDownLatch(100) - system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) - system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) - system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch))) - system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch))) + val senders = 2 + val totalMessages = 100 + val latch = new CountDownLatch(senders) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch, totalMessages / senders))) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch, totalMessages / senders))) awaitCond(latch.getCount == 0, max = 2 minutes) - assert(alice.stateName == NORMAL || alice.stateName == OFFLINE) - assert(bob.stateName == NORMAL || alice.stateName == OFFLINE) + assert(List(NORMAL, OFFLINE, SYNCING).contains(alice.stateName)) + assert(List(NORMAL, OFFLINE, SYNCING).contains(bob.stateName)) } - test("one party sends lots of htlcs send shutdown") { f => + test("one party sends lots of htlcs then shutdown") { f => import f._ - val latch = new CountDownLatch(20) - val senders = system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) :: - system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) :: - system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) :: Nil + val senders = 2 + val totalMessages = 20 + val latch = new CountDownLatch(senders) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch, totalMessages / senders))) awaitCond(latch.getCount == 0, max = 2 minutes) val sender = TestProbe() awaitCond({ sender.send(alice, CMD_CLOSE(None)) sender.expectMsgAnyClassOf(classOf[String], classOf[Status.Failure]) == "ok" }, max = 30 seconds) - senders.foreach(_ ! 'stop) - awaitCond(alice.stateName == CLOSING) - awaitCond(alice.stateName == CLOSING) + awaitCond(alice.stateName == CLOSING, max = 3 minutes, interval = 1 second) + awaitCond(bob.stateName == CLOSING, max = 3 minutes, interval = 1 second) } - test("both parties send lots of htlcs send shutdown") { f => + test("both parties send lots of htlcs then shutdown") { f => import f._ - val latch = new CountDownLatch(30) - val senders = system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) :: - system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch))) :: - system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch))) :: - system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch))) :: Nil - awaitCond(latch.getCount == 0, max = 2 minutes) + val senders = 2 + val totalMessages = 100 + val latch1 = new CountDownLatch(senders) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch1, totalMessages / senders))) + val latch2 = new CountDownLatch(senders) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch2, totalMessages / senders))) + awaitCond(latch1.getCount == 0 && latch2.getCount == 0, max = 2 minutes) val sender = TestProbe() awaitCond({ sender.send(alice, CMD_CLOSE(None)) @@ -191,9 +185,8 @@ class FuzzySpec extends TestkitBaseClass with StateTestsHelperMethods with Loggi // we only need that one of them succeeds resa == "ok" || resb == "ok" }, max = 30 seconds) - senders.foreach(_ ! 'stop) - awaitCond(alice.stateName == CLOSING) - awaitCond(alice.stateName == CLOSING) + awaitCond(alice.stateName == CLOSING, max = 3 minutes, interval = 1 second) + awaitCond(bob.stateName == CLOSING, max = 3 minutes, interval = 1 second) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala index bbb14daafc..fd9058ed77 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala @@ -39,7 +39,8 @@ class ThroughputSpec extends FunSuite { ignore("throughput") { implicit val system = ActorSystem() val pipe = system.actorOf(Props[Pipe], "pipe") - val blockchain = system.actorOf(ZmqWatcher.props(new TestBitcoinClient()), "blockchain") + val blockCount = new AtomicLong() + val blockchain = system.actorOf(ZmqWatcher.props(blockCount, new TestBitcoinClient()), "blockchain") val paymentHandler = system.actorOf(Props(new Actor() { val random = new Random() diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala index 9ffb4c8634..7d9be923c4 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala @@ -46,7 +46,9 @@ trait StateTestsHelperMethods extends TestKitBase { router: TestProbe, relayerA: TestProbe, relayerB: TestProbe, - channelUpdateListener: TestProbe) + channelUpdateListener: TestProbe) { + def currentBlockHeight = alice.underlyingActor.nodeParams.currentBlockHeight + } def init(nodeParamsA: NodeParams = TestConstants.Alice.nodeParams, nodeParamsB: NodeParams = TestConstants.Bob.nodeParams, wallet: EclairWallet = new TestWallet): SetupFixture = { val alice2bob = TestProbe() @@ -106,17 +108,18 @@ trait StateTestsHelperMethods extends TestKitBase { channelUpdateListener.expectMsgType[LocalChannelUpdate] } - def makeCmdAdd(amount: MilliSatoshi, destination: PublicKey): (ByteVector32, CMD_ADD_HTLC) = { + def makeCmdAdd(amount: MilliSatoshi, destination: PublicKey, currentBlockHeight: Long): (ByteVector32, CMD_ADD_HTLC) = { val payment_preimage: ByteVector32 = randomBytes32 val payment_hash: ByteVector32 = Crypto.sha256(payment_preimage) - val expiry = CltvExpiryDelta(144).toCltvExpiry + val expiry = CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight) val cmd = PaymentLifecycle.buildCommand(UUID.randomUUID, payment_hash, Hop(null, destination, null) :: Nil, FinalLegacyPayload(amount, expiry))._1.copy(commit = false) (payment_preimage, cmd) } def addHtlc(amount: MilliSatoshi, s: TestFSMRef[State, Data, Channel], r: TestFSMRef[State, Data, Channel], s2r: TestProbe, r2s: TestProbe): (ByteVector32, UpdateAddHtlc) = { val sender = TestProbe() - val (payment_preimage, cmd) = makeCmdAdd(amount, r.underlyingActor.nodeParams.nodeId) + val currentBlockHeight = s.underlyingActor.nodeParams.currentBlockHeight + val (payment_preimage, cmd) = makeCmdAdd(amount, r.underlyingActor.nodeParams.nodeId, currentBlockHeight) sender.send(s, cmd) sender.expectMsg("ok") val htlc = s2r.expectMsgType[UpdateAddHtlc] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index c66daeedb7..d77f18c617 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -37,7 +37,7 @@ import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.transactions.Transactions.{HtlcSuccessTx, htlcSuccessWeight, htlcTimeoutWeight, weight2fee} import fr.acinq.eclair.transactions.{IN, OUT, Transactions} import fr.acinq.eclair.wire.{AnnouncementSignatures, ChannelUpdate, ClosingSigned, CommitSig, Error, FailureMessageCodecs, PermanentChannelFailure, RevokeAndAck, Shutdown, UpdateAddHtlc, UpdateFailHtlc, UpdateFailMalformedHtlc, UpdateFee, UpdateFulfillHtlc} -import fr.acinq.eclair.{Globals, TestConstants, TestkitBaseClass, randomBytes32, _} +import fr.acinq.eclair.{TestConstants, TestkitBaseClass, randomBytes32, _} import org.scalatest.{Outcome, Tag} import scodec.bits._ @@ -69,7 +69,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val sender = TestProbe() val h = randomBytes32 - val add = CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) sender.expectMsg("ok") val htlc = alice2bob.expectMsgType[UpdateAddHtlc] @@ -87,7 +87,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() val h = randomBytes32 for (i <- 0 until 10) { - sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") val htlc = alice2bob.expectMsgType[UpdateAddHtlc] assert(htlc.id == i && htlc.paymentHash == h) @@ -99,7 +99,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val sender = TestProbe() val h = randomBytes32 - val originHtlc = UpdateAddHtlc(channelId = randomBytes32, id = 5656, amountMsat = 50000000 msat, cltvExpiry = CltvExpiryDelta(144).toCltvExpiry, paymentHash = h, onionRoutingPacket = TestConstants.emptyOnionPacket) + val originHtlc = UpdateAddHtlc(channelId = randomBytes32, id = 5656, amountMsat = 50000000 msat, cltvExpiry = CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), paymentHash = h, onionRoutingPacket = TestConstants.emptyOnionPacket) val cmd = CMD_ADD_HTLC(originHtlc.amountMsat - 10000.msat, h, originHtlc.cltvExpiry - CltvExpiryDelta(7), TestConstants.emptyOnionPacket, upstream = Right(originHtlc)) sender.send(alice, cmd) sender.expectMsg("ok") @@ -117,11 +117,10 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - val currentBlockCount = Globals.blockCount.get - val expiryTooSmall = CltvExpiry(currentBlockCount + 3) + val expiryTooSmall = CltvExpiry(currentBlockHeight + 3) val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, expiryTooSmall, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) - val error = ExpiryTooSmall(channelId(alice), Channel.MIN_CLTV_EXPIRY_DELTA.toCltvExpiry, expiryTooSmall, currentBlockCount) + val error = ExpiryTooSmall(channelId(alice), Channel.MIN_CLTV_EXPIRY_DELTA.toCltvExpiry(currentBlockHeight), expiryTooSmall, currentBlockHeight) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) alice2bob.expectNoMsg(200 millis) } @@ -130,11 +129,10 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - val currentBlockCount = Globals.blockCount.get - val expiryTooBig = (Channel.MAX_CLTV_EXPIRY_DELTA + 1).toCltvExpiry + val expiryTooBig = (Channel.MAX_CLTV_EXPIRY_DELTA + 1).toCltvExpiry(currentBlockHeight) val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, expiryTooBig, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) - val error = ExpiryTooBig(channelId(alice), maximum = Channel.MAX_CLTV_EXPIRY_DELTA.toCltvExpiry, actual = expiryTooBig, blockCount = currentBlockCount) + val error = ExpiryTooBig(channelId(alice), maximum = Channel.MAX_CLTV_EXPIRY_DELTA.toCltvExpiry(currentBlockHeight), actual = expiryTooBig, blockCount = currentBlockHeight) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) alice2bob.expectNoMsg(200 millis) } @@ -143,7 +141,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - val add = CMD_ADD_HTLC(50 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(50 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = HtlcValueTooSmall(channelId(alice), 1000 msat, 50 msat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -154,7 +152,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - val add = CMD_ADD_HTLC(MilliSatoshi(Int.MaxValue), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(MilliSatoshi(Int.MaxValue), randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = InsufficientFunds(channelId(alice), amount = MilliSatoshi(Int.MaxValue), missing = 1376443 sat, reserve = 20000 sat, fees = 8960 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -165,16 +163,16 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - sender.send(alice, CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - sender.send(alice, CMD_ADD_HTLC(200000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(200000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - sender.send(alice, CMD_ADD_HTLC(67600000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(67600000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - val add = CMD_ADD_HTLC(1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = InsufficientFunds(channelId(alice), amount = 1000000 msat, missing = 1000 sat, reserve = 20000 sat, fees = 12400 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -185,13 +183,13 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - sender.send(alice, CMD_ADD_HTLC(300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - sender.send(alice, CMD_ADD_HTLC(300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = InsufficientFunds(channelId(alice), amount = 500000000 msat, missing = 332400 sat, reserve = 20000 sat, fees = 12400 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -202,7 +200,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] - val add = CMD_ADD_HTLC(151000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(151000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(bob, add) val error = HtlcValueTooHighInFlight(channelId(bob), maximum = 150000000, actual = 151000000 msat) sender.expectMsg(Failure(AddHtlcFailed(channelId(bob), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -215,11 +213,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] // Bob accepts a maximum of 30 htlcs for (i <- 0 until 30) { - sender.send(alice, CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] } - val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = TooManyAcceptedHtlcs(channelId(alice), maximum = 30) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -230,7 +228,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - val add1 = CMD_ADD_HTLC(TestConstants.fundingSatoshis.toMilliSatoshi * 2 / 3, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add1 = CMD_ADD_HTLC(TestConstants.fundingSatoshis.toMilliSatoshi * 2 / 3, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add1) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] @@ -238,7 +236,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] // this is over channel-capacity - val add2 = CMD_ADD_HTLC(TestConstants.fundingSatoshis.toMilliSatoshi * 2 / 3, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add2 = CMD_ADD_HTLC(TestConstants.fundingSatoshis.toMilliSatoshi * 2 / 3, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add2) val error = InsufficientFunds(channelId(alice), add2.amount, 564013 sat, 20000 sat, 10680 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add2.paymentHash, error, Local(add2.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add2)))) @@ -255,7 +253,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].localShutdown.isDefined && alice.stateData.asInstanceOf[DATA_NORMAL].remoteShutdown.isEmpty) // actual test starts here - val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = NoMoreHtlcsClosingInProgress(channelId(alice)) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -267,7 +265,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] // let's make alice send an htlc - val add1 = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add1 = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add1) sender.expectMsg("ok") // at the same time bob initiates a closing @@ -288,7 +286,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc") { f => import f._ val initialData = bob.stateData.asInstanceOf[DATA_NORMAL] - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, 150000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, 150000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket) bob ! htlc awaitCond(bob.stateData == initialData.copy(commitments = initialData.commitments.copy(remoteChanges = initialData.commitments.remoteChanges.copy(proposed = initialData.commitments.remoteChanges.proposed :+ htlc), remoteNextHtlcId = 1))) // bob won't forward the add before it is cross-signed @@ -298,7 +296,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (unexpected id)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 42, 150000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 42, 150000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket) bob ! htlc.copy(id = 0) bob ! htlc.copy(id = 1) bob ! htlc.copy(id = 2) @@ -315,7 +313,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (value too small)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, 150 msat, randomBytes32, cltvExpiry = CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, 150 msat, randomBytes32, cltvExpiry = CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket) alice2bob.forward(bob, htlc) val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === HtlcValueTooSmall(channelId(bob), minimum = 1000 msat, actual = 150 msat).getMessage) @@ -330,7 +328,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (insufficient funds)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(Long.MaxValue), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(Long.MaxValue), randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket) alice2bob.forward(bob, htlc) val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = MilliSatoshi(Long.MaxValue), missing = 9223372036083735L sat, reserve = 20000 sat, fees = 8960 sat).getMessage) @@ -345,10 +343,10 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (insufficient funds w/ pending htlcs 1/2)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, 400000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, 200000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, 167600000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 3, 10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, 400000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, 200000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, 167600000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 3, 10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = 10000000 msat, missing = 11720 sat, reserve = 20000 sat, fees = 14120 sat).getMessage) awaitCond(bob.stateName == CLOSING) @@ -362,9 +360,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (insufficient funds w/ pending htlcs 2/2)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, 300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, 300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, 500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, 300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, 300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, 500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = 500000000 msat, missing = 332400 sat, reserve = 20000 sat, fees = 12400 sat).getMessage) awaitCond(bob.stateName == CLOSING) @@ -378,7 +376,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (over max inflight htlc value)") { f => import f._ val tx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - alice2bob.forward(alice, UpdateAddHtlc(ByteVector32.Zeroes, 0, 151000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(alice, UpdateAddHtlc(ByteVector32.Zeroes, 0, 151000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) val error = alice2bob.expectMsgType[Error] assert(new String(error.data.toArray) === HtlcValueTooHighInFlight(channelId(alice), maximum = 150000000, actual = 151000000 msat).getMessage) awaitCond(alice.stateName == CLOSING) @@ -394,9 +392,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx // Bob accepts a maximum of 30 htlcs for (i <- 0 until 30) { - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, i, 1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, i, 1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) } - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 30, 1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 30, 1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket)) val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === TooManyAcceptedHtlcs(channelId(bob), maximum = 30).getMessage) awaitCond(bob.stateName == CLOSING) @@ -421,7 +419,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_SIGN (two identical htlcs in each direction)") { f => import f._ val sender = TestProbe() - val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] @@ -468,19 +466,19 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(a2b_2 > aliceMinOffer && a2b_2 > bobMinReceive) assert(b2a_1 > aliceMinReceive && b2a_1 > bobMinOffer) assert(b2a_2 < aliceMinReceive && b2a_2 > bobMinOffer) - sender.send(alice, CMD_ADD_HTLC(a2b_1.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(a2b_1.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) - sender.send(alice, CMD_ADD_HTLC(a2b_2.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(a2b_2.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) - sender.send(bob, CMD_ADD_HTLC(b2a_1.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(bob, CMD_ADD_HTLC(b2a_1.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") bob2alice.expectMsgType[UpdateAddHtlc] bob2alice.forward(alice) - sender.send(bob, CMD_ADD_HTLC(b2a_2.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(bob, CMD_ADD_HTLC(b2a_2.toMilliSatoshi, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") bob2alice.expectMsgType[UpdateAddHtlc] bob2alice.forward(alice) @@ -500,7 +498,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_SIGN (htlcs with same pubkeyScript but different amounts)") { f => import f._ val sender = TestProbe() - val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) val epsilons = List(3, 1, 5, 7, 6) // unordered on purpose val htlcCount = epsilons.size for (i <- epsilons) { @@ -698,12 +696,12 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val r = randomBytes32 val h = Crypto.sha256(r) - sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") val htlc1 = alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) - sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") val htlc2 = alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) @@ -2029,7 +2027,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // alice = 800 000 // bob = 200 000 - val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala index 00965f35fc..e73e50140e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala @@ -66,7 +66,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - sender.send(alice, CMD_ADD_HTLC(1000000 msat, ByteVector32.Zeroes, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(1000000 msat, ByteVector32.Zeroes, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) val ab_add_0 = alice2bob.expectMsgType[UpdateAddHtlc] // add ->b alice2bob.forward(bob) @@ -143,7 +143,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - sender.send(alice, CMD_ADD_HTLC(1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) val ab_add_0 = alice2bob.expectMsgType[UpdateAddHtlc] // add ->b alice2bob.forward(bob, ab_add_0) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala index 0757f56338..6dc7c367a1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala @@ -56,7 +56,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // alice sends an HTLC to bob val h1 = Crypto.sha256(r1) val amount1 = 300000000 msat - val expiry1 = CltvExpiryDelta(144).toCltvExpiry + val expiry1 = CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight) val cmd1 = PaymentLifecycle.buildCommand(UUID.randomUUID, h1, Hop(null, TestConstants.Bob.nodeParams.nodeId, null) :: Nil, FinalLegacyPayload(amount1, expiry1))._1.copy(commit = false) sender.send(alice, cmd1) sender.expectMsg("ok") @@ -66,7 +66,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // alice sends another HTLC to bob val h2 = Crypto.sha256(r2) val amount2 = 200000000 msat - val expiry2 = CltvExpiryDelta(144).toCltvExpiry + val expiry2 = CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight) val cmd2 = PaymentLifecycle.buildCommand(UUID.randomUUID, h2, Hop(null, TestConstants.Bob.nodeParams.nodeId, null) :: Nil, FinalLegacyPayload(amount2, expiry2))._1.copy(commit = false) sender.send(alice, cmd2) sender.expectMsg("ok") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index dd01ce607e..008e494e10 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -43,7 +43,7 @@ import fr.acinq.eclair.router.{Announcements, AnnouncementsBatchValidationSpec, import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.transactions.Transactions.{HtlcSuccessTx, HtlcTimeoutTx} import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiryDelta, Globals, Kit, LongToBtcAmount, MilliSatoshi, Setup, ShortChannelId, randomBytes32} +import fr.acinq.eclair.{CltvExpiryDelta, Kit, LongToBtcAmount, MilliSatoshi, Setup, ShortChannelId, randomBytes32} import grizzled.slf4j.Logging import org.json4s.JsonAST.JValue import org.json4s.{DefaultFormats, JString} @@ -80,10 +80,10 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val commonConfig = ConfigFactory.parseMap(Map( "eclair.chain" -> "regtest", "eclair.server.public-ips.1" -> "127.0.0.1", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, - "eclair.bitcoind.zmqblock" -> "tcp://127.0.0.1:28334", - "eclair.bitcoind.zmqtx" -> "tcp://127.0.0.1:28335", + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, + "eclair.bitcoind.zmqblock" -> s"tcp://127.0.0.1:$bitcoindZmqBlockPort", + "eclair.bitcoind.zmqtx" -> s"tcp://127.0.0.1:$bitcoindZmqTxPort", "eclair.mindepth-blocks" -> 2, "eclair.max-htlc-value-in-flight-msat" -> 100000000000L, "eclair.router.broadcast-interval" -> "2 second", @@ -345,7 +345,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(failed.id == paymentId) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, Globals.blockCount.get()))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, nodes("A").nodeParams.currentBlockHeight))) } test("send an HTLC A->D with a lower amount than requested") { @@ -365,7 +365,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(failed.id == paymentId) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, Globals.blockCount.get()))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, nodes("A").nodeParams.currentBlockHeight))) } test("send an HTLC A->D with too much overpayment") { @@ -385,7 +385,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(paymentId == failed.id) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(600000000 msat, Globals.blockCount.get()))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(600000000 msat, nodes("A").nodeParams.currentBlockHeight))) } test("send an HTLC A->D with a reasonable overpayment") { @@ -460,7 +460,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService // first we make sure we are in sync with current blockchain height sender.send(bitcoincli, BitcoinReq("getblockcount")) val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] - awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -540,7 +540,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService // first we make sure we are in sync with current blockchain height sender.send(bitcoincli, BitcoinReq("getblockcount")) val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] - awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -617,7 +617,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService // first we make sure we are in sync with current blockchain height sender.send(bitcoincli, BitcoinReq("getblockcount")) val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] - awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -679,7 +679,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService // first we make sure we are in sync with current blockchain height sender.send(bitcoincli, BitcoinReq("getblockcount")) val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] - awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -756,7 +756,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService // first we make sure we are in sync with current blockchain height sender.send(bitcoincli, BitcoinReq("getblockcount")) val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] - awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // first we send 3 mBTC to F so that it has a balance val amountMsat = 300000000.msat sender.send(paymentHandlerF, ReceivePayment(Some(amountMsat), "1 coffee")) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala index 67874c54c7..b62afa5d61 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala @@ -17,18 +17,19 @@ package fr.acinq.eclair.interop.rustytests import java.io.File +import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.{CountDownLatch, TimeUnit} import akka.actor.{ActorRef, ActorSystem, Props} import akka.testkit.{TestFSMRef, TestKit, TestProbe} -import fr.acinq.bitcoin.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.ByteVector32 import fr.acinq.eclair.TestConstants.{Alice, Bob, TestFeeEstimator} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.fee.FeeratesPerKw import fr.acinq.eclair.channel._ import fr.acinq.eclair.payment.NoopPaymentHandler import fr.acinq.eclair.wire.Init -import fr.acinq.eclair.{Globals, LongToBtcAmount, TestUtils} +import fr.acinq.eclair.{LongToBtcAmount, TestUtils} import org.scalatest.{BeforeAndAfterAll, Matchers, Outcome, fixture} import scala.concurrent.duration._ @@ -43,7 +44,7 @@ class RustyTestsSpec extends TestKit(ActorSystem("test")) with Matchers with fix case class FixtureParam(ref: List[String], res: List[String]) override def withFixture(test: OneArgTest): Outcome = { - Globals.blockCount.set(0) + val blockCount = new AtomicLong(0) val latch = new CountDownLatch(1) val pipe: ActorRef = system.actorOf(Props(new SynchronizationPipe(latch))) val alice2blockchain = TestProbe() @@ -54,8 +55,8 @@ class RustyTestsSpec extends TestKit(ActorSystem("test")) with Matchers with fix val router = TestProbe() val wallet = new TestWallet val feeEstimator = new TestFeeEstimator - val alice: TestFSMRef[State, Data, Channel] = TestFSMRef(new Channel(Alice.nodeParams.copy(onChainFeeConf = Alice.nodeParams.onChainFeeConf.copy(feeEstimator = feeEstimator)), wallet, Bob.nodeParams.nodeId, alice2blockchain.ref, router.ref, relayer)) - val bob: TestFSMRef[State, Data, Channel] = TestFSMRef(new Channel(Bob.nodeParams.copy(onChainFeeConf = Bob.nodeParams.onChainFeeConf.copy(feeEstimator = feeEstimator)), wallet, Alice.nodeParams.nodeId, bob2blockchain.ref, router.ref, relayer)) + val alice: TestFSMRef[State, Data, Channel] = TestFSMRef(new Channel(Alice.nodeParams.copy(blockCount = blockCount, onChainFeeConf = Alice.nodeParams.onChainFeeConf.copy(feeEstimator = feeEstimator)), wallet, Bob.nodeParams.nodeId, alice2blockchain.ref, router.ref, relayer)) + val bob: TestFSMRef[State, Data, Channel] = TestFSMRef(new Channel(Bob.nodeParams.copy(blockCount = blockCount, onChainFeeConf = Bob.nodeParams.onChainFeeConf.copy(feeEstimator = feeEstimator)), wallet, Alice.nodeParams.nodeId, bob2blockchain.ref, router.ref, relayer)) val aliceInit = Init(Alice.channelParams.globalFeatures, Alice.channelParams.localFeatures) val bobInit = Init(Bob.channelParams.globalFeatures, Bob.channelParams.localFeatures) // alice and bob will both have 1 000 000 sat diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala index 6361c3813c..592bbfd685 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala @@ -28,7 +28,7 @@ import fr.acinq.eclair.router.Hop import fr.acinq.eclair.wire.Onion.{FinalLegacyPayload, FinalTlvPayload, PerHopPayload, RelayLegacyPayload} import fr.acinq.eclair.wire.OnionTlv.{AmountToForward, OutgoingCltv} import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, Globals, LongToBtcAmount, MilliSatoshi, ShortChannelId, TestConstants, nodeFee, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, ShortChannelId, TestConstants, nodeFee, randomBytes32} import org.scalatest.{BeforeAndAfterAll, FunSuite} import scodec.bits.ByteVector @@ -38,10 +38,6 @@ import scodec.bits.ByteVector class HtlcGenerationSpec extends FunSuite with BeforeAndAfterAll { - override def beforeAll { - Globals.blockCount.set(HtlcGenerationSpec.currentBlockCount) - } - test("compute fees") { val feeBaseMsat = 150000 msat val feeProportionalMillionth = 4L diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala index e44b8d8a05..b142e521f5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala @@ -25,7 +25,7 @@ import fr.acinq.eclair.channel.{CMD_FAIL_HTLC, CMD_FULFILL_HTLC} import fr.acinq.eclair.payment.PaymentLifecycle.ReceivePayment import fr.acinq.eclair.payment.PaymentRequest.ExtraHop import fr.acinq.eclair.wire.{IncorrectOrUnknownPaymentDetails, UpdateAddHtlc} -import fr.acinq.eclair.{CltvExpiryDelta, Globals, LongToBtcAmount, ShortChannelId, TestConstants, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, ShortChannelId, TestConstants, randomKey} import org.scalatest.FunSuiteLike import scodec.bits.ByteVector @@ -45,7 +45,7 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike system.eventStream.subscribe(eventListener.ref, classOf[PaymentReceived]) val amountMsat = 42000 msat - val expiry = CltvExpiryDelta(12).toCltvExpiry + val expiry = CltvExpiryDelta(12).toCltvExpiry(nodeParams.currentBlockHeight) { sender.send(handler, ReceivePayment(Some(amountMsat), "1 coffee")) @@ -81,9 +81,9 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike val pr = sender.expectMsgType[PaymentRequest] assert(nodeParams.db.payments.getIncomingPayment(pr.paymentHash).isEmpty) - val add = UpdateAddHtlc(ByteVector32(ByteVector.fill(32)(1)), 0, amountMsat, pr.paymentHash, cltvExpiry = CltvExpiryDelta(3).toCltvExpiry, TestConstants.emptyOnionPacket) + val add = UpdateAddHtlc(ByteVector32(ByteVector.fill(32)(1)), 0, amountMsat, pr.paymentHash, cltvExpiry = CltvExpiryDelta(3).toCltvExpiry(nodeParams.currentBlockHeight), TestConstants.emptyOnionPacket) sender.send(handler, add) - assert(sender.expectMsgType[CMD_FAIL_HTLC].reason == Right(IncorrectOrUnknownPaymentDetails(amountMsat, Globals.blockCount.get()))) + assert(sender.expectMsgType[CMD_FAIL_HTLC].reason == Right(IncorrectOrUnknownPaymentDetails(amountMsat, nodeParams.currentBlockHeight))) eventListener.expectNoMsg(300 milliseconds) assert(nodeParams.db.payments.getIncomingPayment(pr.paymentHash).isEmpty) } @@ -159,7 +159,7 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike system.eventStream.subscribe(eventListener.ref, classOf[PaymentReceived]) val amountMsat = 42000 msat - val expiry = CltvExpiryDelta(12).toCltvExpiry + val expiry = CltvExpiryDelta(12).toCltvExpiry(nodeParams.currentBlockHeight) sender.send(handler, ReceivePayment(Some(amountMsat), "some desc", expirySeconds_opt = Some(0))) val pr = sender.expectMsgType[PaymentRequest] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala index 957dbdef11..7dcd6417e0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala @@ -45,7 +45,7 @@ import scodec.bits.HexStringSyntax class PaymentLifecycleSpec extends BaseRouterSpec { val defaultAmountMsat = 142000000 msat - val defaultExpiry = Channel.MIN_CLTV_EXPIRY_DELTA.toCltvExpiry + val defaultExpiryDelta = Channel.MIN_CLTV_EXPIRY_DELTA test("send to route") { fixture => import fixture._ @@ -63,7 +63,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) // pre-computed route going from A to D - val request = SendPaymentToRoute(defaultPaymentHash, Seq(a, b, c, d), FinalLegacyPayload(defaultAmountMsat, defaultExpiry)) + val request = SendPaymentToRoute(defaultPaymentHash, Seq(a, b, c, d), FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight))) sender.send(paymentFSM, request) val Transition(_, WAITING_FOR_REQUEST, WAITING_FOR_ROUTE) = monitor.expectMsgClass(classOf[Transition[_]]) @@ -89,7 +89,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(defaultPaymentHash, f, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 5) + val request = SendPayment(defaultPaymentHash, f, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 5) sender.send(paymentFSM, request) val Transition(_, WAITING_FOR_REQUEST, WAITING_FOR_ROUTE) = monitor.expectMsgClass(classOf[Transition[_]]) val routeRequest = routerForwarder.expectMsgType[RouteRequest] @@ -112,7 +112,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 5, routeParams = Some(RouteParams(randomize = false, maxFeeBase = 100 msat, maxFeePct = 0.0, routeMaxLength = 20, routeMaxCltv = CltvExpiryDelta(2016), ratios = None))) + val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 5, routeParams = Some(RouteParams(randomize = false, maxFeeBase = 100 msat, maxFeePct = 0.0, routeMaxLength = 20, routeMaxCltv = CltvExpiryDelta(2016), ratios = None))) sender.send(paymentFSM, request) val Transition(_, WAITING_FOR_REQUEST, WAITING_FOR_ROUTE) = monitor.expectMsgClass(classOf[Transition[_]]) @@ -135,7 +135,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(defaultPaymentHash, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 2) + val request = SendPayment(defaultPaymentHash, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 2) sender.send(paymentFSM, request) awaitCond(paymentFSM.stateName == WAITING_FOR_ROUTE && paymentDb.getOutgoingPayment(id).exists(_.status == OutgoingPaymentStatus.PENDING)) @@ -178,7 +178,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 2) + val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 2) sender.send(paymentFSM, request) awaitCond(paymentFSM.stateName == WAITING_FOR_ROUTE && paymentDb.getOutgoingPayment(id).exists(_.status == OutgoingPaymentStatus.PENDING)) @@ -211,7 +211,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(defaultPaymentHash, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 2) + val request = SendPayment(defaultPaymentHash, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 2) sender.send(paymentFSM, request) awaitCond(paymentFSM.stateName == WAITING_FOR_ROUTE && paymentDb.getOutgoingPayment(id).exists(_.status == OutgoingPaymentStatus.PENDING)) @@ -242,7 +242,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 2) + val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 2) sender.send(paymentFSM, request) awaitCond(paymentFSM.stateName == WAITING_FOR_ROUTE) val WaitingForRoute(_, _, Nil) = paymentFSM.stateData @@ -282,7 +282,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 5) + val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 5) sender.send(paymentFSM, request) awaitCond(paymentFSM.stateName == WAITING_FOR_ROUTE && paymentDb.getOutgoingPayment(id).exists(_.status == OutgoingPaymentStatus.PENDING)) @@ -344,7 +344,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 2) + val request = SendPayment(randomBytes32, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 2) sender.send(paymentFSM, request) awaitCond(paymentFSM.stateName == WAITING_FOR_ROUTE && paymentDb.getOutgoingPayment(id).exists(_.status == OutgoingPaymentStatus.PENDING)) @@ -392,7 +392,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(defaultPaymentHash, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 5) + val request = SendPayment(defaultPaymentHash, d, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 5) sender.send(paymentFSM, request) val Transition(_, WAITING_FOR_REQUEST, WAITING_FOR_ROUTE) = monitor.expectMsgClass(classOf[Transition[_]]) val Transition(_, WAITING_FOR_ROUTE, WAITING_FOR_PAYMENT_COMPLETE) = monitor.expectMsgClass(classOf[Transition[_]]) @@ -442,7 +442,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) // we send a payment to G which is just after the - val request = SendPayment(defaultPaymentHash, g, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), maxAttempts = 5) + val request = SendPayment(defaultPaymentHash, g, FinalLegacyPayload(defaultAmountMsat, defaultExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight)), maxAttempts = 5) sender.send(paymentFSM, request) // the route will be A -> B -> G where B -> G has a channel_update with fees=0 diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala index 1fedf2ab2c..0bc966f149 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala @@ -24,7 +24,7 @@ import fr.acinq.eclair.router.Graph.GraphStructure.{DirectedGraph, GraphEdge} import fr.acinq.eclair.router.Graph.{RichWeight, WeightRatios} import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiryDelta, Globals, LongToBtcAmount, MilliSatoshi, ShortChannelId, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, ShortChannelId, randomKey} import org.scalatest.FunSuite import scodec.bits._ @@ -52,7 +52,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) } @@ -76,7 +76,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(maxFeeBase = 1 msat)) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(maxFeeBase = 1 msat), currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) } @@ -114,7 +114,7 @@ class RouteCalculationSpec extends FunSuite { val graph = makeGraph(updates) - val Success(route) = Router.findRoute(graph, a, d, amount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val Success(route) = Router.findRoute(graph, a, d, amount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) val totalCost = Graph.pathWeight(hops2Edges(route), amount, false, 0, None).cost @@ -125,7 +125,7 @@ class RouteCalculationSpec extends FunSuite { val (desc, update) = makeUpdate(5L, e, f, feeBase = 1 msat, feeProportionalMillionth = 400, minHtlc = 0 msat, maxHtlc = Some(10005 msat)) val graph1 = graph.addEdge(desc, update) - val Success(route1) = Router.findRoute(graph1, a, d, amount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val Success(route1) = Router.findRoute(graph1, a, d, amount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(hops2Ids(route1) === 1 :: 2 :: 3 :: Nil) } @@ -140,7 +140,7 @@ class RouteCalculationSpec extends FunSuite { ).toMap val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(2 :: 5 :: Nil)) } @@ -156,11 +156,11 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route1.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) val graphWithRemovedEdge = g.removeEdge(ChannelDesc(ShortChannelId(3L), c, d)) - val route2 = Router.findRoute(graphWithRemovedEdge, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route2 = Router.findRoute(graphWithRemovedEdge, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route2.map(hops2Ids) === Failure(RouteNotFound)) } @@ -182,7 +182,7 @@ class RouteCalculationSpec extends FunSuite { val graph = makeGraph(updates) - val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(4 :: 3 :: Nil)) } @@ -205,7 +205,7 @@ class RouteCalculationSpec extends FunSuite { val graph = makeGraph(updates) - val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 2, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 2, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(4 :: Nil)) } @@ -226,7 +226,7 @@ class RouteCalculationSpec extends FunSuite { val graph = makeGraph(updates) - val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) == Success(1 :: 2 :: 3 :: Nil)) } @@ -247,7 +247,7 @@ class RouteCalculationSpec extends FunSuite { val graph = makeGraph(updates) - val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Failure(RouteNotFound)) } @@ -269,7 +269,7 @@ class RouteCalculationSpec extends FunSuite { val graph = makeGraph(updates) - val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(graph, f, i, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(1 :: 6 :: 3 :: Nil)) } @@ -285,7 +285,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) } @@ -298,7 +298,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Failure(RouteNotFound)) } @@ -312,7 +312,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Failure(RouteNotFound)) } @@ -325,8 +325,8 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates).addVertex(a).addVertex(e) - assert(Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) === Failure(RouteNotFound)) - assert(Router.findRoute(g, b, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) === Failure(RouteNotFound)) + assert(Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) === Failure(RouteNotFound)) + assert(Router.findRoute(g, b, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) === Failure(RouteNotFound)) } test("route not found (amount too high OR too low)") { @@ -349,8 +349,8 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updatesHi) val g1 = makeGraph(updatesLo) - assert(Router.findRoute(g, a, d, highAmount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) === Failure(RouteNotFound)) - assert(Router.findRoute(g1, a, d, lowAmount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) === Failure(RouteNotFound)) + assert(Router.findRoute(g, a, d, highAmount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) === Failure(RouteNotFound)) + assert(Router.findRoute(g1, a, d, lowAmount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) === Failure(RouteNotFound)) } test("route to self") { @@ -363,7 +363,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, a, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, a, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Failure(CannotRouteToSelf)) } @@ -378,7 +378,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, b, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, b, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(1 :: Nil)) } @@ -394,10 +394,10 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route1.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) - val route2 = Router.findRoute(g, e, a, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route2 = Router.findRoute(g, e, a, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route2.map(hops2Ids) === Failure(RouteNotFound)) } @@ -427,7 +427,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val hops = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS).get + val hops = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000).get assert(hops === Hop(a, b, uab) :: Hop(b, c, ubc) :: Hop(c, d, ucd) :: Hop(d, e, ude) :: Nil) } @@ -469,7 +469,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, ignoredEdges = Set(ChannelDesc(ShortChannelId(3L), c, d)), routeParams = DEFAULT_ROUTE_PARAMS) + val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, ignoredEdges = Set(ChannelDesc(ShortChannelId(3L), c, d)), routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route1.map(hops2Ids) === Failure(RouteNotFound)) // verify that we left the graph untouched @@ -478,7 +478,7 @@ class RouteCalculationSpec extends FunSuite { assert(g.containsVertex(d)) // make sure we can find a route if without the blacklist - val route2 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route2 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route2.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) } @@ -491,14 +491,14 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Failure(RouteNotFound)) // now we add the missing edge to reach the destination val (extraDesc, extraUpdate) = makeUpdate(4L, d, e, 5 msat, 5) val extraGraphEdges = Set(GraphEdge(extraDesc, extraUpdate)) - val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, extraEdges = extraGraphEdges, routeParams = DEFAULT_ROUTE_PARAMS) + val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, extraEdges = extraGraphEdges, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route1.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) } @@ -513,7 +513,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route1.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) assert(route1.get(1).lastUpdate.feeBaseMsat === 10.msat) @@ -521,7 +521,7 @@ class RouteCalculationSpec extends FunSuite { val extraGraphEdges = Set(GraphEdge(extraDesc, extraUpdate)) - val route2 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, extraEdges = extraGraphEdges, routeParams = DEFAULT_ROUTE_PARAMS) + val route2 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, extraEdges = extraGraphEdges, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route2.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) assert(route2.get(1).lastUpdate.feeBaseMsat === 5.msat) } @@ -585,10 +585,10 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - assert(Router.findRoute(g, nodes(0), nodes(18), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS).map(hops2Ids) === Success(0 until 18)) - assert(Router.findRoute(g, nodes(0), nodes(19), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS).map(hops2Ids) === Success(0 until 19)) - assert(Router.findRoute(g, nodes(0), nodes(20), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS).map(hops2Ids) === Success(0 until 20)) - assert(Router.findRoute(g, nodes(0), nodes(21), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS).map(hops2Ids) === Failure(RouteNotFound)) + assert(Router.findRoute(g, nodes(0), nodes(18), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000).map(hops2Ids) === Success(0 until 18)) + assert(Router.findRoute(g, nodes(0), nodes(19), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000).map(hops2Ids) === Success(0 until 19)) + assert(Router.findRoute(g, nodes(0), nodes(20), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000).map(hops2Ids) === Success(0 until 20)) + assert(Router.findRoute(g, nodes(0), nodes(21), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000).map(hops2Ids) === Failure(RouteNotFound)) } test("ignore cheaper route when it has more than 20 hops") { @@ -605,7 +605,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates2) - val route = Router.findRoute(g, nodes(0), nodes(49), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route = Router.findRoute(g, nodes(0), nodes(49), DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(0 :: 1 :: 99 :: 48 :: Nil)) } @@ -622,7 +622,7 @@ class RouteCalculationSpec extends FunSuite { makeUpdate(6, f, d, feeBase = 5 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)) ).toMap) - val route = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(routeMaxCltv = CltvExpiryDelta(28))) + val route = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(routeMaxCltv = CltvExpiryDelta(28)), currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(4 :: 5 :: 6 :: Nil)) } @@ -639,7 +639,7 @@ class RouteCalculationSpec extends FunSuite { makeUpdate(6, b, f, feeBase = 5 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)) ).toMap) - val route = Router.findRoute(g, a, f, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(routeMaxLength = 3)) + val route = Router.findRoute(g, a, f, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(routeMaxLength = 3), currentBlockHeight = 400000) assert(route.map(hops2Ids) === Success(1 :: 6 :: Nil)) } @@ -655,7 +655,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route1.map(hops2Ids) === Success(1 :: 2 :: 4 :: 5 :: Nil)) } @@ -674,7 +674,7 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val route1 = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) + val route1 = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(route1.map(hops2Ids) === Success(1 :: 3 :: 5 :: Nil)) } @@ -807,7 +807,7 @@ class RouteCalculationSpec extends FunSuite { makeUpdate(7L, e, c, feeBase = 9 msat, 0) ).toMap) - (for {_ <- 0 to 10} yield Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 3, routeParams = strictFeeParams)).map { + (for {_ <- 0 to 10} yield Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 3, routeParams = strictFeeParams, currentBlockHeight = 400000)).map { case Failure(thr) => assert(false, thr) case Success(someRoute) => @@ -837,14 +837,14 @@ class RouteCalculationSpec extends FunSuite { val g = makeGraph(updates) - val Success(routeFeeOptimized) = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 0, routeParams = DEFAULT_ROUTE_PARAMS) + val Success(routeFeeOptimized) = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 0, routeParams = DEFAULT_ROUTE_PARAMS, currentBlockHeight = 400000) assert(hops2Nodes(routeFeeOptimized) === (a, b) :: (b, c) :: (c, d) :: Nil) val Success(routeCltvOptimized) = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 0, routeParams = DEFAULT_ROUTE_PARAMS.copy(ratios = Some(WeightRatios( cltvDeltaFactor = 1, ageFactor = 0, capacityFactor = 0 - )))) + ))), currentBlockHeight = 400000) assert(hops2Nodes(routeCltvOptimized) === (a, e) :: (e, f) :: (f, d) :: Nil) @@ -852,7 +852,7 @@ class RouteCalculationSpec extends FunSuite { cltvDeltaFactor = 0, ageFactor = 0, capacityFactor = 1 - )))) + ))), currentBlockHeight = 400000) assert(hops2Nodes(routeCapacityOptimized) === (a, e) :: (e, c) :: (c, d) :: Nil) } @@ -870,13 +870,11 @@ class RouteCalculationSpec extends FunSuite { makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x6"), f, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)) ).toMap) - Globals.blockCount.set(currentBlockHeight) - val Success(routeScoreOptimized) = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT / 2, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(ratios = Some(WeightRatios( ageFactor = 0.33, cltvDeltaFactor = 0.33, capacityFactor = 0.33 - )))) + ))), currentBlockHeight = currentBlockHeight) assert(hops2Nodes(routeScoreOptimized) === (a, b) :: (b, c) :: (c, d) :: Nil) } @@ -897,7 +895,7 @@ class RouteCalculationSpec extends FunSuite { ageFactor = 0.33, cltvDeltaFactor = 0.33, capacityFactor = 0.33 - )))) + ))), currentBlockHeight = 400000) assert(hops2Nodes(routeScoreOptimized) === (a, b) :: (b, c) :: (c, d) :: Nil) } @@ -920,7 +918,7 @@ class RouteCalculationSpec extends FunSuite { ageFactor = 0.33, cltvDeltaFactor = 0.33, capacityFactor = 0.33 - )))) + ))), currentBlockHeight = 400000) assert(hops2Nodes(routeScoreOptimized) === (a, e) :: (e, f) :: (f, d) :: Nil) } @@ -962,8 +960,7 @@ class RouteCalculationSpec extends FunSuite { val targetNode = PublicKey(hex"024655b768ef40951b20053a5c4b951606d4d86085d51238f2c67c7dec29c792ca") val amount = 351000 msat - Globals.blockCount.set(567634) // simulate mainnet block for heuristic - val Success(route) = Router.findRoute(g, thisNode, targetNode, amount, 1, Set.empty, Set.empty, Set.empty, params) + val Success(route) = Router.findRoute(g, thisNode, targetNode, amount, 1, Set.empty, Set.empty, Set.empty, params, currentBlockHeight = 567634) // simulate mainnet block for heuristic assert(route.size == 2) assert(route.last.nextNodeId == targetNode) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala index 52e7226313..e8b6bf96d0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala @@ -30,7 +30,7 @@ import fr.acinq.eclair.router.Announcements.makeChannelUpdate import fr.acinq.eclair.router.RouteCalculationSpec.DEFAULT_AMOUNT_MSAT import fr.acinq.eclair.transactions.Scripts import fr.acinq.eclair.wire.QueryShortChannelIds -import fr.acinq.eclair.{CltvExpiryDelta, Globals, LongToBtcAmount, ShortChannelId, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, ShortChannelId, randomKey} import scodec.bits._ import scala.compat.Platform @@ -252,7 +252,7 @@ class RouterSpec extends BaseRouterSpec { test("ask for channels that we marked as stale for which we receive a new update") { fixture => import fixture._ - val blockHeight = Globals.blockCount.get().toInt - 2020 + val blockHeight = 400000 - 2020 val channelId = ShortChannelId(blockHeight, 5, 0) val announcement = channelAnnouncement(channelId, priv_a, priv_c, priv_funding_a, priv_funding_c) val timestamp = (Platform.currentTime.milliseconds - 14.days - 1.day).toSeconds diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala index 9b1f6f24b4..71759368c9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala @@ -37,6 +37,7 @@ import scala.collection.{SortedSet, immutable, mutable} import scala.compat.Platform import scala.concurrent.duration._ + class RoutingSyncSpec extends TestKit(ActorSystem("test")) with FunSuiteLike { import RoutingSyncSpec._ diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala index d02ce4c1d0..d88099179b 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala @@ -84,6 +84,7 @@ class TransactionsSpec extends FunSuite with Logging { val localDustLimit = 546 sat val toLocalDelay = CltvExpiryDelta(144) val feeratePerKw = fr.acinq.eclair.MinimumFeeratePerKw + val blockHeight = 400000 { // ClaimP2WPKHOutputTx @@ -125,7 +126,7 @@ class TransactionsSpec extends FunSuite with Logging { // HtlcPenaltyTx // first we create a fake commitTx tx, containing only the output that will be spent by the ClaimHtlcSuccessTx val paymentPreimage = randomBytes32 - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry(blockHeight), TestConstants.emptyOnionPacket) val redeemScript = htlcReceived(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash), htlc.cltvExpiry) val pubKeyScript = write(pay2wsh(redeemScript)) val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) @@ -140,7 +141,7 @@ class TransactionsSpec extends FunSuite with Logging { // ClaimHtlcSuccessTx // first we create a fake commitTx tx, containing only the output that will be spent by the ClaimHtlcSuccessTx val paymentPreimage = randomBytes32 - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry(blockHeight), TestConstants.emptyOnionPacket) val pubKeyScript = write(pay2wsh(htlcOffered(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash)))) val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) val claimHtlcSuccessTx = makeClaimHtlcSuccessTx(commitTx, outputsAlreadyUsed = Set.empty, localDustLimit, remoteHtlcPriv.publicKey, localHtlcPriv.publicKey, localRevocationPriv.publicKey, finalPubKeyScript, htlc, feeratePerKw) @@ -154,7 +155,7 @@ class TransactionsSpec extends FunSuite with Logging { // ClaimHtlcTimeoutTx // first we create a fake commitTx tx, containing only the output that will be spent by the ClaimHtlcSuccessTx val paymentPreimage = randomBytes32 - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry(blockHeight), TestConstants.emptyOnionPacket) val pubKeyScript = write(pay2wsh(htlcReceived(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash), htlc.cltvExpiry))) val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) val claimClaimHtlcTimeoutTx = makeClaimHtlcTimeoutTx(commitTx, outputsAlreadyUsed = Set.empty, localDustLimit, remoteHtlcPriv.publicKey, localHtlcPriv.publicKey, localRevocationPriv.publicKey, finalPubKeyScript, htlc, feeratePerKw) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala index b11aeb5888..9d3b690064 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala @@ -115,4 +115,18 @@ class Handlers(fKit: Future[Kit])(implicit ec: ExecutionContext = ExecutionConte def notification(title: String, message: String, notificationType: NotificationType = NOTIFICATION_NONE, showAppName: Boolean = true): Unit = { notifsController.foreach(_.addNotification(if (showAppName) s"Eclair - $title" else title, message, notificationType)) } + + /** + * Retrieves on-chain fees for a funding transaction, using the funding block target set in the config file. + * + * @return Future containing a Long in satoshi per kilobyte + */ + def getFundingFeeRatePerKb(): Future[Long] = { + for { + kit <- fKit + ratePerKw = { + kit.nodeParams.onChainFeeConf.feeEstimator.getFeeratePerKb(target = kit.nodeParams.onChainFeeConf.feeTargets.fundingBlockTarget) + } + } yield ratePerKw + } } diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala index c038671808..379c94bfbd 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala @@ -25,7 +25,7 @@ import fr.acinq.eclair.channel.{Channel, ChannelFlags} import fr.acinq.eclair.gui.utils.Constants import fr.acinq.eclair.gui.{FxApp, Handlers} import fr.acinq.eclair.io.{NodeURI, Peer} -import fr.acinq.eclair.{CoinUtils, Globals, MilliSatoshi} +import fr.acinq.eclair.{CoinUtils, MilliSatoshi} import grizzled.slf4j.Logging import javafx.beans.value.{ChangeListener, ObservableValue} import javafx.event.ActionEvent @@ -33,6 +33,7 @@ import javafx.fxml.FXML import javafx.scene.control._ import javafx.stage.Stage +import scala.concurrent.ExecutionContext import scala.concurrent.duration._ import scala.util.{Failure, Success, Try} @@ -56,7 +57,16 @@ class OpenChannelController(val handlers: Handlers, val stage: Stage) extends Lo @FXML def initialize() = { fundingUnit.setItems(Constants.FX_UNITS_ARRAY_NO_MSAT) fundingUnit.setValue(FxApp.getUnit.label) - feerateField.setText((Globals.feeratesPerKB.get().blocks_6 / 1000).toString) + + handlers.getFundingFeeRatePerKb().onComplete { + case Success(feeSatKb) => + feerateField.setText((feeSatKb / 1000).toString) + feerateError.setText("") + case Failure(t) => + logger.error(s"error when estimating funding fee from GUI: ${t.getLocalizedMessage}") + feerateField.setText("") + feerateError.setText("Could not estimate fees.") + } (ExecutionContext.Implicits.global) simpleConnection.selectedProperty.addListener(new ChangeListener[Boolean] { override def changed(observable: ObservableValue[_ <: Boolean], oldValue: Boolean, newValue: Boolean) = { diff --git a/pom.xml b/pom.xml index 3c8775b350..1a2a01c2bc 100644 --- a/pom.xml +++ b/pom.xml @@ -221,8 +221,7 @@ ${project.build.directory} - -Xmx1024m - -Dfile.encoding=UTF-8 + -Xmx1024m -Dfile.encoding=UTF-8 From d34c0642bfdec9e7295d2bd73b86f837c721f22b Mon Sep 17 00:00:00 2001 From: pm47 Date: Thu, 5 Sep 2019 21:48:07 +0200 Subject: [PATCH 02/54] bump --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From 046997555139cf04fcf5af734c48bbbe9bf1e90a Mon Sep 17 00:00:00 2001 From: pm47 Date: Thu, 5 Sep 2019 22:13:10 +0200 Subject: [PATCH 03/54] Revert "bump" This reverts commit d34c0642bfdec9e7295d2bd73b86f837c721f22b. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From b039d348296dee5372ca5815d8ab2dbe235a750f Mon Sep 17 00:00:00 2001 From: pm47 Date: Thu, 5 Sep 2019 22:38:20 +0200 Subject: [PATCH 04/54] Revert "Revert "bump"" This reverts commit 046997555139cf04fcf5af734c48bbbe9bf1e90a. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From ece227c1b310d2b9825527dade54126d383628f4 Mon Sep 17 00:00:00 2001 From: pm47 Date: Thu, 5 Sep 2019 23:17:59 +0200 Subject: [PATCH 05/54] Revert "Revert "Revert "bump""" This reverts commit b039d348296dee5372ca5815d8ab2dbe235a750f. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From d2678c29c860952212f85a5c33876829b4552fce Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 00:14:14 +0200 Subject: [PATCH 06/54] Revert "Revert "Revert "Revert "bump"""" This reverts commit ece227c1b310d2b9825527dade54126d383628f4. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From 1660a5e356d46bb4c04e1283f4ea91a4c84048aa Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 10:57:01 +0200 Subject: [PATCH 07/54] investigate timeout in IntegrationSpec --- .../eclair/integration/IntegrationSpec.scala | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index 008e494e10..d238938e89 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -54,6 +54,7 @@ import scala.collection.JavaConversions._ import scala.concurrent.Await import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ +import scala.util.Try /** * Created by PM on 15/03/2017. @@ -794,7 +795,27 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService forwardHandlerC.forward(buffer.ref) sigListener.expectMsgType[ChannelSignatureReceived] send(130000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) - forwardHandlerC.expectMsgType[UpdateAddHtlc] + Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { + case t => + println(s"try #1: $t") + Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { + case t => + println(s"try #2: $t") + Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { + case t => + println(s"try #3: $t") + Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { + case t => + println(s"try #4: $t") + Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { + case t => + println(s"try #5: $t") + } + } + } + } + } + println("success 'for forwardHandlerC.expectMsgType[UpdateAddHtlc]'") forwardHandlerC.forward(buffer.ref) val commitmentsF = sigListener.expectMsgType[ChannelSignatureReceived].commitments sigListener.expectNoMsg(1 second) From 5398387521ee9b5c9afa3a8d4f10d5f3161b266b Mon Sep 17 00:00:00 2001 From: Pierre-Marie Padiou Date: Fri, 6 Sep 2019 11:08:31 +0200 Subject: [PATCH 08/54] Update eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala Co-Authored-By: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> --- .../main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala index 4238ad10ec..f1b6acf1df 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentInitiator.scala @@ -37,7 +37,7 @@ class PaymentInitiator(nodeParams: NodeParams, router: ActorRef, register: Actor case p: PaymentInitiator.SendPaymentRequest => val paymentId = UUID.randomUUID() // We add one block in order to not have our htlc fail when a new block has just been found. - val finalExpiry = (p.finalExpiryDelta + 1).toCltvExpiry(nodeParams.currentBlockHeight) + val finalExpiry = p.finalExpiryDelta.toCltvExpiry(nodeParams.currentBlockHeight + 1) val payFsm = context.actorOf(PaymentLifecycle.props(nodeParams, paymentId, router, register)) // NB: we only generate legacy payment onions for now for maximum compatibility. p.predefinedRoute match { From 3208671381ef30d80164aa5d2af6414b0ac62499 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 11:27:20 +0200 Subject: [PATCH 09/54] address @t-bast comments --- .../scala/fr/acinq/eclair/channel/FuzzySpec.scala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala index a28b6c3b79..ffd87954c0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala @@ -143,7 +143,7 @@ class FuzzySpec extends TestkitBaseClass with StateTestsHelperMethods with Loggi import f._ val senders = 2 val totalMessages = 100 - val latch = new CountDownLatch(senders) + val latch = new CountDownLatch(2 * senders) for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch, totalMessages / senders))) for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch, totalMessages / senders))) awaitCond(latch.getCount == 0, max = 2 minutes) @@ -171,11 +171,10 @@ class FuzzySpec extends TestkitBaseClass with StateTestsHelperMethods with Loggi import f._ val senders = 2 val totalMessages = 100 - val latch1 = new CountDownLatch(senders) - for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch1, totalMessages / senders))) - val latch2 = new CountDownLatch(senders) - for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch2, totalMessages / senders))) - awaitCond(latch1.getCount == 0 && latch2.getCount == 0, max = 2 minutes) + val latch = new CountDownLatch(2 * senders) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(alice, paymentHandlerB, latch, totalMessages / senders))) + for (_ <- 0 until senders) system.actorOf(Props(new SenderActor(bob, paymentHandlerA, latch, totalMessages / senders))) + awaitCond(latch.getCount == 0, max = 2 minutes) val sender = TestProbe() awaitCond({ sender.send(alice, CMD_CLOSE(None)) From 483e2f68f1ec772534a5fc372b643ac48ba4b001 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 11:31:04 +0200 Subject: [PATCH 10/54] log ports used for bitcoind --- eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala index 862621b040..b2aa4ff742 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala @@ -33,7 +33,9 @@ object TestUtils { var serverSocket: ServerSocket = null try { serverSocket = new ServerSocket(0) - serverSocket.getLocalPort + val port = serverSocket.getLocalPort + println(s"attributing port=$port") + port } finally { if (serverSocket != null) { serverSocket.close() From bf39b84d399962b5ed24f6eb90efe34b03729d75 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 13:37:04 +0200 Subject: [PATCH 11/54] measure time in IntegrationSpec --- .../eclair/integration/IntegrationSpec.scala | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index d238938e89..c52b7b1321 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -51,6 +51,7 @@ import org.scalatest.{BeforeAndAfterAll, FunSuiteLike} import scodec.bits.ByteVector import scala.collection.JavaConversions._ +import scala.compat.Platform import scala.concurrent.Await import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ @@ -795,27 +796,10 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService forwardHandlerC.forward(buffer.ref) sigListener.expectMsgType[ChannelSignatureReceived] send(130000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) - Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { - case t => - println(s"try #1: $t") - Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { - case t => - println(s"try #2: $t") - Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { - case t => - println(s"try #3: $t") - Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { - case t => - println(s"try #4: $t") - Try(forwardHandlerC.expectMsgType[UpdateAddHtlc]).recover { - case t => - println(s"try #5: $t") - } - } - } - } - } - println("success 'for forwardHandlerC.expectMsgType[UpdateAddHtlc]'") + val t1 = Platform.currentTime.milliseconds + forwardHandlerC.expectMsgType[UpdateAddHtlc] + val t2 = Platform.currentTime.milliseconds + println(s"success 'for forwardHandlerC.expectMsgType[UpdateAddHtlc]' took ${t2 - t1}") forwardHandlerC.forward(buffer.ref) val commitmentsF = sigListener.expectMsgType[ChannelSignatureReceived].commitments sigListener.expectNoMsg(1 second) From 1e028f9869dfdadc6f8372c61985903e46c8919f Mon Sep 17 00:00:00 2001 From: Pierre-Marie Padiou Date: Fri, 6 Sep 2019 14:00:32 +0200 Subject: [PATCH 12/54] added ~infinite timeout on the problematic line --- .../scala/fr/acinq/eclair/integration/IntegrationSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index c52b7b1321..fb5f1c9a2d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -797,7 +797,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService sigListener.expectMsgType[ChannelSignatureReceived] send(130000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) val t1 = Platform.currentTime.milliseconds - forwardHandlerC.expectMsgType[UpdateAddHtlc] + forwardHandlerC.expectMsgType[UpdateAddHtlc](1 hour) val t2 = Platform.currentTime.milliseconds println(s"success 'for forwardHandlerC.expectMsgType[UpdateAddHtlc]' took ${t2 - t1}") forwardHandlerC.forward(buffer.ref) From c5c46f35fb1c563608f700dd643b133cbb5580b9 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 14:26:45 +0200 Subject: [PATCH 13/54] Revert "Revert "Revert "Revert "Revert "bump""""" This reverts commit d2678c29c860952212f85a5c33876829b4552fce. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From de4593af886bedffb4e71409282bd05ca84b3957 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 14:59:21 +0200 Subject: [PATCH 14/54] Revert "Revert "Revert "Revert "Revert "Revert "bump"""""" This reverts commit c5c46f35fb1c563608f700dd643b133cbb5580b9. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From da09b71eb0cfdf96534ea06c1024e90b54dcdb6d Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 15:41:27 +0200 Subject: [PATCH 15/54] more timers --- .../eclair/integration/IntegrationSpec.scala | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index fb5f1c9a2d..4a58f6876c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -782,6 +782,16 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService sender.expectMsgType[UUID] } + def time[T](name: String)(f: => T) = { + val t1 = Platform.currentTime.milliseconds + try { + f + } finally { + val t2 = Platform.currentTime.milliseconds + println(s"$name took ${t2 - t1}") + } + } + val buffer = TestProbe() send(100000000 msat, paymentHandlerF, nodes("C").paymentInitiator) // will be left pending forwardHandlerF.expectMsgType[UpdateAddHtlc] @@ -796,10 +806,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService forwardHandlerC.forward(buffer.ref) sigListener.expectMsgType[ChannelSignatureReceived] send(130000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) - val t1 = Platform.currentTime.milliseconds - forwardHandlerC.expectMsgType[UpdateAddHtlc](1 hour) - val t2 = Platform.currentTime.milliseconds - println(s"success 'for forwardHandlerC.expectMsgType[UpdateAddHtlc]' took ${t2 - t1}") + time("a")(forwardHandlerC.expectMsgType[UpdateAddHtlc](1 hour)) forwardHandlerC.forward(buffer.ref) val commitmentsF = sigListener.expectMsgType[ChannelSignatureReceived].commitments sigListener.expectNoMsg(1 second) @@ -811,22 +818,22 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(htlcTimeoutTxs.size === 2) assert(htlcSuccessTxs.size === 2) // we fulfill htlcs to get the preimagse - buffer.expectMsgType[UpdateAddHtlc] + time("b")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) buffer.forward(paymentHandlerF) - sigListener.expectMsgType[ChannelSignatureReceived] - val preimage1 = sender.expectMsgType[PaymentSucceeded].paymentPreimage - buffer.expectMsgType[UpdateAddHtlc] + time("c")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) + val preimage1 = time("d")(sender.expectMsgType[PaymentSucceeded].paymentPreimage) + time("e")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) buffer.forward(paymentHandlerF) - sigListener.expectMsgType[ChannelSignatureReceived] - sender.expectMsgType[PaymentSucceeded].paymentPreimage - buffer.expectMsgType[UpdateAddHtlc] + time("f")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) + time("g")(sender.expectMsgType[PaymentSucceeded](1 hour).paymentPreimage) + time("h")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) buffer.forward(paymentHandlerC) - sigListener.expectMsgType[ChannelSignatureReceived] - sender.expectMsgType[PaymentSucceeded].paymentPreimage - buffer.expectMsgType[UpdateAddHtlc] + time("i")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) + time("j")(sender.expectMsgType[PaymentSucceeded](1 hour).paymentPreimage) + time("k")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) buffer.forward(paymentHandlerC) - sigListener.expectMsgType[ChannelSignatureReceived] - sender.expectMsgType[PaymentSucceeded].paymentPreimage + time("l")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) + time("m")(sender.expectMsgType[PaymentSucceeded](1 hour).paymentPreimage) // this also allows us to get the channel id val channelId = commitmentsF.channelId // we also retrieve C's default final address From e8ca8d495b266f56da1a226277a4d17d2d42bf9c Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 16:17:24 +0200 Subject: [PATCH 16/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""" This reverts commit de4593af886bedffb4e71409282bd05ca84b3957. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From c7bff5cceeffecacb0ff1fd1db893818b3b85441 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 16:48:44 +0200 Subject: [PATCH 17/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""" This reverts commit e8ca8d495b266f56da1a226277a4d17d2d42bf9c. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From 12236ff4f1ebeca59490429d2179b549f35d7aa2 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 17:23:43 +0200 Subject: [PATCH 18/54] even more timers --- .../acinq/eclair/integration/IntegrationSpec.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index 4a58f6876c..80c37148ce 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -794,17 +794,17 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val buffer = TestProbe() send(100000000 msat, paymentHandlerF, nodes("C").paymentInitiator) // will be left pending - forwardHandlerF.expectMsgType[UpdateAddHtlc] + time("0")(forwardHandlerF.expectMsgType[UpdateAddHtlc](1 hour)) forwardHandlerF.forward(buffer.ref) - sigListener.expectMsgType[ChannelSignatureReceived] + time("1")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) send(110000000 msat, paymentHandlerF, nodes("C").paymentInitiator) // will be left pending - forwardHandlerF.expectMsgType[UpdateAddHtlc] + time("2")(forwardHandlerF.expectMsgType[UpdateAddHtlc](1 hour)) forwardHandlerF.forward(buffer.ref) - sigListener.expectMsgType[ChannelSignatureReceived] + time("3")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) send(120000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) - forwardHandlerC.expectMsgType[UpdateAddHtlc] + time("4")(forwardHandlerC.expectMsgType[UpdateAddHtlc](1 hour)) forwardHandlerC.forward(buffer.ref) - sigListener.expectMsgType[ChannelSignatureReceived] + time("5")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) send(130000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) time("a")(forwardHandlerC.expectMsgType[UpdateAddHtlc](1 hour)) forwardHandlerC.forward(buffer.ref) From 803b04c594d9ef6b071f7dca7df6ae9bd1935a6c Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 17:46:03 +0200 Subject: [PATCH 19/54] fixed last merge --- .../fr/acinq/eclair/channel/states/e/NormalStateSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index 7e1f1c9077..10182a87db 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -163,7 +163,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] - val add = CMD_ADD_HTLC(initialState.commitments.availableBalanceForSend + 1.msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(initialState.commitments.availableBalanceForSend + 1.msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(bob, add) val error = InsufficientFunds(channelId(alice), amount = add.amount, missing = 0 sat, reserve = 10000 sat, fees = 0 sat) From 24e0a57f5c12b857e6adb929022dc07d28926412 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 18:54:55 +0200 Subject: [PATCH 20/54] monitor zmq disconnections --- .../fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala index 59aa04b46a..271de79200 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala @@ -80,10 +80,12 @@ class ZMQActor(address: String, connected: Option[Promise[Done]] = None) extends case event: Event => event.getEvent match { case ZMQ.EVENT_CONNECTED => log.info(s"connected to ${event.getAddress}") + println(s"connected to ${event.getAddress}") Try(connected.map(_.success(Done))) context.system.eventStream.publish(ZMQConnected) case ZMQ.EVENT_DISCONNECTED => log.warning(s"disconnected from ${event.getAddress}") + println(s"disconnected from ${event.getAddress}") context.system.eventStream.publish(ZMQDisconnected) case x => log.error(s"unexpected event $x") } From 72ab343314e5174b135d8542c0b1f097427ae21d Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 19:30:05 +0200 Subject: [PATCH 21/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""" This reverts commit c7bff5cceeffecacb0ff1fd1db893818b3b85441. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 7dfbfd4e44702d8528caf616441b681aeaf55e7e Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 21:04:37 +0200 Subject: [PATCH 22/54] make bitcoind log to stdout --- eclair-core/src/test/resources/integration/bitcoin.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/test/resources/integration/bitcoin.conf b/eclair-core/src/test/resources/integration/bitcoin.conf index 8676e0b42e..0571b89b4f 100644 --- a/eclair-core/src/test/resources/integration/bitcoin.conf +++ b/eclair-core/src/test/resources/integration/bitcoin.conf @@ -1,5 +1,5 @@ regtest=1 -noprinttoconsole=1 +noprinttoconsole=0 server=1 rpcuser=foo rpcpassword=bar From f4d5139093252d5587d277bd544ee9b4d1d832d9 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 22:11:38 +0200 Subject: [PATCH 23/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""" This reverts commit 72ab343314e5174b135d8542c0b1f097427ae21d. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From 20ffd383dcfb5d6ea67b45e2c83ff453bd78260e Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 22:53:36 +0200 Subject: [PATCH 24/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""" This reverts commit f4d5139093252d5587d277bd544ee9b4d1d832d9. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From fd20150e82f7927abd6644545438fe2d865c6307 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Sep 2019 23:36:32 +0200 Subject: [PATCH 25/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""" This reverts commit 20ffd383dcfb5d6ea67b45e2c83ff453bd78260e. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From c6390c2edb8cb5956d1d62c01e006db45dffb120 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 11:54:33 +0200 Subject: [PATCH 26/54] replaced AtomicLong by Array[Long] --- .../src/main/scala/fr/acinq/eclair/NodeParams.scala | 6 +++--- eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala | 2 +- .../acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala | 10 +++++----- .../blockchain/electrum/ElectrumClientPool.scala | 6 +++--- .../eclair/blockchain/electrum/ElectrumWatcher.scala | 8 +++----- .../src/test/scala/fr/acinq/eclair/StartupSpec.scala | 2 +- .../src/test/scala/fr/acinq/eclair/TestConstants.scala | 4 ++-- .../blockchain/electrum/ElectrumClientPoolSpec.scala | 2 +- .../blockchain/electrum/ElectrumWalletSpec.scala | 2 +- .../blockchain/electrum/ElectrumWatcherSpec.scala | 6 +++--- .../scala/fr/acinq/eclair/channel/ThroughputSpec.scala | 4 ++-- .../eclair/interop/rustytests/RustyTestsSpec.scala | 2 +- 12 files changed, 26 insertions(+), 28 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index 6db6b030bb..d91ec378c6 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -42,7 +42,7 @@ import scala.concurrent.duration.FiniteDuration * Created by PM on 26/02/2017. */ case class NodeParams(keyManager: KeyManager, - private val blockCount: AtomicLong, + private val blockCount: Array[Long], alias: String, color: Color, publicAddresses: List[NodeAddress], @@ -82,7 +82,7 @@ case class NodeParams(keyManager: KeyManager, maxPaymentAttempts: Int) { val privateKey = keyManager.nodeKey.privateKey val nodeId = keyManager.nodeId - def currentBlockHeight: Long = blockCount.get + def currentBlockHeight: Long = blockCount(0) } object NodeParams { @@ -127,7 +127,7 @@ object NodeParams { } } - def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases, blockCount: AtomicLong, feeEstimator: FeeEstimator): NodeParams = { + def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases, blockCount: Array[Long], feeEstimator: FeeEstimator): NodeParams = { val chain = config.getString("chain") val chainHash = makeChainHash(chain) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala index 5d4f0a1861..ca64809272 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -99,7 +99,7 @@ class Setup(datadir: File, * It is mainly used to calculate htlc expiries. * The value is read by all actors, hence it needs to be thread-safe. */ - val blockCount = new AtomicLong(0) + val blockCount: Array[Long] = Array(0L) /** * This holds the current feerates, in satoshi-per-kilobytes. diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala index 73511db293..87589b4bbc 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala @@ -39,7 +39,7 @@ import scala.util.Try * - also uses bitcoin-core rpc api, most notably for tx confirmation count and blockcount (because reorgs) * Created by PM on 21/02/2016. */ -class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) extends Actor with ActorLogging { +class ZmqWatcher(blockCount: Array[Long], client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) extends Actor with ActorLogging { import ZmqWatcher._ @@ -80,7 +80,7 @@ class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit client.getBlockCount.map { case count => log.debug(s"setting blockCount=$count") - blockCount.set(count) + blockCount(0) = count context.system.eventStream.publish(CurrentBlockCount(count)) } // TODO: beware of the herd effect @@ -151,7 +151,7 @@ class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit context become watching(watches + w, addWatchedUtxos(watchedUtxos, w), block2tx, nextTick) case PublishAsap(tx) => - val blockCount = this.blockCount.get() + val blockCount = this.blockCount(0) val cltvTimeout = Scripts.cltvTimeout(tx) val csvTimeout = Scripts.csvTimeout(tx) if (csvTimeout > 0) { @@ -168,7 +168,7 @@ class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit case WatchEventConfirmed(BITCOIN_PARENT_TX_CONFIRMED(tx), blockHeight, _, _) => log.info(s"parent tx of txid=${tx.txid} has been confirmed") - val blockCount = this.blockCount.get() + val blockCount = this.blockCount(0) val csvTimeout = Scripts.csvTimeout(tx) val absTimeout = blockHeight + csvTimeout if (absTimeout > blockCount) { @@ -226,7 +226,7 @@ class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit object ZmqWatcher { - def props(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) = Props(new ZmqWatcher(blockCount, client)(ec)) + def props(blockCount: Array[Long], client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) = Props(new ZmqWatcher(blockCount, client)(ec)) case object TickNewBlock diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala index 117b204bf1..563d7293a2 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala @@ -32,7 +32,7 @@ import scala.concurrent.ExecutionContext import scala.concurrent.duration._ import scala.util.Random -class ElectrumClientPool(blockCount: AtomicLong, serverAddresses: Set[ElectrumServerAddress])(implicit val ec: ExecutionContext) extends Actor with FSM[ElectrumClientPool.State, ElectrumClientPool.Data] { +class ElectrumClientPool(blockCount: Array[Long], serverAddresses: Set[ElectrumServerAddress])(implicit val ec: ExecutionContext) extends Actor with FSM[ElectrumClientPool.State, ElectrumClientPool.Data] { import ElectrumClientPool._ val statusListeners = collection.mutable.HashSet.empty[ActorRef] @@ -166,10 +166,10 @@ class ElectrumClientPool(blockCount: AtomicLong, serverAddresses: Set[ElectrumSe private def updateBlockCount(blockCount: Long): Unit = { // when synchronizing we don't want to advertise previous blocks - if (this.blockCount.get() < blockCount) { + if (this.blockCount(0) < blockCount) { log.debug("current blockchain height={}", blockCount) context.system.eventStream.publish(CurrentBlockCount(blockCount)) - this.blockCount.set(blockCount) + this.blockCount(0) = blockCount } } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala index 48aab4bbe3..ef41558623 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala @@ -16,8 +16,6 @@ package fr.acinq.eclair.blockchain.electrum -import java.util.concurrent.atomic.AtomicLong - import akka.actor.{Actor, ActorLogging, ActorRef, Stash, Terminated} import fr.acinq.bitcoin.{BlockHeader, ByteVector32, Script, Transaction, TxIn, TxOut} import fr.acinq.eclair.blockchain._ @@ -30,7 +28,7 @@ import scala.collection.SortedMap import scala.collection.immutable.Queue -class ElectrumWatcher(blockCount: AtomicLong, client: ActorRef) extends Actor with Stash with ActorLogging { +class ElectrumWatcher(blockCount: Array[Long], client: ActorRef) extends Actor with Stash with ActorLogging { client ! ElectrumClient.AddStatusListener(self) @@ -163,7 +161,7 @@ class ElectrumWatcher(blockCount: AtomicLong, client: ActorRef) extends Actor wi case ElectrumClient.ServerError(ElectrumClient.GetTransaction(txid, Some(origin: ActorRef)), _) => origin ! GetTxWithMetaResponse(txid, None, tip.time) case PublishAsap(tx) => - val blockCount = this.blockCount.get() + val blockCount = this.blockCount(0) val cltvTimeout = Scripts.cltvTimeout(tx) val csvTimeout = Scripts.csvTimeout(tx) if (csvTimeout > 0) { @@ -184,7 +182,7 @@ class ElectrumWatcher(blockCount: AtomicLong, client: ActorRef) extends Actor wi case WatchEventConfirmed(BITCOIN_PARENT_TX_CONFIRMED(tx), blockHeight, _, _) => log.info(s"parent tx of txid=${tx.txid} has been confirmed") - val blockCount = this.blockCount.get() + val blockCount = this.blockCount(0) val csvTimeout = Scripts.csvTimeout(tx) val absTimeout = blockHeight + csvTimeout if (absTimeout > blockCount) { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala index e0931dba52..31bd16ff49 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala @@ -45,7 +45,7 @@ class StartupSpec extends FunSuite { val conf = illegalAliasConf.withFallback(ConfigFactory.parseResources("reference.conf").getConfig("eclair")) val keyManager = new LocalKeyManager(seed = randomBytes32, chainHash = Block.TestnetGenesisBlock.hash) - val blockCount = new AtomicLong(0) + val blockCount = Array(0L) // try to create a NodeParams instance with a conf that contains an illegal alias val nodeParamsAttempt = Try(NodeParams.makeNodeParams(conf, keyManager, None, TestConstants.inMemoryDb(), blockCount, new TestConstants.TestFeeEstimator)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index c0b57b4956..efb9dca1e9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -66,7 +66,7 @@ object TestConstants { // This is a function, and not a val! When called will return a new NodeParams def nodeParams = NodeParams( keyManager = keyManager, - blockCount = new AtomicLong(400000), + blockCount = Array(400000L), alias = "alice", color = Color(1, 2, 3), publicAddresses = NodeAddress.fromParts("localhost", 9731).get :: Nil, @@ -143,7 +143,7 @@ object TestConstants { def nodeParams = NodeParams( keyManager = keyManager, - blockCount = new AtomicLong(400000), + blockCount = Array(400000L), alias = "bob", color = Color(4, 5, 6), publicAddresses = NodeAddress.fromParts("localhost", 9732).get :: Nil, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala index 0aca5ca3ee..06bfc0c217 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala @@ -67,7 +67,7 @@ class ElectrumClientPoolSpec extends TestKit(ActorSystem("test")) with FunSuiteL val addresses = random.shuffle(serverAddresses.toSeq).take(2).toSet + ElectrumClientPool.ElectrumServerAddress(new InetSocketAddress("electrum.acinq.co", 50002), SSL.STRICT) stream.close() assert(addresses.nonEmpty) - pool = system.actorOf(Props(new ElectrumClientPool(new AtomicLong(), addresses)), "electrum-client") + pool = system.actorOf(Props(new ElectrumClientPool(Array(0L), addresses)), "electrum-client") } test("connect to an electrumx mainnet server") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala index ee18f3e7ce..0302829bb7 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala @@ -88,7 +88,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike } test("wait until wallet is ready") { - electrumClient = system.actorOf(Props(new ElectrumClientPool(new AtomicLong(), Set(ElectrumServerAddress(new InetSocketAddress("localhost", electrumPort), SSL.OFF))))) + electrumClient = system.actorOf(Props(new ElectrumClientPool(Array(0L), Set(ElectrumServerAddress(new InetSocketAddress("localhost", electrumPort), SSL.OFF))))) wallet = system.actorOf(Props(new ElectrumWallet(seed, electrumClient, WalletParameters(Block.RegtestGenesisBlock.hash, new SqliteWalletDb(DriverManager.getConnection("jdbc:sqlite::memory:")), minimumFee = 5000 sat))), "wallet") val probe = TestProbe() awaitCond({ diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala index 38d0f92476..377c952959 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala @@ -56,7 +56,7 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("watch for confirmed transactions") { val probe = TestProbe() - val blockCount = new AtomicLong() + val blockCount = Array(0L) val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(electrumAddress)))) val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) @@ -82,7 +82,7 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("watch for spent transactions") { val probe = TestProbe() - val blockCount = new AtomicLong() + val blockCount = Array(0L) val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(electrumAddress)))) val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) @@ -127,7 +127,7 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike } test("get transaction") { - val blockCount = new AtomicLong() + val blockCount = Array(0L) val mainnetAddress = ElectrumServerAddress(new InetSocketAddress("electrum.acinq.co", 50002), SSL.STRICT) val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(mainnetAddress)))) val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala index 04b380baeb..5008fb9efd 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala @@ -39,7 +39,7 @@ class ThroughputSpec extends FunSuite { ignore("throughput") { implicit val system = ActorSystem() val pipe = system.actorOf(Props[Pipe], "pipe") - val blockCount = new AtomicLong() + val blockCount = Array(0L) val blockchain = system.actorOf(ZmqWatcher.props(blockCount, new TestBitcoinClient()), "blockchain") val paymentHandler = system.actorOf(Props(new Actor() { val random = new Random() @@ -86,7 +86,7 @@ class ThroughputSpec extends FunSuite { pipe ! (alice, bob) latch.await() - var i = new AtomicLong(0) + var i = Array(0L) val random = new Random() def msg = random.nextInt(100) % 5 match { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala index 6b3468d35b..e13b984b1d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala @@ -44,7 +44,7 @@ class RustyTestsSpec extends TestKit(ActorSystem("test")) with Matchers with fix case class FixtureParam(ref: List[String], res: List[String]) override def withFixture(test: OneArgTest): Outcome = { - val blockCount = new AtomicLong(0) + val blockCount = Array(0L) val latch = new CountDownLatch(1) val pipe: ActorRef = system.actorOf(Props(new SynchronizationPipe(latch))) val alice2blockchain = TestProbe() From c312046ebb0b9d8693fc57e7478c712125b908db Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 13:27:09 +0200 Subject: [PATCH 27/54] Revert "make bitcoind log to stdout" This reverts commit 7dfbfd4e44702d8528caf616441b681aeaf55e7e. --- eclair-core/src/test/resources/integration/bitcoin.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/test/resources/integration/bitcoin.conf b/eclair-core/src/test/resources/integration/bitcoin.conf index 0571b89b4f..8676e0b42e 100644 --- a/eclair-core/src/test/resources/integration/bitcoin.conf +++ b/eclair-core/src/test/resources/integration/bitcoin.conf @@ -1,5 +1,5 @@ regtest=1 -noprinttoconsole=0 +noprinttoconsole=1 server=1 rpcuser=foo rpcpassword=bar From ba37284efbdda5af4b692a7a030b080b9ad364f6 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 13:36:04 +0200 Subject: [PATCH 28/54] use bitcoin-cli to get block height --- .../eclair/integration/IntegrationSpec.scala | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index 80c37148ce..3477e8a566 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -460,8 +460,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val stateListener = TestProbe() nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height - sender.send(bitcoincli, BitcoinReq("getblockcount")) - val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] + val currentBlockCount = getBlockCount awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() @@ -534,14 +533,19 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService awaitAnnouncements(nodes.filterKeys(_ == "A"), 9, 11, 24) } + def getBlockCount: Long = { + val sender = TestProbe() + sender.send(bitcoincli, BitcoinReq("getblockcount")) + sender.expectMsgType[JValue](10 seconds).extract[Long] + } + test("propagate a fulfill upstream when a downstream htlc is redeemed on-chain (remote commit)") { val sender = TestProbe() // we subscribe to C's channel state transitions val stateListener = TestProbe() nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height - sender.send(bitcoincli, BitcoinReq("getblockcount")) - val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] + val currentBlockCount = getBlockCount awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() @@ -617,8 +621,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val stateListener = TestProbe() nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height - sender.send(bitcoincli, BitcoinReq("getblockcount")) - val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] + val currentBlockCount = getBlockCount awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() @@ -679,8 +682,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val stateListener = TestProbe() nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height - sender.send(bitcoincli, BitcoinReq("getblockcount")) - val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] + val currentBlockCount = getBlockCount awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() @@ -756,8 +758,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val paymentHandlerC = nodes("C").system.actorOf(LocalPaymentHandler.props(nodes("C").nodeParams)) val paymentHandlerF = nodes("F5").system.actorOf(LocalPaymentHandler.props(nodes("F5").nodeParams)) // first we make sure we are in sync with current blockchain height - sender.send(bitcoincli, BitcoinReq("getblockcount")) - val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] + val currentBlockCount = getBlockCount awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) // first we send 3 mBTC to F so that it has a balance val amountMsat = 300000000.msat From 84583f4339fa2a019689f998e68eb01bfa5da461 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 14:26:12 +0200 Subject: [PATCH 29/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""" This reverts commit fd20150e82f7927abd6644545438fe2d865c6307. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 99a96770649871cc565a9da4911ae7ccf9dee6fa Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 14:56:28 +0200 Subject: [PATCH 30/54] reduce parallelism level in tests --- eclair-core/src/test/resources/application.conf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/eclair-core/src/test/resources/application.conf b/eclair-core/src/test/resources/application.conf index 393fa212cb..10b36d83bb 100644 --- a/eclair-core/src/test/resources/application.conf +++ b/eclair-core/src/test/resources/application.conf @@ -7,6 +7,14 @@ akka { # enable DEBUG logging of all LoggingFSMs for events, transitions and timers fsm = on } + default-dispatcher { + fork-join-executor { + parallelism-max = 1 + } + thead-pool-executor { + parallelism-max = 1 + } + } } test { From d75e8ad3fbdc4b5cf49504c693a70a8d012e0f12 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 15:20:51 +0200 Subject: [PATCH 31/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""""" This reverts commit 84583f4339fa2a019689f998e68eb01bfa5da461. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From fa80d134b3260417b909b4cb497f1eb4549a2825 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 15:25:17 +0200 Subject: [PATCH 32/54] more memory --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 10c833307c..0c2bb222a7 100644 --- a/pom.xml +++ b/pom.xml @@ -222,7 +222,7 @@ ${project.build.directory} - -Xmx1024m -Dfile.encoding=UTF-8 + -Xmx1500m -Dfile.encoding=UTF-8 From 5560aaed5e81228d78e81b91d20cffcb93611f47 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 15:50:54 +0200 Subject: [PATCH 33/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""""" This reverts commit d75e8ad3fbdc4b5cf49504c693a70a8d012e0f12. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 629cd3954c437e84b4990a69b9800cfc84051fb9 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 16:15:01 +0200 Subject: [PATCH 34/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""""""" This reverts commit 5560aaed5e81228d78e81b91d20cffcb93611f47. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From d81369ed5de2b9cac9796a5881db895849f1cf7f Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 15:48:54 +0200 Subject: [PATCH 35/54] removed synchronized function to get available ports --- .../src/test/scala/fr/acinq/eclair/TestUtils.scala | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala index b2aa4ff742..0dc7084d55 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala @@ -18,6 +18,9 @@ package fr.acinq.eclair import java.io.File import java.net.ServerSocket +import java.util.concurrent.atomic.AtomicInteger + +import scala.util.Random object TestUtils { @@ -29,7 +32,8 @@ object TestUtils { .get("buildDirectory") // this is defined if we run from maven .getOrElse(new File(sys.props("user.dir"), "target").getAbsolutePath) // otherwise we probably are in intellij, so we build it manually assuming that user.dir == path to the module - def availablePort: Int = synchronized { + + /*def availablePort: Int = synchronized { var serverSocket: ServerSocket = null try { serverSocket = new ServerSocket(0) @@ -41,5 +45,10 @@ object TestUtils { serverSocket.close() } } - } + }*/ + + private val ports = new AtomicInteger(35000) + + def availablePort = ports.incrementAndGet() + } From 00181d6be36fb7f017eb5a21f9c29bed20f4715a Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 19:45:12 +0200 Subject: [PATCH 36/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""""""" This reverts commit 629cd3954c437e84b4990a69b9800cfc84051fb9. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 34db44eeeaaf751e01655c74fa52ea2d1cd5f7a3 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 20:39:15 +0200 Subject: [PATCH 37/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""""""""" This reverts commit 00181d6be36fb7f017eb5a21f9c29bed20f4715a. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From e43afac8a65edd47bb68b9e0a7ef2dad4cb5b843 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 21:09:09 +0200 Subject: [PATCH 38/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""""""""" This reverts commit 34db44eeeaaf751e01655c74fa52ea2d1cd5f7a3. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 646aee8352f8477789d9abee8f614e4db4286855 Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 9 Sep 2019 23:00:36 +0200 Subject: [PATCH 39/54] trying diff port range --- eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala index 0dc7084d55..ac2d00f40d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala @@ -47,7 +47,7 @@ object TestUtils { } }*/ - private val ports = new AtomicInteger(35000) + private val ports = new AtomicInteger(65000) def availablePort = ports.incrementAndGet() From 001b4dc274241a2023f5ac8ff56d7b3c5d3d7547 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 11:37:33 +0200 Subject: [PATCH 40/54] reduced change subset --- .../blockchain/bitcoind/zmq/ZMQActor.scala | 2 - .../src/test/resources/application.conf | 8 --- .../scala/fr/acinq/eclair/TestUtils.scala | 24 ------- .../bitcoind/BitcoinCoreWalletSpec.scala | 4 +- .../blockchain/bitcoind/BitcoindService.scala | 39 ++-------- .../bitcoind/ExtendedBitcoinClientSpec.scala | 4 +- .../electrum/ElectrumxService.scala | 10 ++- .../fee/BitcoinCoreFeeProviderSpec.scala | 4 +- .../eclair/integration/IntegrationSpec.scala | 72 ++++++++----------- 9 files changed, 47 insertions(+), 120 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala index 271de79200..59aa04b46a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/zmq/ZMQActor.scala @@ -80,12 +80,10 @@ class ZMQActor(address: String, connected: Option[Promise[Done]] = None) extends case event: Event => event.getEvent match { case ZMQ.EVENT_CONNECTED => log.info(s"connected to ${event.getAddress}") - println(s"connected to ${event.getAddress}") Try(connected.map(_.success(Done))) context.system.eventStream.publish(ZMQConnected) case ZMQ.EVENT_DISCONNECTED => log.warning(s"disconnected from ${event.getAddress}") - println(s"disconnected from ${event.getAddress}") context.system.eventStream.publish(ZMQDisconnected) case x => log.error(s"unexpected event $x") } diff --git a/eclair-core/src/test/resources/application.conf b/eclair-core/src/test/resources/application.conf index 10b36d83bb..393fa212cb 100644 --- a/eclair-core/src/test/resources/application.conf +++ b/eclair-core/src/test/resources/application.conf @@ -7,14 +7,6 @@ akka { # enable DEBUG logging of all LoggingFSMs for events, transitions and timers fsm = on } - default-dispatcher { - fork-join-executor { - parallelism-max = 1 - } - thead-pool-executor { - parallelism-max = 1 - } - } } test { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala index ac2d00f40d..4f5ecdcb6f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala @@ -17,10 +17,6 @@ package fr.acinq.eclair import java.io.File -import java.net.ServerSocket -import java.util.concurrent.atomic.AtomicInteger - -import scala.util.Random object TestUtils { @@ -31,24 +27,4 @@ object TestUtils { .props .get("buildDirectory") // this is defined if we run from maven .getOrElse(new File(sys.props("user.dir"), "target").getAbsolutePath) // otherwise we probably are in intellij, so we build it manually assuming that user.dir == path to the module - - - /*def availablePort: Int = synchronized { - var serverSocket: ServerSocket = null - try { - serverSocket = new ServerSocket(0) - val port = serverSocket.getLocalPort - println(s"attributing port=$port") - port - } finally { - if (serverSocket != null) { - serverSocket.close() - } - } - }*/ - - private val ports = new AtomicInteger(65000) - - def availablePort = ports.incrementAndGet() - } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala index 136e09822e..c16c1d6e7d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala @@ -45,8 +45,8 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> bitcoindPort, - "eclair.bitcoind.rpcport" -> bitcoindRpcPort, + "eclair.bitcoind.port" -> 28333, + "eclair.bitcoind.rpcport" -> 28332, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala index 359d6f88e0..518e6ed1a7 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala @@ -28,11 +28,10 @@ import fr.acinq.eclair.TestUtils import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, BitcoinJsonRPCClient} import fr.acinq.eclair.integration.IntegrationSpec import grizzled.slf4j.Logging -import org.json4s.JsonAST.{JArray, JDecimal, JInt, JString, JValue} +import org.json4s.JsonAST.JValue import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ -import scala.io.Source trait BitcoindService extends Logging { self: TestKitBase => @@ -40,14 +39,6 @@ trait BitcoindService extends Logging { implicit val system: ActorSystem implicit val sttpBackend = OkHttpFutureBackend() - val bitcoindPort: Int = TestUtils.availablePort - - val bitcoindRpcPort: Int = TestUtils.availablePort - - val bitcoindZmqBlockPort: Int = TestUtils.availablePort - - val bitcoindZmqTxPort: Int = TestUtils.availablePort - import scala.sys.process._ val INTEGRATION_TMP_DIR = new File(TestUtils.BUILD_DIRECTORY, s"integration-${UUID.randomUUID()}") @@ -65,17 +56,11 @@ trait BitcoindService extends Logging { def startBitcoind(): Unit = { Files.createDirectories(PATH_BITCOIND_DATADIR.toPath) if (!Files.exists(new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath)) { - val is = classOf[IntegrationSpec].getResourceAsStream("/integration/bitcoin.conf") - val conf = Source.fromInputStream(is).mkString - .replace("28333", bitcoindPort.toString) - .replace("28332", bitcoindRpcPort.toString) - .replace("28334", bitcoindZmqBlockPort.toString) - .replace("28335", bitcoindZmqTxPort.toString) - Files.writeString(new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath, conf) + Files.copy(classOf[IntegrationSpec].getResourceAsStream("/integration/bitcoin.conf"), new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath, StandardCopyOption.REPLACE_EXISTING) } bitcoind = s"$PATH_BITCOIND -datadir=$PATH_BITCOIND_DATADIR".run() - bitcoinrpcclient = new BasicBitcoinJsonRPCClient(user = "foo", password = "bar", host = "localhost", port = bitcoindRpcPort) + bitcoinrpcclient = new BasicBitcoinJsonRPCClient(user = "foo", password = "bar", host = "localhost", port = 28332) bitcoincli = system.actorOf(Props(new Actor { override def receive: Receive = { case BitcoinReq(method) => bitcoinrpcclient.invoke(method) pipeTo sender @@ -98,23 +83,11 @@ trait BitcoindService extends Logging { logger.info(s"waiting for bitcoind to initialize...") awaitCond({ sender.send(bitcoincli, BitcoinReq("getnetworkinfo")) - sender.expectMsgType[Any](5 second) match { - case j: JValue => j \ "version" match { - case JInt(_) => true - case _ => false - } - case _ => false - } - }, max = 3 minutes, interval = 2 seconds) + sender.receiveOne(5 second).isInstanceOf[JValue] + }, max = 30 seconds, interval = 500 millis) logger.info(s"generating initial blocks...") sender.send(bitcoincli, BitcoinReq("generate", 150)) - val JArray(res) = sender.expectMsgType[JValue](3 minutes) - assert(res.size == 150) - awaitCond({ - sender.send(bitcoincli, BitcoinReq("getbalance")) - val JDecimal(balance) = sender.expectMsgType[JDecimal](30 seconds) - balance > 100 - }, max = 3 minutes, interval = 2 second) + sender.expectMsgType[JValue](30 seconds) } } \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala index 86e139e54c..945c6db054 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala @@ -38,8 +38,8 @@ class ExtendedBitcoinClientSpec extends TestKit(ActorSystem("test")) with Bitcoi "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> bitcoindPort, - "eclair.bitcoind.rpcport" -> bitcoindRpcPort, + "eclair.bitcoind.port" -> 28333, + "eclair.bitcoind.rpcport" -> 28332, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala index 71b487f3e8..ba1266f04a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala @@ -20,28 +20,26 @@ import com.spotify.docker.client.{DefaultDockerClient, DockerClient} import com.whisk.docker.impl.spotify.SpotifyDockerFactory import com.whisk.docker.scalatest.DockerTestKit import com.whisk.docker.{DockerContainer, DockerFactory} -import fr.acinq.eclair.TestUtils -import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import org.scalatest.Suite trait ElectrumxService extends DockerTestKit { - self: Suite with BitcoindService => + self: Suite => - val electrumPort = TestUtils.availablePort + val electrumPort = 47000 val electrumxContainer = if (System.getProperty("os.name").startsWith("Linux")) { // "host" mode will let the container access the host network on linux // we use our own docker image because other images on Docker lag behind and don't yet support 1.4 DockerContainer("acinq/electrumx") .withNetworkMode("host") - .withEnv(s"DAEMON_URL=http://foo:bar@localhost:$bitcoindRpcPort", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") + .withEnv("DAEMON_URL=http://foo:bar@localhost:28332", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") //.withLogLineReceiver(LogLineReceiver(true, println)) } else { // on windows or oxs, host mode is not available, but from docker 18.03 on host.docker.internal can be used instead // host.docker.internal is not (yet ?) available on linux though DockerContainer("acinq/electrumx") .withPorts(electrumPort -> Some(electrumPort)) - .withEnv(s"DAEMON_URL=http://foo:bar@host.docker.internal:$bitcoindRpcPort", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") + .withEnv("DAEMON_URL=http://foo:bar@host.docker.internal:28332", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") //.withLogLineReceiver(LogLineReceiver(true, println)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala index 1ad9f555ff..126218bab9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala @@ -42,8 +42,8 @@ class BitcoinCoreFeeProviderSpec extends TestKit(ActorSystem("test")) with Bitco "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> bitcoindPort, - "eclair.bitcoind.rpcport" -> bitcoindRpcPort, + "eclair.bitcoind.port" -> 28333, + "eclair.bitcoind.rpcport" -> 28332, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index 3477e8a566..2bdd3b6d48 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -82,10 +82,10 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val commonConfig = ConfigFactory.parseMap(Map( "eclair.chain" -> "regtest", "eclair.server.public-ips.1" -> "127.0.0.1", - "eclair.bitcoind.port" -> bitcoindPort, - "eclair.bitcoind.rpcport" -> bitcoindRpcPort, - "eclair.bitcoind.zmqblock" -> s"tcp://127.0.0.1:$bitcoindZmqBlockPort", - "eclair.bitcoind.zmqtx" -> s"tcp://127.0.0.1:$bitcoindZmqTxPort", + "eclair.bitcoind.port" -> 28333, + "eclair.bitcoind.rpcport" -> 28332, + "eclair.bitcoind.zmqblock" -> "tcp://127.0.0.1:28334", + "eclair.bitcoind.zmqtx" -> "tcp://127.0.0.1:28335", "eclair.mindepth-blocks" -> 2, "eclair.max-htlc-value-in-flight-msat" -> 100000000000L, "eclair.router.broadcast-interval" -> "2 second", @@ -347,7 +347,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(failed.id == paymentId) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, nodes("A").nodeParams.currentBlockHeight))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, getBlockCount))) } test("send an HTLC A->D with a lower amount than requested") { @@ -367,7 +367,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(failed.id == paymentId) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, nodes("A").nodeParams.currentBlockHeight))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat, getBlockCount))) } test("send an HTLC A->D with too much overpayment") { @@ -387,7 +387,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(paymentId == failed.id) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(600000000 msat, nodes("A").nodeParams.currentBlockHeight))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(600000000 msat, getBlockCount))) } test("send an HTLC A->D with a reasonable overpayment") { @@ -461,7 +461,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height val currentBlockCount = getBlockCount - awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(getBlockCount == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -546,7 +546,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height val currentBlockCount = getBlockCount - awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(getBlockCount == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -622,7 +622,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height val currentBlockCount = getBlockCount - awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(getBlockCount == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -683,7 +683,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService nodes("C").system.eventStream.subscribe(stateListener.ref, classOf[ChannelStateChanged]) // first we make sure we are in sync with current blockchain height val currentBlockCount = getBlockCount - awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(getBlockCount == currentBlockCount, max = 20 seconds, interval = 1 second) // NB: F has a no-op payment handler, allowing us to manually fulfill htlcs val htlcReceiver = TestProbe() // we register this probe as the final payment handler @@ -759,7 +759,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val paymentHandlerF = nodes("F5").system.actorOf(LocalPaymentHandler.props(nodes("F5").nodeParams)) // first we make sure we are in sync with current blockchain height val currentBlockCount = getBlockCount - awaitCond(nodes("A").nodeParams.currentBlockHeight == currentBlockCount, max = 20 seconds, interval = 1 second) + awaitCond(getBlockCount == currentBlockCount, max = 20 seconds, interval = 1 second) // first we send 3 mBTC to F so that it has a balance val amountMsat = 300000000.msat sender.send(paymentHandlerF, ReceivePayment(Some(amountMsat), "1 coffee")) @@ -783,31 +783,21 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService sender.expectMsgType[UUID] } - def time[T](name: String)(f: => T) = { - val t1 = Platform.currentTime.milliseconds - try { - f - } finally { - val t2 = Platform.currentTime.milliseconds - println(s"$name took ${t2 - t1}") - } - } - val buffer = TestProbe() send(100000000 msat, paymentHandlerF, nodes("C").paymentInitiator) // will be left pending - time("0")(forwardHandlerF.expectMsgType[UpdateAddHtlc](1 hour)) + forwardHandlerF.expectMsgType[UpdateAddHtlc] forwardHandlerF.forward(buffer.ref) - time("1")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) + sigListener.expectMsgType[ChannelSignatureReceived] send(110000000 msat, paymentHandlerF, nodes("C").paymentInitiator) // will be left pending - time("2")(forwardHandlerF.expectMsgType[UpdateAddHtlc](1 hour)) + forwardHandlerF.expectMsgType[UpdateAddHtlc] forwardHandlerF.forward(buffer.ref) - time("3")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) + sigListener.expectMsgType[ChannelSignatureReceived] send(120000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) - time("4")(forwardHandlerC.expectMsgType[UpdateAddHtlc](1 hour)) + forwardHandlerC.expectMsgType[UpdateAddHtlc] forwardHandlerC.forward(buffer.ref) - time("5")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) + sigListener.expectMsgType[ChannelSignatureReceived] send(130000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) - time("a")(forwardHandlerC.expectMsgType[UpdateAddHtlc](1 hour)) + forwardHandlerC.expectMsgType[UpdateAddHtlc] forwardHandlerC.forward(buffer.ref) val commitmentsF = sigListener.expectMsgType[ChannelSignatureReceived].commitments sigListener.expectNoMsg(1 second) @@ -819,22 +809,22 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(htlcTimeoutTxs.size === 2) assert(htlcSuccessTxs.size === 2) // we fulfill htlcs to get the preimagse - time("b")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) + buffer.expectMsgType[UpdateAddHtlc] buffer.forward(paymentHandlerF) - time("c")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) - val preimage1 = time("d")(sender.expectMsgType[PaymentSucceeded].paymentPreimage) - time("e")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) + sigListener.expectMsgType[ChannelSignatureReceived] + val preimage1 = sender.expectMsgType[PaymentSucceeded].paymentPreimage + buffer.expectMsgType[UpdateAddHtlc] buffer.forward(paymentHandlerF) - time("f")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) - time("g")(sender.expectMsgType[PaymentSucceeded](1 hour).paymentPreimage) - time("h")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) + sigListener.expectMsgType[ChannelSignatureReceived] + sender.expectMsgType[PaymentSucceeded].paymentPreimage + buffer.expectMsgType[UpdateAddHtlc] buffer.forward(paymentHandlerC) - time("i")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) - time("j")(sender.expectMsgType[PaymentSucceeded](1 hour).paymentPreimage) - time("k")(buffer.expectMsgType[UpdateAddHtlc](1 hour)) + sigListener.expectMsgType[ChannelSignatureReceived] + sender.expectMsgType[PaymentSucceeded].paymentPreimage + buffer.expectMsgType[UpdateAddHtlc] buffer.forward(paymentHandlerC) - time("l")(sigListener.expectMsgType[ChannelSignatureReceived](1 hour)) - time("m")(sender.expectMsgType[PaymentSucceeded](1 hour).paymentPreimage) + sigListener.expectMsgType[ChannelSignatureReceived] + sender.expectMsgType[PaymentSucceeded].paymentPreimage // this also allows us to get the channel id val channelId = commitmentsF.channelId // we also retrieve C's default final address From ddfc40408888be6104e2bd12d412fdb7d2b8d5b0 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 14:01:38 +0200 Subject: [PATCH 41/54] Revert "replaced AtomicLong by Array[Long]" This reverts commit c6390c2edb8cb5956d1d62c01e006db45dffb120. --- .../src/main/scala/fr/acinq/eclair/NodeParams.scala | 6 +++--- eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala | 2 +- .../acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala | 10 +++++----- .../blockchain/electrum/ElectrumClientPool.scala | 6 +++--- .../eclair/blockchain/electrum/ElectrumWatcher.scala | 8 +++++--- .../src/test/scala/fr/acinq/eclair/StartupSpec.scala | 2 +- .../src/test/scala/fr/acinq/eclair/TestConstants.scala | 4 ++-- .../blockchain/electrum/ElectrumClientPoolSpec.scala | 2 +- .../blockchain/electrum/ElectrumWalletSpec.scala | 2 +- .../blockchain/electrum/ElectrumWatcherSpec.scala | 6 +++--- .../scala/fr/acinq/eclair/channel/ThroughputSpec.scala | 4 ++-- .../eclair/interop/rustytests/RustyTestsSpec.scala | 2 +- 12 files changed, 28 insertions(+), 26 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index d91ec378c6..6db6b030bb 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -42,7 +42,7 @@ import scala.concurrent.duration.FiniteDuration * Created by PM on 26/02/2017. */ case class NodeParams(keyManager: KeyManager, - private val blockCount: Array[Long], + private val blockCount: AtomicLong, alias: String, color: Color, publicAddresses: List[NodeAddress], @@ -82,7 +82,7 @@ case class NodeParams(keyManager: KeyManager, maxPaymentAttempts: Int) { val privateKey = keyManager.nodeKey.privateKey val nodeId = keyManager.nodeId - def currentBlockHeight: Long = blockCount(0) + def currentBlockHeight: Long = blockCount.get } object NodeParams { @@ -127,7 +127,7 @@ object NodeParams { } } - def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases, blockCount: Array[Long], feeEstimator: FeeEstimator): NodeParams = { + def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases, blockCount: AtomicLong, feeEstimator: FeeEstimator): NodeParams = { val chain = config.getString("chain") val chainHash = makeChainHash(chain) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala index ca64809272..5d4f0a1861 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -99,7 +99,7 @@ class Setup(datadir: File, * It is mainly used to calculate htlc expiries. * The value is read by all actors, hence it needs to be thread-safe. */ - val blockCount: Array[Long] = Array(0L) + val blockCount = new AtomicLong(0) /** * This holds the current feerates, in satoshi-per-kilobytes. diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala index 87589b4bbc..73511db293 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala @@ -39,7 +39,7 @@ import scala.util.Try * - also uses bitcoin-core rpc api, most notably for tx confirmation count and blockcount (because reorgs) * Created by PM on 21/02/2016. */ -class ZmqWatcher(blockCount: Array[Long], client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) extends Actor with ActorLogging { +class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) extends Actor with ActorLogging { import ZmqWatcher._ @@ -80,7 +80,7 @@ class ZmqWatcher(blockCount: Array[Long], client: ExtendedBitcoinClient)(implici client.getBlockCount.map { case count => log.debug(s"setting blockCount=$count") - blockCount(0) = count + blockCount.set(count) context.system.eventStream.publish(CurrentBlockCount(count)) } // TODO: beware of the herd effect @@ -151,7 +151,7 @@ class ZmqWatcher(blockCount: Array[Long], client: ExtendedBitcoinClient)(implici context become watching(watches + w, addWatchedUtxos(watchedUtxos, w), block2tx, nextTick) case PublishAsap(tx) => - val blockCount = this.blockCount(0) + val blockCount = this.blockCount.get() val cltvTimeout = Scripts.cltvTimeout(tx) val csvTimeout = Scripts.csvTimeout(tx) if (csvTimeout > 0) { @@ -168,7 +168,7 @@ class ZmqWatcher(blockCount: Array[Long], client: ExtendedBitcoinClient)(implici case WatchEventConfirmed(BITCOIN_PARENT_TX_CONFIRMED(tx), blockHeight, _, _) => log.info(s"parent tx of txid=${tx.txid} has been confirmed") - val blockCount = this.blockCount(0) + val blockCount = this.blockCount.get() val csvTimeout = Scripts.csvTimeout(tx) val absTimeout = blockHeight + csvTimeout if (absTimeout > blockCount) { @@ -226,7 +226,7 @@ class ZmqWatcher(blockCount: Array[Long], client: ExtendedBitcoinClient)(implici object ZmqWatcher { - def props(blockCount: Array[Long], client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) = Props(new ZmqWatcher(blockCount, client)(ec)) + def props(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit ec: ExecutionContext = ExecutionContext.global) = Props(new ZmqWatcher(blockCount, client)(ec)) case object TickNewBlock diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala index 563d7293a2..117b204bf1 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPool.scala @@ -32,7 +32,7 @@ import scala.concurrent.ExecutionContext import scala.concurrent.duration._ import scala.util.Random -class ElectrumClientPool(blockCount: Array[Long], serverAddresses: Set[ElectrumServerAddress])(implicit val ec: ExecutionContext) extends Actor with FSM[ElectrumClientPool.State, ElectrumClientPool.Data] { +class ElectrumClientPool(blockCount: AtomicLong, serverAddresses: Set[ElectrumServerAddress])(implicit val ec: ExecutionContext) extends Actor with FSM[ElectrumClientPool.State, ElectrumClientPool.Data] { import ElectrumClientPool._ val statusListeners = collection.mutable.HashSet.empty[ActorRef] @@ -166,10 +166,10 @@ class ElectrumClientPool(blockCount: Array[Long], serverAddresses: Set[ElectrumS private def updateBlockCount(blockCount: Long): Unit = { // when synchronizing we don't want to advertise previous blocks - if (this.blockCount(0) < blockCount) { + if (this.blockCount.get() < blockCount) { log.debug("current blockchain height={}", blockCount) context.system.eventStream.publish(CurrentBlockCount(blockCount)) - this.blockCount(0) = blockCount + this.blockCount.set(blockCount) } } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala index ef41558623..48aab4bbe3 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala @@ -16,6 +16,8 @@ package fr.acinq.eclair.blockchain.electrum +import java.util.concurrent.atomic.AtomicLong + import akka.actor.{Actor, ActorLogging, ActorRef, Stash, Terminated} import fr.acinq.bitcoin.{BlockHeader, ByteVector32, Script, Transaction, TxIn, TxOut} import fr.acinq.eclair.blockchain._ @@ -28,7 +30,7 @@ import scala.collection.SortedMap import scala.collection.immutable.Queue -class ElectrumWatcher(blockCount: Array[Long], client: ActorRef) extends Actor with Stash with ActorLogging { +class ElectrumWatcher(blockCount: AtomicLong, client: ActorRef) extends Actor with Stash with ActorLogging { client ! ElectrumClient.AddStatusListener(self) @@ -161,7 +163,7 @@ class ElectrumWatcher(blockCount: Array[Long], client: ActorRef) extends Actor w case ElectrumClient.ServerError(ElectrumClient.GetTransaction(txid, Some(origin: ActorRef)), _) => origin ! GetTxWithMetaResponse(txid, None, tip.time) case PublishAsap(tx) => - val blockCount = this.blockCount(0) + val blockCount = this.blockCount.get() val cltvTimeout = Scripts.cltvTimeout(tx) val csvTimeout = Scripts.csvTimeout(tx) if (csvTimeout > 0) { @@ -182,7 +184,7 @@ class ElectrumWatcher(blockCount: Array[Long], client: ActorRef) extends Actor w case WatchEventConfirmed(BITCOIN_PARENT_TX_CONFIRMED(tx), blockHeight, _, _) => log.info(s"parent tx of txid=${tx.txid} has been confirmed") - val blockCount = this.blockCount(0) + val blockCount = this.blockCount.get() val csvTimeout = Scripts.csvTimeout(tx) val absTimeout = blockHeight + csvTimeout if (absTimeout > blockCount) { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala index 31bd16ff49..e0931dba52 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala @@ -45,7 +45,7 @@ class StartupSpec extends FunSuite { val conf = illegalAliasConf.withFallback(ConfigFactory.parseResources("reference.conf").getConfig("eclair")) val keyManager = new LocalKeyManager(seed = randomBytes32, chainHash = Block.TestnetGenesisBlock.hash) - val blockCount = Array(0L) + val blockCount = new AtomicLong(0) // try to create a NodeParams instance with a conf that contains an illegal alias val nodeParamsAttempt = Try(NodeParams.makeNodeParams(conf, keyManager, None, TestConstants.inMemoryDb(), blockCount, new TestConstants.TestFeeEstimator)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index efb9dca1e9..c0b57b4956 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -66,7 +66,7 @@ object TestConstants { // This is a function, and not a val! When called will return a new NodeParams def nodeParams = NodeParams( keyManager = keyManager, - blockCount = Array(400000L), + blockCount = new AtomicLong(400000), alias = "alice", color = Color(1, 2, 3), publicAddresses = NodeAddress.fromParts("localhost", 9731).get :: Nil, @@ -143,7 +143,7 @@ object TestConstants { def nodeParams = NodeParams( keyManager = keyManager, - blockCount = Array(400000L), + blockCount = new AtomicLong(400000), alias = "bob", color = Color(4, 5, 6), publicAddresses = NodeAddress.fromParts("localhost", 9732).get :: Nil, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala index 06bfc0c217..0aca5ca3ee 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumClientPoolSpec.scala @@ -67,7 +67,7 @@ class ElectrumClientPoolSpec extends TestKit(ActorSystem("test")) with FunSuiteL val addresses = random.shuffle(serverAddresses.toSeq).take(2).toSet + ElectrumClientPool.ElectrumServerAddress(new InetSocketAddress("electrum.acinq.co", 50002), SSL.STRICT) stream.close() assert(addresses.nonEmpty) - pool = system.actorOf(Props(new ElectrumClientPool(Array(0L), addresses)), "electrum-client") + pool = system.actorOf(Props(new ElectrumClientPool(new AtomicLong(), addresses)), "electrum-client") } test("connect to an electrumx mainnet server") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala index 0302829bb7..ee18f3e7ce 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala @@ -88,7 +88,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike } test("wait until wallet is ready") { - electrumClient = system.actorOf(Props(new ElectrumClientPool(Array(0L), Set(ElectrumServerAddress(new InetSocketAddress("localhost", electrumPort), SSL.OFF))))) + electrumClient = system.actorOf(Props(new ElectrumClientPool(new AtomicLong(), Set(ElectrumServerAddress(new InetSocketAddress("localhost", electrumPort), SSL.OFF))))) wallet = system.actorOf(Props(new ElectrumWallet(seed, electrumClient, WalletParameters(Block.RegtestGenesisBlock.hash, new SqliteWalletDb(DriverManager.getConnection("jdbc:sqlite::memory:")), minimumFee = 5000 sat))), "wallet") val probe = TestProbe() awaitCond({ diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala index 377c952959..38d0f92476 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala @@ -56,7 +56,7 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("watch for confirmed transactions") { val probe = TestProbe() - val blockCount = Array(0L) + val blockCount = new AtomicLong() val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(electrumAddress)))) val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) @@ -82,7 +82,7 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("watch for spent transactions") { val probe = TestProbe() - val blockCount = Array(0L) + val blockCount = new AtomicLong() val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(electrumAddress)))) val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) @@ -127,7 +127,7 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike } test("get transaction") { - val blockCount = Array(0L) + val blockCount = new AtomicLong() val mainnetAddress = ElectrumServerAddress(new InetSocketAddress("electrum.acinq.co", 50002), SSL.STRICT) val electrumClient = system.actorOf(Props(new ElectrumClientPool(blockCount, Set(mainnetAddress)))) val watcher = system.actorOf(Props(new ElectrumWatcher(blockCount, electrumClient))) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala index 5008fb9efd..04b380baeb 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala @@ -39,7 +39,7 @@ class ThroughputSpec extends FunSuite { ignore("throughput") { implicit val system = ActorSystem() val pipe = system.actorOf(Props[Pipe], "pipe") - val blockCount = Array(0L) + val blockCount = new AtomicLong() val blockchain = system.actorOf(ZmqWatcher.props(blockCount, new TestBitcoinClient()), "blockchain") val paymentHandler = system.actorOf(Props(new Actor() { val random = new Random() @@ -86,7 +86,7 @@ class ThroughputSpec extends FunSuite { pipe ! (alice, bob) latch.await() - var i = Array(0L) + var i = new AtomicLong(0) val random = new Random() def msg = random.nextInt(100) % 5 match { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala index e13b984b1d..6b3468d35b 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala @@ -44,7 +44,7 @@ class RustyTestsSpec extends TestKit(ActorSystem("test")) with Matchers with fix case class FixtureParam(ref: List[String], res: List[String]) override def withFixture(test: OneArgTest): Outcome = { - val blockCount = Array(0L) + val blockCount = new AtomicLong(0) val latch = new CountDownLatch(1) val pipe: ActorRef = system.actorOf(Props(new SynchronizationPipe(latch))) val alice2blockchain = TestProbe() From 7e3ee239cc58c844f8c62e6e16a4f3167edd486f Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 14:15:20 +0200 Subject: [PATCH 42/54] log get/set to atomiclong --- .../src/main/scala/fr/acinq/eclair/NodeParams.scala | 9 ++++++++- .../fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index 6db6b030bb..d3c226a147 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -19,6 +19,7 @@ package fr.acinq.eclair import java.io.File import java.net.InetSocketAddress import java.nio.file.Files +import java.util.UUID import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong @@ -82,7 +83,13 @@ case class NodeParams(keyManager: KeyManager, maxPaymentAttempts: Int) { val privateKey = keyManager.nodeKey.privateKey val nodeId = keyManager.nodeId - def currentBlockHeight: Long = blockCount.get + def currentBlockHeight: Long = { + val uuid = UUID.randomUUID() + println(s"$uuid start get") + val b = blockCount.get + println(s"$uuid end get") + b + } } object NodeParams { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala index 73511db293..3c8b7d8d4e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala @@ -16,6 +16,7 @@ package fr.acinq.eclair.blockchain.bitcoind +import java.util.UUID import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicLong @@ -80,7 +81,10 @@ class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit client.getBlockCount.map { case count => log.debug(s"setting blockCount=$count") + val uuid = UUID.randomUUID() + println(s"$uuid start set") blockCount.set(count) + println(s"$uuid end set") context.system.eventStream.publish(CurrentBlockCount(count)) } // TODO: beware of the herd effect From 51e1e4d84e712d221adda75d65a6ffaee30ede70 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 14:53:04 +0200 Subject: [PATCH 43/54] Revert "log get/set to atomiclong" This reverts commit 7e3ee239cc58c844f8c62e6e16a4f3167edd486f. --- .../src/main/scala/fr/acinq/eclair/NodeParams.scala | 9 +-------- .../fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala | 4 ---- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index d3c226a147..6db6b030bb 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -19,7 +19,6 @@ package fr.acinq.eclair import java.io.File import java.net.InetSocketAddress import java.nio.file.Files -import java.util.UUID import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong @@ -83,13 +82,7 @@ case class NodeParams(keyManager: KeyManager, maxPaymentAttempts: Int) { val privateKey = keyManager.nodeKey.privateKey val nodeId = keyManager.nodeId - def currentBlockHeight: Long = { - val uuid = UUID.randomUUID() - println(s"$uuid start get") - val b = blockCount.get - println(s"$uuid end get") - b - } + def currentBlockHeight: Long = blockCount.get } object NodeParams { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala index 3c8b7d8d4e..73511db293 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/ZmqWatcher.scala @@ -16,7 +16,6 @@ package fr.acinq.eclair.blockchain.bitcoind -import java.util.UUID import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicLong @@ -81,10 +80,7 @@ class ZmqWatcher(blockCount: AtomicLong, client: ExtendedBitcoinClient)(implicit client.getBlockCount.map { case count => log.debug(s"setting blockCount=$count") - val uuid = UUID.randomUUID() - println(s"$uuid start set") blockCount.set(count) - println(s"$uuid end set") context.system.eventStream.publish(CurrentBlockCount(count)) } // TODO: beware of the herd effect From 4722ba867932a0057a754f5158d75fa68c47554d Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 14:59:56 +0200 Subject: [PATCH 44/54] different way of returning the current block count --- .../fr/acinq/eclair/integration/IntegrationSpec.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index 2bdd3b6d48..7836483ec6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -534,9 +534,10 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService } def getBlockCount: Long = { - val sender = TestProbe() - sender.send(bitcoincli, BitcoinReq("getblockcount")) - sender.expectMsgType[JValue](10 seconds).extract[Long] + // we make sure that all nodes have the same value + awaitCond(nodes.values.map(_.nodeParams.currentBlockHeight).toSet.size == 1, max = 1 minute, interval = 1 second) + // and we return it (NB: it could be a different value at this point + nodes.values.head.nodeParams.currentBlockHeight } test("propagate a fulfill upstream when a downstream htlc is redeemed on-chain (remote commit)") { From c07ecd72bfa11fa3023ef663ef64329c1a6252f6 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 15:33:38 +0200 Subject: [PATCH 45/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""""""""""" This reverts commit e43afac8a65edd47bb68b9e0a7ef2dad4cb5b843. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From a823702b3e64860420747794395e0ec91bf761c1 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 16:02:33 +0200 Subject: [PATCH 46/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""""""""""" This reverts commit c07ecd72bfa11fa3023ef663ef64329c1a6252f6. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 2a3e738e07598502e582961c22880d1855bf2572 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 16:40:50 +0200 Subject: [PATCH 47/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""""""""""""" This reverts commit a823702b3e64860420747794395e0ec91bf761c1. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From 9199b5ae67b5f53842278cd0cfaaa6e02f217b32 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 16:59:59 +0200 Subject: [PATCH 48/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""""""""""""" This reverts commit 2a3e738e07598502e582961c22880d1855bf2572. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 5db3a48bffb1e653e9ea7442df027eedc50093c5 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 17:23:50 +0200 Subject: [PATCH 49/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""""""""""""""" This reverts commit 9199b5ae67b5f53842278cd0cfaaa6e02f217b32. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From cd2341079e830d6c19c81df6230cc7037074eea9 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 17:46:50 +0200 Subject: [PATCH 50/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""""""""""""""" This reverts commit 5db3a48bffb1e653e9ea7442df027eedc50093c5. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From edd4f7eb29a46ff6cea7ae50c23cd7ad33983593 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 20:27:58 +0200 Subject: [PATCH 51/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump"""""""""""""""""""""""""" This reverts commit cd2341079e830d6c19c81df6230cc7037074eea9. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae9abf156f..704fe3db90 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,4 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to + From e253386cbb4dfe3328ea07f063fc68724bcf153e Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 21:00:44 +0200 Subject: [PATCH 52/54] Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "bump""""""""""""""""""""""""""" This reverts commit edd4f7eb29a46ff6cea7ae50c23cd7ad33983593. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 704fe3db90..ae9abf156f 100644 --- a/README.md +++ b/README.md @@ -232,4 +232,3 @@ zmqpubrawtx=tcp://127.0.0.1:29001 * [1] [The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments](https://lightning.network/lightning-network-paper.pdf) by Joseph Poon and Thaddeus Dryja * [2] [Reaching The Ground With Lightning](https://github.com/ElementsProject/lightning/raw/master/doc/deployable-lightning.pdf) by Rusty Russell * [3] [Lightning Network Explorer](https://explorer.acinq.co) - Explore testnet LN nodes you can connect to - From 20549397e16a09af4655b00833442dd82dcb8a57 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 21:42:55 +0200 Subject: [PATCH 53/54] dynamically assign ports for bitcoind in tests --- .../scala/fr/acinq/eclair/TestUtils.scala | 15 +++++++ .../bitcoind/BitcoinCoreWalletSpec.scala | 4 +- .../blockchain/bitcoind/BitcoindService.scala | 39 ++++++++++++++++--- .../bitcoind/ExtendedBitcoinClientSpec.scala | 4 +- .../electrum/ElectrumxService.scala | 10 +++-- .../fee/BitcoinCoreFeeProviderSpec.scala | 4 +- .../eclair/integration/IntegrationSpec.scala | 8 ++-- 7 files changed, 64 insertions(+), 20 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala index 4f5ecdcb6f..7213a9ff96 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestUtils.scala @@ -17,6 +17,7 @@ package fr.acinq.eclair import java.io.File +import java.net.ServerSocket object TestUtils { @@ -27,4 +28,18 @@ object TestUtils { .props .get("buildDirectory") // this is defined if we run from maven .getOrElse(new File(sys.props("user.dir"), "target").getAbsolutePath) // otherwise we probably are in intellij, so we build it manually assuming that user.dir == path to the module + + + def availablePort: Int = synchronized { + var serverSocket: ServerSocket = null + try { + serverSocket = new ServerSocket(0) + serverSocket.getLocalPort + } finally { + if (serverSocket != null) { + serverSocket.close() + } + } + } + } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala index c16c1d6e7d..136e09822e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala @@ -45,8 +45,8 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala index 518e6ed1a7..359d6f88e0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala @@ -28,10 +28,11 @@ import fr.acinq.eclair.TestUtils import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, BitcoinJsonRPCClient} import fr.acinq.eclair.integration.IntegrationSpec import grizzled.slf4j.Logging -import org.json4s.JsonAST.JValue +import org.json4s.JsonAST.{JArray, JDecimal, JInt, JString, JValue} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ +import scala.io.Source trait BitcoindService extends Logging { self: TestKitBase => @@ -39,6 +40,14 @@ trait BitcoindService extends Logging { implicit val system: ActorSystem implicit val sttpBackend = OkHttpFutureBackend() + val bitcoindPort: Int = TestUtils.availablePort + + val bitcoindRpcPort: Int = TestUtils.availablePort + + val bitcoindZmqBlockPort: Int = TestUtils.availablePort + + val bitcoindZmqTxPort: Int = TestUtils.availablePort + import scala.sys.process._ val INTEGRATION_TMP_DIR = new File(TestUtils.BUILD_DIRECTORY, s"integration-${UUID.randomUUID()}") @@ -56,11 +65,17 @@ trait BitcoindService extends Logging { def startBitcoind(): Unit = { Files.createDirectories(PATH_BITCOIND_DATADIR.toPath) if (!Files.exists(new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath)) { - Files.copy(classOf[IntegrationSpec].getResourceAsStream("/integration/bitcoin.conf"), new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath, StandardCopyOption.REPLACE_EXISTING) + val is = classOf[IntegrationSpec].getResourceAsStream("/integration/bitcoin.conf") + val conf = Source.fromInputStream(is).mkString + .replace("28333", bitcoindPort.toString) + .replace("28332", bitcoindRpcPort.toString) + .replace("28334", bitcoindZmqBlockPort.toString) + .replace("28335", bitcoindZmqTxPort.toString) + Files.writeString(new File(PATH_BITCOIND_DATADIR.toString, "bitcoin.conf").toPath, conf) } bitcoind = s"$PATH_BITCOIND -datadir=$PATH_BITCOIND_DATADIR".run() - bitcoinrpcclient = new BasicBitcoinJsonRPCClient(user = "foo", password = "bar", host = "localhost", port = 28332) + bitcoinrpcclient = new BasicBitcoinJsonRPCClient(user = "foo", password = "bar", host = "localhost", port = bitcoindRpcPort) bitcoincli = system.actorOf(Props(new Actor { override def receive: Receive = { case BitcoinReq(method) => bitcoinrpcclient.invoke(method) pipeTo sender @@ -83,11 +98,23 @@ trait BitcoindService extends Logging { logger.info(s"waiting for bitcoind to initialize...") awaitCond({ sender.send(bitcoincli, BitcoinReq("getnetworkinfo")) - sender.receiveOne(5 second).isInstanceOf[JValue] - }, max = 30 seconds, interval = 500 millis) + sender.expectMsgType[Any](5 second) match { + case j: JValue => j \ "version" match { + case JInt(_) => true + case _ => false + } + case _ => false + } + }, max = 3 minutes, interval = 2 seconds) logger.info(s"generating initial blocks...") sender.send(bitcoincli, BitcoinReq("generate", 150)) - sender.expectMsgType[JValue](30 seconds) + val JArray(res) = sender.expectMsgType[JValue](3 minutes) + assert(res.size == 150) + awaitCond({ + sender.send(bitcoincli, BitcoinReq("getbalance")) + val JDecimal(balance) = sender.expectMsgType[JDecimal](30 seconds) + balance > 100 + }, max = 3 minutes, interval = 2 second) } } \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala index 945c6db054..86e139e54c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/ExtendedBitcoinClientSpec.scala @@ -38,8 +38,8 @@ class ExtendedBitcoinClientSpec extends TestKit(ActorSystem("test")) with Bitcoi "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala index ba1266f04a..71b487f3e8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumxService.scala @@ -20,26 +20,28 @@ import com.spotify.docker.client.{DefaultDockerClient, DockerClient} import com.whisk.docker.impl.spotify.SpotifyDockerFactory import com.whisk.docker.scalatest.DockerTestKit import com.whisk.docker.{DockerContainer, DockerFactory} +import fr.acinq.eclair.TestUtils +import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import org.scalatest.Suite trait ElectrumxService extends DockerTestKit { - self: Suite => + self: Suite with BitcoindService => - val electrumPort = 47000 + val electrumPort = TestUtils.availablePort val electrumxContainer = if (System.getProperty("os.name").startsWith("Linux")) { // "host" mode will let the container access the host network on linux // we use our own docker image because other images on Docker lag behind and don't yet support 1.4 DockerContainer("acinq/electrumx") .withNetworkMode("host") - .withEnv("DAEMON_URL=http://foo:bar@localhost:28332", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") + .withEnv(s"DAEMON_URL=http://foo:bar@localhost:$bitcoindRpcPort", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") //.withLogLineReceiver(LogLineReceiver(true, println)) } else { // on windows or oxs, host mode is not available, but from docker 18.03 on host.docker.internal can be used instead // host.docker.internal is not (yet ?) available on linux though DockerContainer("acinq/electrumx") .withPorts(electrumPort -> Some(electrumPort)) - .withEnv("DAEMON_URL=http://foo:bar@host.docker.internal:28332", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") + .withEnv(s"DAEMON_URL=http://foo:bar@host.docker.internal:$bitcoindRpcPort", "COIN=BitcoinSegwit", "NET=regtest", s"TCP_PORT=$electrumPort") //.withLogLineReceiver(LogLineReceiver(true, println)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala index 126218bab9..1ad9f555ff 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala @@ -42,8 +42,8 @@ class BitcoinCoreFeeProviderSpec extends TestKit(ActorSystem("test")) with Bitco "eclair.chain" -> "regtest", "eclair.spv" -> false, "eclair.server.public-ips.1" -> "localhost", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, "eclair.router-broadcast-interval" -> "2 second", "eclair.auto-reconnect" -> false)) val config = ConfigFactory.load(commonConfig).getConfig("eclair") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index 7836483ec6..92dc0bae4f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -82,10 +82,10 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val commonConfig = ConfigFactory.parseMap(Map( "eclair.chain" -> "regtest", "eclair.server.public-ips.1" -> "127.0.0.1", - "eclair.bitcoind.port" -> 28333, - "eclair.bitcoind.rpcport" -> 28332, - "eclair.bitcoind.zmqblock" -> "tcp://127.0.0.1:28334", - "eclair.bitcoind.zmqtx" -> "tcp://127.0.0.1:28335", + "eclair.bitcoind.port" -> bitcoindPort, + "eclair.bitcoind.rpcport" -> bitcoindRpcPort, + "eclair.bitcoind.zmqblock" -> s"tcp://127.0.0.1:$bitcoindZmqBlockPort", + "eclair.bitcoind.zmqtx" -> s"tcp://127.0.0.1:$bitcoindZmqTxPort", "eclair.mindepth-blocks" -> 2, "eclair.max-htlc-value-in-flight-msat" -> 100000000000L, "eclair.router.broadcast-interval" -> "2 second", From 69f67df925337a0880044e9636449093b54442d7 Mon Sep 17 00:00:00 2001 From: pm47 Date: Tue, 10 Sep 2019 21:45:31 +0200 Subject: [PATCH 54/54] put back 1G ram for tests --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0c2bb222a7..10c833307c 100644 --- a/pom.xml +++ b/pom.xml @@ -222,7 +222,7 @@ ${project.build.directory} - -Xmx1500m -Dfile.encoding=UTF-8 + -Xmx1024m -Dfile.encoding=UTF-8