From bc075481bb67531e3aa2596c3a844c4ab38bd192 Mon Sep 17 00:00:00 2001 From: t-bast Date: Wed, 14 Feb 2024 09:36:46 +0100 Subject: [PATCH] Move firstRemoteCommitIndex to Commitment While it requires more duplication in the codecs, because we didn't version the commitments codec, it is cleaner to have this filed in the commitment instead of having it in the funding status. --- .../fr/acinq/eclair/channel/ChannelData.scala | 12 +- .../fr/acinq/eclair/channel/Commitments.scala | 23 ++- .../fr/acinq/eclair/channel/fsm/Channel.scala | 10 +- .../channel/fsm/ChannelOpenDualFunded.scala | 2 +- .../channel/fsm/ChannelOpenSingleFunded.scala | 6 +- .../channel/fsm/CommonFundingHandlers.scala | 5 +- .../channel/fund/InteractiveTxBuilder.scala | 8 +- .../channel/version0/ChannelTypes0.scala | 1 + .../channel/version3/ChannelTypes3.scala | 2 +- .../channel/version4/ChannelCodecs4.scala | 143 ++++++++++++++---- .../eclair/channel/CommitmentsSpec.scala | 4 +- .../eclair/json/JsonSerializersSpec.scala | 2 +- .../eclair/payment/PaymentPacketSpec.scala | 2 +- .../internal/channel/ChannelCodecsSpec.scala | 4 +- .../channel/version4/ChannelCodecs4Spec.scala | 1 - 15 files changed, 153 insertions(+), 72 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala index 853112a10e..ebc8c7aa5d 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala @@ -417,11 +417,6 @@ sealed trait LocalFundingStatus { def signedTx_opt: Option[Transaction] /** We store local signatures for the purpose of retransmitting if the funding/splicing flow is interrupted. */ def localSigs_opt: Option[TxSignatures] - /** - * Commitment index of the first remote commitment we signed that spends this funding transaction. - * Once the funding transaction confirms, our peer won't be able to publish revoked commitments with lower indices. - */ - def firstCommitIndex_opt: Option[Long] } object LocalFundingStatus { sealed trait NotLocked extends LocalFundingStatus @@ -436,16 +431,15 @@ object LocalFundingStatus { */ case class SingleFundedUnconfirmedFundingTx(signedTx_opt: Option[Transaction]) extends UnconfirmedFundingTx with NotLocked { override val localSigs_opt: Option[TxSignatures] = None - override val firstCommitIndex_opt: Option[Long] = None } - case class DualFundedUnconfirmedFundingTx(sharedTx: SignedSharedTransaction, createdAt: BlockHeight, fundingParams: InteractiveTxParams, firstCommitIndex_opt: Option[Long]) extends UnconfirmedFundingTx with NotLocked { + case class DualFundedUnconfirmedFundingTx(sharedTx: SignedSharedTransaction, createdAt: BlockHeight, fundingParams: InteractiveTxParams) extends UnconfirmedFundingTx with NotLocked { override val signedTx_opt: Option[Transaction] = sharedTx.signedTx_opt override val localSigs_opt: Option[TxSignatures] = Some(sharedTx.localSigs) } - case class ZeroconfPublishedFundingTx(tx: Transaction, localSigs_opt: Option[TxSignatures], firstCommitIndex_opt: Option[Long]) extends UnconfirmedFundingTx with Locked { + case class ZeroconfPublishedFundingTx(tx: Transaction, localSigs_opt: Option[TxSignatures]) extends UnconfirmedFundingTx with Locked { override val signedTx_opt: Option[Transaction] = Some(tx) } - case class ConfirmedFundingTx(tx: Transaction, localSigs_opt: Option[TxSignatures], firstCommitIndex_opt: Option[Long]) extends LocalFundingStatus with Locked { + case class ConfirmedFundingTx(tx: Transaction, localSigs_opt: Option[TxSignatures]) extends LocalFundingStatus with Locked { override val signedTx_opt: Option[Transaction] = Some(tx) } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 695ef47559..3126f23318 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -1,7 +1,6 @@ package fr.acinq.eclair.channel import akka.event.LoggingAdapter -import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong, Script, Transaction, TxId} import fr.acinq.eclair.blockchain.fee.{FeeratePerByte, FeeratePerKw, FeeratesPerKw, OnChainFeeConf} @@ -266,12 +265,16 @@ case class NextRemoteCommit(sig: CommitSig, commit: RemoteCommit) /** * A minimal commitment for a given funding tx. * - * @param fundingTxIndex index of the funding tx in the life of the channel: - * - initial funding tx has index 0 - * - splice txs have index 1, 2, ... - * - commitments that share the same index are rbfed + * @param fundingTxIndex index of the funding tx in the life of the channel: + * - initial funding tx has index 0 + * - splice txs have index 1, 2, ... + * - commitments that share the same index are rbfed + * @param firstRemoteCommitIndex index of the first remote commitment we signed that spends the funding transaction. + * Once the funding transaction confirms, our peer won't be able to publish revoked + * commitments with lower commitment indices. */ case class Commitment(fundingTxIndex: Long, + firstRemoteCommitIndex: Long, remoteFundingPubKey: PublicKey, localFundingStatus: LocalFundingStatus, remoteFundingStatus: RemoteFundingStatus, localCommit: LocalCommit, remoteCommit: RemoteCommit, nextRemoteCommit_opt: Option[NextRemoteCommit]) { @@ -730,6 +733,7 @@ object Commitment { /** Subset of Commitments when we want to work with a single, specific commitment. */ case class FullCommitment(params: ChannelParams, changes: CommitmentChanges, fundingTxIndex: Long, + firstRemoteCommitIndex: Long, remoteFundingPubKey: PublicKey, localFundingStatus: LocalFundingStatus, remoteFundingStatus: RemoteFundingStatus, localCommit: LocalCommit, remoteCommit: RemoteCommit, nextRemoteCommit_opt: Option[NextRemoteCommit]) { @@ -739,7 +743,7 @@ case class FullCommitment(params: ChannelParams, changes: CommitmentChanges, val commitInput = localCommit.commitTxAndRemoteSig.commitTx.input val fundingTxId = commitInput.outPoint.txid val capacity = commitInput.txOut.amount - val commitment = Commitment(fundingTxIndex, remoteFundingPubKey, localFundingStatus, remoteFundingStatus, localCommit, remoteCommit, nextRemoteCommit_opt) + val commitment = Commitment(fundingTxIndex, firstRemoteCommitIndex, remoteFundingPubKey, localFundingStatus, remoteFundingStatus, localCommit, remoteCommit, nextRemoteCommit_opt) def localChannelReserve: Satoshi = commitment.localChannelReserve(params) @@ -803,7 +807,7 @@ case class Commitments(params: ChannelParams, lazy val availableBalanceForReceive: MilliSatoshi = active.map(_.availableBalanceForReceive(params, changes)).min // We always use the last commitment that was created, to make sure we never go back in time. - val latest = FullCommitment(params, changes, active.head.fundingTxIndex, active.head.remoteFundingPubKey, active.head.localFundingStatus, active.head.remoteFundingStatus, active.head.localCommit, active.head.remoteCommit, active.head.nextRemoteCommit_opt) + val latest = FullCommitment(params, changes, active.head.fundingTxIndex, active.head.firstRemoteCommitIndex, active.head.remoteFundingPubKey, active.head.localFundingStatus, active.head.remoteFundingStatus, active.head.localCommit, active.head.remoteCommit, active.head.nextRemoteCommit_opt) val all: Seq[Commitment] = active ++ inactive @@ -1148,11 +1152,6 @@ case class Commitments(params: ChannelParams, all.find(_.fundingTxId == fundingTxId).flatMap(_.localFundingStatus.localSigs_opt) } - /** Return the index of the first remote commitment we signed spending the given funding transaction. */ - def firstCommitIndex(fundingTxId: TxId): Option[Long] = { - all.find(_.fundingTxId == fundingTxId).flatMap(_.localFundingStatus.firstCommitIndex_opt) - } - /** * Update the local/remote funding status * diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala index ccad0d52e1..ffab4a6a2b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala @@ -1094,7 +1094,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with case Event(msg: TxSignatures, d: DATA_NORMAL) => d.commitments.latest.localFundingStatus match { - case dfu@LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _, _) if fundingTx.txId == msg.txId => + case dfu@LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _) if fundingTx.txId == msg.txId => // we already sent our tx_signatures InteractiveTxSigningSession.addRemoteSigs(keyManager, d.commitments.params, dfu.fundingParams, fundingTx, msg) match { case Left(cause) => @@ -1138,7 +1138,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with } case Event(w: WatchPublishedTriggered, d: DATA_NORMAL) => - val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid), d.commitments.firstCommitIndex(w.tx.txid)) + val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid)) d.commitments.updateLocalFundingStatus(w.tx.txid, fundingStatus) match { case Right((commitments1, _)) => watchFundingConfirmed(w.tx.txid, Some(nodeParams.channelConf.minDepthBlocks), delay_opt = None) @@ -1857,7 +1857,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with case d: DATA_NORMAL => d.spliceStatus match { case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingTlv(status.fundingTx.txId)) case _ => d.commitments.latest.localFundingStatus match { - case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _, _) => Set(ChannelReestablishTlv.NextFundingTlv(fundingTx.txId)) + case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _) => Set(ChannelReestablishTlv.NextFundingTlv(fundingTx.txId)) case _ => Set.empty } } @@ -2241,11 +2241,11 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with // slightly before us. In that case, the WatchConfirmed may trigger first, and it would be inefficient to let the // WatchPublished override our funding status: it will make us set a new WatchConfirmed that will instantly // trigger and rewrite the funding status again. - val alreadyConfirmed = d.commitments.active.map(_.localFundingStatus).collect { case LocalFundingStatus.ConfirmedFundingTx(tx, _, _) => tx }.exists(_.txid == w.tx.txid) + val alreadyConfirmed = d.commitments.active.map(_.localFundingStatus).collect { case LocalFundingStatus.ConfirmedFundingTx(tx, _) => tx }.exists(_.txid == w.tx.txid) if (alreadyConfirmed) { stay() } else { - val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid), d.commitments.firstCommitIndex(w.tx.txid)) + val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid)) d.commitments.updateLocalFundingStatus(w.tx.txid, fundingStatus) match { case Right((commitments1, _)) => log.info(s"zero-conf funding txid=${w.tx.txid} has been published") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala index b9758d2918..335cf163ff 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala @@ -679,7 +679,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { case Event(w: WatchPublishedTriggered, d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED) => log.info("funding txid={} was successfully published for zero-conf channelId={}", w.tx.txid, d.channelId) - val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid), d.commitments.firstCommitIndex(w.tx.txid)) + val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid)) d.commitments.updateLocalFundingStatus(w.tx.txid, fundingStatus) match { case Right((commitments1, _)) => // we still watch the funding tx for confirmation even if we can use the zero-conf channel right away diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala index 646b0819db..024738c32c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.channel.fsm import akka.actor.Status import akka.actor.typed.scaladsl.adapter.actorRefAdapter import akka.pattern.pipe -import fr.acinq.bitcoin.scalacompat.{SatoshiLong, Script, TxHash} +import fr.acinq.bitcoin.scalacompat.{SatoshiLong, Script} import fr.acinq.eclair.blockchain.OnChainWallet.MakeFundingTxResponse import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._ import fr.acinq.eclair.channel.Helpers.Funding @@ -277,6 +277,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { ) val commitment = Commitment( fundingTxIndex = 0, + firstRemoteCommitIndex = 0, remoteFundingPubKey = remoteFundingPubKey, localFundingStatus = SingleFundedUnconfirmedFundingTx(None), remoteFundingStatus = RemoteFundingStatus.NotLocked, @@ -323,6 +324,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { case Success(_) => val commitment = Commitment( fundingTxIndex = 0, + firstRemoteCommitIndex = 0, remoteFundingPubKey = remoteFundingPubKey, localFundingStatus = SingleFundedUnconfirmedFundingTx(Some(fundingTx)), remoteFundingStatus = RemoteFundingStatus.NotLocked, @@ -389,7 +391,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { stay() using d.copy(deferred = Some(remoteChannelReady)) // no need to store, they will re-send if we get disconnected case Event(w: WatchPublishedTriggered, d: DATA_WAIT_FOR_FUNDING_CONFIRMED) => - val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, None, None) + val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, None) d.commitments.updateLocalFundingStatus(w.tx.txid, fundingStatus) match { case Right((commitments1, _)) => log.info("funding txid={} was successfully published for zero-conf channelId={}", w.tx.txid, d.channelId) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala index 73db9124e7..b383d800f9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala @@ -27,7 +27,6 @@ import fr.acinq.eclair.channel.LocalFundingStatus.{ConfirmedFundingTx, DualFunde import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel.{ANNOUNCEMENTS_MINCONF, BroadcastChannelUpdate, PeriodicRefresh, REFRESH_CHANNEL_UPDATE_INTERVAL} import fr.acinq.eclair.db.RevokedHtlcInfoCleaner -import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire.protocol.{AnnouncementSignatures, ChannelReady, ChannelReadyTlv, TlvStream} import scala.concurrent.duration.{DurationInt, FiniteDuration} @@ -83,12 +82,12 @@ trait CommonFundingHandlers extends CommonHandlers { } case _ => () // in the dual-funding case, we have already verified the funding tx } - val fundingStatus = ConfirmedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid), d.commitments.firstCommitIndex(w.tx.txid)) + val fundingStatus = ConfirmedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid)) context.system.eventStream.publish(TransactionConfirmed(d.channelId, remoteNodeId, w.tx)) // When a splice transaction confirms, it double-spends all the commitment transactions that only applied to the // previous funding transaction. Our peer cannot publish the corresponding revoked commitments anymore, so we can // clean-up the htlc data that we were storing for the matching penalty transactions. - fundingStatus.firstCommitIndex_opt.foreach { + d.commitments.all.find(_.fundingTxId == w.tx.txid).map(_.firstRemoteCommitIndex).foreach { commitIndex => context.system.eventStream.publish(RevokedHtlcInfoCleaner.ForgetHtlcInfos(d.channelId, commitIndex)) } d.commitments.updateLocalFundingStatus(w.tx.txid, fundingStatus).map { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala index 59075ce6a4..d5b8f12c40 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala @@ -963,8 +963,8 @@ object InteractiveTxSigningSession { val localPerCommitmentPoint = nodeParams.channelKeyManager.commitmentPoint(channelKeyPath, localCommitIndex) LocalCommit.fromCommitSig(nodeParams.channelKeyManager, channelParams, fundingTx.txId, fundingTxIndex, fundingParams.remoteFundingPubKey, commitInput, remoteCommitSig, localCommitIndex, unsignedLocalCommit.spec, localPerCommitmentPoint).map { signedLocalCommit => if (shouldSignFirst(fundingParams.isInitiator, channelParams, fundingTx.tx)) { - val fundingStatus = LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx, nodeParams.currentBlockHeight, fundingParams, Some(remoteCommit.index)) - val commitment = Commitment(fundingTxIndex, fundingParams.remoteFundingPubKey, fundingStatus, RemoteFundingStatus.NotLocked, signedLocalCommit, remoteCommit, None) + val fundingStatus = LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx, nodeParams.currentBlockHeight, fundingParams) + val commitment = Commitment(fundingTxIndex, remoteCommit.index, fundingParams.remoteFundingPubKey, fundingStatus, RemoteFundingStatus.NotLocked, signedLocalCommit, remoteCommit, None) SendingSigs(fundingStatus, commitment, fundingTx.localSigs) } else { this.copy(localCommit = Right(signedLocalCommit)) @@ -988,8 +988,8 @@ object InteractiveTxSigningSession { Left(f) case Right(fullySignedTx) => log.info("interactive-tx fully signed with {} local inputs, {} remote inputs, {} local outputs and {} remote outputs", fullySignedTx.tx.localInputs.length, fullySignedTx.tx.remoteInputs.length, fullySignedTx.tx.localOutputs.length, fullySignedTx.tx.remoteOutputs.length) - val fundingStatus = LocalFundingStatus.DualFundedUnconfirmedFundingTx(fullySignedTx, nodeParams.currentBlockHeight, fundingParams, Some(remoteCommit.index)) - val commitment = Commitment(fundingTxIndex, fundingParams.remoteFundingPubKey, fundingStatus, RemoteFundingStatus.NotLocked, signedLocalCommit, remoteCommit, None) + val fundingStatus = LocalFundingStatus.DualFundedUnconfirmedFundingTx(fullySignedTx, nodeParams.currentBlockHeight, fundingParams) + val commitment = Commitment(fundingTxIndex, remoteCommit.index, fundingParams.remoteFundingPubKey, fundingStatus, RemoteFundingStatus.NotLocked, signedLocalCommit, remoteCommit, None) Right(SendingSigs(fundingStatus, commitment, fullySignedTx.localSigs)) } } 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 4d3d4bab63..e5fb015785 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 @@ -239,6 +239,7 @@ private[channel] object ChannelTypes0 { } val commitment = Commitment( fundingTxIndex = 0, + firstRemoteCommitIndex = 0, remoteFundingPubKey = remoteParams.fundingPubKey, // We set an empty funding tx, even if it may be confirmed already (and the channel fully operational). We could // have set a specific Unknown status, but it would have forced us to keep it forever. We will retrieve the diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala index 2720b5b440..ce14345e8e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala @@ -45,7 +45,7 @@ private[channel] object ChannelTypes3 { def migrate(): channel.Commitments = channel.Commitments( ChannelParams(channelId, channelConfig, channelFeatures, localParams, remoteParams.migrate(), channelFlags), CommitmentChanges(localChanges, remoteChanges, localNextHtlcId, remoteNextHtlcId), - Seq(Commitment(fundingTxIndex = 0, remoteFundingPubKey = remoteParams.fundingPubKey, localFundingStatus, remoteFundingStatus, localCommit, remoteCommit, remoteNextCommitInfo.left.toOption.map(w => NextRemoteCommit(w.sent, w.nextRemoteCommit)))), + Seq(Commitment(fundingTxIndex = 0, firstRemoteCommitIndex = 0, remoteFundingPubKey = remoteParams.fundingPubKey, localFundingStatus, remoteFundingStatus, localCommit, remoteCommit, remoteNextCommitInfo.left.toOption.map(w => NextRemoteCommit(w.sent, w.nextRemoteCommit)))), inactive = Nil, remoteNextCommitInfo.fold(w => Left(WaitForRev(w.sentAfterLocalCommitIndex)), remotePerCommitmentPoint => Right(remotePerCommitmentPoint)), remotePerCommitmentSecrets, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala index 8e6a451cc0..e8be2ded6e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala @@ -364,20 +364,10 @@ private[channel] object ChannelCodecs4 { .typecase(0x01, partiallySignedSharedTransactionCodec) .typecase(0x02, fullySignedSharedTransactionCodec) - private val dualFundedUnconfirmedFundingTxWithoutCommitIndexCodec: Codec[DualFundedUnconfirmedFundingTx] = ( - ("sharedTx" | signedSharedTransactionCodec) :: - ("createdAt" | blockHeight) :: - ("fundingParams" | fundingParamsCodec) :: - provide(Option.empty[Long])).as[DualFundedUnconfirmedFundingTx].xmap( - dfu => fillSharedInputScript(dfu), - dfu => dfu - ) - private val dualFundedUnconfirmedFundingTxCodec: Codec[DualFundedUnconfirmedFundingTx] = ( ("sharedTx" | signedSharedTransactionCodec) :: ("createdAt" | blockHeight) :: - ("fundingParams" | fundingParamsCodec) :: - ("commitIndex" | optional(bool8, uint64overflow))).as[DualFundedUnconfirmedFundingTx].xmap( + ("fundingParams" | fundingParamsCodec)).as[DualFundedUnconfirmedFundingTx].xmap( dfu => fillSharedInputScript(dfu), dfu => dfu ) @@ -399,14 +389,11 @@ private[channel] object ChannelCodecs4 { val fundingTxStatusCodec: Codec[LocalFundingStatus] = discriminated[LocalFundingStatus].by(uint8) .typecase(0x01, optional(bool8, txCodec).as[SingleFundedUnconfirmedFundingTx]) - .typecase(0x07, dualFundedUnconfirmedFundingTxCodec) - .typecase(0x08, (txCodec :: optional(bool8, lengthDelimited(txSignaturesCodec)) :: optional(bool8, uint64overflow)).as[ZeroconfPublishedFundingTx]) - .typecase(0x09, (txCodec :: optional(bool8, lengthDelimited(txSignaturesCodec)) :: optional(bool8, uint64overflow)).as[ConfirmedFundingTx]) - .typecase(0x02, dualFundedUnconfirmedFundingTxWithoutCommitIndexCodec) - .typecase(0x05, (txCodec :: optional(bool8, lengthDelimited(txSignaturesCodec)) :: provide(Option.empty[Long])).as[ZeroconfPublishedFundingTx]) - .typecase(0x06, (txCodec :: optional(bool8, lengthDelimited(txSignaturesCodec)) :: provide(Option.empty[Long])).as[ConfirmedFundingTx]) - .typecase(0x03, (txCodec :: provide(Option.empty[TxSignatures]) :: provide(Option.empty[Long])).as[ZeroconfPublishedFundingTx]) - .typecase(0x04, (txCodec :: provide(Option.empty[TxSignatures]) :: provide(Option.empty[Long])).as[ConfirmedFundingTx]) + .typecase(0x02, dualFundedUnconfirmedFundingTxCodec) + .typecase(0x05, (txCodec :: optional(bool8, lengthDelimited(txSignaturesCodec))).as[ZeroconfPublishedFundingTx]) + .typecase(0x06, (txCodec :: optional(bool8, lengthDelimited(txSignaturesCodec))).as[ConfirmedFundingTx]) + .typecase(0x03, (txCodec :: provide(Option.empty[TxSignatures])).as[ZeroconfPublishedFundingTx]) + .typecase(0x04, (txCodec :: provide(Option.empty[TxSignatures])).as[ConfirmedFundingTx]) val remoteFundingStatusCodec: Codec[RemoteFundingStatus] = discriminated[RemoteFundingStatus].by(uint8) .typecase(0x01, provide(RemoteFundingStatus.NotLocked)) @@ -445,8 +432,19 @@ private[channel] object ChannelCodecs4 { ("sig" | lengthDelimited(commitSigCodec)) :: ("commit" | remoteCommitCodec(commitmentSpecCodec))).as[NextRemoteCommit] + private def commitmentCodecWithoutFirstRemoteCommitIndex(htlcs: Set[DirectedHtlc]): Codec[Commitment] = ( + ("fundingTxIndex" | uint32) :: + ("firstRemoteCommitIndex" | provide(0L)) :: + ("fundingPubKey" | publicKey) :: + ("fundingTxStatus" | fundingTxStatusCodec) :: + ("remoteFundingStatus" | remoteFundingStatusCodec) :: + ("localCommit" | localCommitCodec(minimalCommitmentSpecCodec(htlcs))) :: + ("remoteCommit" | remoteCommitCodec(minimalCommitmentSpecCodec(htlcs.map(_.opposite)))) :: + ("nextRemoteCommit_opt" | optional(bool8, nextRemoteCommitCodec(minimalCommitmentSpecCodec(htlcs.map(_.opposite)))))).as[Commitment] + private def commitmentCodec(htlcs: Set[DirectedHtlc]): Codec[Commitment] = ( ("fundingTxIndex" | uint32) :: + ("firstRemoteCommitIndex" | uint64overflow) :: ("fundingPubKey" | publicKey) :: ("fundingTxStatus" | fundingTxStatusCodec) :: ("remoteFundingStatus" | remoteFundingStatusCodec) :: @@ -507,6 +505,21 @@ private[channel] object ChannelCodecs4 { } } + val commitmentsCodecWithoutFirstRemoteCommitIndex: Codec[Commitments] = ( + ("params" | paramsCodec) :: + ("changes" | changesCodec) :: + (("htlcs" | setCodec(htlcCodec)) >>:~ { htlcs => + ("active" | listOfN(uint16, commitmentCodecWithoutFirstRemoteCommitIndex(htlcs))) :: + ("inactive" | listOfN(uint16, commitmentCodecWithoutFirstRemoteCommitIndex(htlcs))) :: + ("remoteNextCommitInfo" | either(bool8, waitForRevCodec, publicKey)) :: + ("remotePerCommitmentSecrets" | byteAligned(ShaChain.shaChainCodec)) :: + ("originChannels" | originsMapCodec) :: + ("remoteChannelData_opt" | optional(bool8, varsizebinarydata)) + })).as[EncodedCommitments].xmap( + encoded => encoded.toCommitments, + commitments => EncodedCommitments(commitments) + ) + val commitmentsCodec: Codec[Commitments] = ( ("params" | paramsCodec) :: ("changes" | changesCodec) :: @@ -522,6 +535,9 @@ private[channel] object ChannelCodecs4 { commitments => EncodedCommitments(commitments) ) + val versionedCommitmentsCodec: Codec[Commitments] = discriminated[Commitments].by(uint8) + .typecase(0x01, commitmentsCodec) + val closingFeeratesCodec: Codec[ClosingFeerates] = ( ("preferred" | feeratePerKw) :: ("min" | feeratePerKw) :: @@ -582,13 +598,23 @@ private[channel] object ChannelCodecs4 { .\(0x02) { case status: SpliceStatus.SpliceWaitingForSigs => status }(interactiveTxWaitingForSigsCodec.as[channel.SpliceStatus.SpliceWaitingForSigs]) val DATA_WAIT_FOR_FUNDING_CONFIRMED_00_Codec: Codec[DATA_WAIT_FOR_FUNDING_CONFIRMED] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("waitingSince" | blockHeight) :: + ("deferred" | optional(bool8, lengthDelimited(channelReadyCodec))) :: + ("lastSent" | either(bool8, lengthDelimited(fundingCreatedCodec), lengthDelimited(fundingSignedCodec)))).as[DATA_WAIT_FOR_FUNDING_CONFIRMED] + + val DATA_WAIT_FOR_FUNDING_CONFIRMED_0a_Codec: Codec[DATA_WAIT_FOR_FUNDING_CONFIRMED] = ( + ("commitments" | versionedCommitmentsCodec) :: ("waitingSince" | blockHeight) :: ("deferred" | optional(bool8, lengthDelimited(channelReadyCodec))) :: ("lastSent" | either(bool8, lengthDelimited(fundingCreatedCodec), lengthDelimited(fundingSignedCodec)))).as[DATA_WAIT_FOR_FUNDING_CONFIRMED] val DATA_WAIT_FOR_CHANNEL_READY_01_Codec: Codec[DATA_WAIT_FOR_CHANNEL_READY] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("shortIds" | shortids)).as[DATA_WAIT_FOR_CHANNEL_READY] + + val DATA_WAIT_FOR_CHANNEL_READY_0b_Codec: Codec[DATA_WAIT_FOR_CHANNEL_READY] = ( + ("commitments" | versionedCommitmentsCodec) :: ("shortIds" | shortids)).as[DATA_WAIT_FOR_CHANNEL_READY] val DATA_WAIT_FOR_DUAL_FUNDING_SIGNED_09_Codec: Codec[DATA_WAIT_FOR_DUAL_FUNDING_SIGNED] = ( @@ -600,7 +626,16 @@ private[channel] object ChannelCodecs4 { ("remoteChannelData_opt" | optional(bool8, varsizebinarydata))).as[DATA_WAIT_FOR_DUAL_FUNDING_SIGNED] val DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED_02_Codec: Codec[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("localPushAmount" | millisatoshi) :: + ("remotePushAmount" | millisatoshi) :: + ("waitingSince" | blockHeight) :: + ("lastChecked" | blockHeight) :: + ("rbfStatus" | rbfStatusCodec) :: + ("deferred" | optional(bool8, lengthDelimited(channelReadyCodec)))).as[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] + + val DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED_0c_Codec: Codec[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] = ( + ("commitments" | versionedCommitmentsCodec) :: ("localPushAmount" | millisatoshi) :: ("remotePushAmount" | millisatoshi) :: ("waitingSince" | blockHeight) :: @@ -609,11 +644,25 @@ private[channel] object ChannelCodecs4 { ("deferred" | optional(bool8, lengthDelimited(channelReadyCodec)))).as[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] val DATA_WAIT_FOR_DUAL_FUNDING_READY_03_Codec: Codec[DATA_WAIT_FOR_DUAL_FUNDING_READY] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("shortIds" | shortids)).as[DATA_WAIT_FOR_DUAL_FUNDING_READY] + + val DATA_WAIT_FOR_DUAL_FUNDING_READY_0d_Codec: Codec[DATA_WAIT_FOR_DUAL_FUNDING_READY] = ( + ("commitments" | versionedCommitmentsCodec) :: ("shortIds" | shortids)).as[DATA_WAIT_FOR_DUAL_FUNDING_READY] val DATA_NORMAL_04_Codec: Codec[DATA_NORMAL] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("shortids" | shortids) :: + ("channelAnnouncement" | optional(bool8, lengthDelimited(channelAnnouncementCodec))) :: + ("channelUpdate" | lengthDelimited(channelUpdateCodec)) :: + ("localShutdown" | optional(bool8, lengthDelimited(shutdownCodec))) :: + ("remoteShutdown" | optional(bool8, lengthDelimited(shutdownCodec))) :: + ("closingFeerates" | optional(bool8, closingFeeratesCodec)) :: + ("spliceStatus" | spliceStatusCodec)).as[DATA_NORMAL] + + val DATA_NORMAL_0e_Codec: Codec[DATA_NORMAL] = ( + ("commitments" | versionedCommitmentsCodec) :: ("shortids" | shortids) :: ("channelAnnouncement" | optional(bool8, lengthDelimited(channelAnnouncementCodec))) :: ("channelUpdate" | lengthDelimited(channelUpdateCodec)) :: @@ -623,20 +672,45 @@ private[channel] object ChannelCodecs4 { ("spliceStatus" | spliceStatusCodec)).as[DATA_NORMAL] val DATA_SHUTDOWN_05_Codec: Codec[DATA_SHUTDOWN] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("localShutdown" | lengthDelimited(shutdownCodec)) :: + ("remoteShutdown" | lengthDelimited(shutdownCodec)) :: + ("closingFeerates" | optional(bool8, closingFeeratesCodec))).as[DATA_SHUTDOWN] + + val DATA_SHUTDOWN_0f_Codec: Codec[DATA_SHUTDOWN] = ( + ("commitments" | versionedCommitmentsCodec) :: ("localShutdown" | lengthDelimited(shutdownCodec)) :: ("remoteShutdown" | lengthDelimited(shutdownCodec)) :: ("closingFeerates" | optional(bool8, closingFeeratesCodec))).as[DATA_SHUTDOWN] val DATA_NEGOTIATING_06_Codec: Codec[DATA_NEGOTIATING] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("localShutdown" | lengthDelimited(shutdownCodec)) :: + ("remoteShutdown" | lengthDelimited(shutdownCodec)) :: + ("closingTxProposed" | listOfN(uint16, listOfN(uint16, lengthDelimited(closingTxProposedCodec)))) :: + ("bestUnpublishedClosingTx_opt" | optional(bool8, closingTxCodec))).as[DATA_NEGOTIATING] + + val DATA_NEGOTIATING_10_Codec: Codec[DATA_NEGOTIATING] = ( + ("commitments" | versionedCommitmentsCodec) :: ("localShutdown" | lengthDelimited(shutdownCodec)) :: ("remoteShutdown" | lengthDelimited(shutdownCodec)) :: ("closingTxProposed" | listOfN(uint16, listOfN(uint16, lengthDelimited(closingTxProposedCodec)))) :: ("bestUnpublishedClosingTx_opt" | optional(bool8, closingTxCodec))).as[DATA_NEGOTIATING] val DATA_CLOSING_07_Codec: Codec[DATA_CLOSING] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("waitingSince" | blockHeight) :: + ("finalScriptPubKey" | lengthDelimited(bytes)) :: + ("mutualCloseProposed" | listOfN(uint16, closingTxCodec)) :: + ("mutualClosePublished" | listOfN(uint16, closingTxCodec)) :: + ("localCommitPublished" | optional(bool8, localCommitPublishedCodec)) :: + ("remoteCommitPublished" | optional(bool8, remoteCommitPublishedCodec)) :: + ("nextRemoteCommitPublished" | optional(bool8, remoteCommitPublishedCodec)) :: + ("futureRemoteCommitPublished" | optional(bool8, remoteCommitPublishedCodec)) :: + ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).as[DATA_CLOSING] + + val DATA_CLOSING_11_Codec: Codec[DATA_CLOSING] = ( + ("commitments" | versionedCommitmentsCodec) :: ("waitingSince" | blockHeight) :: ("finalScriptPubKey" | lengthDelimited(bytes)) :: ("mutualCloseProposed" | listOfN(uint16, closingTxCodec)) :: @@ -648,12 +722,25 @@ private[channel] object ChannelCodecs4 { ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).as[DATA_CLOSING] val DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_08_Codec: Codec[DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT] = ( - ("commitments" | commitmentsCodec) :: + ("commitments" | commitmentsCodecWithoutFirstRemoteCommitIndex) :: + ("remoteChannelReestablish" | channelReestablishCodec)).as[DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT] + + val DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_12_Codec: Codec[DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT] = ( + ("commitments" | versionedCommitmentsCodec) :: ("remoteChannelReestablish" | channelReestablishCodec)).as[DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT] } // Order matters! val channelDataCodec: Codec[PersistentChannelData] = discriminated[PersistentChannelData].by(uint16) + .typecase(0x12, Codecs.DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_12_Codec) + .typecase(0x11, Codecs.DATA_CLOSING_11_Codec) + .typecase(0x10, Codecs.DATA_NEGOTIATING_10_Codec) + .typecase(0x0f, Codecs.DATA_SHUTDOWN_0f_Codec) + .typecase(0x0e, Codecs.DATA_NORMAL_0e_Codec) + .typecase(0x0d, Codecs.DATA_WAIT_FOR_DUAL_FUNDING_READY_0d_Codec) + .typecase(0x0c, Codecs.DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED_0c_Codec) + .typecase(0x0b, Codecs.DATA_WAIT_FOR_CHANNEL_READY_0b_Codec) + .typecase(0x0a, Codecs.DATA_WAIT_FOR_FUNDING_CONFIRMED_0a_Codec) .typecase(0x09, Codecs.DATA_WAIT_FOR_DUAL_FUNDING_SIGNED_09_Codec) .typecase(0x08, Codecs.DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_08_Codec) .typecase(0x07, Codecs.DATA_CLOSING_07_Codec) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala index 4ec9b9a026..34a6aebc6e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala @@ -495,7 +495,7 @@ object CommitmentsSpec { Commitments( ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announceChannel)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), - List(Commitment(0, remoteFundingPubKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), + List(Commitment(0, 0, remoteFundingPubKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, Right(randomKey().publicKey), ShaChain.init, @@ -514,7 +514,7 @@ object CommitmentsSpec { Commitments( ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announceChannel)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), - List(Commitment(0, remoteFundingPubKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), + List(Commitment(0, 0, remoteFundingPubKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, Right(randomKey().publicKey), ShaChain.init, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala index 90ff1ecde8..6ff72c66cd 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala @@ -133,7 +133,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat Commitments( ChannelParams(dummyBytes32, ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = true)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), - List(Commitment(0, dummyPublicKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), + List(Commitment(0, 0, dummyPublicKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, Right(dummyPublicKey), ShaChain.init, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala index eecfa5d933..213779c489 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala @@ -737,7 +737,7 @@ object PaymentPacketSpec { new Commitments( ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParams, remoteParams, channelFlags), CommitmentChanges(localChanges, remoteChanges, 0, 0), - List(Commitment(0, null, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), + List(Commitment(0, 0, null, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, Right(randomKey().publicKey), ShaChain.init, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala index cde6a80a7d..b6df964c9c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala @@ -93,7 +93,7 @@ class ChannelCodecsSpec extends AnyFunSuite { // and re-encode it with the new codec val bin_new = ByteVector(channelDataCodec.encode(data_new).require.toByteVector.toArray) // data should now be encoded under the new format - assert(bin_new.startsWith(hex"040000")) + assert(bin_new.startsWith(hex"04000a")) // now let's decode it again val data_new2 = channelDataCodec.decode(bin_new.toBitVector).require.value // data should match perfectly @@ -324,7 +324,7 @@ object ChannelCodecsSpec { val commitments = Commitments( ChannelParams(channelId, ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, channelFlags), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 32, remoteNextHtlcId = 4), - Seq(Commitment(fundingTxIndex, remoteFundingPubKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.NotLocked, localCommit, remoteCommit, None)), + Seq(Commitment(fundingTxIndex, 0, remoteFundingPubKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.NotLocked, localCommit, remoteCommit, None)), remoteNextCommitInfo = Right(randomKey().publicKey), remotePerCommitmentSecrets = ShaChain.init, originChannels = origins) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala index ac16627e6e..a1706baef6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala @@ -183,7 +183,6 @@ class ChannelCodecs4Spec extends AnyFunSuite { )), remoteFundingPubKey = PrivateKey(ByteVector.fromValidHex("01" * 32)).publicKey, localOutputs = Nil, lockTime = 0, dustLimit = 330.sat, targetFeerate = FeeratePerKw(FeeratePerByte(3.sat)), requireConfirmedInputs = RequireConfirmedInputs(forLocal = false, forRemote = false)), - firstCommitIndex_opt = None ) assert(decoded == dualFundedUnconfirmedFundingTx) }