Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions eclair-core/src/main/scala/fr/acinq/eclair/Features.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -492,7 +486,6 @@ object Features {
WakeUpNotificationClient,
TrampolinePaymentPrototype,
AsyncPaymentPrototype,
SplicePrototype,
OnTheFlyFunding,
FundingFeeCredit,
PhoenixZeroReserve
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
173 changes: 28 additions & 145 deletions eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
54 changes: 0 additions & 54 deletions eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -255,42 +255,14 @@ 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]].
*
* @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.
Expand All @@ -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 {
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
)
}
Expand Down Expand Up @@ -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]))
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -584,9 +565,6 @@ object LightningMessageCodecs {
.typecase(41045, addFeeCreditCodec)
.typecase(41046, currentFeeCreditCodec)
//
.typecase(37000, experimentalSpliceInitCodec)
.typecase(37002, experimentalSpliceAckCodec)
.typecase(37004, experimentalSpliceLockedCodec)
//

//
Expand Down
Loading
Loading