From 54368d7d42c7804a93ed9bfefe6f466d0429c548 Mon Sep 17 00:00:00 2001 From: pm47 Date: Thu, 18 Jul 2019 14:54:18 +0200 Subject: [PATCH] made using/storing/sending consistent --- .../fr/acinq/eclair/channel/Channel.scala | 93 +++++++++++-------- 1 file changed, 52 insertions(+), 41 deletions(-) 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 3199abcbe4..ec9a68d4a1 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 @@ -19,7 +19,7 @@ package fr.acinq.eclair.channel import akka.actor.{ActorRef, FSM, OneForOneStrategy, Props, Status, SupervisorStrategy} import akka.event.Logging.MDC import akka.pattern.pipe -import fr.acinq.bitcoin.Crypto.{PublicKey, PrivateKey, sha256} +import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey, sha256} import fr.acinq.bitcoin._ import fr.acinq.eclair._ import fr.acinq.eclair.blockchain._ @@ -434,7 +434,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId blockchain ! WatchSpent(self, commitInput.outPoint.txid, commitInput.outPoint.index.toInt, commitments.commitInput.txOut.publicKeyScript, BITCOIN_FUNDING_SPENT) // TODO: should we wait for an acknowledgment from the watcher? blockchain ! WatchConfirmed(self, commitInput.outPoint.txid, commitments.commitInput.txOut.publicKeyScript, nodeParams.minDepthBlocks, BITCOIN_FUNDING_DEPTHOK) context.system.scheduler.scheduleOnce(FUNDING_TIMEOUT_FUNDEE, self, BITCOIN_FUNDING_TIMEOUT) - goto(WAIT_FOR_FUNDING_CONFIRMED) using store(DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments, None, now, None, Right(fundingSigned))) sending fundingSigned + goto(WAIT_FOR_FUNDING_CONFIRMED) using DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments, None, now, None, Right(fundingSigned)) storing() sending fundingSigned } case Event(CMD_CLOSE(_), _) => goto(CLOSED) replying "ok" @@ -529,7 +529,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId // as soon as it reaches NORMAL state, and before it is announced on the network // (this id might be updated when the funding tx gets deeply buried, if there was a reorg in the meantime) val shortChannelId = ShortChannelId(blockHeight, txIndex, commitments.commitInput.outPoint.index.toInt) - goto(WAIT_FOR_FUNDING_LOCKED) using store(DATA_WAIT_FOR_FUNDING_LOCKED(commitments, shortChannelId, fundingLocked)) sending fundingLocked + goto(WAIT_FOR_FUNDING_LOCKED) using DATA_WAIT_FOR_FUNDING_LOCKED(commitments, shortChannelId, fundingLocked) storing() sending fundingLocked case Failure(t) => log.error(t, "") goto(CLOSED) @@ -564,7 +564,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId val initialChannelUpdate = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, shortChannelId, nodeParams.expiryDeltaBlocks, d.commitments.remoteParams.htlcMinimumMsat, nodeParams.feeBaseMsat, nodeParams.feeProportionalMillionth, commitments.localCommit.spec.totalFunds, enable = Helpers.aboveReserve(d.commitments)) // we need to periodically re-send channel updates, otherwise channel will be considered stale and get pruned by network context.system.scheduler.schedule(initialDelay = REFRESH_CHANNEL_UPDATE_INTERVAL, interval = REFRESH_CHANNEL_UPDATE_INTERVAL, receiver = self, message = BroadcastChannelUpdate(PeriodicRefresh)) - goto(NORMAL) using store(DATA_NORMAL(commitments.copy(remoteNextCommitInfo = Right(nextPerCommitmentPoint)), shortChannelId, buried = false, None, initialChannelUpdate, None, None)) + goto(NORMAL) using DATA_NORMAL(commitments.copy(remoteNextCommitInfo = Right(nextPerCommitmentPoint)), shortChannelId, buried = false, None, initialChannelUpdate, None, None) storing() case Event(remoteAnnSigs: AnnouncementSignatures, d: DATA_WAIT_FOR_FUNDING_LOCKED) if d.commitments.announceChannel => log.debug(s"received remote announcement signatures, delaying") @@ -722,7 +722,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId } // we expect a quick response from our peer setTimer(RevocationTimeout.toString, RevocationTimeout(commitments1.remoteCommit.index, peer = context.parent), timeout = nodeParams.revocationTimeout, repeat = false) - handleCommandSuccess(sender, store(d.copy(commitments = commitments1))) sending commit + handleCommandSuccess(sender, d.copy(commitments = commitments1)) storing() sending commit case Failure(cause) => handleCommandError(cause, c) } case Left(waitForRevocation) => @@ -740,7 +740,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId self ! CMD_SIGN } context.system.eventStream.publish(ChannelSignatureReceived(self, commitments1)) - stay using store(d.copy(commitments = commitments1)) sending revocation + stay using d.copy(commitments = commitments1) storing() sending revocation case Failure(cause) => handleLocalError(cause, d, Some(commit)) } @@ -763,9 +763,9 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId val localShutdown = Shutdown(d.channelId, commitments1.localParams.defaultFinalScriptPubKey) // note: it means that we had pending htlcs to sign, therefore we go to SHUTDOWN, not to NEGOTIATING require(commitments1.remoteCommit.spec.htlcs.size > 0, "we must have just signed new htlcs, otherwise we would have sent our Shutdown earlier") - goto(SHUTDOWN) using store(DATA_SHUTDOWN(commitments1, localShutdown, d.remoteShutdown.get)) sending localShutdown + goto(SHUTDOWN) using DATA_SHUTDOWN(commitments1, localShutdown, d.remoteShutdown.get) storing() sending localShutdown } else { - stay using store(d.copy(commitments = commitments1)) + stay using d.copy(commitments = commitments1) storing() } case Failure(cause) => handleLocalError(cause, d, Some(revocation)) } @@ -783,7 +783,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId handleCommandError(InvalidFinalScript(d.channelId), c) else { val shutdown = Shutdown(d.channelId, localScriptPubKey) - handleCommandSuccess(sender, store(d.copy(localShutdown = Some(shutdown)))) sending shutdown + handleCommandSuccess(sender, d.copy(localShutdown = Some(shutdown))) storing() sending shutdown } case Event(remoteShutdown@Shutdown(_, remoteScriptPubKey), d: DATA_NORMAL) => @@ -837,15 +837,15 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId if (d.commitments.localParams.isFunder) { // we are funder, need to initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = Closing.makeFirstClosingTx(keyManager, d.commitments, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey) - goto(NEGOTIATING) using store(DATA_NEGOTIATING(d.commitments, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx.tx, closingSigned))), bestUnpublishedClosingTx_opt = None)) sending sendList :+ closingSigned + goto(NEGOTIATING) using DATA_NEGOTIATING(d.commitments, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx.tx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending sendList :+ closingSigned } else { // we are fundee, will wait for their closing_signed - goto(NEGOTIATING) using store(DATA_NEGOTIATING(d.commitments, localShutdown, remoteShutdown, closingTxProposed = List(List()), bestUnpublishedClosingTx_opt = None)) sending sendList + goto(NEGOTIATING) using DATA_NEGOTIATING(d.commitments, localShutdown, remoteShutdown, closingTxProposed = List(List()), bestUnpublishedClosingTx_opt = None) storing() sending sendList } } else { // there are some pending signed htlcs, we need to fail/fulfill them - goto(SHUTDOWN) using store(DATA_SHUTDOWN(d.commitments, localShutdown, remoteShutdown)) sending sendList + goto(SHUTDOWN) using DATA_SHUTDOWN(d.commitments, localShutdown, remoteShutdown) storing() sending sendList } } @@ -879,7 +879,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId Some(Helpers.makeAnnouncementSignatures(nodeParams, d.commitments, shortChannelId)) } else None // we use GOTO instead of stay because we want to fire transitions - goto(NORMAL) using store(d.copy(shortChannelId = shortChannelId, buried = true, channelUpdate = channelUpdate)) sending localAnnSigs_opt.toSeq + goto(NORMAL) using d.copy(shortChannelId = shortChannelId, buried = true, channelUpdate = channelUpdate) storing() sending localAnnSigs_opt.toSeq case Event(remoteAnnSigs: AnnouncementSignatures, d: DATA_NORMAL) if d.commitments.announceChannel => // channels are publicly announced if both parties want it (defined as feature bit) @@ -894,7 +894,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId import d.commitments.{localParams, remoteParams} val channelAnn = Announcements.makeChannelAnnouncement(nodeParams.chainHash, localAnnSigs.shortChannelId, nodeParams.nodeId, remoteParams.nodeId, keyManager.fundingPublicKey(localParams.channelKeyPath).publicKey, remoteParams.fundingPubKey, localAnnSigs.nodeSignature, remoteAnnSigs.nodeSignature, localAnnSigs.bitcoinSignature, remoteAnnSigs.bitcoinSignature) // we use GOTO instead of stay because we want to fire transitions - goto(NORMAL) using store(d.copy(channelAnnouncement = Some(channelAnn))) + goto(NORMAL) using d.copy(channelAnnouncement = Some(channelAnn)) storing() case Some(_) => // they have sent their announcement sigs, but we already have a valid channel announcement // this can happen if our announcement_signatures was lost during a disconnection @@ -916,7 +916,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId log.info(s"updating relay fees: prevFeeBaseMsat={} nextFeeBaseMsat={} prevFeeProportionalMillionths={} nextFeeProportionalMillionths={}", d.channelUpdate.feeBaseMsat, feeBaseMsat, d.channelUpdate.feeProportionalMillionths, feeProportionalMillionths) val channelUpdate = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, d.shortChannelId, d.channelUpdate.cltvExpiryDelta, d.channelUpdate.htlcMinimumMsat, feeBaseMsat, feeProportionalMillionths, d.commitments.localCommit.spec.totalFunds, enable = Helpers.aboveReserve(d.commitments)) // we use GOTO instead of stay because we want to fire transitions - goto(NORMAL) using store(d.copy(channelUpdate = channelUpdate)) replying "ok" + goto(NORMAL) using d.copy(channelUpdate = channelUpdate) storing() replying "ok" case Event(BroadcastChannelUpdate(reason), d: DATA_NORMAL) => val age = Platform.currentTime.milliseconds - d.channelUpdate.timestamp.seconds @@ -929,7 +929,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case _ => log.info(s"refreshing channel_update announcement (reason=$reason)") // we use GOTO instead of stay because we want to fire transitions - goto(NORMAL) using store(d.copy(channelUpdate = channelUpdate1)) + goto(NORMAL) using d.copy(channelUpdate = channelUpdate1) storing() } case Event(WatchEventSpent(BITCOIN_FUNDING_SPENT, tx), d: DATA_NORMAL) if tx.txid == d.commitments.remoteCommit.txid => handleRemoteSpentCurrent(tx, d) @@ -1062,7 +1062,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId context.system.eventStream.publish(ChannelSignatureSent(self, commitments1)) // we expect a quick response from our peer setTimer(RevocationTimeout.toString, RevocationTimeout(commitments1.remoteCommit.index, peer = context.parent), timeout = nodeParams.revocationTimeout, repeat = false) - handleCommandSuccess(sender, store(d.copy(commitments = commitments1))) sending commit + handleCommandSuccess(sender, d.copy(commitments = commitments1)) storing() sending commit case Failure(cause) => handleCommandError(cause, c) } case Left(waitForRevocation) => @@ -1080,17 +1080,17 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId if (d.commitments.localParams.isFunder) { // we are funder, need to initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = Closing.makeFirstClosingTx(keyManager, commitments1, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey) - goto(NEGOTIATING) using store(DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx.tx, closingSigned))), bestUnpublishedClosingTx_opt = None)) sending revocation :: closingSigned :: Nil + goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx.tx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending revocation :: closingSigned :: Nil } else { // we are fundee, will wait for their closing_signed - goto(NEGOTIATING) using store(DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, closingTxProposed = List(List()), bestUnpublishedClosingTx_opt = None)) sending revocation + goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, closingTxProposed = List(List()), bestUnpublishedClosingTx_opt = None) storing() sending revocation } } else { if (Commitments.localHasChanges(commitments1)) { // if we have newly acknowledged changes let's sign them self ! CMD_SIGN } - stay using store(d.copy(commitments = commitments1)) sending revocation + stay using d.copy(commitments = commitments1) storing() sending revocation } case Failure(cause) => handleLocalError(cause, d, Some(commit)) } @@ -1116,16 +1116,16 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId if (d.commitments.localParams.isFunder) { // we are funder, need to initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = Closing.makeFirstClosingTx(keyManager, commitments1, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey) - goto(NEGOTIATING) using store(DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx.tx, closingSigned))), bestUnpublishedClosingTx_opt = None)) sending closingSigned + goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx.tx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending closingSigned } else { // we are fundee, will wait for their closing_signed - goto(NEGOTIATING) using store(DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, closingTxProposed = List(List()), bestUnpublishedClosingTx_opt = None)) + goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, closingTxProposed = List(List()), bestUnpublishedClosingTx_opt = None) storing() } } else { if (Commitments.localHasChanges(commitments1) && d.commitments.remoteNextCommitInfo.left.map(_.reSignAsap) == Left(true)) { self ! CMD_SIGN } - stay using store(d.copy(commitments = commitments1)) + stay using d.copy(commitments = commitments1) storing() } case Failure(cause) => handleLocalError(cause, d, Some(revocation)) } @@ -1180,13 +1180,13 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId val closingTxProposed1 = d.closingTxProposed match { case previousNegotiations :+ currentNegotiation => previousNegotiations :+ (currentNegotiation :+ ClosingTxProposed(closingTx.tx, closingSigned)) } - handleMutualClose(signedClosingTx, Left(store(d.copy(closingTxProposed = closingTxProposed1, bestUnpublishedClosingTx_opt = Some(signedClosingTx))))) sending closingSigned + handleMutualClose(signedClosingTx, Left(d.copy(closingTxProposed = closingTxProposed1, bestUnpublishedClosingTx_opt = Some(signedClosingTx)))) sending closingSigned } else { log.info(s"proposing closingFeeSatoshis=${closingSigned.feeSatoshis}") val closingTxProposed1 = d.closingTxProposed match { case previousNegotiations :+ currentNegotiation => previousNegotiations :+ (currentNegotiation :+ ClosingTxProposed(closingTx.tx, closingSigned)) } - stay using store(d.copy(closingTxProposed = closingTxProposed1, bestUnpublishedClosingTx_opt = Some(signedClosingTx))) sending closingSigned + stay using d.copy(closingTxProposed = closingTxProposed1, bestUnpublishedClosingTx_opt = Some(signedClosingTx)) storing() sending closingSigned } case Failure(cause) => handleLocalError(cause, d, Some(c)) } @@ -1230,7 +1230,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId doPublish(remoteCommitPublished1) remoteCommitPublished1 } - stay using store(d.copy(commitments = commitments1, localCommitPublished = localCommitPublished1, remoteCommitPublished = remoteCommitPublished1, nextRemoteCommitPublished = nextRemoteCommitPublished1)) + stay using d.copy(commitments = commitments1, localCommitPublished = localCommitPublished1, remoteCommitPublished = remoteCommitPublished1, nextRemoteCommitPublished = nextRemoteCommitPublished1) storing() case Failure(cause) => handleCommandError(cause, c) } @@ -1296,7 +1296,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId tx_opt.foreach(claimTx => blockchain ! WatchSpent(self, tx, claimTx.txIn.head.outPoint.index.toInt, BITCOIN_OUTPUT_SPENT)) rev1 } - stay using store(d.copy(revokedCommitPublished = revokedCommitPublished1)) + stay using d.copy(revokedCommitPublished = revokedCommitPublished1) storing() case Event(WatchEventConfirmed(BITCOIN_TX_CONFIRMED(tx), blockHeight, _, _), d: DATA_CLOSING) => log.info(s"txid=${tx.txid} has reached mindepth, updating closing state") @@ -1353,9 +1353,9 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case Some(closingType) => log.info(s"channel closed (type=$closingType)") context.system.eventStream.publish(ChannelClosed(self, d.channelId, closingType, d.commitments)) - goto(CLOSED) using store(d1) + goto(CLOSED) using d1 storing() case None => - stay using store(d1) + stay using d1 storing() } case Event(_: ChannelReestablish, d: DATA_CLOSING) => @@ -1434,7 +1434,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId log.info(s"updating relay fees: prevFeeBaseMsat={} nextFeeBaseMsat={} prevFeeProportionalMillionths={} nextFeeProportionalMillionths={}", d.channelUpdate.feeBaseMsat, feeBaseMsat, d.channelUpdate.feeProportionalMillionths, feeProportionalMillionths) val channelUpdate = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, d.shortChannelId, d.channelUpdate.cltvExpiryDelta, d.channelUpdate.htlcMinimumMsat, feeBaseMsat, feeProportionalMillionths, d.commitments.localCommit.spec.totalFunds, enable = false) // we're in OFFLINE state, we don't broadcast the new update right away, we will do that when next time we go to NORMAL state - stay using store(d.copy(channelUpdate = channelUpdate)) replying "ok" + stay using d.copy(channelUpdate = channelUpdate) storing() replying "ok" case Event(getTxResponse: GetTxWithMetaResponse, d: DATA_WAIT_FOR_FUNDING_CONFIRMED) if getTxResponse.txid == d.commitments.commitInput.outPoint.txid => handleGetFundingTx(getTxResponse, d.waitingSince, d.fundingTx) @@ -1480,7 +1480,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId // would punish us by taking all the funds in the channel val exc = PleasePublishYourCommitment(d.channelId) val error = Error(d.channelId, exc.getMessage) - goto(WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT) using store(DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT(d.commitments, channelReestablish)) sending error + goto(WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT) using DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT(d.commitments, channelReestablish) storing() sending error } else { // they lied! the last per_commitment_secret they claimed to have received from us is invalid throw InvalidRevokedCommitProof(d.channelId, d.commitments.localCommit.index, nextRemoteRevocationNumber, yourLastPerCommitmentSecret) @@ -1493,7 +1493,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId // not that if they don't comply, we could publish our own commitment (it is not stale, otherwise we would be in the case above) val exc = PleasePublishYourCommitment(d.channelId) val error = Error(d.channelId, exc.getMessage) - goto(WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT) using store(DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT(d.commitments, channelReestablish)) sending error + goto(WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT) using DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT(d.commitments, channelReestablish) storing() sending error case _ => // normal case, our data is up-to-date if (channelReestablish.nextLocalCommitmentNumber == 1 && d.commitments.localCommit.index == 0) { @@ -1553,7 +1553,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId // we could use the last closing_signed we sent, but network fees may have changed while we were offline so it is better to restart from scratch val (closingTx, closingSigned) = Closing.makeFirstClosingTx(keyManager, d.commitments, d.localShutdown.scriptPubKey, d.remoteShutdown.scriptPubKey) val closingTxProposed1 = d.closingTxProposed :+ List(ClosingTxProposed(closingTx.tx, closingSigned)) - goto(NEGOTIATING) using store(d.copy(closingTxProposed = closingTxProposed1)) sending d.localShutdown :: closingSigned :: Nil + goto(NEGOTIATING) using d.copy(closingTxProposed = closingTxProposed1) storing() sending d.localShutdown :: closingSigned :: Nil } else { // we start a new round of negotiation val closingTxProposed1 = if (d.closingTxProposed.last.isEmpty) d.closingTxProposed else d.closingTxProposed :+ List() @@ -1884,7 +1884,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case Left(negotiating) => DATA_CLOSING(negotiating.commitments, fundingTx = None, waitingSince = now, negotiating.closingTxProposed.flatten.map(_.unsignedTx), mutualClosePublished = closingTx :: Nil) case Right(closing) => closing.copy(mutualClosePublished = closing.mutualClosePublished :+ closingTx) } - goto(CLOSING) using store(nextData) + goto(CLOSING) using nextData storing() } def doPublish(closingTx: Transaction) = { @@ -1916,7 +1916,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case _ => DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = now, mutualCloseProposed = Nil, localCommitPublished = Some(localCommitPublished)) } - goto(CLOSING) using store(nextData) + goto(CLOSING) using nextData storing() } } @@ -1991,7 +1991,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case _ => DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = now, mutualCloseProposed = Nil, remoteCommitPublished = Some(remoteCommitPublished)) } - goto(CLOSING) using store(nextData) + goto(CLOSING) using nextData storing() } def handleRemoteSpentFuture(commitTx: Transaction, d: DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT) = { @@ -2002,7 +2002,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId val nextData = DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = now, Nil, futureRemoteCommitPublished = Some(remoteCommitPublished)) doPublish(remoteCommitPublished) - goto(CLOSING) using store(nextData) + goto(CLOSING) using nextData storing() } def handleRemoteSpentNext(commitTx: Transaction, d: HasCommitments) = { @@ -2021,7 +2021,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case _ => DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = now, mutualCloseProposed = Nil, nextRemoteCommitPublished = Some(remoteCommitPublished)) } - goto(CLOSING) using store(nextData) + goto(CLOSING) using nextData storing() } def doPublish(remoteCommitPublished: RemoteCommitPublished) = { @@ -2058,7 +2058,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId // NB: if there is a revoked commitment, we can't be in DATA_WAIT_FOR_FUNDING_CONFIRMED so we don't have the case where fundingTx is defined case _ => DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = now, mutualCloseProposed = Nil, revokedCommitPublished = revokedCommitPublished :: Nil) } - goto(CLOSING) using store(nextData) sending error + goto(CLOSING) using nextData storing() sending error case None => // the published tx was neither their current commitment nor a revoked one log.error(s"couldn't identify txid=${tx.txid}, something very bad is going on!!!") @@ -2201,7 +2201,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId context.system.eventStream.publish(NetworkFeePaid(self, remoteNodeId, channelId, tx, fee, desc)) } - def store[T](d: T)(implicit tp: T <:< HasCommitments): T = { + def store(d: HasCommitments) = { log.debug(s"updating database record for channelId={}", d.channelId) nodeParams.db.channels.addOrUpdateChannel(d) context.system.eventStream.publish(ChannelPersisted(self, remoteNodeId, d.channelId, d)) @@ -2212,8 +2212,19 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case class MyState(state: FSM.State[fr.acinq.eclair.channel.State, Data]) { + def storing(): FSM.State[fr.acinq.eclair.channel.State, Data] = { + state.stateData match { + case d: HasCommitments => + store(d) + state + case _ => + log.error(s"can't store data=${state.stateData} in state=${state.stateName}") + state + } + } + def sending(msgs: Seq[LightningMessage]): FSM.State[fr.acinq.eclair.channel.State, Data] = { - msgs.foreach(forwarder ! _) + msgs.foreach(sending) state }