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 ce3f9fc2da..6db6b030bb 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 5979599b02..5d4f0a1861 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}
@@ -93,12 +94,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"),
@@ -170,7 +190,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)
}
@@ -193,8 +213,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")
@@ -208,10 +228,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
@@ -220,11 +240,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 3c6577f792..616c3b2b39 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 e213d8161f..98e8062eea 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
@@ -25,7 +25,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, _}
+import fr.acinq.eclair.{MilliSatoshi, _}
// @formatter:off
case class LocalChanges(proposed: List[UpdateMessage], signed: List[UpdateMessage], acked: List[UpdateMessage]) {
@@ -120,17 +120,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..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
+ 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 {
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 ca93d70a7e..c907524ccd 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
@@ -412,7 +412,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
@@ -493,7 +493,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
@@ -938,15 +938,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.forall(isStale) && update2_opt.forall(isStale)
}
- 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
@@ -1226,12 +1226,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 = {
@@ -1251,7 +1250,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 ae1d63138a..c0b57b4956 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,
@@ -141,6 +143,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..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/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 c1cb4abb29..f486a370fa 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,106 +81,99 @@ 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(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)
- 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
+ val senders = 2
+ val totalMessages = 100
+ 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({
@@ -191,9 +184,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 67b4f02867..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,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 a06ac26323..c1ee38216e 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()
@@ -107,17 +109,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 5cccec7309..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
@@ -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,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)
@@ -177,16 +175,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))))
@@ -197,13 +195,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))))
@@ -214,7 +212,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))))
@@ -227,11 +225,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))))
@@ -242,7 +240,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]
@@ -250,7 +248,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))))
@@ -267,7 +265,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))))
@@ -279,7 +277,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
@@ -300,7 +298,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
@@ -310,7 +308,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)
@@ -327,7 +325,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)
@@ -342,7 +340,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)
@@ -357,10 +355,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)
@@ -374,9 +372,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)
@@ -390,7 +388,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)
@@ -406,9 +404,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)
@@ -433,7 +431,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]
@@ -480,19 +478,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)
@@ -512,7 +510,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) {
@@ -710,12 +708,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)
@@ -2041,7 +2039,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..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
@@ -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}
@@ -51,9 +51,11 @@ 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._
+import scala.util.Try
/**
* Created by PM on 15/03/2017.
@@ -80,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",
@@ -345,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, Globals.blockCount.get())))
+ 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") {
@@ -365,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, Globals.blockCount.get())))
+ 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") {
@@ -385,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, Globals.blockCount.get())))
+ 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") {
@@ -458,9 +460,8 @@ 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]
- awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second)
+ val currentBlockCount = getBlockCount
+ 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
@@ -532,15 +533,21 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
awaitAnnouncements(nodes.filterKeys(_ == "A"), 9, 11, 24)
}
+ def getBlockCount: 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)") {
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]
- awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second)
+ val currentBlockCount = getBlockCount
+ 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
@@ -615,9 +622,8 @@ 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]
- awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second)
+ val currentBlockCount = getBlockCount
+ 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
@@ -677,9 +683,8 @@ 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]
- awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second)
+ val currentBlockCount = getBlockCount
+ 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
@@ -754,9 +759,8 @@ 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]
- awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second)
+ val currentBlockCount = getBlockCount
+ 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"))
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 2772b1f591..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
@@ -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 ec467dad57..f55117a88e 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
@@ -21,10 +21,10 @@ import fr.acinq.bitcoin.{Block, ByteVector32, ByteVector64, Satoshi}
import fr.acinq.eclair.payment.PaymentRequest.ExtraHop
import fr.acinq.eclair.router.Graph.GraphStructure.DirectedGraph.graphEdgeToHop
import fr.acinq.eclair.router.Graph.GraphStructure.{DirectedGraph, GraphEdge}
-import fr.acinq.eclair.router.Graph.{RichWeight, RoutingHeuristics, WeightRatios}
+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, ToMilliSatoshiConversion, randomKey}
+import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, ShortChannelId, ToMilliSatoshiConversion, randomKey}
import org.scalatest.FunSuite
import scodec.bits._
@@ -51,7 +51,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))
}
@@ -74,7 +74,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))
}
@@ -111,7 +111,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, isPartial = false, 0, None).cost
@@ -122,7 +122,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)
}
@@ -137,7 +137,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))
}
@@ -152,11 +152,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))
}
@@ -177,7 +177,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))
}
@@ -199,7 +199,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))
}
@@ -220,7 +220,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))
}
@@ -241,7 +241,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))
}
@@ -262,7 +262,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))
}
@@ -277,7 +277,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))
}
@@ -289,7 +289,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))
}
@@ -302,7 +302,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))
}
@@ -314,8 +314,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)") {
@@ -337,8 +337,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") {
@@ -350,7 +350,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))
}
@@ -364,7 +364,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))
}
@@ -380,10 +380,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))
}
@@ -412,7 +412,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)
}
@@ -449,7 +449,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
@@ -458,7 +458,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))
}
@@ -471,14 +471,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))
}
@@ -492,7 +492,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)
@@ -500,7 +500,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)
}
@@ -560,10 +560,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") {
@@ -579,7 +579,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))
}
@@ -595,7 +595,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))
}
@@ -611,7 +611,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))
}
@@ -626,7 +626,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))
}
@@ -644,7 +644,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))
}
@@ -772,7 +772,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) => fail(thr)
case Success(someRoute) =>
@@ -801,14 +801,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)
@@ -816,7 +816,7 @@ class RouteCalculationSpec extends FunSuite {
cltvDeltaFactor = 0,
ageFactor = 0,
capacityFactor = 1
- ))))
+ ))), currentBlockHeight = 400000)
assert(hops2Nodes(routeCapacityOptimized) === (a, e) :: (e, c) :: (c, d) :: Nil)
}
@@ -833,13 +833,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)
}
@@ -858,7 +856,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)
}
@@ -879,7 +877,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)
}
@@ -920,8 +918,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 f3785dd226..3405475651 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
@@ -269,7 +269,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 161a4adb19..10c833307c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -222,8 +222,7 @@
${project.build.directory}
- -Xmx1024m
- -Dfile.encoding=UTF-8
+ -Xmx1024m -Dfile.encoding=UTF-8