diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala index 2325beaf3b..2e53f9fecb 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala @@ -427,12 +427,6 @@ object Features { val mandatory = 152 } - // TODO: @pm47 custom splices implementation for phoenix, to be replaced once splices is spec-ed (currently reserved here: https://github.com/lightning/bolts/issues/605) - case object SplicePrototype extends Feature with InitFeature { - val rfcName = "splice_prototype" - val mandatory = 154 - } - case object SimpleTaprootChannelsPhoenix extends Feature with InitFeature with NodeFeature with ChannelTypeFeature { val rfcName = "option_simple_taproot_phoenix" val mandatory = 564 @@ -492,7 +486,6 @@ object Features { WakeUpNotificationClient, TrampolinePaymentPrototype, AsyncPaymentPrototype, - SplicePrototype, OnTheFlyFunding, FundingFeeCredit, PhoenixZeroReserve 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 5a630f50df..dd18fca801 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 @@ -33,8 +33,6 @@ case class ChannelParams(channelId: ByteVector32, val remoteNodeId: PublicKey = remoteParams.nodeId // If we've set the 0-conf feature bit for this peer, we will always use 0-conf with them. val zeroConf: Boolean = localParams.initFeatures.hasFeature(Features.ZeroConf) - // TODO: we keep supporting the legacy splicing protocol for non-upgraded Phoenix users. - lazy val useLegacySpliceProtocol = remoteParams.initFeatures.hasFeature(Features.SplicePrototype) /** We update local/global features at reconnection. */ def updateFeatures(localInit: Init, remoteInit: Init): ChannelParams = copy( 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 407f0cb903..f0d84e8f54 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 @@ -247,8 +247,6 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // we record the announcement_signatures messages we already sent to avoid unnecessary retransmission var announcementSigsSent = Set.empty[RealShortChannelId] // we keep track of the splice_locked we sent after channel_reestablish and it's funding tx index to avoid sending it again - // TODO: we can remove that once we stop supporting the legacy splicing protocol - private var spliceLockedSent = Map.empty[TxId, Long] private def trimAnnouncementSigsStashIfNeeded(): Unit = { if (announcementSigsStash.size >= 10) { @@ -260,17 +258,6 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } } - private def trimSpliceLockedSentIfNeeded(): Unit = { - if (spliceLockedSent.size >= 10) { - // We shouldn't store an unbounded number of splice_locked: on long-lived connections where we do a lot of splice - // transactions, we only need to keep track of the most recent ones. - val oldestFundingTxId = spliceLockedSent.toSeq - .sortBy { case (_, fundingTxIndex) => fundingTxIndex } - .map { case (fundingTxId, _) => fundingTxId }.head - spliceLockedSent -= oldestFundingTxId - } - } - val txPublisher = txPublisherFactory.spawnTxPublisher(context, remoteNodeId) // this will be used to detect htlc timeouts @@ -956,7 +943,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } case Event(cmd: CMD_SPLICE, d: DATA_NORMAL) => - if (!d.commitments.remoteChannelParams.initFeatures.hasFeature(Features.Splicing) && !d.commitments.remoteChannelParams.initFeatures.hasFeature(Features.SplicePrototype)) { + if (!d.commitments.remoteChannelParams.initFeatures.hasFeature(Features.Splicing)) { log.warning("cannot initiate splice, peer doesn't support splicing") cmd.replyTo ! RES_FAILURE(cmd, CommandUnavailableInThisState(d.channelId, "splice", NORMAL)) stay() @@ -1477,12 +1464,10 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(w: WatchPublishedTriggered, d: DATA_NORMAL) => val fundingStatus = LocalFundingStatus.ZeroconfPublishedFundingTx(w.tx, d.commitments.localFundingSigs(w.tx.txid), d.commitments.liquidityPurchase(w.tx.txid)) d.commitments.updateLocalFundingStatus(w.tx.txid, fundingStatus, d.lastAnnouncedFundingTxId_opt) match { - case Right((commitments1, commitment)) => + case Right((commitments1, _)) => watchFundingConfirmed(w.tx.txid, Some(nodeParams.channelConf.minDepth), delay_opt = None) maybeEmitEventsPostSplice(d.aliases, d.commitments, commitments1, d.lastAnnouncement_opt) maybeUpdateMaxHtlcAmount(d.channelUpdate.htlcMaximumMsat, commitments1) - spliceLockedSent += (commitment.fundingTxId -> commitment.fundingTxIndex) - trimSpliceLockedSentIfNeeded() stay() using d.copy(commitments = commitments1) storing() sending SpliceLocked(d.channelId, w.tx.txid) case Left(_) => stay() } @@ -1493,11 +1478,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // We check if this commitment was already locked before receiving the event (which happens when using 0-conf // or for the initial funding transaction). If it was previously not locked, we must send splice_locked now. val previouslyNotLocked = d.commitments.all.exists(c => c.fundingTxId == commitment.fundingTxId && c.localFundingStatus.isInstanceOf[LocalFundingStatus.NotLocked]) - val spliceLocked_opt = if (previouslyNotLocked) { - spliceLockedSent += (commitment.fundingTxId -> commitment.fundingTxIndex) - trimSpliceLockedSentIfNeeded() - Some(SpliceLocked(d.channelId, w.tx.txid)) - } else None + val spliceLocked_opt = if (previouslyNotLocked) Some(SpliceLocked(d.channelId, w.tx.txid)) else None // If the channel is public and we've received the remote splice_locked, we send our announcement_signatures // in order to generate the channel_announcement. val remoteLocked = commitment.fundingTxIndex == 0 || d.commitments.all.exists(c => c.fundingTxId == commitment.fundingTxId && c.remoteFundingStatus == RemoteFundingStatus.Locked) @@ -1520,25 +1501,6 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(msg: SpliceLocked, d: DATA_NORMAL) => d.commitments.updateRemoteFundingStatus(msg.fundingTxId, d.lastAnnouncedFundingTxId_opt) match { case Right((commitments1, commitment)) => - val spliceLocked_opt = if (d.channelParams.useLegacySpliceProtocol) { - // If we have both already sent splice_locked for this commitment, then we are receiving splice_locked - // again after a reconnection and must retransmit our splice_locked and new announcement_signatures. Nodes - // retransmit splice_locked after a reconnection when they have received splice_locked but NOT matching signatures - // before the last disconnect. If a matching splice_locked has already been sent since reconnecting, then do not - // retransmit splice_locked to avoid a loop. - // NB: It is important both nodes retransmit splice_locked after reconnecting to ensure new Taproot nonces - // are exchanged for channel announcements. - val isLatestLocked = d.commitments.lastLocalLocked_opt.exists(_.fundingTxId == msg.fundingTxId) && d.commitments.lastRemoteLocked_opt.exists(_.fundingTxId == msg.fundingTxId) - if (d.commitments.announceChannel && isLatestLocked && !spliceLockedSent.contains(commitment.fundingTxId)) { - spliceLockedSent += (commitment.fundingTxId -> commitment.fundingTxIndex) - trimSpliceLockedSentIfNeeded() - Some(SpliceLocked(d.channelId, commitment.fundingTxId)) - } else { - None - } - } else { - None - } // If the commitment is confirmed, we were waiting to receive the remote splice_locked before sending our announcement_signatures. val localAnnSigs_opt = commitment.signAnnouncement(nodeParams, commitments1.channelParams, channelKeys.fundingKey(commitment.fundingTxIndex)) match { case Some(localAnnSigs) if !announcementSigsSent.contains(localAnnSigs.shortChannelId) => @@ -1551,7 +1513,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } maybeEmitEventsPostSplice(d.aliases, d.commitments, commitments1, d.lastAnnouncement_opt) maybeUpdateMaxHtlcAmount(d.channelUpdate.htlcMaximumMsat, commitments1) - stay() using d.copy(commitments = commitments1) storing() sending spliceLocked_opt.toSeq ++ localAnnSigs_opt.toSeq + stay() using d.copy(commitments = commitments1) storing() sending localAnnSigs_opt.toSeq case Left(_) => stay() } @@ -2417,11 +2379,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(INPUT_RECONNECTED(r, localInit, remoteInit), d: DATA_WAIT_FOR_DUAL_FUNDING_SIGNED) => activeConnection = r val myFirstPerCommitmentPoint = channelKeys.commitmentPoint(0) - val nextFundingTlv = if (d.channelParams.useLegacySpliceProtocol) { - Set[ChannelReestablishTlv](ChannelReestablishTlv.ExperimentalNextFundingTlv(d.signingSession.fundingTxId)) - } else { - Set[ChannelReestablishTlv](ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(d.signingSession.fundingTxId, d.signingSession.retransmitRemoteCommitSig)) - } + val nextFundingTlv = Set[ChannelReestablishTlv](ChannelReestablishTlv.NextFundingTlv(d.signingSession.fundingTxId, d.signingSession.retransmitRemoteCommitSig)) val nonceTlvs = d.signingSession.fundingParams.commitmentFormat match { case _: SegwitV0CommitmentFormat => Set.empty case _: SimpleTaprootChannelCommitmentFormat => @@ -2439,7 +2397,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } val channelReestablish = ChannelReestablish( channelId = d.channelId, - nextLocalCommitmentNumber = d.signingSession.nextLocalCommitmentNumber(d.channelParams.useLegacySpliceProtocol), + nextLocalCommitmentNumber = 1, nextRemoteRevocationNumber = 0, yourLastPerCommitmentSecret = PrivateKey(ByteVector32.Zeroes), myCurrentPerCommitmentPoint = myFirstPerCommitmentPoint, @@ -2453,61 +2411,25 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val remotePerCommitmentSecrets = d.commitments.remotePerCommitmentSecrets val yourLastPerCommitmentSecret = remotePerCommitmentSecrets.lastIndex.flatMap(remotePerCommitmentSecrets.getHash).getOrElse(ByteVector32.Zeroes) val myCurrentPerCommitmentPoint = channelKeys.commitmentPoint(d.commitments.localCommitIndex) - // TODO: replace by d.commitments.localCommitIndex + 1 when removing support for the legacy splice protocol. - val nextLocalCommitmentNumber = d match { - case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match { - case DualFundingStatus.RbfWaitingForSigs(status) => status.nextLocalCommitmentNumber(d.channelParams.useLegacySpliceProtocol) - case _ => d.commitments.localCommitIndex + 1 - } - case d: DATA_NORMAL => d.spliceStatus match { - case SpliceStatus.SpliceWaitingForSigs(status) => status.nextLocalCommitmentNumber(d.channelParams.useLegacySpliceProtocol) - case _ => d.commitments.localCommitIndex + 1 - } - case _ => d.commitments.localCommitIndex + 1 - } // If we disconnected while signing a funding transaction, we may need our peer to (re)transmit their tx_signatures and commit_sig. - val rbfTlv: Set[ChannelReestablishTlv] = if (d.channelParams.useLegacySpliceProtocol) { - d match { - case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match { - case DualFundingStatus.RbfWaitingForSigs(status) => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(status.fundingTx.txId)) - case _ => d.latestFundingTx.sharedTx match { - case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(d.latestFundingTx.sharedTx.txId)) - case _: InteractiveTxBuilder.FullySignedSharedTransaction => Set.empty - } - } - case d: DATA_NORMAL => d.spliceStatus match { - case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(status.fundingTx.txId)) - case _ => d.commitments.latest.localFundingStatus match { - case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _, _) => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(fundingTx.txId)) - case _ => Set.empty - } + val rbfTlv: Set[ChannelReestablishTlv] = d match { + case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match { + case DualFundingStatus.RbfWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingTlv(status.fundingTx.txId, status.retransmitRemoteCommitSig)) + case _ => d.latestFundingTx.sharedTx match { + case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.NextFundingTlv(d.latestFundingTx.sharedTx.txId, retransmitCommitSig = false)) + case _: InteractiveTxBuilder.FullySignedSharedTransaction => Set.empty } - case _ => Set.empty } - } else { - d match { - case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match { - case DualFundingStatus.RbfWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(status.fundingTx.txId, status.retransmitRemoteCommitSig)) - case _ => d.latestFundingTx.sharedTx match { - case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(d.latestFundingTx.sharedTx.txId, retransmitCommitSig = false)) - case _: InteractiveTxBuilder.FullySignedSharedTransaction => Set.empty - } - } - case d: DATA_NORMAL => d.spliceStatus match { - case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(status.fundingTx.txId, status.retransmitRemoteCommitSig)) - case _ => d.commitments.latest.localFundingStatus match { - case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _, _) => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(fundingTx.txId, retransmitCommitSig = false)) - case _ => Set.empty - } + case d: DATA_NORMAL => d.spliceStatus match { + case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingTlv(status.fundingTx.txId, status.retransmitRemoteCommitSig)) + case _ => d.commitments.latest.localFundingStatus match { + case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _, _) => Set(ChannelReestablishTlv.NextFundingTlv(fundingTx.txId, retransmitCommitSig = false)) + case _ => Set.empty } - case _ => Set.empty } + case _ => Set.empty } - val lastFundingLockedTlvs: Set[ChannelReestablishTlv] = if (d.channelParams.useLegacySpliceProtocol) { - val myCurrentFundingLocked_opt = d.commitments.lastLocalLocked_opt.map(c => ChannelReestablishTlv.ExperimentalMyCurrentFundingLockedTlv(c.fundingTxId)) - val yourLastFundingLocked_opt = d.commitments.lastRemoteLocked_opt.map(c => ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asExperimentalYourLastFundingLocked(c.fundingTxId)) - myCurrentFundingLocked_opt.toSet ++ yourLastFundingLocked_opt.toSet - } else if (d.channelParams.remoteParams.initFeatures.hasFeature(Features.Splicing)) { + val lastFundingLockedTlvs: Set[ChannelReestablishTlv] = if (d.channelParams.remoteParams.initFeatures.hasFeature(Features.Splicing)) { d.commitments.lastLocalLocked_opt.map(c => { // We ask our peer to retransmit their announcement_signatures if we haven't already announced that splice. val retransmitAnnSigs = d match { @@ -2552,7 +2474,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val channelReestablish = ChannelReestablish( channelId = d.channelId, - nextLocalCommitmentNumber = nextLocalCommitmentNumber, + nextLocalCommitmentNumber = d.commitments.localCommitIndex + 1, nextRemoteRevocationNumber = d.commitments.remoteCommitIndex, yourLastPerCommitmentSecret = PrivateKey(yourLastPerCommitmentSecret), myCurrentPerCommitmentPoint = myCurrentPerCommitmentPoint, @@ -2603,13 +2525,8 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall handleLocalError(f, d, Some(channelReestablish)) case _ => remoteNextCommitNonces = channelReestablish.nextCommitNonces - val retransmitCommitSig = if (d.channelParams.useLegacySpliceProtocol) { - channelReestablish.nextLocalCommitmentNumber == 0 - } else { - channelReestablish.retransmitInteractiveTxCommitSig - } channelReestablish.nextFundingTxId_opt match { - case Some(fundingTxId) if fundingTxId == d.signingSession.fundingTx.txId && retransmitCommitSig => + case Some(fundingTxId) if fundingTxId == d.signingSession.fundingTx.txId && channelReestablish.retransmitInteractiveTxCommitSig => // They haven't received our commit_sig: we retransmit it, and will send our tx_signatures once we've received // their commit_sig or their tx_signatures (depending on who must send tx_signatures first). val fundingParams = d.signingSession.fundingParams @@ -2633,16 +2550,11 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Some(f) => handleLocalError(f, d, Some(channelReestablish)) case None => remoteNextCommitNonces = channelReestablish.nextCommitNonces - val retransmitCommitSig = if (d.channelParams.useLegacySpliceProtocol) { - channelReestablish.nextLocalCommitmentNumber == 0 - } else { - channelReestablish.retransmitInteractiveTxCommitSig - } channelReestablish.nextFundingTxId_opt match { case Some(fundingTxId) => d.status match { case DualFundingStatus.RbfWaitingForSigs(signingSession) if signingSession.fundingTx.txId == fundingTxId => - if (retransmitCommitSig) { + if (channelReestablish.retransmitInteractiveTxCommitSig) { // They haven't received our commit_sig: we retransmit it. // We're also waiting for signatures from them, and will send our tx_signatures once we receive them. val fundingParams = signingSession.fundingParams @@ -2659,7 +2571,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case _ if d.latestFundingTx.sharedTx.txId == fundingTxId => // We've already received their commit_sig and sent our tx_signatures. We retransmit our tx_signatures // and our commit_sig if they haven't received it already. - if (retransmitCommitSig) { + if (channelReestablish.retransmitInteractiveTxCommitSig) { val remoteNonce_opt = channelReestablish.currentCommitNonce_opt d.commitments.latest.remoteCommit.sign(d.commitments.channelParams, d.commitments.latest.remoteCommitParams, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput(channelKeys), d.commitments.latest.commitmentFormat, remoteNonce_opt) match { case Left(e) => handleLocalError(e, d, Some(channelReestablish)) @@ -2694,15 +2606,10 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val channelReady = createChannelReady(d.aliases, d.commitments) // We've already received their commit_sig and sent our tx_signatures. We retransmit our tx_signatures // and our commit_sig if they haven't received it already. - val retransmitCommitSig = if (d.channelParams.useLegacySpliceProtocol) { - channelReestablish.nextLocalCommitmentNumber == 0 - } else { - channelReestablish.retransmitInteractiveTxCommitSig - } channelReestablish.nextFundingTxId_opt match { case Some(fundingTxId) if fundingTxId == d.commitments.latest.fundingTxId => d.commitments.latest.localFundingStatus.localSigs_opt match { - case Some(txSigs) if retransmitCommitSig => + case Some(txSigs) if channelReestablish.retransmitInteractiveTxCommitSig => log.info("re-sending commit_sig and tx_signatures for fundingTxIndex={} fundingTxId={}", d.commitments.latest.fundingTxIndex, d.commitments.latest.fundingTxId) val remoteNonce_opt = channelReestablish.currentCommitNonce_opt d.commitments.latest.remoteCommit.sign(d.commitments.channelParams, d.commitments.latest.remoteCommitParams, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput(channelKeys), d.commitments.latest.commitmentFormat, remoteNonce_opt) match { @@ -2754,11 +2661,9 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Some(f) => handleLocalError(f, d, Some(channelReestablish)) case None => remoteNextCommitNonces = channelReestablish.nextCommitNonces - // We re-send our latest splice_locked if needed. - val spliceLocked_opt = resendSpliceLockedIfNeeded(commitments1) // We retransmit our latest announcement_signatures if our peer requests it. val spliceAnnSigs_opt = resendSpliceAnnSigsIfNeeded(channelReestablish, commitments1) - sendQueue = sendQueue ++ spliceLocked_opt.toSeq ++ spliceAnnSigs_opt.toSeq + sendQueue = sendQueue ++ spliceAnnSigs_opt.toSeq // We may need to retransmit updates and/or commit_sig and/or revocation to resume the channel. sendQueue = sendQueue ++ syncSuccess.retransmit @@ -3261,7 +3166,6 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case _ -> OFFLINE => announcementSigsStash = Map.empty announcementSigsSent = Set.empty - spliceLockedSent = Map.empty[TxId, Long] remoteNextCommitNonces = Map.empty localCloseeNonce_opt = None remoteCloseeNonce_opt = None @@ -3462,7 +3366,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // will also send announcement_signatures. val notAnnouncedYet = d.commitments.announceChannel && c.shortChannelId_opt.nonEmpty && d.lastAnnouncement_opt.isEmpty // If our peer is a phoenix wallet using the legacy splicing protocol, we always retransmit channel_ready. - val channelReady_opt = if (notAnnouncedYet || notReceivedByRemote || d.channelParams.useLegacySpliceProtocol) { + val channelReady_opt = if (notAnnouncedYet || notReceivedByRemote) { log.debug("re-sending channel_ready") Some(createChannelReady(d.aliases, d.commitments)) } else { @@ -3484,16 +3388,11 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall private def resumeSpliceSigningSessionIfNeeded(channelReestablish: ChannelReestablish, d: DATA_NORMAL): (SpliceStatus, Queue[LightningMessage]) = { var sendQueue = Queue.empty[LightningMessage] - val retransmitCommitSig = if (d.channelParams.useLegacySpliceProtocol) { - channelReestablish.nextLocalCommitmentNumber == d.commitments.remoteCommitIndex - } else { - channelReestablish.retransmitInteractiveTxCommitSig - } val spliceStatus1 = channelReestablish.nextFundingTxId_opt match { case Some(fundingTxId) => d.spliceStatus match { case SpliceStatus.SpliceWaitingForSigs(signingSession) if signingSession.fundingTx.txId == fundingTxId => - if (retransmitCommitSig) { + if (channelReestablish.retransmitInteractiveTxCommitSig) { // They haven't received our commit_sig: we retransmit it. // We're also waiting for signatures from them, and will send our tx_signatures once we receive them. log.info("re-sending commit_sig for splice attempt with fundingTxIndex={} fundingTxId={}", signingSession.fundingTxIndex, signingSession.fundingTx.txId) @@ -3510,7 +3409,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case dfu: LocalFundingStatus.DualFundedUnconfirmedFundingTx => // We've already received their commit_sig and sent our tx_signatures. We retransmit our // tx_signatures and our commit_sig if they haven't received it already. - if (retransmitCommitSig) { + if (channelReestablish.retransmitInteractiveTxCommitSig) { log.info("re-sending commit_sig and tx_signatures for fundingTxIndex={} fundingTxId={}", d.commitments.latest.fundingTxIndex, d.commitments.latest.fundingTxId) val remoteNonce_opt = channelReestablish.currentCommitNonce_opt d.commitments.latest.remoteCommit.sign(d.commitments.channelParams, d.commitments.latest.remoteCommitParams, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput(channelKeys), d.commitments.latest.commitmentFormat, remoteNonce_opt) match { @@ -3539,22 +3438,6 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall (spliceStatus1, sendQueue) } - private def resendSpliceLockedIfNeeded(commitments: Commitments): Option[SpliceLocked] = { - commitments.lastLocalLocked_opt match { - case None => None - // We only send splice_locked for splice transactions. - case Some(c) if c.fundingTxIndex == 0 => None - case Some(c) => - // We only send splice_locked for legacy phoenix wallets using the old splicing protocol. - if (commitments.channelParams.useLegacySpliceProtocol) { - log.debug("re-sending splice_locked for fundingTxId={}", c.fundingTxId) - Some(SpliceLocked(commitments.channelId, c.fundingTxId)) - } else { - None - } - } - } - private def resendSpliceAnnSigsIfNeeded(channelReestablish: ChannelReestablish, commitments: Commitments): Option[AnnouncementSignatures] = { commitments.lastLocalLocked_opt match { case None => None 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 b054ecc980..2d5c0819ee 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 @@ -1209,13 +1209,6 @@ object InteractiveTxSigningSession { // If we haven't received the remote commit_sig, we will request a retransmission on reconnection. val retransmitRemoteCommitSig: Boolean = localCommit.isLeft - // For the legacy splice protocol, we use the next_commitment_number to let our peer know whether they needed to - // retransmit commit_sig or not. We're now using an explicit bit instead, but need to maintain backwards-compatibility. - def nextLocalCommitmentNumber(useLegacySpliceProtocol: Boolean): Long = localCommit match { - case Left(unsignedCommit) if useLegacySpliceProtocol => unsignedCommit.index - case _ => localCommitIndex + 1 - } - def localFundingKey(channelKeys: ChannelKeys): PrivateKey = channelKeys.fundingKey(fundingTxIndex) def commitInput(fundingKey: PrivateKey): InputInfo = { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala index 4a81d38cc4..b3a3e9cb47 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala @@ -207,15 +207,7 @@ class PeerConnection(keyPair: KeyPair, conf: PeerConnection.Conf, switchboard: A stay() case Event(msg: LightningMessage, d: ConnectedData) if sender() != d.transport => // if the message doesn't originate from the transport, it is an outgoing message - val useExperimentalSplice = d.remoteInit.features.hasFeature(Features.SplicePrototype) msg match { - // If our peer is using the experimental splice version, we convert splice messages. - case msg: SpliceInit if useExperimentalSplice => d.transport forward ExperimentalSpliceInit.from(msg) - case msg: SpliceAck if useExperimentalSplice => d.transport forward ExperimentalSpliceAck.from(msg) - case msg: SpliceLocked if useExperimentalSplice => d.transport forward ExperimentalSpliceLocked.from(msg) - case msg: TxAddInput if useExperimentalSplice => d.transport forward msg.copy(tlvStream = TlvStream(msg.tlvStream.records.filterNot(_.isInstanceOf[TxAddInputTlv.SharedInputTxId]))) - case msg: TxSignatures if useExperimentalSplice => d.transport forward msg.copy(tlvStream = TlvStream(msg.tlvStream.records.filterNot(_.isInstanceOf[TxSignaturesTlv.PreviousFundingTxSig]))) - case batch: CommitSigBatch if useExperimentalSplice => batch.messages.foreach(msg => d.transport forward msg.copy(tlvStream = TlvStream(msg.tlvStream.records.filterNot(_.isInstanceOf[CommitSigTlv.FundingTx])))) case batch: CommitSigBatch => // We insert a start_batch message to let our peer know how many commit_sig they will receive. d.transport forward StartBatch.commitSigBatch(batch.channelId, batch.batchSize) @@ -399,51 +391,6 @@ class PeerConnection(keyPair: KeyPair, conf: PeerConnection.Conf, switchboard: A d.peer ! msg stay() using d.copy(commitSigBatch_opt = None) } - case msg: CommitSig => - // We keep supporting the experimental version of splicing that older Phoenix wallets use. - // Once we're confident that enough Phoenix users have upgraded, we should remove this branch. - msg.tlvStream.get[CommitSigTlv.ExperimentalBatchTlv].map(_.size) match { - case Some(batchSize) if batchSize > 25 => - log.warning("received legacy batch of commit_sig exceeding our threshold ({} > 25), processing messages individually", batchSize) - // We don't want peers to be able to exhaust our memory by sending batches of dummy messages that we keep in RAM. - d.peer ! msg - stay() - case Some(batchSize) if batchSize > 1 => - d.legacyCommitSigBatch_opt match { - case Some(pending) if pending.channelId != msg.channelId || pending.batchSize != batchSize => - log.warning("received invalid commit_sig batch while a different batch isn't complete") - // This should never happen, otherwise it will likely lead to a force-close. - d.peer ! CommitSigBatch(pending.received) - stay() using d.copy(legacyCommitSigBatch_opt = Some(PendingCommitSigBatch(msg.channelId, batchSize, Seq(msg)))) - case Some(pending) => - val received1 = pending.received :+ msg - if (received1.size == batchSize) { - log.debug("received last commit_sig in legacy batch for channel_id={}", msg.channelId) - d.peer ! CommitSigBatch(received1) - stay() using d.copy(legacyCommitSigBatch_opt = None) - } else { - log.debug("received commit_sig {}/{} in legacy batch for channel_id={}", received1.size, batchSize, msg.channelId) - stay() using d.copy(legacyCommitSigBatch_opt = Some(pending.copy(received = received1))) - } - case None => - log.debug("received first commit_sig in legacy batch of size {} for channel_id={}", batchSize, msg.channelId) - stay() using d.copy(legacyCommitSigBatch_opt = Some(PendingCommitSigBatch(msg.channelId, batchSize, Seq(msg)))) - } - case _ => - log.debug("received individual commit_sig for channel_id={}", msg.channelId) - d.peer ! msg - stay() - } - // If our peer is using the experimental splice version, we convert splice messages. - case msg: ExperimentalSpliceInit => - d.peer ! msg.toSpliceInit - stay() - case msg: ExperimentalSpliceAck => - d.peer ! msg.toSpliceAck - stay() - case msg: ExperimentalSpliceLocked => - d.peer ! msg.toSpliceLocked - stay() case _ => d.peer ! msg stay() @@ -677,7 +624,6 @@ object PeerConnection { behavior: Behavior = Behavior(), expectedPong_opt: Option[ExpectedPong] = None, commitSigBatch_opt: Option[PendingCommitSigBatch] = None, - legacyCommitSigBatch_opt: Option[PendingCommitSigBatch] = None, isPersistent: Boolean) extends Data with HasTransport case class PendingCommitSigBatch(channelId: ByteVector32, batchSize: Int, received: Seq[CommitSig]) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala index 6c6ec2ed13..29ddbd22ea 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala @@ -17,7 +17,7 @@ package fr.acinq.eclair.wire.protocol import fr.acinq.bitcoin.scalacompat.Musig2.IndividualNonce -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Satoshi, TxHash, TxId} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Satoshi, TxId} import fr.acinq.eclair.channel.ChannelSpendSignature.PartialSignatureWithNonce import fr.acinq.eclair.channel.{ChannelType, ChannelTypes} import fr.acinq.eclair.wire.protocol.CommonCodecs._ @@ -255,31 +255,6 @@ sealed trait ChannelReestablishTlv extends Tlv object ChannelReestablishTlv { - /** TODO: replaced by [[NextFundingTlv]], remove once Phoenix users have upgraded. */ - case class ExperimentalNextFundingTlv(txId: TxId) extends ChannelReestablishTlv - - /** - * We unfortunately have a conflict between the splicing protocol we use for Phoenix and the official one. - * The official protocol uses TLV = 1 for the next_funding TLV, which should be implemented by [[NextFundingTlv]] - * (which is commented out below). - * The splicing protocol used for Phoenix also uses TLV = 1, but for a different TLV that was removed from the - * official splicing protocol (your_last_funding_locked), which contained the txid of the last [[ChannelReady]] or - * [[SpliceLocked]] message received before disconnecting, if any. - * - * To guarantee backwards-compatibility, we create a TLV field that may contain both options. When using the official - * splicing protocol, it will contain 33 bytes (a txid and a bitfield), while when using the legacy protocol it only - * contains a txid, which lets us easily distinguish the two. - * - * TODO: once we can remove support for Phoenix users with the legacy splicing protocol, this should just be replaced - * by [[NextFundingTlv]] which is commented out below and should be uncommented. - */ - case class NextFundingOrExperimentalYourLastFundingLockedTlv(data: ByteVector) extends ChannelReestablishTlv { - val isOfficial: Boolean = data.size == 33 - val txId: TxId = TxId(TxHash(ByteVector32(data.take(32)))) - // NB: this is only used for the official splicing protocol. - val retransmitCommitSig: Boolean = if (isOfficial) (data.last.toInt % 2) == 1 else false - } - /** * When disconnected in the middle of an interactive-tx session, this field is used to request a retransmission of * [[TxSignatures]] for the given [[txId]]. @@ -287,10 +262,7 @@ object ChannelReestablishTlv { * @param txId the txid of the partially signed funding transaction. * @param retransmitCommitSig true if [[CommitSig]] must be retransmitted before [[TxSignatures]]. */ - // case class NextFundingTlv(txId: TxId, retransmitCommitSig: Boolean) extends ChannelReestablishTlv - - /** TODO: replaced by [[MyCurrentFundingLockedTlv]], remove once Phoenix users have upgraded. */ - case class ExperimentalMyCurrentFundingLockedTlv(txId: TxId) extends ChannelReestablishTlv + case class NextFundingTlv(txId: TxId, retransmitCommitSig: Boolean) extends ChannelReestablishTlv /** * @param txId the txid of our latest outgoing [[ChannelReady]] or [[SpliceLocked]] for this channel. @@ -311,27 +283,8 @@ object ChannelReestablishTlv { */ case class NextLocalNoncesTlv(nonces: Seq[(TxId, IndividualNonce)]) extends ChannelReestablishTlv - object ExperimentalNextFundingTlv { - val codec: Codec[ExperimentalNextFundingTlv] = tlvField(txIdAsHash) - } - - // object NextFundingTlv { - // val codec: Codec[NextFundingTlv] = tlvField(("next_funding_txid" | txIdAsHash) :: ("retransmit_flags" | (ignore(7) :: bool))) - // } - - object NextFundingOrExperimentalYourLastFundingLockedTlv { - def asNextFunding(txId: TxId, retransmitCommitSig: Boolean): NextFundingOrExperimentalYourLastFundingLockedTlv = { - val retransmitFlags = if (retransmitCommitSig) ByteVector.fromValidHex("01") else ByteVector.fromValidHex("00") - NextFundingOrExperimentalYourLastFundingLockedTlv(TxHash(txId).value ++ retransmitFlags) - } - - def asExperimentalYourLastFundingLocked(txId: TxId): NextFundingOrExperimentalYourLastFundingLockedTlv = NextFundingOrExperimentalYourLastFundingLockedTlv(TxHash(txId).value) - - val codec: Codec[NextFundingOrExperimentalYourLastFundingLockedTlv] = tlvField(bytes) - } - - object ExperimentalMyCurrentFundingLockedTlv { - val codec: Codec[ExperimentalMyCurrentFundingLockedTlv] = tlvField("my_current_funding_locked_txid" | txIdAsHash) + object NextFundingTlv { + val codec: Codec[NextFundingTlv] = tlvField(("next_funding_txid" | txIdAsHash) :: ("retransmit_flags" | (ignore(7) :: bool))) } object MyCurrentFundingLockedTlv { @@ -347,11 +300,7 @@ object ChannelReestablishTlv { } val channelReestablishTlvCodec: Codec[TlvStream[ChannelReestablishTlv]] = tlvStream(discriminated[ChannelReestablishTlv].by(varint) - .typecase(UInt64(0), ExperimentalNextFundingTlv.codec) - // TODO: replace with the commented line below when removing support for the legacy splicing protocol. - .typecase(UInt64(1), NextFundingOrExperimentalYourLastFundingLockedTlv.codec) - // .typecase(UInt64(1), NextFundingTlv.codec) - .typecase(UInt64(3), ExperimentalMyCurrentFundingLockedTlv.codec) + .typecase(UInt64(1), NextFundingTlv.codec) .typecase(UInt64(5), MyCurrentFundingLockedTlv.codec) .typecase(UInt64(22), NextLocalNoncesTlv.codec) .typecase(UInt64(24), CurrentCommitNonceTlv.codec) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala index 3eb0c34b98..f5355aa0b4 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/InteractiveTxTlv.scala @@ -36,9 +36,6 @@ object TxAddInputTlv { /** When doing a splice, the initiator must provide the previous funding txId instead of the whole transaction. */ case class SharedInputTxId(txId: TxId) extends TxAddInputTlv - /** Same as [[SharedInputTxId]] for peers who only support the experimental version of splicing. */ - case class ExperimentalSharedInputTxId(txId: TxId) extends TxAddInputTlv - /** * When creating an interactive-tx where both participants sign a taproot input, we don't need to provide the entire * previous transaction in [[TxAddInput]]: signatures will commit to the txOut of *all* of the transaction's inputs, @@ -53,7 +50,6 @@ object TxAddInputTlv { val txAddInputTlvCodec: Codec[TlvStream[TxAddInputTlv]] = tlvStream(discriminated[TxAddInputTlv].by(varint) // Note that we actually encode as a tx_hash to be consistent with other lightning messages. .typecase(UInt64(0), tlvField(txIdAsHash.as[SharedInputTxId])) - .typecase(UInt64(1105), tlvField(txIdAsHash.as[ExperimentalSharedInputTxId])) .typecase(UInt64(1111), PrevTxOut.codec) ) } @@ -106,13 +102,9 @@ object TxSignaturesTlv { /** When doing a splice for a taproot channel, each peer must provide their partial signature for the previous musig2 funding output. */ case class PreviousFundingTxPartialSig(partialSigWithNonce: PartialSignatureWithNonce) extends TxSignaturesTlv - /** Same as [[PreviousFundingTxSig]] for peers who only support the experimental version of splicing. */ - case class ExperimentalPreviousFundingTxSig(sig: ByteVector64) extends TxSignaturesTlv - val txSignaturesTlvCodec: Codec[TlvStream[TxSignaturesTlv]] = tlvStream(discriminated[TxSignaturesTlv].by(varint) .typecase(UInt64(0), tlvField(bytes64.as[PreviousFundingTxSig])) .typecase(UInt64(2), tlvField(partialSignatureWithNonce.as[PreviousFundingTxPartialSig])) - .typecase(UInt64(601), tlvField(bytes64.as[ExperimentalPreviousFundingTxSig])) ) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala index 95797a7080..21b03e3e66 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala @@ -437,36 +437,17 @@ object LightningMessageCodecs { ("fundingPubkey" | publicKey) :: ("tlvStream" | SpliceInitTlv.spliceInitTlvCodec)).as[SpliceInit] - val experimentalSpliceInitCodec: Codec[ExperimentalSpliceInit] = ( - ("channelId" | bytes32) :: - ("fundingContribution" | satoshiSigned) :: - ("feerate" | feeratePerKw) :: - ("lockTime" | uint32) :: - ("fundingPubkey" | publicKey) :: - ("tlvStream" | SpliceInitTlv.spliceInitTlvCodec)).as[ExperimentalSpliceInit] - val spliceAckCodec: Codec[SpliceAck] = ( ("channelId" | bytes32) :: ("fundingContribution" | satoshiSigned) :: ("fundingPubkey" | publicKey) :: ("tlvStream" | SpliceAckTlv.spliceAckTlvCodec)).as[SpliceAck] - val experimentalSpliceAckCodec: Codec[ExperimentalSpliceAck] = ( - ("channelId" | bytes32) :: - ("fundingContribution" | satoshiSigned) :: - ("fundingPubkey" | publicKey) :: - ("tlvStream" | SpliceAckTlv.spliceAckTlvCodec)).as[ExperimentalSpliceAck] - val spliceLockedCodec: Codec[SpliceLocked] = ( ("channelId" | bytes32) :: ("fundingTxHash" | txIdAsHash) :: ("tlvStream" | SpliceLockedTlv.spliceLockedTlvCodec)).as[SpliceLocked] - val experimentalSpliceLockedCodec: Codec[ExperimentalSpliceLocked] = ( - ("channelId" | bytes32) :: - ("fundingTxHash" | txIdAsHash) :: - ("tlvStream" | SpliceLockedTlv.spliceLockedTlvCodec)).as[ExperimentalSpliceLocked] - val stfuCodec: Codec[Stfu] = ( ("channelId" | bytes32) :: ("initiator" | byte.xmap[Boolean](b => b != 0, b => if (b) 1 else 0))).as[Stfu] @@ -584,9 +565,6 @@ object LightningMessageCodecs { .typecase(41045, addFeeCreditCodec) .typecase(41046, currentFeeCreditCodec) // - .typecase(37000, experimentalSpliceInitCodec) - .typecase(37002, experimentalSpliceAckCodec) - .typecase(37004, experimentalSpliceLockedCodec) // // diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala index 8f405b55dd..eed2989b2b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala @@ -97,14 +97,13 @@ case class TxAddInput(channelId: ByteVector32, tlvStream: TlvStream[TxAddInputTlv] = TlvStream.empty) extends InteractiveTxConstructionMessage with HasChannelId with HasSerialId { /** This field may replace [[previousTx_opt]] when using taproot. */ val previousTxOut_opt: Option[InputInfo] = tlvStream.get[TxAddInputTlv.PrevTxOut].map(tlv => InputInfo(OutPoint(tlv.txId, previousTxOutput), TxOut(tlv.amount, tlv.publicKeyScript))) - val sharedInput_opt: Option[OutPoint] = tlvStream.get[TxAddInputTlv.SharedInputTxId].map(i => OutPoint(i.txId, previousTxOutput)).orElse(tlvStream.get[TxAddInputTlv.ExperimentalSharedInputTxId].map(i => OutPoint(i.txId, previousTxOutput))) + val sharedInput_opt: Option[OutPoint] = tlvStream.get[TxAddInputTlv.SharedInputTxId].map(i => OutPoint(i.txId, previousTxOutput)) } object TxAddInput { def apply(channelId: ByteVector32, serialId: UInt64, sharedInput: OutPoint, sequence: Long): TxAddInput = { val tlvs = Set[TxAddInputTlv]( TxAddInputTlv.SharedInputTxId(sharedInput.txid), - TxAddInputTlv.ExperimentalSharedInputTxId(sharedInput.txid), ) TxAddInput(channelId, serialId, None, sharedInput.index, sequence, TlvStream(tlvs)) } @@ -144,7 +143,7 @@ case class TxSignatures(channelId: ByteVector32, txId: TxId, witnesses: Seq[ScriptWitness], tlvStream: TlvStream[TxSignaturesTlv] = TlvStream.empty) extends InteractiveTxMessage with HasChannelId { - val previousFundingTxSig_opt: Option[ByteVector64] = tlvStream.get[TxSignaturesTlv.PreviousFundingTxSig].map(_.sig).orElse(tlvStream.get[TxSignaturesTlv.ExperimentalPreviousFundingTxSig].map(_.sig)) + val previousFundingTxSig_opt: Option[ByteVector64] = tlvStream.get[TxSignaturesTlv.PreviousFundingTxSig].map(_.sig) val previousFundingTxPartialSig_opt: Option[PartialSignatureWithNonce] = tlvStream.get[TxSignaturesTlv.PreviousFundingTxPartialSig].map(_.partialSigWithNonce) } @@ -159,11 +158,6 @@ object TxSignatures { case Some(partialSig: PartialSignatureWithNonce) => Some(TxSignaturesTlv.PreviousFundingTxPartialSig(partialSig)) case None => None }, - // We keep supporting the experimental splicing protocol. - previousFundingSig_opt match { - case Some(IndividualSignature(sig)) => Some(TxSignaturesTlv.ExperimentalPreviousFundingTxSig(sig)) - case _ => None - } ).flatten TxSignatures(channelId, tx.txid, witnesses, TlvStream(tlvs)) } @@ -222,16 +216,9 @@ case class ChannelReestablish(channelId: ByteVector32, yourLastPerCommitmentSecret: PrivateKey, myCurrentPerCommitmentPoint: PublicKey, tlvStream: TlvStream[ChannelReestablishTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId { - val nextFundingTxId_opt: Option[TxId] = tlvStream.get[ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv] match { - case Some(tlv) if tlv.isOfficial => Some(tlv.txId) - case _ => tlvStream.get[ChannelReestablishTlv.ExperimentalNextFundingTlv].map(_.txId) - } - val retransmitInteractiveTxCommitSig: Boolean = tlvStream.get[ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv].exists(_.retransmitCommitSig) - val myCurrentFundingLocked_opt: Option[TxId] = tlvStream.get[ChannelReestablishTlv.MyCurrentFundingLockedTlv].map(_.txId).orElse(tlvStream.get[ChannelReestablishTlv.ExperimentalMyCurrentFundingLockedTlv].map(_.txId)) - val yourLastFundingLocked_opt: Option[TxId] = tlvStream.get[ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv] match { - case Some(tlv) if !tlv.isOfficial => Some(tlv.txId) - case _ => None - } + val nextFundingTxId_opt: Option[TxId] = tlvStream.get[ChannelReestablishTlv.NextFundingTlv].map(_.txId) + val retransmitInteractiveTxCommitSig: Boolean = tlvStream.get[ChannelReestablishTlv.NextFundingTlv].exists(_.retransmitCommitSig) + val myCurrentFundingLocked_opt: Option[TxId] = tlvStream.get[ChannelReestablishTlv.MyCurrentFundingLockedTlv].map(_.txId) val retransmitAnnSigs: Boolean = tlvStream.get[ChannelReestablishTlv.MyCurrentFundingLockedTlv].exists(_.retransmitAnnSigs) val nextCommitNonces: Map[TxId, IndividualNonce] = tlvStream.get[ChannelReestablishTlv.NextLocalNoncesTlv].map(_.nonces.toMap).getOrElse(Map.empty) val currentCommitNonce_opt: Option[IndividualNonce] = tlvStream.get[ChannelReestablishTlv.CurrentCommitNonceTlv].map(_.nonce) @@ -430,19 +417,6 @@ object SpliceInit { apply(channelId, fundingContribution, lockTime, feerate, fundingPubKey, pushAmount, requireConfirmedInputs, requestFunding_opt, None) } -case class ExperimentalSpliceInit(channelId: ByteVector32, - fundingContribution: Satoshi, - feerate: FeeratePerKw, - lockTime: Long, - fundingPubKey: PublicKey, - tlvStream: TlvStream[SpliceInitTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId { - def toSpliceInit: SpliceInit = SpliceInit(channelId, fundingContribution, feerate, lockTime, fundingPubKey, tlvStream) -} - -object ExperimentalSpliceInit { - def from(msg: SpliceInit): ExperimentalSpliceInit = ExperimentalSpliceInit(msg.channelId, msg.fundingContribution, msg.feerate, msg.lockTime, msg.fundingPubKey, msg.tlvStream) -} - case class SpliceAck(channelId: ByteVector32, fundingContribution: Satoshi, fundingPubKey: PublicKey, @@ -469,32 +443,11 @@ object SpliceAck { apply(channelId, fundingContribution, fundingPubKey, pushAmount, requireConfirmedInputs, willFund_opt, feeCreditUsed_opt, None) } -case class ExperimentalSpliceAck(channelId: ByteVector32, - fundingContribution: Satoshi, - fundingPubKey: PublicKey, - tlvStream: TlvStream[SpliceAckTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId { - def toSpliceAck: SpliceAck = SpliceAck(channelId, fundingContribution, fundingPubKey, tlvStream) -} - -object ExperimentalSpliceAck { - def from(msg: SpliceAck): ExperimentalSpliceAck = ExperimentalSpliceAck(msg.channelId, msg.fundingContribution, msg.fundingPubKey, msg.tlvStream) -} - case class SpliceLocked(channelId: ByteVector32, fundingTxId: TxId, tlvStream: TlvStream[SpliceLockedTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId { } -case class ExperimentalSpliceLocked(channelId: ByteVector32, - fundingTxId: TxId, - tlvStream: TlvStream[SpliceLockedTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId { - def toSpliceLocked: SpliceLocked = SpliceLocked(channelId, fundingTxId, tlvStream) -} - -object ExperimentalSpliceLocked { - def from(msg: SpliceLocked): ExperimentalSpliceLocked = ExperimentalSpliceLocked(msg.channelId, msg.fundingTxId, msg.tlvStream) -} - case class Shutdown(channelId: ByteVector32, scriptPubKey: ByteVector, tlvStream: TlvStream[ShutdownTlv] = TlvStream.empty) extends ChannelMessage with HasChannelId with ForbiddenMessageWhenQuiescent { diff --git a/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/fundee/data.json index 00359d1dd1..f1c29fba23 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/fundee/data.json @@ -14,7 +14,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json index 00607d6828..614b2fef9f 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050001-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050002-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/050002-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json index 8f24844a1b..e341aeb7e1 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050002-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050002-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/fundee/data.json index effb9f28de..cef9c23db7 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/fundee/data.json @@ -13,7 +13,6 @@ "activated" : { "option_route_blinding" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -40,7 +39,6 @@ "option_route_blinding" : "optional", "option_provide_storage" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/funder/data.json index aec54a2192..64a530da86 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050003-DATA_WAIT_FOR_DUAL_FUNDING_SIGNED/funder/data.json @@ -14,7 +14,6 @@ "option_route_blinding" : "optional", "option_provide_storage" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -40,7 +39,6 @@ "activated" : { "option_route_blinding" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/fundee/data.json index a58fd441bf..0d095c1da3 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/fundee/data.json @@ -14,7 +14,6 @@ "activated" : { "option_route_blinding" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "option_route_blinding" : "optional", "option_provide_storage" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/funder/data.json index 396d0320b2..13ba552625 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050004-DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED/funder/data.json @@ -15,7 +15,6 @@ "option_route_blinding" : "optional", "option_provide_storage" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "activated" : { "option_route_blinding" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050005-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/050005-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json index ed5e877948..c455575e64 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050005-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050005-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json @@ -15,7 +15,6 @@ "option_route_blinding" : "optional", "option_provide_storage" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "activated" : { "option_route_blinding" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced-splice/data.json b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced-splice/data.json index a45a824832..25860f3c7c 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced-splice/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced-splice/data.json @@ -15,7 +15,6 @@ "option_route_blinding" : "optional", "option_provide_storage" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "activated" : { "option_route_blinding" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced/data.json b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced/data.json index ad8e02ed61..9ffb34c974 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/fundee/data.json index 5ae49350f7..dce59881ca 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/fundee/data.json @@ -14,7 +14,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/funder/data.json index 22c05b772c..4d5a6baec6 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/funder/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/splice-commitment-upgrade/data.json b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/splice-commitment-upgrade/data.json index 4a4b9aa91c..bca9606338 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/splice-commitment-upgrade/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/splice-commitment-upgrade/data.json @@ -15,7 +15,6 @@ "option_route_blinding" : "optional", "option_provide_storage" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "activated" : { "option_route_blinding" : "optional", "option_dual_fund" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/anchor-outputs/data.json b/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/anchor-outputs/data.json index 3c4eb67c38..ccaf24e86b 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/anchor-outputs/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/anchor-outputs/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/taproot/data.json b/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/taproot/data.json index c17f677034..1d3ff13bc7 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/taproot/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050007-DATA_SHUTDOWN/taproot/data.json @@ -16,7 +16,6 @@ "option_simple_close" : "optional", "option_simple_taproot_phoenix" : "optional", "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_quiesce" : "optional", @@ -45,7 +44,6 @@ "option_simple_taproot_phoenix" : "optional", "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_quiesce" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050008-DATA_NEGOTIATING/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/050008-DATA_NEGOTIATING/fundee/data.json index 4e7a724f6d..42819821c8 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050008-DATA_NEGOTIATING/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050008-DATA_NEGOTIATING/fundee/data.json @@ -14,7 +14,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/anchor-outputs/data.json b/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/anchor-outputs/data.json index 6bc8aee948..abbfdee509 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/anchor-outputs/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/anchor-outputs/data.json @@ -15,7 +15,6 @@ "activated" : { "option_simple_close" : "optional", "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -43,7 +42,6 @@ "option_simple_close" : "optional", "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/taproot/data.json b/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/taproot/data.json index 62e5d660de..9bc2cbce59 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/taproot/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/050009-DATA_NEGOTIATING_SIMPLE/taproot/data.json @@ -18,7 +18,6 @@ "option_simple_taproot_phoenix" : "optional", "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_quiesce" : "optional", @@ -43,7 +42,6 @@ "option_simple_close" : "optional", "option_simple_taproot_phoenix" : "optional", "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_quiesce" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/local/data.json b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/local/data.json index 5f55537978..bf06a2b4a3 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/local/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/local/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/next-remote/data.json b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/next-remote/data.json index cec6b56ccc..8955c14c56 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/next-remote/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/next-remote/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/remote/data.json b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/remote/data.json index 8dbe936e3d..8b21172d6f 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/remote/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/remote/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/revoked/data.json b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/revoked/data.json index 301a5c95df..ef8d2026c0 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/revoked/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/05000a-DATA_CLOSING/revoked/data.json @@ -15,7 +15,6 @@ "activated" : { "option_route_blinding" : "optional", "option_provide_storage" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", @@ -41,7 +40,6 @@ "initFeatures" : { "activated" : { "option_route_blinding" : "optional", - "splice_prototype" : "optional", "payment_secret" : "mandatory", "gossip_queries_ex" : "optional", "option_anchor_outputs" : "optional", diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala index 053d3929cc..1252dea8da 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala @@ -1902,31 +1902,6 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik (channelReestablishAlice, channelReestablishBob) } - private def reconnectWithLegacyPeer(f: FixtureParam, sendReestablish: Boolean = true): (ChannelReestablish, ChannelReestablish) = { - import f._ - - // Modify both nodes' state data so they see each other as using the legacy splice protocol. - // This must be done before INPUT_RECONNECTED because the channel_reestablish is constructed using the current state data. - Seq(alice, bob).foreach { node => - val data = node.stateData.asInstanceOf[DATA_NORMAL] - val newData = data.modify(_.commitments.channelParams.remoteParams.initFeatures).using { features => - features.remove(Features.Splicing).add(Features.SplicePrototype, FeatureSupport.Optional) - } - node.setState(node.stateName, newData) - } - - // Use legacy features for reconnection so that updateFeatures preserves the legacy setting. - val baseFeatures = alice.commitments.localChannelParams.initFeatures - val legacyInit = Init(baseFeatures.remove(Features.Splicing).add(Features.SplicePrototype, FeatureSupport.Optional)) - alice ! INPUT_RECONNECTED(alice2bob.ref, legacyInit, legacyInit) - bob ! INPUT_RECONNECTED(bob2alice.ref, legacyInit, legacyInit) - val channelReestablishAlice = alice2bob.expectMsgType[ChannelReestablish] - if (sendReestablish) alice2bob.forward(bob) - val channelReestablishBob = bob2alice.expectMsgType[ChannelReestablish] - if (sendReestablish) bob2alice.forward(alice) - (channelReestablishAlice, channelReestablishBob) - } - test("disconnect (tx_complete not received)") { f => import f._ // Disconnection with one side sending commit_sig @@ -2009,7 +1984,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(channelReestablishBob1.retransmitInteractiveTxCommitSig) assert(channelReestablishBob1.nextLocalCommitmentNumber == bobCommitIndex + 1) alice2bob.forward(bob, channelReestablishAlice1) - bob2alice.forward(alice, channelReestablishBob1.copy(tlvStream = TlvStream(channelReestablishBob1.tlvStream.records.filterNot(_.isInstanceOf[ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv])))) + bob2alice.forward(alice, channelReestablishBob1.copy(tlvStream = TlvStream(channelReestablishBob1.tlvStream.records.filterNot(_.isInstanceOf[ChannelReestablishTlv.NextFundingTlv])))) // In that case Alice won't retransmit commit_sig and the splice won't complete since they haven't exchanged tx_signatures. assert(bob2alice.expectMsgType[CommitSig].fundingTxId_opt.contains(spliceStatus.signingSession.fundingTx.txId)) bob2alice.forward(alice) @@ -2058,97 +2033,6 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs) } - test("disconnect (commit_sig not received) with legacy peer") { f => - import f._ - - val htlcs = setupHtlcs(f) - val aliceCommitIndex = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommitIndex - val bobCommitIndex = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommitIndex - - val sender = initiateSpliceWithoutSigs(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), spliceOut_opt = Some(SpliceOut(100_000 sat, defaultSpliceOutScriptPubKey))) - alice2bob.expectMsgType[CommitSig] // Bob doesn't receive Alice's commit_sig - bob2alice.expectMsgType[CommitSig] // Alice doesn't receive Bob's commit_sig - awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].spliceStatus.isInstanceOf[SpliceStatus.SpliceWaitingForSigs]) - val spliceStatus = alice.stateData.asInstanceOf[DATA_NORMAL].spliceStatus.asInstanceOf[SpliceStatus.SpliceWaitingForSigs] - - disconnect(f) - - val (channelReestablishAlice, channelReestablishBob) = reconnectWithLegacyPeer(f) - - // Experimental protocol uses an experimental TLV. - assert(channelReestablishAlice.nextFundingTxId_opt.contains(spliceStatus.signingSession.fundingTx.txId)) - assert(channelReestablishAlice.tlvStream.get[ChannelReestablishTlv.ExperimentalNextFundingTlv].map(_.txId).contains(spliceStatus.signingSession.fundingTx.txId)) - // Experimental protocol doesn't use the explicit retransmit flag. - assert(!channelReestablishAlice.retransmitInteractiveTxCommitSig) - // Experimental protocol rolls back nextLocalCommitmentNumber to signal commit_sig wasn't received. - assert(channelReestablishAlice.nextLocalCommitmentNumber == aliceCommitIndex) - assert(channelReestablishBob.nextLocalCommitmentNumber == bobCommitIndex) - - // Legacy peers always retransmit channel_ready for the initial funding. - alice2bob.expectMsgType[ChannelReady] - alice2bob.forward(bob) - bob2alice.expectMsgType[ChannelReady] - bob2alice.forward(alice) - - // Both sides retransmit commit_sig. - assert(alice2bob.expectMsgType[CommitSig].fundingTxId_opt.contains(spliceStatus.signingSession.fundingTx.txId)) - alice2bob.forward(bob) - assert(bob2alice.expectMsgType[CommitSig].fundingTxId_opt.contains(spliceStatus.signingSession.fundingTx.txId)) - bob2alice.forward(alice) - bob2alice.expectMsgType[TxSignatures] - bob2alice.forward(alice) - alice2bob.expectMsgType[TxSignatures] - alice2bob.forward(bob) - sender.expectMsgType[RES_SPLICE] - - val spliceTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localFundingStatus.signedTx_opt.get - assert(spliceTx.txid == spliceStatus.signingSession.fundingTx.txId) - alice2blockchain.expectWatchFundingConfirmed(spliceTx.txid) - bob2blockchain.expectWatchFundingConfirmed(spliceTx.txid) - alice ! WatchFundingConfirmedTriggered(BlockHeight(42), 0, spliceTx) - alice2bob.expectMsgType[SpliceLocked] - alice2bob.forward(bob) - bob ! WatchFundingConfirmedTriggered(BlockHeight(42), 0, spliceTx) - bob2alice.expectMsgType[SpliceLocked] - bob2alice.forward(alice) - awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.active.size == 1) - awaitCond(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.active.size == 1) - - resolveHtlcs(f, htlcs) - } - - test("re-send splice_locked for legacy peers") { f => - import f._ - - val fundingTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat, pushAmount = 0 msat))) - checkWatchConfirmed(f, fundingTx) - - // Both sides confirm the splice and exchange splice_locked. - alice ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx) - alice2blockchain.expectMsgTypeHaving[WatchFundingSpent](_.txId == fundingTx.txid) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx.txid) - alice2bob.forward(bob) - bob ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx) - bob2blockchain.expectMsgTypeHaving[WatchFundingSpent](_.txId == fundingTx.txid) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx.txid) - bob2alice.forward(alice) - awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.active.size == 1) - awaitCond(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.active.size == 1) - - disconnect(f) - val (channelReestablishAlice, channelReestablishBob) = reconnectWithLegacyPeer(f) - - // With the experimental protocol, peers retransmit splice_locked on reconnection. - assert(channelReestablishAlice.myCurrentFundingLocked_opt.contains(fundingTx.txid)) - assert(channelReestablishBob.myCurrentFundingLocked_opt.contains(fundingTx.txid)) - assert(!channelReestablishAlice.retransmitAnnSigs) - assert(!channelReestablishBob.retransmitAnnSigs) - assert(alice2bob.expectMsgType[SpliceLocked].fundingTxId == fundingTx.txid) - alice2bob.forward(bob) - assert(bob2alice.expectMsgType[SpliceLocked].fundingTxId == fundingTx.txid) - bob2alice.forward(alice) - } - test("don't re-send splice_locked on reconnection") { f => import f._ diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala index cc7904d6e8..52fb3d32da 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala @@ -19,12 +19,11 @@ package fr.acinq.eclair.io import akka.actor.PoisonPill import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, OutPoint, SatoshiLong, Transaction, TxId} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32} import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} import fr.acinq.eclair.Features._ import fr.acinq.eclair.TestConstants._ import fr.acinq.eclair.TestUtils.randomTxId -import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel.ChannelSpendSignature.IndividualSignature import fr.acinq.eclair.crypto.TransportHandler import fr.acinq.eclair.io.Peer.ConnectionDown @@ -353,85 +352,6 @@ class PeerConnectionSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wi transport.expectNoMessage(100 millis) } - test("receive legacy batch of commit_sig messages") { f => - import f._ - connect(nodeParams, remoteNodeId, switchboard, router, connection, transport, peerConnection, peer) - - // We receive a batch of commit_sig messages from a first channel. - val channelId1 = randomBytes32() - val commitSigs1 = Seq( - CommitSig(channelId1, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(2))), - CommitSig(channelId1, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(2))), - ) - transport.send(peerConnection, commitSigs1.head) - transport.expectMsg(TransportHandler.ReadAck(commitSigs1.head)) - peer.expectNoMessage(100 millis) - transport.send(peerConnection, commitSigs1.last) - transport.expectMsg(TransportHandler.ReadAck(commitSigs1.last)) - peer.expectMsg(CommitSigBatch(commitSigs1)) - - // We receive a batch of commit_sig messages from a second channel. - val channelId2 = randomBytes32() - val commitSigs2 = Seq( - CommitSig(channelId2, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(3))), - CommitSig(channelId2, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(3))), - CommitSig(channelId2, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(3))), - ) - commitSigs2.dropRight(1).foreach(commitSig => { - transport.send(peerConnection, commitSig) - transport.expectMsg(TransportHandler.ReadAck(commitSig)) - }) - peer.expectNoMessage(100 millis) - transport.send(peerConnection, commitSigs2.last) - transport.expectMsg(TransportHandler.ReadAck(commitSigs2.last)) - peer.expectMsg(CommitSigBatch(commitSigs2)) - - // We receive another batch of commit_sig messages from the first channel, with unrelated messages in the batch. - val commitSigs3 = Seq( - CommitSig(channelId1, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(2))), - CommitSig(channelId1, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(2))), - ) - transport.send(peerConnection, commitSigs3.head) - transport.expectMsg(TransportHandler.ReadAck(commitSigs3.head)) - val spliceLocked1 = SpliceLocked(channelId1, randomTxId()) - transport.send(peerConnection, spliceLocked1) - transport.expectMsg(TransportHandler.ReadAck(spliceLocked1)) - peer.expectMsg(spliceLocked1) - val spliceLocked2 = SpliceLocked(channelId2, randomTxId()) - transport.send(peerConnection, spliceLocked2) - transport.expectMsg(TransportHandler.ReadAck(spliceLocked2)) - peer.expectMsg(spliceLocked2) - peer.expectNoMessage(100 millis) - transport.send(peerConnection, commitSigs3.last) - transport.expectMsg(TransportHandler.ReadAck(commitSigs3.last)) - peer.expectMsg(CommitSigBatch(commitSigs3)) - - // We start receiving a batch of commit_sig messages from the first channel, interleaved with a batch from the second - // channel, which is not supported. - val commitSigs4 = Seq( - CommitSig(channelId1, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(2))), - CommitSig(channelId2, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(2))), - CommitSig(channelId2, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(2))), - ) - transport.send(peerConnection, commitSigs4.head) - transport.expectMsg(TransportHandler.ReadAck(commitSigs4.head)) - peer.expectNoMessage(100 millis) - transport.send(peerConnection, commitSigs4(1)) - transport.expectMsg(TransportHandler.ReadAck(commitSigs4(1))) - peer.expectMsg(CommitSigBatch(commitSigs4.take(1))) - transport.send(peerConnection, commitSigs4.last) - transport.expectMsg(TransportHandler.ReadAck(commitSigs4.last)) - peer.expectMsg(CommitSigBatch(commitSigs4.tail)) - - // We receive a batch that exceeds our threshold: we process them individually. - val invalidCommitSigs = (0 until 30).map(_ => CommitSig(channelId2, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.ExperimentalBatchTlv(30)))) - invalidCommitSigs.foreach(commitSig => { - transport.send(peerConnection, commitSig) - transport.expectMsg(TransportHandler.ReadAck(commitSig)) - peer.expectMsg(commitSig) - }) - } - test("receive batch of commit_sig messages") { f => import f._ connect(nodeParams, remoteNodeId, switchboard, router, connection, transport, peerConnection, peer) @@ -724,53 +644,5 @@ class PeerConnectionSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wi } } - test("convert experimental splice messages") { f => - import f._ - val remoteInit = protocol.Init(Bob.nodeParams.features.initFeatures().add(Features.SplicePrototype, FeatureSupport.Optional)) - connect(nodeParams, remoteNodeId, switchboard, router, connection, transport, peerConnection, peer, remoteInit) - - val spliceInit = SpliceInit(randomBytes32(), 100_000 sat, FeeratePerKw(5000 sat), 0, randomKey().publicKey) - val spliceAck = SpliceAck(randomBytes32(), 50_000 sat, randomKey().publicKey) - val spliceLocked = SpliceLocked(randomBytes32(), TxId(randomBytes32())) - - // Outgoing messages use the experimental version of splicing. - peer.send(peerConnection, spliceInit) - transport.expectMsg(ExperimentalSpliceInit.from(spliceInit)) - peer.send(peerConnection, spliceAck) - transport.expectMsg(ExperimentalSpliceAck.from(spliceAck)) - peer.send(peerConnection, spliceLocked) - transport.expectMsg(ExperimentalSpliceLocked.from(spliceLocked)) - - // Incoming messages are converted from their experimental version. - transport.send(peerConnection, ExperimentalSpliceInit.from(spliceInit)) - peer.expectMsg(spliceInit) - transport.expectMsgType[TransportHandler.ReadAck] - transport.send(peerConnection, ExperimentalSpliceAck.from(spliceAck)) - peer.expectMsg(spliceAck) - transport.expectMsgType[TransportHandler.ReadAck] - transport.send(peerConnection, ExperimentalSpliceLocked.from(spliceLocked)) - peer.expectMsg(spliceLocked) - transport.expectMsgType[TransportHandler.ReadAck] - - // Incompatible TLVs are dropped when sending messages to peers using the experimental version. - val txAddInput = TxAddInput(randomBytes32(), UInt64(0), OutPoint(TxId(randomBytes32()), 3), 0) - assert(txAddInput.tlvStream.get[TxAddInputTlv.SharedInputTxId].nonEmpty) - peer.send(peerConnection, txAddInput) - assert(transport.expectMsgType[TxAddInput].tlvStream.get[TxAddInputTlv.SharedInputTxId].isEmpty) - val txSignatures = TxSignatures(randomBytes32(), Transaction(2, Nil, Nil, 0), Nil, Some(IndividualSignature(randomBytes64()))) - assert(txSignatures.tlvStream.get[TxSignaturesTlv.PreviousFundingTxSig].nonEmpty) - peer.send(peerConnection, txSignatures) - assert(transport.expectMsgType[TxSignatures].tlvStream.get[TxSignaturesTlv.PreviousFundingTxSig].isEmpty) - val channelId = randomBytes32() - val commitSigBatch = CommitSigBatch(Seq( - CommitSig(channelId, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.FundingTx(TxId(randomBytes32())), CommitSigTlv.ExperimentalBatchTlv(2))), - CommitSig(channelId, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.FundingTx(TxId(randomBytes32())), CommitSigTlv.ExperimentalBatchTlv(2))), - )) - peer.send(peerConnection, commitSigBatch) - assert(transport.expectMsgType[CommitSig].tlvStream.get[CommitSigTlv.FundingTx].isEmpty) - assert(transport.expectMsgType[CommitSig].tlvStream.get[CommitSigTlv.FundingTx].isEmpty) - transport.expectNoMessage(100 millis) - } - } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala index 3db9f6fce5..bcd5817165 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala @@ -159,14 +159,8 @@ class LightningMessageCodecsSpec extends AnyFunSuite { hex"0023" ++ channelId ++ signature ++ hex"fe47010000 07 cccccccccccccc" -> FundingSigned(channelId, signature, TlvStream[FundingSignedTlv](Set.empty[FundingSignedTlv], Set(GenericTlv(tlvTag, hex"cccccccccccccc")))), hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point), - hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"00 20" ++ txId.value.reverse -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.ExperimentalNextFundingTlv(txId))), - // TODO: replace those test vectors with the commented ones below when we remove support for the legacy splicing protocol. - hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"01 20" ++ txId.value.reverse -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv(txId.value.reverse))), - hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"01 21" ++ txId.value.reverse ++ hex"00" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv(txId.value.reverse ++ hex"00"))), - hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"01 21" ++ txId.value.reverse ++ hex"01" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv(txId.value.reverse ++ hex"01"))), - // hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"01 21" ++ txId.value.reverse ++ hex"00" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingTlv(txId, retransmitCommitSig = false))), - // hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"01 21" ++ txId.value.reverse ++ hex"01" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingTlv(txId, retransmitCommitSig = true))), - hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"03 20" ++ txId.value.reverse -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.ExperimentalMyCurrentFundingLockedTlv(txId))), + hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"01 21" ++ txId.value.reverse ++ hex"00" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingTlv(txId, retransmitCommitSig = false))), + hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"01 21" ++ txId.value.reverse ++ hex"01" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.NextFundingTlv(txId, retransmitCommitSig = true))), hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"05 21" ++ txId.value.reverse ++ hex"00" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.MyCurrentFundingLockedTlv(txId, retransmitAnnSigs = false))), hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"05 21" ++ txId.value.reverse ++ hex"01" -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.MyCurrentFundingLockedTlv(txId, retransmitAnnSigs = true))), hex"0088" ++ channelId ++ hex"0001020304050607 0809aabbccddeeff" ++ key.value ++ point.value ++ hex"18 42" ++ nonce.data -> ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.CurrentCommitNonceTlv(nonce))), @@ -229,7 +223,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { TxAddInput(channelId1, UInt64(561), Some(tx1), 1, 5) -> hex"0042 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000231 00f7 020000000001014ade359c5deb7c1cde2e94f401854658f97d7fa31c17ce9a831db253120a0a410100000017160014eb9a5bd79194a23d19d6ec473c768fb74f9ed32cffffffff021ca408000000000017a914946118f24bb7b37d5e9e39579e4a411e70f5b6a08763e703000000000017a9143638b2602d11f934c04abc6adb1494f69d1f14af8702473044022059ddd943b399211e4266a349f26b3289979e29f9b067792c6cfa8cc5ae25f44602204d627a5a5b603d0562e7969011fb3d64908af90a3ec7c876eaa9baf61e1958af012102f5188df1da92ed818581c29778047800ed6635788aa09d9469f7d17628f7323300000000 00000001 00000005", TxAddInput(channelId2, UInt64(0), Some(tx2), 2, 0) -> hex"0042 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0000000000000000 0100 0200000000010142180a8812fc79a3da7fb2471eff3e22d7faee990604c2ba7f2fc8dfb15b550a0200000000feffffff030f241800000000001976a9146774040642a78ca3b8b395e70f8391b21ec026fc88ac4a155801000000001600148d2e0b57adcb8869e603fd35b5179caf053361253b1d010000000000160014e032f4f4b9f8611df0d30a20648c190c263bbc33024730440220506005aa347f5b698542cafcb4f1a10250aeb52a609d6fd67ef68f9c1a5d954302206b9bb844343f4012bccd9d08a0f5430afb9549555a3252e499be7df97aae477a012103976d6b3eea3de4b056cd88cdfd50a22daf121e0fb5c6e45ba0f40e1effbd275a00000000 00000002 00000000", TxAddInput(channelId1, UInt64(561), Some(tx1), 0, 0) -> hex"0042 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000231 00f7 020000000001014ade359c5deb7c1cde2e94f401854658f97d7fa31c17ce9a831db253120a0a410100000017160014eb9a5bd79194a23d19d6ec473c768fb74f9ed32cffffffff021ca408000000000017a914946118f24bb7b37d5e9e39579e4a411e70f5b6a08763e703000000000017a9143638b2602d11f934c04abc6adb1494f69d1f14af8702473044022059ddd943b399211e4266a349f26b3289979e29f9b067792c6cfa8cc5ae25f44602204d627a5a5b603d0562e7969011fb3d64908af90a3ec7c876eaa9baf61e1958af012102f5188df1da92ed818581c29778047800ed6635788aa09d9469f7d17628f7323300000000 00000000 00000000", - TxAddInput(channelId1, UInt64(561), OutPoint(tx1, 1), 5) -> hex"0042 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000231 0000 00000001 00000005 00201f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106 fd0451201f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106", + TxAddInput(channelId1, UInt64(561), OutPoint(tx1, 1), 5) -> hex"0042 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000231 0000 00000001 00000005 00201f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106", TxAddInput(channelId1, UInt64(561), None, 1, 0xfffffffdL, TlvStream(TxAddInputTlv.PrevTxOut(tx2.txid, 22_549_834 sat, hex"00148d2e0b57adcb8869e603fd35b5179caf05336125"))) -> hex"0042 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000231 0000 00000001 fffffffd fd04573efc7aa8845f192959202c1b7ff704e7cbddded463c05e844676a94ccb4bed69f1000000000158154a00148d2e0b57adcb8869e603fd35b5179caf05336125", TxAddOutput(channelId1, UInt64(1105), 2047 sat, hex"00149357014afd0ccd265658c9ae81efa995e771f472") -> hex"0043 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000451 00000000000007ff 0016 00149357014afd0ccd265658c9ae81efa995e771f472", TxAddOutput(channelId1, UInt64(1105), 2047 sat, hex"00149357014afd0ccd265658c9ae81efa995e771f472", TlvStream(Set.empty[TxAddOutputTlv], Set(GenericTlv(UInt64(301), hex"2a")))) -> hex"0043 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000000000000451 00000000000007ff 0016 00149357014afd0ccd265658c9ae81efa995e771f472 fd012d012a", @@ -241,7 +235,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { TxComplete(channelId1, TlvStream(Set.empty[TxCompleteTlv], Set(GenericTlv(UInt64(231), hex"deadbeef"), GenericTlv(UInt64(507), hex"")))) -> hex"0046 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e704deadbeef fd01fb00", TxSignatures(channelId1, tx2, Seq(ScriptWitness(Seq(hex"68656c6c6f2074686572652c2074686973206973206120626974636f6e212121", hex"82012088a820add57dfe5277079d069ca4ad4893c96de91f88ffb981fdc6a2a34d5336c66aff87")), ScriptWitness(Seq(hex"304402207de9ba56bb9f641372e805782575ee840a899e61021c8b1572b3ec1d5b5950e9022069e9ba998915dae193d3c25cb89b5e64370e6a3a7755e7f31cf6d7cbc2a49f6d01", hex"034695f5b7864c580bf11f9f8cb1a94eb336f2ce9ef872d2ae1a90ee276c772484"))), None) -> hex"0047 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa fc7aa8845f192959202c1b7ff704e7cbddded463c05e844676a94ccb4bed69f1 0002 004a 022068656c6c6f2074686572652c2074686973206973206120626974636f6e2121212782012088a820add57dfe5277079d069ca4ad4893c96de91f88ffb981fdc6a2a34d5336c66aff87 006b 0247304402207de9ba56bb9f641372e805782575ee840a899e61021c8b1572b3ec1d5b5950e9022069e9ba998915dae193d3c25cb89b5e64370e6a3a7755e7f31cf6d7cbc2a49f6d0121034695f5b7864c580bf11f9f8cb1a94eb336f2ce9ef872d2ae1a90ee276c772484", TxSignatures(channelId2, tx1, Nil, None) -> hex"0047 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 1f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106 0000", - TxSignatures(channelId2, tx1, Nil, Some(IndividualSignature(signature))) -> hex"0047 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 1f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106 0000 0040aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb fd025940aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + TxSignatures(channelId2, tx1, Nil, Some(IndividualSignature(signature))) -> hex"0047 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 1f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106 0000 0040aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", TxSignatures(channelId2, tx1, Nil, Some(PartialSignatureWithNonce(partialSig, fundingNonce))) -> hex"0047 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 1f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106 0000 02 62 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb a49ff67b08c720b993c946556cde1be1c3b664bc847c4792135dfd6ef0986e00e9871808c6620b0420567dad525b27431453d4434fd326f8ac56496639b72326eb5d", TxInitRbf(channelId1, 8388607, FeeratePerKw(4000 sat)) -> hex"0048 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 007fffff 00000fa0", TxInitRbf(channelId1, 0, FeeratePerKw(4000 sat), 1_500_000 sat, requireConfirmedInputs = true, None) -> hex"0048 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 00000000 00000fa0 0008000000000016e360 0200", @@ -862,84 +856,4 @@ class LightningMessageCodecsSpec extends AnyFunSuite { } } - test("channel_reestablish backwards-compatibility with legacy splice TLVs") { - val channelId = randomBytes32() - val key = randomKey() - val point = randomKey().publicKey - val txId1 = randomTxId() - val txId2 = randomTxId() - val txId3 = randomTxId() - - def reestablish(tlvs: ChannelReestablishTlv*): ChannelReestablish = { - ChannelReestablish(channelId, 1, 0, key, point, TlvStream(tlvs: _*)) - } - - // Legacy TLVs: tag 0 (experimental next_funding) + tag 1 (experimental your_last_funding_locked) + tag 3 (experimental my_current_funding_locked). - { - val msg = reestablish( - ChannelReestablishTlv.ExperimentalNextFundingTlv(txId1), - ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asExperimentalYourLastFundingLocked(txId2), - ChannelReestablishTlv.ExperimentalMyCurrentFundingLockedTlv(txId3), - ) - assert(msg.nextFundingTxId_opt.contains(txId1)) - assert(!msg.retransmitInteractiveTxCommitSig) - assert(msg.yourLastFundingLocked_opt.contains(txId2)) - assert(msg.myCurrentFundingLocked_opt.contains(txId3)) - assert(!msg.retransmitAnnSigs) - val encoded = lightningMessageCodec.encode(msg).require - assert(lightningMessageCodec.decode(encoded).require.value == msg) - } - - // Official TLVs with retransmit flags set: tag 1 (official next_funding) + tag 5 (my_current_funding_locked). - { - val msg = reestablish( - ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(txId1, retransmitCommitSig = true), - ChannelReestablishTlv.MyCurrentFundingLockedTlv(txId2, retransmitAnnSigs = true), - ) - assert(msg.nextFundingTxId_opt.contains(txId1)) - assert(msg.retransmitInteractiveTxCommitSig) - assert(msg.yourLastFundingLocked_opt.isEmpty) - assert(msg.myCurrentFundingLocked_opt.contains(txId2)) - assert(msg.retransmitAnnSigs) - val encoded = lightningMessageCodec.encode(msg).require - assert(lightningMessageCodec.decode(encoded).require.value == msg) - } - - // Official TLVs with retransmit flags unset. - { - val msg = reestablish( - ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(txId1, retransmitCommitSig = false), - ChannelReestablishTlv.MyCurrentFundingLockedTlv(txId2, retransmitAnnSigs = false), - ) - assert(msg.nextFundingTxId_opt.contains(txId1)) - assert(!msg.retransmitInteractiveTxCommitSig) - assert(msg.yourLastFundingLocked_opt.isEmpty) - assert(msg.myCurrentFundingLocked_opt.contains(txId2)) - assert(!msg.retransmitAnnSigs) - val encoded = lightningMessageCodec.encode(msg).require - assert(lightningMessageCodec.decode(encoded).require.value == msg) - } - - // my_current_funding_locked priority: official tag 5 takes priority over legacy tag 3. - { - val msg = reestablish( - ChannelReestablishTlv.ExperimentalMyCurrentFundingLockedTlv(txId1), - ChannelReestablishTlv.MyCurrentFundingLockedTlv(txId2, retransmitAnnSigs = false), - ) - assert(msg.myCurrentFundingLocked_opt.contains(txId2)) - val encoded = lightningMessageCodec.encode(msg).require - assert(lightningMessageCodec.decode(encoded).require.value == msg) - } - - // Empty TLV stream: all splice-related accessors return None/false. - { - val msg = ChannelReestablish(channelId, 1, 0, key, point) - assert(msg.nextFundingTxId_opt.isEmpty) - assert(!msg.retransmitInteractiveTxCommitSig) - assert(msg.yourLastFundingLocked_opt.isEmpty) - assert(msg.myCurrentFundingLocked_opt.isEmpty) - assert(!msg.retransmitAnnSigs) - } - } - }