diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/blockchain/PeerWatcher.scala b/eclair-node/src/main/scala/fr/acinq/eclair/blockchain/PeerWatcher.scala index 988aafc24..136c3f399 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/blockchain/PeerWatcher.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/blockchain/PeerWatcher.scala @@ -75,9 +75,10 @@ class PeerWatcher(client: ExtendedBitcoinClient, blockCount: Long)(implicit ec: // absolute timeout in blocks val timeout = Math.max(cltvTimeout, csvTimeout) if (timeout <= currentBlockCount) { + log.info(s"publishing tx ${Transaction.write(tx)}") publish(tx) } else { - log.info(s"delaying publication of tx $tx until block=$timeout (curblock=$currentBlockCount)") + log.info(s"delaying publication of tx ${Transaction.write(tx)} until block=$timeout (curblock=$currentBlockCount)") val block2tx1 = block2tx.updated(timeout, tx +: block2tx.getOrElse(timeout, Seq.empty[Transaction])) context.become(watching(watches, block2tx1, currentBlockCount)) } diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/channel/Channel.scala b/eclair-node/src/main/scala/fr/acinq/eclair/channel/Channel.scala index e6c8aa597..f0effe48e 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/channel/Channel.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/channel/Channel.scala @@ -310,8 +310,9 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, router: ActorRef, re case Event(e: Error, d: DATA_WAIT_FOR_FUNDING_LOCKED_INTERNAL) => log.error(s"peer sent $e, closing connection") // see bolt #2: A node MUST fail the connection if it receives an err message - blockchain ! PublishAsap(d.commitments.localCommit.publishableTxs.commitTx.tx) - blockchain ! WatchConfirmed(self, d.commitments.localCommit.publishableTxs.commitTx.tx.txid, d.params.minimumDepth, BITCOIN_CLOSE_DONE) + val localCommitTx = d.commitments.localCommit.publishableTxs.commitTx.tx + blockchain ! PublishAsap(localCommitTx) + blockchain ! WatchConfirmed(self, localCommitTx.txid, d.params.minimumDepth, BITCOIN_LOCALCOMMIT_DONE) // there can't be htlcs at this stage // TODO: LocalCommitPublished.claimDelayedOutputTx should be defined val localCommitPublished = LocalCommitPublished(d.commitments.localCommit.publishableTxs.commitTx.tx, None, Nil, Nil, Nil) @@ -672,9 +673,9 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, router: ActorRef, re case Event(WatchEventConfirmed(BITCOIN_CLOSE_DONE, _, _), d: DATA_CLOSING) if d.mutualClosePublished.isDefined => goto(CLOSED) - case Event(WatchEventConfirmed(BITCOIN_SPEND_OURS_DONE, _, _), d: DATA_CLOSING) if d.localCommitPublished.isDefined => goto(CLOSED) + case Event(WatchEventConfirmed(BITCOIN_LOCALCOMMIT_DONE, _, _), d: DATA_CLOSING) if d.localCommitPublished.isDefined => goto(CLOSED) - case Event(WatchEventConfirmed(BITCOIN_SPEND_THEIRS_DONE, _, _), d: DATA_CLOSING) if d.remoteCommitPublished.isDefined => goto(CLOSED) + case Event(WatchEventConfirmed(BITCOIN_REMOTECOMMIT_DONE, _, _), d: DATA_CLOSING) if d.remoteCommitPublished.isDefined => goto(CLOSED) case Event(WatchEventConfirmed(BITCOIN_PUNISHMENT_DONE, _, _), d: DATA_CLOSING) if d.revokedCommitPublished.size > 0 => goto(CLOSED) @@ -778,7 +779,7 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, router: ActorRef, re blockchain ! PublishAsap(tx) // TODO hardcoded mindepth + shouldn't we watch the claim tx instead? - blockchain ! WatchConfirmed(self, tx.txid, 3, BITCOIN_SPEND_OURS_DONE) + blockchain ! WatchConfirmed(self, tx.txid, 3, BITCOIN_LOCALCOMMIT_DONE) val localCommitPublished = Helpers.Closing.claimCurrentLocalCommitTxOutputs(d.commitments, tx) localCommitPublished.claimMainDelayedOutputTx.foreach(tx => blockchain ! PublishAsap(tx)) @@ -799,7 +800,7 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, router: ActorRef, re require(tx.txid == d.commitments.remoteCommit.txid, "txid mismatch") // TODO hardcoded mindepth + shouldn't we watch the claim tx instead? - blockchain ! WatchConfirmed(self, tx.txid, 3, BITCOIN_SPEND_THEIRS_DONE) + blockchain ! WatchConfirmed(self, tx.txid, 3, BITCOIN_REMOTECOMMIT_DONE) val remoteCommitPublished = Helpers.Closing.claimCurrentRemoteCommitTxOutputs(d.commitments, tx) remoteCommitPublished.claimMainOutputTx.foreach(tx => blockchain ! PublishAsap(tx)) diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala b/eclair-node/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala index 8ae2c706b..d8e9a4953 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala @@ -66,9 +66,8 @@ case object BITCOIN_FUNDING_DEPTHOK extends BitcoinEvent case object BITCOIN_FUNDING_LOST extends BitcoinEvent case object BITCOIN_FUNDING_TIMEOUT extends BitcoinEvent case object BITCOIN_FUNDING_SPENT extends BitcoinEvent -case object BITCOIN_FUNDING_OURCOMMIT_DELAYPASSED extends BitcoinEvent -case object BITCOIN_SPEND_THEIRS_DONE extends BitcoinEvent -case object BITCOIN_SPEND_OURS_DONE extends BitcoinEvent +case object BITCOIN_LOCALCOMMIT_DONE extends BitcoinEvent +case object BITCOIN_REMOTECOMMIT_DONE extends BitcoinEvent case object BITCOIN_PUNISHMENT_DONE extends BitcoinEvent case object BITCOIN_CLOSE_DONE extends BitcoinEvent case class BITCOIN_FUNDING_OTHER_CHANNEL_SPENT(channelId: Long) extends BitcoinEvent diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedInternalStateSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedInternalStateSpec.scala index 24a9d5a27..bc0d53aec 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedInternalStateSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedInternalStateSpec.scala @@ -105,7 +105,7 @@ class WaitForFundingLockedInternalStateSpec extends TestkitBaseClass { alice ! Error(0, "oops".getBytes) awaitCond(alice.stateName == CLOSING) alice2blockchain.expectMsg(PublishAsap(tx)) - alice2blockchain.expectMsgType[WatchConfirmed] + assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_LOCALCOMMIT_DONE) } } @@ -115,7 +115,7 @@ class WaitForFundingLockedInternalStateSpec extends TestkitBaseClass { alice ! CMD_CLOSE(None) awaitCond(alice.stateName == CLOSING) alice2blockchain.expectMsg(PublishAsap(tx)) - alice2blockchain.expectMsgType[WatchConfirmed] + assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_CLOSE_DONE) } } diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala index 283c21386..754fb8c73 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingLockedStateSpec.scala @@ -115,7 +115,7 @@ class WaitForFundingLockedStateSpec extends TestkitBaseClass { alice ! Error(0, "oops".getBytes) awaitCond(alice.stateName == CLOSING) alice2blockchain.expectMsg(PublishAsap(tx)) - alice2blockchain.expectMsgType[WatchConfirmed] + assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_LOCALCOMMIT_DONE) } } @@ -125,7 +125,7 @@ class WaitForFundingLockedStateSpec extends TestkitBaseClass { alice ! CMD_CLOSE(None) awaitCond(alice.stateName == CLOSING) alice2blockchain.expectMsg(PublishAsap(tx)) - alice2blockchain.expectMsgType[WatchConfirmed] + assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_CLOSE_DONE) } } diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index e14880c51..597787ffb 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -2,7 +2,7 @@ package fr.acinq.eclair.channel.states.e import akka.actor.Props import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.Crypto.{Point, Scalar} +import fr.acinq.bitcoin.Crypto.Scalar import fr.acinq.bitcoin.{BinaryData, Crypto, Satoshi, Script, ScriptFlags, Transaction} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.blockchain._ @@ -820,7 +820,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(bobCommitTx.txOut.size == 6) // two main outputs and 4 pending htlcs alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, bobCommitTx) - alice2blockchain.expectMsgType[WatchConfirmed].txId == bobCommitTx.txid + val watch = alice2blockchain.expectMsgType[WatchConfirmed] + assert(watch.txId === bobCommitTx.txid) + assert(watch.event === BITCOIN_REMOTECOMMIT_DONE) // in addition to its main output, alice can only claim 3 out of 4 htlcs, she can't do anything regarding the htlc sent by bob for which she does not have the preimage val amountClaimed = (for (i <- 0 until 4) yield { @@ -872,7 +874,10 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(revokedTx.txOut.size == 6) alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, revokedTx) alice2bob.expectMsgType[Error] - alice2blockchain.expectMsgType[WatchConfirmed] + + val watch = alice2blockchain.expectMsgType[WatchConfirmed] + assert(watch.txId === revokedTx.txid) + assert(watch.event === BITCOIN_PUNISHMENT_DONE) val mainTx = alice2blockchain.expectMsgType[PublishAsap].tx val punishTx = alice2blockchain.expectMsgType[PublishAsap].tx @@ -919,7 +924,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { alice2blockchain.expectMsg(PublishAsap(aliceCommitTx)) assert(aliceCommitTx.txOut.size == 6) // two main outputs and 4 pending htlcs - alice2blockchain.expectMsgType[WatchConfirmed].txId == aliceCommitTx.txid + val watch = alice2blockchain.expectMsgType[WatchConfirmed] + assert(watch.txId === aliceCommitTx.txid) + assert(watch.event === BITCOIN_LOCALCOMMIT_DONE) // alice can only claim 3 out of 4 htlcs, she can't do anything regarding the htlc sent by bob for which she does not have the htlc // so we expect 7 transactions: diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala index 3a2270693..aeeededcf 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala @@ -359,7 +359,9 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(bobCommitTx.txOut.size == 4) // two main outputs and 2 pending htlcs alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, bobCommitTx) - alice2blockchain.expectMsgType[WatchConfirmed].txId == bobCommitTx.txid + val watch = alice2blockchain.expectMsgType[WatchConfirmed] + assert(watch.txId === bobCommitTx.txid) + assert(watch.event === BITCOIN_REMOTECOMMIT_DONE) val amountClaimed = (for (i <- 0 until 3) yield { val claimHtlcTx = alice2blockchain.expectMsgType[PublishAsap].tx @@ -395,7 +397,10 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // bob published the revoked tx alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, revokedTx) alice2bob.expectMsgType[Error] - alice2blockchain.expectMsgType[WatchConfirmed] + + val watch = alice2blockchain.expectMsgType[WatchConfirmed] + assert(watch.txId === revokedTx.txid) + assert(watch.event === BITCOIN_PUNISHMENT_DONE) val mainTx = alice2blockchain.expectMsgType[PublishAsap].tx val punishTx = alice2blockchain.expectMsgType[PublishAsap].tx @@ -420,7 +425,9 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { alice2blockchain.expectMsg(PublishAsap(aliceCommitTx)) assert(aliceCommitTx.txOut.size == 4) // two main outputs and two htlcs - alice2blockchain.expectMsgType[WatchConfirmed].txId == aliceCommitTx.txid + val watch = alice2blockchain.expectMsgType[WatchConfirmed] + assert(watch.txId === aliceCommitTx.txid) + assert(watch.event === BITCOIN_LOCALCOMMIT_DONE) // alice can claim both htlc after a timeout // so we expect 5 transactions: diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala index 78df606af..b99b056ab 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala @@ -67,9 +67,9 @@ class NegotiatingStateSpec extends TestkitBaseClass with StateTestsHelperMethods bob2alice.forward(alice) } while (aliceCloseFee != bobCloseFee) alice2blockchain.expectMsgType[PublishAsap] - alice2blockchain.expectMsgType[WatchConfirmed] + assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_CLOSE_DONE) bob2blockchain.expectMsgType[PublishAsap] - bob2blockchain.expectMsgType[WatchConfirmed] + assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_CLOSE_DONE) awaitCond(alice.stateName == CLOSING) awaitCond(bob.stateName == CLOSING) } @@ -91,7 +91,7 @@ class NegotiatingStateSpec extends TestkitBaseClass with StateTestsHelperMethods // actual test starts here assert(alice.stateName == NEGOTIATING) val mutualCloseTx = bob2blockchain.expectMsgType[PublishAsap].tx - bob2blockchain.expectMsgType[WatchConfirmed] + assert(bob2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_CLOSE_DONE) alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, mutualCloseTx) alice2blockchain.expectNoMsg(1 second) assert(alice.stateName == NEGOTIATING) @@ -104,7 +104,7 @@ class NegotiatingStateSpec extends TestkitBaseClass with StateTestsHelperMethods alice ! Error(0, "oops".getBytes()) awaitCond(alice.stateName == CLOSING) alice2blockchain.expectMsg(PublishAsap(tx)) - alice2blockchain.expectMsgType[WatchConfirmed] + assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_LOCALCOMMIT_DONE) } } diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala index 350a6f43b..5ff031042 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala @@ -120,7 +120,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { } } - test("recv BITCOIN_SPEND_OURS_DONE") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, _) => + test("recv BITCOIN_LOCALCOMMIT_DONE") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, _) => within(30 seconds) { // an error occurs and alice publishes her commit tx val aliceCommitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx @@ -131,7 +131,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(alice.stateData.asInstanceOf[DATA_CLOSING].localCommitPublished.isDefined) // actual test starts here - alice ! WatchEventConfirmed(BITCOIN_SPEND_OURS_DONE, 0, 0) + alice ! WatchEventConfirmed(BITCOIN_LOCALCOMMIT_DONE, 0, 0) awaitCond(alice.stateName == CLOSED) } } @@ -152,7 +152,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { } } - test("recv BITCOIN_SPEND_THEIRS_DONE") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, bobCommitTxes) => + test("recv BITCOIN_REMOTECOMMIT_DONE") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, bobCommitTxes) => within(30 seconds) { mutualClose(alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain) val initialState = alice.stateData.asInstanceOf[DATA_CLOSING] @@ -166,7 +166,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(alice.stateData.asInstanceOf[DATA_CLOSING].copy(remoteCommitPublished = None) == initialState) // actual test starts here - alice ! WatchEventConfirmed(BITCOIN_SPEND_THEIRS_DONE, 0, 0) + alice ! WatchEventConfirmed(BITCOIN_REMOTECOMMIT_DONE, 0, 0) awaitCond(alice.stateName == CLOSED) } }