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 0bdc131c8b..77ac86b6eb 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 @@ -1364,7 +1364,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId } val revokedCommitPublished1 = d.revokedCommitPublished.map { rev => val (rev1, penaltyTxs) = Closing.claimRevokedHtlcTxOutputs(keyManager, d.commitments, rev, tx, nodeParams.onChainFeeConf.feeEstimator) - penaltyTxs.foreach(claimTx => txPublisher ! PublishRawTx(claimTx.tx)) + penaltyTxs.foreach(claimTx => txPublisher ! PublishRawTx(claimTx.tx, claimTx.desc)) penaltyTxs.foreach(claimTx => blockchain ! WatchSpent(self, tx.txid, claimTx.input.outPoint.index.toInt, BITCOIN_OUTPUT_SPENT, hints = Set(claimTx.tx.txid))) rev1 } @@ -1378,7 +1378,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId // If the tx is one of our HTLC txs, we now publish a 3rd-stage claim-htlc-tx that claims its output. val (localCommitPublished1, claimHtlcTx_opt) = Closing.claimLocalCommitHtlcTxOutput(localCommitPublished, keyManager, d.commitments, tx, nodeParams.onChainFeeConf.feeEstimator, nodeParams.onChainFeeConf.feeTargets) claimHtlcTx_opt.foreach(claimHtlcTx => { - txPublisher ! PublishRawTx(claimHtlcTx.tx) + txPublisher ! PublishRawTx(claimHtlcTx.tx, claimHtlcTx.desc) blockchain ! WatchConfirmed(self, claimHtlcTx.tx.txid, nodeParams.minDepthBlocks, BITCOIN_TX_CONFIRMED(claimHtlcTx.tx)) }) Closing.updateLocalCommitPublished(localCommitPublished1, tx) @@ -2013,7 +2013,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case Some(fundingTx) => // if we are funder, we never give up log.info(s"republishing the funding tx...") - txPublisher ! PublishRawTx(fundingTx) + txPublisher ! PublishRawTx(fundingTx, "funding-tx") // we also check if the funding tx has been double-spent checkDoubleSpent(fundingTx) context.system.scheduler.scheduleOnce(1 day, blockchain, GetTxWithMeta(txid)) @@ -2165,7 +2165,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId } private def doPublish(closingTx: ClosingTx): Unit = { - txPublisher ! PublishRawTx(closingTx.tx) + txPublisher ! PublishRawTx(closingTx.tx, closingTx.desc) blockchain ! WatchConfirmed(self, closingTx.tx.txid, nodeParams.minDepthBlocks, BITCOIN_TX_CONFIRMED(closingTx.tx)) } @@ -2232,12 +2232,11 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId val publishQueue = commitments.commitmentFormat match { case Transactions.DefaultCommitmentFormat => - val txs = List(commitTx) ++ claimMainDelayedOutputTx.map(_.tx) ++ htlcTxs.values.flatten.map(_.tx) ++ claimHtlcDelayedTxs.map(_.tx) - txs.map(tx => PublishRawTx(tx)) + List(PublishRawTx(commitTx, "commit-tx")) ++ (claimMainDelayedOutputTx ++ htlcTxs.values.flatten ++ claimHtlcDelayedTxs).map(tx => PublishRawTx(tx.tx, tx.desc)) case Transactions.AnchorOutputsCommitmentFormat => val claimLocalAnchor = claimAnchorTxs.collect { case tx: Transactions.ClaimLocalAnchorOutputTx => SignAndPublishTx(tx, commitments) } val redeemableHtlcTxs = htlcTxs.values.collect { case Some(tx) => SignAndPublishTx(tx, commitments) } - List(PublishRawTx(commitTx)) ++ claimLocalAnchor ++ claimMainDelayedOutputTx.map(tx => PublishRawTx(tx.tx)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishRawTx(tx.tx)) + List(PublishRawTx(commitTx, "commit-tx")) ++ claimLocalAnchor ++ claimMainDelayedOutputTx.map(tx => PublishRawTx(tx.tx, tx.desc)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishRawTx(tx.tx, tx.desc)) } publishIfNeeded(publishQueue, irrevocablySpent) @@ -2300,7 +2299,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId private def doPublish(remoteCommitPublished: RemoteCommitPublished): Unit = { import remoteCommitPublished._ - val publishQueue = (claimMainOutputTx ++ claimHtlcTxs.values.flatten).map(tx => PublishRawTx(tx.tx)) + val publishQueue = (claimMainOutputTx ++ claimHtlcTxs.values.flatten).map(tx => PublishRawTx(tx.tx, tx.desc)) publishIfNeeded(publishQueue, irrevocablySpent) // we watch: @@ -2339,7 +2338,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId private def doPublish(revokedCommitPublished: RevokedCommitPublished): Unit = { import revokedCommitPublished._ - val publishQueue = (claimMainOutputTx ++ mainPenaltyTx ++ htlcPenaltyTxs ++ claimHtlcDelayedPenaltyTxs).map(tx => PublishRawTx(tx.tx)) + val publishQueue = (claimMainOutputTx ++ mainPenaltyTx ++ htlcPenaltyTxs ++ claimHtlcDelayedPenaltyTxs).map(tx => PublishRawTx(tx.tx, tx.desc)) publishIfNeeded(publishQueue, irrevocablySpent) // we watch: diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala index af48f3a67e..ac6e12d537 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala @@ -293,7 +293,7 @@ sealed trait CommitPublished { * @param claimHtlcDelayedTxs 3rd-stage txs (spending the output of HTLC txs). * @param claimAnchorTxs txs spending anchor outputs to bump the feerate of the commitment tx (if applicable). */ -case class LocalCommitPublished(commitTx: Transaction, claimMainDelayedOutputTx: Option[ClaimLocalDelayedOutputTx], htlcTxs: Map[OutPoint, Option[HtlcTx]], claimHtlcDelayedTxs: List[ClaimLocalDelayedOutputTx], claimAnchorTxs: List[ClaimAnchorOutputTx], irrevocablySpent: Map[OutPoint, Transaction]) extends CommitPublished { +case class LocalCommitPublished(commitTx: Transaction, claimMainDelayedOutputTx: Option[ClaimLocalDelayedOutputTx], htlcTxs: Map[OutPoint, Option[HtlcTx]], claimHtlcDelayedTxs: List[HtlcDelayedTx], claimAnchorTxs: List[ClaimAnchorOutputTx], irrevocablySpent: Map[OutPoint, Transaction]) extends CommitPublished { /** * A local commit is considered done when: * - all commitment tx outputs that we can spend have been spent and confirmed (even if the spending tx was not ours) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index 257efd8bd2..75ea60347e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -511,7 +511,7 @@ object Helpers { val feeratePerKwDelayed = feeEstimator.getFeeratePerKw(feeTargets.claimMainBlockTarget) // first we will claim our main output as soon as the delay is over - val mainDelayedTx = generateTx("main-delayed-output") { + val mainDelayedTx = generateTx("local-main-delayed") { Transactions.makeClaimLocalDelayedOutputTx(tx, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPubkey, localParams.defaultFinalScriptPubKey, feeratePerKwDelayed).map(claimDelayed => { val sig = keyManager.sign(claimDelayed, keyManager.delayedPaymentPoint(channelKeyPath), localPerCommitmentPoint, TxOwner.Local, commitmentFormat) Transactions.addSigs(claimDelayed, sig) @@ -572,13 +572,12 @@ object Helpers { val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, commitments.localCommit.index.toInt) val localRevocationPubkey = Generators.revocationPubKey(remoteParams.revocationBasepoint, localPerCommitmentPoint) val localDelayedPubkey = Generators.derivePubKey(keyManager.delayedPaymentPoint(channelKeyPath).publicKey, localPerCommitmentPoint) - val htlcDelayedTx = generateTx("claim-htlc-delayed") { - Transactions.makeClaimLocalDelayedOutputTx(tx, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPubkey, localParams.defaultFinalScriptPubKey, feeratePerKwDelayed).map(claimDelayed => { + val htlcDelayedTx = generateTx("htlc-delayed") { + Transactions.makeHtlcDelayedTx(tx, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPubkey, localParams.defaultFinalScriptPubKey, feeratePerKwDelayed).map(claimDelayed => { val sig = keyManager.sign(claimDelayed, keyManager.delayedPaymentPoint(channelKeyPath), localPerCommitmentPoint, TxOwner.Local, commitmentFormat) Transactions.addSigs(claimDelayed, sig) }) } - val localCommitPublished1 = localCommitPublished.copy(claimHtlcDelayedTxs = localCommitPublished.claimHtlcDelayedTxs ++ htlcDelayedTx.toSeq) (localCommitPublished1, htlcDelayedTx) } else { @@ -688,13 +687,13 @@ object Helpers { val feeratePerKwMain = feeEstimator.getFeeratePerKw(feeTargets.claimMainBlockTarget) val mainTx = commitments.commitmentFormat match { - case DefaultCommitmentFormat => generateTx("claim-p2wpkh-output") { + case DefaultCommitmentFormat => generateTx("remote-main") { Transactions.makeClaimP2WPKHOutputTx(tx, commitments.localParams.dustLimit, localPubkey, commitments.localParams.defaultFinalScriptPubKey, feeratePerKwMain).map(claimMain => { val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), remotePerCommitmentPoint, TxOwner.Local, commitments.commitmentFormat) Transactions.addSigs(claimMain, localPubkey, sig) }) } - case AnchorOutputsCommitmentFormat => generateTx("claim-remote-delayed-output") { + case AnchorOutputsCommitmentFormat => generateTx("remote-main-delayed") { Transactions.makeClaimRemoteDelayedOutputTx(tx, commitments.localParams.dustLimit, localPaymentPoint, commitments.localParams.defaultFinalScriptPubKey, feeratePerKwMain).map(claimMain => { val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, commitments.commitmentFormat) Transactions.addSigs(claimMain, sig) @@ -750,7 +749,7 @@ object Helpers { case v if v.paysDirectlyToWallet => log.info(s"channel uses option_static_remotekey to pay directly to our wallet, there is nothing to do") None - case v if v.hasAnchorOutputs => generateTx("claim-remote-delayed-output") { + case v if v.hasAnchorOutputs => generateTx("remote-main-delayed") { Transactions.makeClaimRemoteDelayedOutputTx(commitTx, localParams.dustLimit, localPaymentPoint, localParams.defaultFinalScriptPubKey, feeratePerKwMain).map(claimMain => { val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, commitmentFormat) Transactions.addSigs(claimMain, sig) @@ -842,7 +841,7 @@ object Helpers { val feeratePerKwPenalty = feeEstimator.getFeeratePerKw(target = 1) val penaltyTxs = Transactions.makeClaimHtlcDelayedOutputPenaltyTxs(htlcTx, localParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, localParams.defaultFinalScriptPubKey, feeratePerKwPenalty).flatMap(claimHtlcDelayedOutputPenaltyTx => { - generateTx("claim-htlc-delayed-penalty") { + generateTx("htlc-delayed-penalty") { claimHtlcDelayedOutputPenaltyTx.map(htlcDelayedPenalty => { val sig = keyManager.sign(htlcDelayedPenalty, keyManager.revocationPoint(channelKeyPath), remotePerCommitmentSecret, TxOwner.Local, commitmentFormat) val signedTx = Transactions.addSigs(htlcDelayedPenalty, sig) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/TxPublisher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/TxPublisher.scala index 4efcb82f1f..885556014e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/TxPublisher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/TxPublisher.scala @@ -49,15 +49,17 @@ object TxPublisher { sealed trait Command sealed trait PublishTx extends Command { def tx: Transaction + def desc: String } /** Publish a fully signed transaction without modifying it. */ - case class PublishRawTx(tx: Transaction) extends PublishTx + case class PublishRawTx(tx: Transaction, desc: String) extends PublishTx /** * Publish an unsigned transaction. Once (csv and cltv) delays have been satisfied, the tx publisher will set the fees, * sign the transaction and broadcast it. */ case class SignAndPublishTx(txInfo: TransactionWithInputInfo, commitments: Commitments) extends PublishTx { override def tx: Transaction = txInfo.tx + override def desc: String = txInfo.desc } case class WrappedCurrentBlockCount(currentBlockCount: Long) extends Command case class ParentTxConfirmed(childTx: PublishTx, parentTxId: ByteVector32) extends Command @@ -193,12 +195,12 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, if (csvTimeouts.nonEmpty) { csvTimeouts.foreach { case (parentTxId, csvTimeout) => - log.info(s"txid=${p.tx.txid} has a relative timeout of $csvTimeout blocks, watching parentTxId=$parentTxId tx={}", p.tx) + log.info(s"${p.desc} txid=${p.tx.txid} has a relative timeout of $csvTimeout blocks, watching parentTxId=$parentTxId tx={}", p.tx) watcher ! WatchConfirmed(watchConfirmedResponseMapper.toClassic, parentTxId, minDepth = csvTimeout, BITCOIN_PARENT_TX_CONFIRMED(p)) } run(cltvDelayedTxs, csvDelayedTxs + (p.tx.txid -> TxWithRelativeDelay(p, csvTimeouts.keySet))) } else if (cltvTimeout > blockCount) { - log.info(s"delaying publication of txid=${p.tx.txid} until block=$cltvTimeout (current block=$blockCount)") + log.info(s"delaying publication of ${p.desc} txid=${p.tx.txid} until block=$cltvTimeout (current block=$blockCount)") val cltvDelayedTxs1 = cltvDelayedTxs + (cltvTimeout -> (cltvDelayedTxs.getOrElse(cltvTimeout, Seq.empty) :+ p)) run(cltvDelayedTxs1, csvDelayedTxs) } else { @@ -207,17 +209,17 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, } case ParentTxConfirmed(p, parentTxId) => - log.info(s"parent tx of txid=${p.tx.txid} has been confirmed (parent txid=$parentTxId)") + log.info(s"parent tx of ${p.desc} txid=${p.tx.txid} has been confirmed (parent txid=$parentTxId)") val blockCount = nodeParams.currentBlockHeight csvDelayedTxs.get(p.tx.txid) match { case Some(TxWithRelativeDelay(_, parentTxIds)) => val txWithRelativeDelay1 = TxWithRelativeDelay(p, parentTxIds - parentTxId) if (txWithRelativeDelay1.parentTxIds.isEmpty) { - log.info(s"all parent txs of txid=${p.tx.txid} have been confirmed") + log.info(s"all parent txs of ${p.desc} txid=${p.tx.txid} have been confirmed") val csvDelayedTx1 = csvDelayedTxs - p.tx.txid val cltvTimeout = Scripts.cltvTimeout(p.tx) if (cltvTimeout > blockCount) { - log.info(s"delaying publication of txid=${p.tx.txid} until block=$cltvTimeout (current block=$blockCount)") + log.info(s"delaying publication of ${p.desc} txid=${p.tx.txid} until block=$cltvTimeout (current block=$blockCount)") val cltvDelayedTxs1 = cltvDelayedTxs + (cltvTimeout -> (cltvDelayedTxs.getOrElse(cltvTimeout, Seq.empty) :+ p)) run(cltvDelayedTxs1, csvDelayedTx1) } else { @@ -225,11 +227,11 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, run(cltvDelayedTxs, csvDelayedTx1) } } else { - log.info(s"some parent txs of txid=${p.tx.txid} are still unconfirmed (parent txids=${txWithRelativeDelay1.parentTxIds.mkString(",")})") + log.info(s"some parent txs of ${p.desc} txid=${p.tx.txid} are still unconfirmed (parent txids=${txWithRelativeDelay1.parentTxIds.mkString(",")})") run(cltvDelayedTxs, csvDelayedTxs + (p.tx.txid -> txWithRelativeDelay1)) } case None => - log.warn(s"txid=${p.tx.txid} not found for parent txid=$parentTxId") + log.warn(s"${p.desc} txid=${p.tx.txid} not found for parent txid=$parentTxId") Behaviors.same } @@ -252,7 +254,7 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, private def publish(p: PublishTx): Future[ByteVector32] = { p match { case SignAndPublishTx(txInfo, commitments) => - log.info("publishing tx: input={}:{} txid={} tx={}", txInfo.input.outPoint.txid, txInfo.input.outPoint.index, p.tx.txid, p.tx) + log.info("publishing {}: input={}:{} txid={} tx={}", txInfo.desc, txInfo.input.outPoint.txid, txInfo.input.outPoint.index, p.tx.txid, p.tx) val publishF = txInfo match { case tx: ClaimLocalAnchorOutputTx => publishLocalAnchorTx(tx, commitments) case tx: HtlcTx => publishHtlcTx(tx, commitments) @@ -262,16 +264,16 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, } publishF.recoverWith { case t: Throwable if t.getMessage.contains("(code: -4)") || t.getMessage.contains("(code: -6)") => - log.warn("not enough funds to publish tx, will retry next block: reason={} input={}:{} txid={}", t.getMessage, txInfo.input.outPoint.txid, txInfo.input.outPoint.index, p.tx.txid) + log.warn("not enough funds to publish {}, will retry next block: reason={} input={}:{} txid={}", txInfo.desc, t.getMessage, txInfo.input.outPoint.txid, txInfo.input.outPoint.index, p.tx.txid) context.self ! PublishNextBlock(p) Future.failed(t) case t: Throwable => - log.error("cannot publish tx: reason={} input={}:{} txid={}", t.getMessage, txInfo.input.outPoint.txid, txInfo.input.outPoint.index, p.tx.txid) + log.error("cannot publish {}: reason={} input={}:{} txid={}", txInfo.desc, t.getMessage, txInfo.input.outPoint.txid, txInfo.input.outPoint.index, p.tx.txid) Future.failed(t) } - case PublishRawTx(tx) => - log.info("publishing tx: txid={} tx={}", tx.txid, tx) - publish(tx) + case PublishRawTx(tx, desc) => + log.info("publishing {}: txid={} tx={}", desc, tx.txid, tx) + publish(tx, desc) } } @@ -279,10 +281,10 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, * This method uses a single thread to publish transactions so that it preserves the order of publication. * We need that to prevent concurrency issues while publishing parent and child transactions. */ - private def publish(tx: Transaction): Future[ByteVector32] = { + private def publish(tx: Transaction, desc: String): Future[ByteVector32] = { client.publishTransaction(tx)(singleThreadExecutionContext).recoverWith { case t: Throwable => - log.error("cannot publish tx: reason={} txid={}", t.getMessage, tx.txid) + log.error("cannot publish {}: reason={} txid={}", desc, t.getMessage, tx.txid) Future.failed(t) } } @@ -296,17 +298,17 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, val commitTx = commitments.localCommit.publishableTxs.commitTx.tx val targetFeerate = feeEstimator.getFeeratePerKw(feeTargets.commitmentBlockTarget) if (targetFeerate <= commitFeerate) { - log.info(s"publishing commit tx without the anchor (current feerate=$commitFeerate): txid=${commitTx.txid}") + log.info(s"publishing commit-tx without the anchor (current feerate=$commitFeerate): txid=${commitTx.txid}") Future.successful(commitTx.txid) } else { - log.info(s"bumping commit tx with the anchor (target feerate=$targetFeerate): txid=${commitTx.txid}") + log.info(s"bumping commit-tx with the anchor (target feerate=$targetFeerate): txid=${commitTx.txid}") addInputs(txInfo, targetFeerate, commitments).flatMap(claimAnchorTx => { val claimAnchorSig = keyManager.sign(claimAnchorTx, keyManager.fundingPublicKey(commitments.localParams.fundingKeyPath), TxOwner.Local, commitments.commitmentFormat) val signedClaimAnchorTx = addSigs(claimAnchorTx, claimAnchorSig) val commitInfo = ExtendedBitcoinClient.PreviousTx(signedClaimAnchorTx.input, signedClaimAnchorTx.tx.txIn.head.witness) client.signTransaction(signedClaimAnchorTx.tx, Seq(commitInfo)) }).flatMap(signTxResponse => { - publish(signTxResponse.tx) + publish(signTxResponse.tx, txInfo.desc) }) } } @@ -366,10 +368,10 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, if (targetFeerate <= currentFeerate) { val localSig = keyManager.sign(txInfo, localHtlcBasepoint, localPerCommitmentPoint, TxOwner.Local, commitments.commitmentFormat) val signedHtlcTx = txWithWitnessData.addSigs(localSig, commitments.commitmentFormat) - log.info("publishing htlc tx without adding inputs: txid={}", signedHtlcTx.tx.txid) - publish(signedHtlcTx.tx) + log.info("publishing {} without adding inputs: txid={}", txInfo.desc, signedHtlcTx.tx.txid) + publish(signedHtlcTx.tx, txInfo.desc) } else { - log.info("publishing htlc tx with additional inputs: commit input={}:{} target feerate={}", txInfo.input.outPoint.txid, txInfo.input.outPoint.index, targetFeerate) + log.info("publishing {} with additional inputs: commit input={}:{} target feerate={}", txInfo.desc, txInfo.input.outPoint.txid, txInfo.input.outPoint.index, targetFeerate) addInputs(txInfo, targetFeerate, commitments).flatMap(unsignedTx => { val localSig = keyManager.sign(unsignedTx, localHtlcBasepoint, localPerCommitmentPoint, TxOwner.Local, commitments.commitmentFormat) val signedHtlcTx = txWithWitnessData.updateTx(unsignedTx.tx).addSigs(localSig, commitments.commitmentFormat) @@ -378,8 +380,8 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, // NB: bitcoind messes up the witness stack for our htlc input, so we need to restore it. // See /~https://github.com/bitcoin/bitcoin/issues/21151 val completeTx = signedHtlcTx.tx.copy(txIn = signedHtlcTx.tx.txIn.head +: signTxResponse.tx.txIn.tail) - log.info("publishing bumped htlc tx: commit input={}:{} txid={} tx={}", txInfo.input.outPoint.txid, txInfo.input.outPoint.index, completeTx.txid, completeTx) - publish(completeTx) + log.info("publishing bumped {}: commit input={}:{} txid={} tx={}", txInfo.desc, txInfo.input.outPoint.txid, txInfo.input.outPoint.index, completeTx.txid, completeTx) + publish(completeTx, txInfo.desc) }) }) } @@ -408,7 +410,7 @@ private class TxPublisher(nodeParams: NodeParams, watcher: akka.actor.ActorRef, // change output amount (unless bitcoind didn't add any change output, in that case we will overpay the fee slightly). val weightRatio = 1.0 + (htlcInputMaxWeight.toDouble / (htlcTxWeight + claimP2WPKHOutputWeight)) client.fundTransaction(txNotFunded, FundTransactionOptions(targetFeerate * weightRatio, lockUtxos = true, changePosition = Some(1))).map(fundTxResponse => { - log.info(s"added ${fundTxResponse.tx.txIn.length} wallet input(s) and ${fundTxResponse.tx.txOut.length - 1} wallet output(s) to htlc tx spending commit input=${txInfo.input.outPoint.txid}:${txInfo.input.outPoint.index}") + log.info(s"added ${fundTxResponse.tx.txIn.length} wallet input(s) and ${fundTxResponse.tx.txOut.length - 1} wallet output(s) to ${txInfo.desc} spending commit input=${txInfo.input.outPoint.txid}:${txInfo.input.outPoint.index}") // We add the HTLC input (from the commit tx) and restore the HTLC output. // NB: we can't modify them because they are signed by our peer (with SIGHASH_SINGLE | SIGHASH_ANYONECANPAY). val txWithHtlcInput = fundTxResponse.tx.copy( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala index e065ab4a2b..8bcb68f82e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala @@ -82,6 +82,7 @@ object Transactions { sealed trait TransactionWithInputInfo { def input: InputInfo + def desc: String def tx: Transaction def fee: Satoshi = input.txOut.amount - tx.txOut.map(_.amount).sum def minRelayFee: Satoshi = { @@ -92,7 +93,7 @@ object Transactions { def sighash(txOwner: TxOwner, commitmentFormat: CommitmentFormat): Int = SIGHASH_ALL } - case class CommitTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo + case class CommitTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo { override def desc: String = "commit-tx" } sealed trait HtlcTx extends TransactionWithInputInfo { def htlcId: Long override def sighash(txOwner: TxOwner, commitmentFormat: CommitmentFormat): Int = commitmentFormat match { @@ -103,22 +104,23 @@ object Transactions { } } } - case class HtlcSuccessTx(input: InputInfo, tx: Transaction, paymentHash: ByteVector32, htlcId: Long) extends HtlcTx - case class HtlcTimeoutTx(input: InputInfo, tx: Transaction, htlcId: Long) extends HtlcTx + case class HtlcSuccessTx(input: InputInfo, tx: Transaction, paymentHash: ByteVector32, htlcId: Long) extends HtlcTx { override def desc: String = "htlc-success" } + case class HtlcTimeoutTx(input: InputInfo, tx: Transaction, htlcId: Long) extends HtlcTx { override def desc: String = "htlc-timeout" } + case class HtlcDelayedTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo { override def desc: String = "htlc-delayed" } sealed trait ClaimHtlcTx extends TransactionWithInputInfo { def htlcId: Long } - case class ClaimHtlcSuccessTx(input: InputInfo, tx: Transaction, htlcId: Long) extends ClaimHtlcTx - case class ClaimHtlcTimeoutTx(input: InputInfo, tx: Transaction, htlcId: Long) extends ClaimHtlcTx + case class ClaimHtlcSuccessTx(input: InputInfo, tx: Transaction, htlcId: Long) extends ClaimHtlcTx { override def desc: String = "claim-htlc-success" } + case class ClaimHtlcTimeoutTx(input: InputInfo, tx: Transaction, htlcId: Long) extends ClaimHtlcTx { override def desc: String = "claim-htlc-timeout" } sealed trait ClaimAnchorOutputTx extends TransactionWithInputInfo - case class ClaimLocalAnchorOutputTx(input: InputInfo, tx: Transaction) extends ClaimAnchorOutputTx - case class ClaimRemoteAnchorOutputTx(input: InputInfo, tx: Transaction) extends ClaimAnchorOutputTx + case class ClaimLocalAnchorOutputTx(input: InputInfo, tx: Transaction) extends ClaimAnchorOutputTx { override def desc: String = "local-anchor" } + case class ClaimRemoteAnchorOutputTx(input: InputInfo, tx: Transaction) extends ClaimAnchorOutputTx { override def desc: String = "remote-anchor" } sealed trait ClaimRemoteCommitMainOutputTx extends TransactionWithInputInfo - case class ClaimP2WPKHOutputTx(input: InputInfo, tx: Transaction) extends ClaimRemoteCommitMainOutputTx - case class ClaimRemoteDelayedOutputTx(input: InputInfo, tx: Transaction) extends ClaimRemoteCommitMainOutputTx - case class ClaimLocalDelayedOutputTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo - case class ClaimHtlcDelayedOutputPenaltyTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo - case class MainPenaltyTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo - case class HtlcPenaltyTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo - case class ClosingTx(input: InputInfo, tx: Transaction, toLocalOutput: Option[OutputInfo]) extends TransactionWithInputInfo + case class ClaimP2WPKHOutputTx(input: InputInfo, tx: Transaction) extends ClaimRemoteCommitMainOutputTx { override def desc: String = "remote-main" } + case class ClaimRemoteDelayedOutputTx(input: InputInfo, tx: Transaction) extends ClaimRemoteCommitMainOutputTx { override def desc: String = "remote-main-delayed" } + case class ClaimLocalDelayedOutputTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo { override def desc: String = "local-main-delayed" } + case class MainPenaltyTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo { override def desc: String = "main-penalty" } + case class HtlcPenaltyTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo { override def desc: String = "htlc-penalty" } + case class ClaimHtlcDelayedOutputPenaltyTx(input: InputInfo, tx: Transaction) extends TransactionWithInputInfo { override def desc: String = "htlc-delayed-penalty" } + case class ClosingTx(input: InputInfo, tx: Transaction, toLocalOutput: Option[OutputInfo]) extends TransactionWithInputInfo { override def desc: String = "closing" } sealed trait TxGenerationSkipped case object OutputNotFound extends TxGenerationSkipped { override def toString = "output not found (probably trimmed)" } @@ -130,9 +132,9 @@ object Transactions { * - [[ClaimLocalDelayedOutputTx]] spends to-local output of [[CommitTx]] after a delay * - When using anchor outputs, [[ClaimLocalAnchorOutputTx]] spends to-local anchor of [[CommitTx]] * - [[HtlcSuccessTx]] spends htlc-received outputs of [[CommitTx]] for which we have the preimage - * - [[ClaimLocalDelayedOutputTx]] spends [[HtlcSuccessTx]] after a delay + * - [[HtlcDelayedTx]] spends [[HtlcSuccessTx]] after a delay * - [[HtlcTimeoutTx]] spends htlc-sent outputs of [[CommitTx]] after a timeout - * - [[ClaimLocalDelayedOutputTx]] spends [[HtlcTimeoutTx]] after a delay + * - [[HtlcDelayedTx]] spends [[HtlcTimeoutTx]] after a delay * * When *remote* *current* [[CommitTx]] is published: * - When using the default commitment format, [[ClaimP2WPKHOutputTx]] spends to-local output of [[CommitTx]] @@ -166,7 +168,7 @@ object Transactions { // 143 bytes (accepted_htlc_script) + 327 bytes (success_witness) + 41 bytes (commitment_input) = 511 bytes // See /~https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#expected-weight-of-htlc-timeout-and-htlc-success-transactions val htlcInputMaxWeight = 511 - val claimHtlcDelayedWeight = 483 + val htlcDelayedWeight = 483 val claimHtlcSuccessWeight = 571 val claimHtlcTimeoutWeight = 545 val mainPenaltyWeight = 484 @@ -593,13 +595,25 @@ object Transactions { } } + def makeHtlcDelayedTx(htlcTx: Transaction, localDustLimit: Satoshi, localRevocationPubkey: PublicKey, toLocalDelay: CltvExpiryDelta, localDelayedPaymentPubkey: PublicKey, localFinalScriptPubKey: ByteVector, feeratePerKw: FeeratePerKw): Either[TxGenerationSkipped, HtlcDelayedTx] = { + makeLocalDelayedOutputTx(htlcTx, localDustLimit, localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey, localFinalScriptPubKey, feeratePerKw).map { + case (input, tx) => HtlcDelayedTx(input, tx) + } + } + def makeClaimLocalDelayedOutputTx(commitTx: Transaction, localDustLimit: Satoshi, localRevocationPubkey: PublicKey, toLocalDelay: CltvExpiryDelta, localDelayedPaymentPubkey: PublicKey, localFinalScriptPubKey: ByteVector, feeratePerKw: FeeratePerKw): Either[TxGenerationSkipped, ClaimLocalDelayedOutputTx] = { + makeLocalDelayedOutputTx(commitTx, localDustLimit, localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey, localFinalScriptPubKey, feeratePerKw).map { + case (input, tx) => ClaimLocalDelayedOutputTx(input, tx) + } + } + + private def makeLocalDelayedOutputTx(parentTx: Transaction, localDustLimit: Satoshi, localRevocationPubkey: PublicKey, toLocalDelay: CltvExpiryDelta, localDelayedPaymentPubkey: PublicKey, localFinalScriptPubKey: ByteVector, feeratePerKw: FeeratePerKw): Either[TxGenerationSkipped, (InputInfo, Transaction)] = { val redeemScript = toLocalDelayed(localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey) val pubkeyScript = write(pay2wsh(redeemScript)) - findPubKeyScriptIndex(commitTx, pubkeyScript) match { + findPubKeyScriptIndex(parentTx, pubkeyScript) match { case Left(skip) => Left(skip) case Right(outputIndex) => - val input = InputInfo(OutPoint(commitTx, outputIndex), commitTx.txOut(outputIndex), write(redeemScript)) + val input = InputInfo(OutPoint(parentTx, outputIndex), parentTx.txOut(outputIndex), write(redeemScript)) // unsigned transaction val tx = Transaction( version = 2, @@ -614,7 +628,7 @@ object Transactions { Left(AmountBelowDustLimit) } else { val tx1 = tx.copy(txOut = tx.txOut.head.copy(amount = amount) :: Nil) - Right(ClaimLocalDelayedOutputTx(input, tx1)) + Right(input, tx1) } } } @@ -837,6 +851,11 @@ object Transactions { claimDelayedOutputTx.copy(tx = claimDelayedOutputTx.tx.updateWitness(0, witness)) } + def addSigs(htlcDelayedTx: HtlcDelayedTx, localSig: ByteVector64): HtlcDelayedTx = { + val witness = witnessToLocalDelayedAfterDelay(localSig, htlcDelayedTx.input.redeemScript) + htlcDelayedTx.copy(tx = htlcDelayedTx.tx.updateWitness(0, witness)) + } + def addSigs(claimAnchorOutputTx: ClaimLocalAnchorOutputTx, localSig: ByteVector64): ClaimLocalAnchorOutputTx = { val witness = witnessAnchor(localSig, claimAnchorOutputTx.input.redeemScript) claimAnchorOutputTx.copy(tx = claimAnchorOutputTx.tx.updateWitness(0, witness)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala index 16e477e214..5595284450 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala @@ -57,7 +57,7 @@ private[channel] object ChannelTypes0 { val claimHtlcDelayedTxsNew = claimHtlcDelayedTxs.map(tx => { val htlcTx = htlcTxs.find(_.txid == tx.txIn.head.outPoint.txid) require(htlcTx.nonEmpty, s"3rd-stage htlc tx doesn't spend one of our htlc txs: claim-htlc-tx=$tx, htlc-txs=${htlcTxs.mkString(",")}") - ClaimLocalDelayedOutputTx(getPartialInputInfo(htlcTx.get, tx), tx) + HtlcDelayedTx(getPartialInputInfo(htlcTx.get, tx), tx) }) channel.LocalCommitPublished(commitTx, claimMainDelayedOutputTxNew, htlcTxsNew, claimHtlcDelayedTxsNew, Nil, irrevocablySpentNew) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala index 7dd4abbb95..597b526ec7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala @@ -104,6 +104,7 @@ private[channel] object ChannelCodecs2 { val commitTxCodec: Codec[CommitTx] = (("inputInfo" | inputInfoCodec) :: ("tx" | txCodec)).as[CommitTx] val htlcSuccessTxCodec: Codec[HtlcSuccessTx] = (("inputInfo" | inputInfoCodec) :: ("tx" | txCodec) :: ("paymentHash" | bytes32) :: ("htlcId" | uint64overflow)).as[HtlcSuccessTx] val htlcTimeoutTxCodec: Codec[HtlcTimeoutTx] = (("inputInfo" | inputInfoCodec) :: ("tx" | txCodec) :: ("htlcId" | uint64overflow)).as[HtlcTimeoutTx] + val htlcDelayedTxCodec: Codec[HtlcDelayedTx] = (("inputInfo" | inputInfoCodec) :: ("tx" | txCodec)).as[HtlcDelayedTx] val claimHtlcSuccessTxCodec: Codec[ClaimHtlcSuccessTx] = (("inputInfo" | inputInfoCodec) :: ("tx" | txCodec) :: ("htlcId" | uint64overflow)).as[ClaimHtlcSuccessTx] val claimHtlcTimeoutTxCodec: Codec[ClaimHtlcTimeoutTx] = (("inputInfo" | inputInfoCodec) :: ("tx" | txCodec) :: ("htlcId" | uint64overflow)).as[ClaimHtlcTimeoutTx] val claimLocalDelayedOutputTxCodec: Codec[ClaimLocalDelayedOutputTx] = (("inputInfo" | inputInfoCodec) :: ("tx" | txCodec)).as[ClaimLocalDelayedOutputTx] @@ -131,6 +132,7 @@ private[channel] object ChannelCodecs2 { .typecase(0x12, claimRemoteAnchorOutputTxCodec) .typecase(0x13, claimRemoteDelayedOutputTxCodec) .typecase(0x14, claimHtlcDelayedOutputPenaltyTxCodec) + .typecase(0x15, htlcDelayedTxCodec) val claimRemoteCommitMainOutputTxCodec: Codec[ClaimRemoteCommitMainOutputTx] = discriminated[ClaimRemoteCommitMainOutputTx].by(uint8) .typecase(0x01, claimP2WPKHOutputTxCodec) @@ -239,7 +241,7 @@ private[channel] object ChannelCodecs2 { ("commitTx" | txCodec) :: ("claimMainDelayedOutputTx" | optional(bool8, claimLocalDelayedOutputTxCodec)) :: ("htlcTxs" | mapCodec(outPointCodec, optional(bool8, htlcTxCodec))) :: - ("claimHtlcDelayedTx" | listOfN(uint16, claimLocalDelayedOutputTxCodec)) :: + ("claimHtlcDelayedTx" | listOfN(uint16, htlcDelayedTxCodec)) :: ("claimAnchorTxs" | listOfN(uint16, claimAnchorOutputTxCodec)) :: ("spent" | spentMapCodec)).as[LocalCommitPublished] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/TxPublisherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/TxPublisherSpec.scala index b94b6dbcc1..18ec4a2792 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/TxPublisherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/TxPublisherSpec.scala @@ -146,7 +146,7 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin bitcoinWallet.signTransaction(funded).pipeTo(probe.ref) probe.expectMsgType[SignTransactionResponse].tx } - txPublisher ! PublishRawTx(tx1) + txPublisher ! PublishRawTx(tx1, "funding-tx") createBlocks(4) assert(!getMempool.exists(_.txid === tx1.txid)) // tx should not be broadcast yet createBlocks(1) @@ -154,7 +154,7 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin // tx2 has a relative delay but no absolute delay val tx2 = createSpendP2WPKH(tx1, priv, priv.publicKey, 10000 sat, sequence = 2, lockTime = 0) - txPublisher ! PublishRawTx(tx2) + txPublisher ! PublishRawTx(tx2, "child-tx") val watchParentTx2 = alice2blockchain.expectMsgType[WatchConfirmed] assert(watchParentTx2.txId === tx1.txid) assert(watchParentTx2.minDepth === 2) @@ -164,7 +164,7 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin // tx3 has both relative and absolute delays val tx3 = createSpendP2WPKH(tx2, priv, priv.publicKey, 10000 sat, sequence = 1, lockTime = blockCount.get + 5) - txPublisher ! PublishRawTx(tx3) + txPublisher ! PublishRawTx(tx3, "grand-child-tx") val watchParentTx3 = alice2blockchain.expectMsgType[WatchConfirmed] assert(watchParentTx3.txId === tx2.txid) assert(watchParentTx3.minDepth === 1) @@ -191,8 +191,8 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin bitcoinWallet.signTransaction(funded).pipeTo(probe.ref) probe.expectMsgType[SignTransactionResponse].tx }) - txPublisher ! PublishRawTx(parentTx1) - txPublisher ! PublishRawTx(parentTx2) + txPublisher ! PublishRawTx(parentTx1, "parent-tx-1") + txPublisher ! PublishRawTx(parentTx2, "parent-tx-2") assert(getMempoolTxs(2).map(_.txid).toSet === Set(parentTx1.txid, parentTx2.txid)) val tx = { @@ -213,7 +213,7 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin } Transaction.correctlySpends(tx, parentTx1 :: parentTx2 :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) - txPublisher ! PublishRawTx(tx) + txPublisher ! PublishRawTx(tx, "child-tx") val watches = Seq( alice2blockchain.expectMsgType[WatchConfirmed], alice2blockchain.expectMsgType[WatchConfirmed], @@ -237,20 +237,20 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin def closeChannelWithoutHtlcs(f: Fixture): (Transaction, SignAndPublishTx) = { import f._ - val commitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx + val commitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx probe.send(alice, CMD_FORCECLOSE(probe.ref)) probe.expectMsgType[CommandSuccess[CMD_FORCECLOSE]] // Forward the commit tx to the publisher. - val commit = alice2blockchain.expectMsg(PublishRawTx(commitTx)) + val commit = alice2blockchain.expectMsg(PublishRawTx(commitTx.tx, commitTx.desc)) txPublisher ! commit // Forward the anchor tx to the publisher. val anchor = alice2blockchain.expectMsgType[SignAndPublishTx] - assert(anchor.txInfo.input.outPoint.txid === commitTx.txid) + assert(anchor.txInfo.input.outPoint.txid === commitTx.tx.txid) assert(anchor.txInfo.isInstanceOf[ClaimLocalAnchorOutputTx]) txPublisher ! anchor - (commitTx, anchor) + (commitTx.tx, anchor) } test("commit tx feerate high enough, not spending anchor output") { @@ -391,15 +391,15 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin probe.expectMsgType[CommandSuccess[CMD_FULFILL_HTLC]] // Force-close channel and verify txs sent to watcher. - val commitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx + val commitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx val currentFeerate = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.spec.feeratePerKw assert(currentFeerate < TestConstants.feeratePerKw) - assert(commitTx.txOut.size === 6) + assert(commitTx.tx.txOut.size === 6) probe.send(alice, CMD_FORCECLOSE(probe.ref)) probe.expectMsgType[CommandSuccess[CMD_FORCECLOSE]] - alice2blockchain.expectMsg(PublishRawTx(commitTx)) - txPublisher ! PublishRawTx(commitTx) + alice2blockchain.expectMsg(PublishRawTx(commitTx.tx, commitTx.desc)) + txPublisher ! PublishRawTx(commitTx.tx, commitTx.desc) assert(alice2blockchain.expectMsgType[SignAndPublishTx].txInfo.isInstanceOf[ClaimLocalAnchorOutputTx]) alice2blockchain.expectMsgType[PublishRawTx] // claim main output val htlcSuccess = alice2blockchain.expectMsgType[SignAndPublishTx] @@ -413,7 +413,7 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin alice2blockchain.expectMsgType[WatchSpent] // htlc-timeout tx alice2blockchain.expectNoMessage(100 millis) - (commitTx, htlcSuccess, htlcTimeout) + (commitTx.tx, htlcSuccess, htlcTimeout) } test("htlc tx feerate high enough, not adding wallet inputs") { @@ -548,11 +548,11 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin crossSign(bob, alice, bob2alice, alice2bob) // Force-close channel and verify txs sent to watcher. - val commitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - assert(commitTx.txOut.size === 5) + val commitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx + assert(commitTx.tx.txOut.size === 5) probe.send(alice, CMD_FORCECLOSE(probe.ref)) probe.expectMsgType[CommandSuccess[CMD_FORCECLOSE]] - alice2blockchain.expectMsg(PublishRawTx(commitTx)) + alice2blockchain.expectMsg(PublishRawTx(commitTx.tx, commitTx.desc)) val anchorTx = alice2blockchain.expectMsgType[SignAndPublishTx] alice2blockchain.expectMsgType[PublishRawTx] // claim main output alice2blockchain.expectMsgType[WatchConfirmed] // commit tx @@ -561,14 +561,14 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin alice2blockchain.expectNoMessage(100 millis) // Publish and confirm the commit tx. - txPublisher ! PublishRawTx(commitTx) + txPublisher ! PublishRawTx(commitTx.tx, commitTx.desc) txPublisher ! anchorTx getMempoolTxs(2) createBlocks(2) probe.send(alice, CMD_FULFILL_HTLC(htlc.id, r, replyTo_opt = Some(probe.ref))) probe.expectMsgType[CommandSuccess[CMD_FULFILL_HTLC]] - alice2blockchain.expectMsg(PublishRawTx(commitTx)) + alice2blockchain.expectMsg(PublishRawTx(commitTx.tx, commitTx.desc)) val anchorTx2 = alice2blockchain.expectMsgType[SignAndPublishTx] assert(anchorTx2.txInfo === anchorTx.txInfo) alice2blockchain.expectMsgType[PublishRawTx] // claim main output @@ -580,9 +580,9 @@ class TxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike with Bitcoin txPublisher ! htlcSuccess val w = alice2blockchain.expectMsgType[WatchConfirmed] - assert(w.txId === commitTx.txid) + assert(w.txId === commitTx.tx.txid) assert(w.minDepth === 1) - txPublisher ! ParentTxConfirmed(htlcSuccess, commitTx.txid) + txPublisher ! ParentTxConfirmed(htlcSuccess, commitTx.tx.txid) // The HTLC-success tx will be immediately published. val htlcSuccessTx = getMempoolTxs(1).head 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 0407a962df..ff53bd7fa4 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 @@ -281,11 +281,11 @@ trait StateTestsHelperMethods extends TestKitBase { assert(s2blockchain.expectMsgType[SignAndPublishTx].txInfo.isInstanceOf[ClaimLocalAnchorOutputTx]) } // if s has a main output in the commit tx (when it has a non-dust balance), it should be claimed - localCommitPublished.claimMainDelayedOutputTx.foreach(tx => s2blockchain.expectMsg(PublishRawTx(tx.tx))) + localCommitPublished.claimMainDelayedOutputTx.foreach(tx => s2blockchain.expectMsg(PublishRawTx(tx.tx, tx.desc))) closingState.commitments.commitmentFormat match { case Transactions.DefaultCommitmentFormat => // all htlcs success/timeout should be published as-is, without claiming their outputs - s2blockchain.expectMsgAllOf(localCommitPublished.htlcTxs.values.toSeq.collect { case Some(tx) => PublishRawTx(tx.tx) }: _*) + s2blockchain.expectMsgAllOf(localCommitPublished.htlcTxs.values.toSeq.collect { case Some(tx) => PublishRawTx(tx.tx, tx.desc) }: _*) assert(localCommitPublished.claimHtlcDelayedTxs.isEmpty) case Transactions.AnchorOutputsCommitmentFormat => // all htlcs success/timeout should be published with a fee bumping strategy, without claiming their outputs @@ -325,12 +325,12 @@ trait StateTestsHelperMethods extends TestKitBase { // if s has a main output in the commit tx (when it has a non-dust balance), it should be claimed remoteCommitPublished.claimMainOutputTx.foreach(claimMain => { Transaction.correctlySpends(claimMain.tx, rCommitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) - s2blockchain.expectMsg(PublishRawTx(claimMain.tx)) + s2blockchain.expectMsg(PublishRawTx(claimMain.tx, claimMain.desc)) }) // all htlcs success/timeout should be claimed val claimHtlcTxs = remoteCommitPublished.claimHtlcTxs.values.collect { case Some(tx: ClaimHtlcTx) => tx }.toSeq claimHtlcTxs.foreach(claimHtlc => Transaction.correctlySpends(claimHtlc.tx, rCommitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)) - s2blockchain.expectMsgAllOf(claimHtlcTxs.map(claimHtlc => PublishRawTx(claimHtlc.tx)): _*) + s2blockchain.expectMsgAllOf(claimHtlcTxs.map(claimHtlc => PublishRawTx(claimHtlc.tx, claimHtlc.desc)): _*) // we watch the confirmation of the "final" transactions that send funds to our wallets (main delayed output and 2nd stage htlc transactions) assert(s2blockchain.expectMsgType[WatchConfirmed].event == BITCOIN_TX_CONFIRMED(rCommitTx)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala index 01a12328a2..4939e6d30c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala @@ -173,7 +173,7 @@ class WaitForFundingConfirmedStateSpec extends TestKitBaseClass with FixtureAnyF val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CONFIRMED].commitments.localCommit.publishableTxs.commitTx.tx alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, Transaction(0, Nil, Nil, 0)) alice2bob.expectMsgType[Error] - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) awaitCond(alice.stateName == ERR_INFORMATION_LEAK) } @@ -182,7 +182,7 @@ class WaitForFundingConfirmedStateSpec extends TestKitBaseClass with FixtureAnyF val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CONFIRMED].commitments.localCommit.publishableTxs.commitTx.tx alice ! Error(ByteVector32.Zeroes, "oops") awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] // claim-main-delayed assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(tx)) } @@ -201,7 +201,7 @@ class WaitForFundingConfirmedStateSpec extends TestKitBaseClass with FixtureAnyF val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CONFIRMED].commitments.localCommit.publishableTxs.commitTx.tx alice ! CMD_FORCECLOSE(sender.ref) awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] // claim-main-delayed assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(tx)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala index 43e91908f2..5fd94ce0bf 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala @@ -103,7 +103,7 @@ class WaitForFundingLockedStateSpec extends TestKitBaseClass with FixtureAnyFunS val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_LOCKED].commitments.localCommit.publishableTxs.commitTx.tx alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, Transaction(0, Nil, Nil, 0)) alice2bob.expectMsgType[Error] - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] awaitCond(alice.stateName == ERR_INFORMATION_LEAK) } @@ -113,7 +113,7 @@ class WaitForFundingLockedStateSpec extends TestKitBaseClass with FixtureAnyFunS val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_LOCKED].commitments.localCommit.publishableTxs.commitTx.tx alice ! Error(ByteVector32.Zeroes, "oops") awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(tx)) } @@ -132,7 +132,7 @@ class WaitForFundingLockedStateSpec extends TestKitBaseClass with FixtureAnyFunS val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_LOCKED].commitments.localCommit.publishableTxs.commitTx.tx alice ! CMD_FORCECLOSE(sender.ref) awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(tx)) } 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 bc97b48691..c69c8e9df9 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 @@ -444,7 +444,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === UnexpectedHtlcId(channelId(bob), expected = 4, actual = 42).getMessage) awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -459,7 +459,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -474,7 +474,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -505,7 +505,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -521,7 +521,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -535,7 +535,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -553,7 +553,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -867,7 +867,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -882,7 +882,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray).startsWith("invalid commitment signature")) awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -901,7 +901,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with bob ! badCommitSig val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === HtlcSigCountMismatch(channelId(bob), expected = 1, actual = 2).getMessage) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -920,7 +920,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with bob ! badCommitSig val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray).startsWith("invalid htlc signature")) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -1032,7 +1032,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -1046,7 +1046,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -1286,7 +1286,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -1299,7 +1299,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -1317,7 +1317,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout alice2blockchain.expectMsgType[WatchConfirmed] @@ -1487,7 +1487,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val error = alice2bob.expectMsgType[Error] assert(new String(error.data.toArray) === InvalidFailureCode(ByteVector32.Zeroes).getMessage) awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout alice2blockchain.expectMsgType[WatchConfirmed] @@ -1506,7 +1506,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -1519,7 +1519,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -1611,7 +1611,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(alice.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === alice.stateData.asInstanceOf[DATA_CLOSING].channelId) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] alice2blockchain.expectMsgType[WatchConfirmed] } @@ -1628,7 +1628,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx //bob2blockchain.expectMsgType[PublishTx] // main delayed (removed because of the high fees) bob2blockchain.expectMsgType[WatchConfirmed] } @@ -1662,7 +1662,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(commitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === commitTx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -1717,7 +1717,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -2047,7 +2047,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val aliceCommitTx = initialState.commitments.localCommit.publishableTxs.commitTx.tx alice ! CurrentBlockCount(400145) - alice2blockchain.expectMsg(PublishRawTx(aliceCommitTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === aliceCommitTx) alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout @@ -2081,7 +2081,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with assert(isFatal) assert(err.isInstanceOf[HtlcsWillTimeoutUpstream]) - bob2blockchain.expectMsg(PublishRawTx(initialCommitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === initialCommitTx) bob2blockchain.expectMsgType[PublishTx] // main delayed assert(bob2blockchain.expectMsgType[PublishTx].tx.txOut === htlcSuccessTx.txOut) assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(initialCommitTx)) @@ -2114,7 +2114,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with assert(isFatal) assert(err.isInstanceOf[HtlcsWillTimeoutUpstream]) - bob2blockchain.expectMsg(PublishRawTx(initialCommitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === initialCommitTx) bob2blockchain.expectMsgType[PublishTx] // main delayed assert(bob2blockchain.expectMsgType[PublishTx].tx.txOut === htlcSuccessTx.txOut) assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(initialCommitTx)) @@ -2151,7 +2151,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with assert(isFatal) assert(err.isInstanceOf[HtlcsWillTimeoutUpstream]) - bob2blockchain.expectMsg(PublishRawTx(initialCommitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === initialCommitTx) bob2blockchain.expectMsgType[PublishTx] // main delayed assert(bob2blockchain.expectMsgType[PublishTx].tx.txOut === htlcSuccessTx.txOut) assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(initialCommitTx)) @@ -2510,7 +2510,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // an error occurs and alice publishes her commit tx val aliceCommitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx alice ! Error(ByteVector32.Zeroes, "oops") - alice2blockchain.expectMsg(PublishRawTx(aliceCommitTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === aliceCommitTx) assert(aliceCommitTx.txOut.size == 6) // two main outputs and 4 pending htlcs awaitCond(alice.stateName == CLOSING) assert(alice.stateData.asInstanceOf[DATA_CLOSING].localCommitPublished.isDefined) @@ -2563,7 +2563,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // an error occurs and alice publishes her commit tx val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx bob ! Error(ByteVector32.Zeroes, "oops") - bob2blockchain.expectMsg(PublishRawTx(bobCommitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === bobCommitTx) assert(bobCommitTx.txOut.size == 1) // only one main output alice2blockchain.expectNoMsg(1 second) 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 fdbeb48fe3..8dae3f9f88 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 @@ -483,13 +483,13 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with assert(isFatal) assert(err.isInstanceOf[HtlcsWillTimeoutUpstream]) - bob2blockchain.expectMsg(PublishRawTx(initialCommitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === initialCommitTx) bob2blockchain.expectMsgType[PublishTx] // main delayed assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(initialCommitTx)) bob2blockchain.expectMsgType[WatchConfirmed] // main delayed bob2blockchain.expectMsgType[WatchSpent] // htlc - bob2blockchain.expectMsg(PublishRawTx(initialCommitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === initialCommitTx) bob2blockchain.expectMsgType[PublishTx] // main delayed assert(bob2blockchain.expectMsgType[PublishTx].tx.txOut === htlcSuccessTx.txOut) assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(initialCommitTx)) @@ -546,7 +546,7 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // alice is funder alice ! CurrentFeerates(networkFeerate) if (shouldClose) { - alice2blockchain.expectMsg(PublishRawTx(aliceCommitTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === aliceCommitTx) } else { alice2blockchain.expectNoMsg() } @@ -655,7 +655,7 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // bob is fundee bob ! CurrentFeerates(networkFeerate) if (shouldClose) { - bob2blockchain.expectMsg(PublishRawTx(bobCommitTx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === bobCommitTx) } else { bob2blockchain.expectNoMsg() } 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 d9e68267da..acb29237bb 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 @@ -184,7 +184,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit alice ! fulfill alice2bob.expectMsgType[Error] awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout 1 alice2blockchain.expectMsgType[PublishTx] // htlc timeout 2 @@ -197,7 +197,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit alice ! UpdateFulfillHtlc(ByteVector32.Zeroes, 42, ByteVector32.Zeroes) alice2bob.expectMsgType[Error] awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout 1 alice2blockchain.expectMsgType[PublishTx] // htlc timeout 2 @@ -288,7 +288,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit alice ! UpdateFailHtlc(ByteVector32.Zeroes, 42, ByteVector.fill(152)(0)) alice2bob.expectMsgType[Error] awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout 1 alice2blockchain.expectMsgType[PublishTx] // htlc timeout 2 @@ -311,7 +311,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit val error = alice2bob.expectMsgType[Error] assert(new String(error.data.toArray) === InvalidFailureCode(ByteVector32.Zeroes).getMessage) awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout 1 alice2blockchain.expectMsgType[PublishTx] // htlc timeout 2 @@ -379,7 +379,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit bob ! CommitSig(ByteVector32.Zeroes, ByteVector64.Zeroes, Nil) bob2alice.expectMsgType[Error] awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx bob2blockchain.expectMsgType[PublishTx] // main delayed bob2blockchain.expectMsgType[WatchConfirmed] } @@ -390,7 +390,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit bob ! CommitSig(ByteVector32.Zeroes, ByteVector64.Zeroes, Nil) bob2alice.expectMsgType[Error] awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx bob2blockchain.expectMsgType[PublishTx] // main delayed bob2blockchain.expectMsgType[WatchConfirmed] } @@ -446,7 +446,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit bob ! RevokeAndAck(ByteVector32.Zeroes, PrivateKey(randomBytes32), PrivateKey(randomBytes32).publicKey) bob2alice.expectMsgType[Error] awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx bob2blockchain.expectMsgType[PublishTx] // main delayed bob2blockchain.expectMsgType[PublishTx] // htlc success bob2blockchain.expectMsgType[WatchConfirmed] @@ -459,7 +459,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit alice ! RevokeAndAck(ByteVector32.Zeroes, PrivateKey(randomBytes32), PrivateKey(randomBytes32).publicKey) alice2bob.expectMsgType[Error] awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout 1 alice2blockchain.expectMsgType[PublishTx] // htlc timeout 2 @@ -547,7 +547,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit alice ! UpdateFee(ByteVector32.Zeroes, FeeratePerKw(12000 sat)) alice2bob.expectMsgType[Error] awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout 1 alice2blockchain.expectMsgType[PublishTx] // htlc timeout 2 @@ -564,7 +564,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === CannotAffordFees(channelId(bob), missing = 72120000L sat, reserve = 20000L sat, fees = 72400000L sat).getMessage) awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx //bob2blockchain.expectMsgType[PublishTx] // main delayed (removed because of the high fees) bob2blockchain.expectMsgType[WatchConfirmed] } @@ -576,7 +576,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === "local/remote feerates are too different: remoteFeeratePerKw=65000 localFeeratePerKw=10000") awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx bob2blockchain.expectMsgType[PublishTx] // main delayed bob2blockchain.expectMsgType[WatchConfirmed] } @@ -588,7 +588,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === "remote fee rate is too small: remoteFeeratePerKw=252") awaitCond(bob.stateName == CLOSING) - bob2blockchain.expectMsg(PublishRawTx(tx)) // commit tx + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) // commit tx bob2blockchain.expectMsgType[PublishTx] // main delayed bob2blockchain.expectMsgType[WatchConfirmed] } @@ -615,7 +615,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit val initialState = alice.stateData.asInstanceOf[DATA_SHUTDOWN] val aliceCommitTx = initialState.commitments.localCommit.publishableTxs.commitTx.tx alice ! CurrentBlockCount(400145) - alice2blockchain.expectMsg(PublishRawTx(aliceCommitTx)) // commit tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === aliceCommitTx) // commit tx alice2blockchain.expectMsgType[PublishTx] // main delayed alice2blockchain.expectMsgType[PublishTx] // htlc timeout 1 alice2blockchain.expectMsgType[PublishTx] // htlc timeout 2 @@ -851,7 +851,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit val sender = TestProbe() alice ! CMD_FORCECLOSE(sender.ref) sender.expectMsgType[RES_SUCCESS[CMD_FORCECLOSE]] - alice2blockchain.expectMsg(PublishRawTx(aliceCommitTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === aliceCommitTx) awaitCond(alice.stateName == CLOSING) assert(alice.stateData.asInstanceOf[DATA_CLOSING].localCommitPublished.isDefined) val lcp = alice.stateData.asInstanceOf[DATA_CLOSING].localCommitPublished.get @@ -885,7 +885,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit import f._ val aliceCommitTx = alice.stateData.asInstanceOf[DATA_SHUTDOWN].commitments.localCommit.publishableTxs.commitTx.tx alice ! Error(ByteVector32.Zeroes, "oops") - alice2blockchain.expectMsg(PublishRawTx(aliceCommitTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === aliceCommitTx) assert(aliceCommitTx.txOut.size == 4) // two main outputs and two htlcs awaitCond(alice.stateName == CLOSING) assert(alice.stateData.asInstanceOf[DATA_CLOSING].localCommitPublished.isDefined) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala index 2864fdf4c1..f5704626aa 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala @@ -163,7 +163,7 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike sender.send(bob, aliceCloseSig.copy(feeSatoshis = 99000 sat)) // sig doesn't matter, it is checked later val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray).startsWith("invalid close fee: fee_satoshis=Satoshi(99000)")) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -175,7 +175,7 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike bob ! aliceCloseSig.copy(signature = ByteVector64.Zeroes) val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray).startsWith("invalid close signature")) - bob2blockchain.expectMsg(PublishRawTx(tx)) + assert(bob2blockchain.expectMsgType[PublishRawTx].tx === tx) bob2blockchain.expectMsgType[PublishTx] bob2blockchain.expectMsgType[WatchConfirmed] } @@ -200,7 +200,7 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike val mutualCloseTx = bob2blockchain.expectMsgType[PublishTx].tx assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(mutualCloseTx)) alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, mutualCloseTx) - alice2blockchain.expectMsg(PublishRawTx(mutualCloseTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === mutualCloseTx) assert(alice2blockchain.expectMsgType[WatchConfirmed].txId === mutualCloseTx.txid) alice2blockchain.expectNoMsg(100 millis) assert(alice.stateName == CLOSING) @@ -220,7 +220,7 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike val Right(bobClosingTx) = Closing.checkClosingSignature(Bob.channelKeyManager, d.commitments, d.localShutdown.scriptPubKey, d.remoteShutdown.scriptPubKey, aliceClose1.feeSatoshis, aliceClose1.signature) alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, bobClosingTx.tx) - alice2blockchain.expectMsg(PublishRawTx(bobClosingTx.tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === bobClosingTx.tx) assert(alice2blockchain.expectMsgType[WatchConfirmed].txId === bobClosingTx.tx.txid) alice2blockchain.expectNoMsg(100 millis) assert(alice.stateName == CLOSING) @@ -238,7 +238,7 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike val tx = alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localCommit.publishableTxs.commitTx.tx alice ! Error(ByteVector32.Zeroes, "oops") awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === tx) alice2blockchain.expectMsgType[PublishTx] assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(tx)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala index e384d16009..fea556c959 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala @@ -194,7 +194,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // test starts here alice ! GetTxWithMetaResponse(fundingTx.txid, None, System.currentTimeMillis.milliseconds.toSeconds) alice2bob.expectNoMsg(200 millis) - alice2blockchain.expectMsg(PublishRawTx(fundingTx)) // we republish the funding tx + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === fundingTx) // we republish the funding tx assert(alice.stateName == CLOSING) // the above expectNoMsg will make us wait, so this checks that we are still in CLOSING } @@ -304,7 +304,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // let's make alice publish this closing tx alice ! Error(ByteVector32.Zeroes, "") awaitCond(alice.stateName == CLOSING) - alice2blockchain.expectMsg(PublishRawTx(mutualCloseTx.tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === mutualCloseTx.tx) assert(mutualCloseTx === alice.stateData.asInstanceOf[DATA_CLOSING].mutualClosePublished.last) // actual test starts here @@ -779,10 +779,10 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // Alice receives the preimage for the first HTLC from downstream; she can now claim the corresponding HTLC output. alice ! CMD_FULFILL_HTLC(htlc1.id, r1, commit = true) - alice2blockchain.expectMsg(PublishRawTx(closingState.claimMainOutputTx.get.tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === closingState.claimMainOutputTx.get.tx) val claimHtlcSuccessTx = getClaimHtlcSuccessTxs(alice.stateData.asInstanceOf[DATA_CLOSING].remoteCommitPublished.get).head.tx Transaction.correctlySpends(claimHtlcSuccessTx, bobCommitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) - alice2blockchain.expectMsg(PublishRawTx(claimHtlcSuccessTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === claimHtlcSuccessTx) // Alice resets watches on all relevant transactions. assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(bobCommitTx)) @@ -948,11 +948,11 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // Alice receives the preimage for the first HTLC from downstream; she can now claim the corresponding HTLC output. alice ! CMD_FULFILL_HTLC(htlc1.id, r1, commit = true) - alice2blockchain.expectMsg(PublishRawTx(closingState.claimMainOutputTx.get.tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === closingState.claimMainOutputTx.get.tx) val claimHtlcSuccessTx = getClaimHtlcSuccessTxs(alice.stateData.asInstanceOf[DATA_CLOSING].nextRemoteCommitPublished.get).head.tx Transaction.correctlySpends(claimHtlcSuccessTx, bobCommitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) - alice2blockchain.expectMsg(PublishRawTx(claimHtlcSuccessTx)) - alice2blockchain.expectMsg(PublishRawTx(claimHtlcTimeoutTx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === claimHtlcSuccessTx) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === claimHtlcTimeoutTx) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(bobCommitTx)) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(closingState.claimMainOutputTx.get.tx)) @@ -1192,9 +1192,9 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // alice publishes the penalty txs if (!channelVersion.paysDirectlyToWallet) { - alice2blockchain.expectMsg(PublishRawTx(rvk.claimMainOutputTx.get.tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === rvk.claimMainOutputTx.get.tx) } - alice2blockchain.expectMsg(PublishRawTx(rvk.mainPenaltyTx.get.tx)) + assert(alice2blockchain.expectMsgType[PublishRawTx].tx === rvk.mainPenaltyTx.get.tx) assert(Set(alice2blockchain.expectMsgType[PublishTx].tx, alice2blockchain.expectMsgType[PublishTx].tx) === rvk.htlcPenaltyTxs.map(_.tx).toSet) for (penaltyTx <- penaltyTxs) { Transaction.correctlySpends(penaltyTx.tx, bobRevokedTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) 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 923795ecfb..a95051c3d3 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 @@ -127,15 +127,15 @@ class TransactionsSpec extends AnyFunSuite with Logging { assert(claimP2WPKHOutputTx.fee >= claimP2WPKHOutputTx.minRelayFee) } { - // ClaimHtlcDelayedTx - // first we create a fake htlcSuccessOrTimeoutTx tx, containing only the output that will be spent by the ClaimDelayedOutputTx + // HtlcDelayedTx + // first we create a fake htlcSuccessOrTimeoutTx tx, containing only the output that will be spent by the 3rd-stage tx val pubKeyScript = write(pay2wsh(toLocalDelayed(localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey))) val htlcSuccessOrTimeoutTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(20000 sat, pubKeyScript) :: Nil, lockTime = 0) - val Right(claimHtlcDelayedTx) = makeClaimLocalDelayedOutputTx(htlcSuccessOrTimeoutTx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + val Right(htlcDelayedTx) = makeHtlcDelayedTx(htlcSuccessOrTimeoutTx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) // we use dummy signatures to compute the weight - val weight = Transaction.weight(addSigs(claimHtlcDelayedTx, PlaceHolderSig).tx) - assert(claimHtlcDelayedWeight == weight) - assert(claimHtlcDelayedTx.fee >= claimHtlcDelayedTx.minRelayFee) + val weight = Transaction.weight(addSigs(htlcDelayedTx, PlaceHolderSig).tx) + assert(htlcDelayedWeight == weight) + assert(htlcDelayedTx.fee >= htlcDelayedTx.minRelayFee) } { // MainPenaltyTx @@ -317,13 +317,13 @@ class TransactionsSpec extends AnyFunSuite with Logging { } { // local spends delayed output of htlc1 timeout tx - val Right(claimHtlcDelayed) = makeClaimLocalDelayedOutputTx(htlcTimeoutTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - val localSig = sign(claimHtlcDelayed, localDelayedPaymentPriv, TxOwner.Local, DefaultCommitmentFormat) - val signedTx = addSigs(claimHtlcDelayed, localSig) + val Right(htlcDelayed) = makeHtlcDelayedTx(htlcTimeoutTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + val localSig = sign(htlcDelayed, localDelayedPaymentPriv, TxOwner.Local, DefaultCommitmentFormat) + val signedTx = addSigs(htlcDelayed, localSig) assert(checkSpendable(signedTx).isSuccess) // local can't claim delayed output of htlc3 timeout tx because it is below the dust limit - val claimHtlcDelayed1 = makeClaimLocalDelayedOutputTx(htlcTimeoutTxs(0).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - assert(claimHtlcDelayed1 === Left(OutputNotFound)) + val htlcDelayed1 = makeHtlcDelayedTx(htlcTimeoutTxs(0).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + assert(htlcDelayed1 === Left(OutputNotFound)) } { // remote spends local->remote htlc1/htlc3 output directly in case of success @@ -347,13 +347,13 @@ class TransactionsSpec extends AnyFunSuite with Logging { } { // local spends delayed output of htlc2 success tx - val Right(claimHtlcDelayed) = makeClaimLocalDelayedOutputTx(htlcSuccessTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - val localSig = sign(claimHtlcDelayed, localDelayedPaymentPriv, TxOwner.Local, DefaultCommitmentFormat) - val signedTx = addSigs(claimHtlcDelayed, localSig) + val Right(htlcDelayed) = makeHtlcDelayedTx(htlcSuccessTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + val localSig = sign(htlcDelayed, localDelayedPaymentPriv, TxOwner.Local, DefaultCommitmentFormat) + val signedTx = addSigs(htlcDelayed, localSig) assert(checkSpendable(signedTx).isSuccess) // local can't claim delayed output of htlc4 success tx because it is below the dust limit - val claimHtlcDelayed1 = makeClaimLocalDelayedOutputTx(htlcSuccessTxs(0).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - assert(claimHtlcDelayed1 === Left(AmountBelowDustLimit)) + val htlcDelayed1 = makeHtlcDelayedTx(htlcSuccessTxs(0).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + assert(htlcDelayed1 === Left(AmountBelowDustLimit)) } { // local spends main delayed output @@ -588,13 +588,13 @@ class TransactionsSpec extends AnyFunSuite with Logging { } { // local spends delayed output of htlc1 timeout tx - val Right(claimHtlcDelayed) = makeClaimLocalDelayedOutputTx(htlcTimeoutTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - val localSig = sign(claimHtlcDelayed, localDelayedPaymentPriv, TxOwner.Local, AnchorOutputsCommitmentFormat) - val signedTx = addSigs(claimHtlcDelayed, localSig) + val Right(htlcDelayed) = makeHtlcDelayedTx(htlcTimeoutTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + val localSig = sign(htlcDelayed, localDelayedPaymentPriv, TxOwner.Local, AnchorOutputsCommitmentFormat) + val signedTx = addSigs(htlcDelayed, localSig) assert(checkSpendable(signedTx).isSuccess) // local can't claim delayed output of htlc3 timeout tx because it is below the dust limit - val claimHtlcDelayed1 = makeClaimLocalDelayedOutputTx(htlcTimeoutTxs(0).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - assert(claimHtlcDelayed1 === Left(OutputNotFound)) + val htlcDelayed1 = makeHtlcDelayedTx(htlcTimeoutTxs(0).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + assert(htlcDelayed1 === Left(OutputNotFound)) } { // local spends offered htlc with HTLC-success tx @@ -617,11 +617,11 @@ class TransactionsSpec extends AnyFunSuite with Logging { } { // local spends delayed output of htlc2a and htlc2b success txs - val Right(claimHtlcDelayedA) = makeClaimLocalDelayedOutputTx(htlcSuccessTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - val Right(claimHtlcDelayedB) = makeClaimLocalDelayedOutputTx(htlcSuccessTxs(2).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) - for (claimHtlcDelayed <- Seq(claimHtlcDelayedA, claimHtlcDelayedB)) { - val localSig = sign(claimHtlcDelayed, localDelayedPaymentPriv, TxOwner.Local, AnchorOutputsCommitmentFormat) - val signedTx = addSigs(claimHtlcDelayed, localSig) + val Right(htlcDelayedA) = makeHtlcDelayedTx(htlcSuccessTxs(1).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + val Right(htlcDelayedB) = makeHtlcDelayedTx(htlcSuccessTxs(2).tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) + for (htlcDelayed <- Seq(htlcDelayedA, htlcDelayedB)) { + val localSig = sign(htlcDelayed, localDelayedPaymentPriv, TxOwner.Local, AnchorOutputsCommitmentFormat) + val signedTx = addSigs(htlcDelayed, localSig) assert(checkSpendable(signedTx).isSuccess) } // local can't claim delayed output of htlc4 success tx because it is below the dust limit