@@ -26,7 +26,7 @@ import fr.acinq.eclair.channel.fund.{InteractiveTxBuilder, InteractiveTxSigningS
2626import fr .acinq .eclair .io .Peer
2727import fr .acinq .eclair .transactions .CommitmentSpec
2828import fr .acinq .eclair .transactions .Transactions ._
29- import fr .acinq .eclair .wire .protocol .{ChannelAnnouncement , ChannelReady , ChannelReestablish , ChannelUpdate , ClosingSigned , CommitSig , FailureMessage , FundingCreated , FundingSigned , Init , OnionRoutingPacket , OpenChannel , OpenDualFundedChannel , Shutdown , SpliceInit , Stfu , TxSignatures , UpdateAddHtlc , UpdateFailHtlc , UpdateFailMalformedHtlc , UpdateFulfillHtlc }
29+ import fr .acinq .eclair .wire .protocol .{ChannelAnnouncement , ChannelReady , ChannelReestablish , ChannelUpdate , ClosingSigned , CommitSig , FailureMessage , FundingCreated , FundingSigned , Init , OnionRoutingPacket , OpenChannel , OpenDualFundedChannel , Shutdown , SpliceInit , Stfu , TxInitRbf , TxSignatures , UpdateAddHtlc , UpdateFailHtlc , UpdateFailMalformedHtlc , UpdateFulfillHtlc }
3030import fr .acinq .eclair .{Alias , BlockHeight , CltvExpiry , CltvExpiryDelta , Features , InitFeature , MilliSatoshi , MilliSatoshiLong , RealShortChannelId , TimestampMilli , UInt64 }
3131import scodec .bits .ByteVector
3232
@@ -193,36 +193,39 @@ sealed trait Command extends PossiblyHarmful
193193sealed trait HasReplyToCommand extends Command { def replyTo : ActorRef }
194194sealed trait HasOptionalReplyToCommand extends Command { def replyTo_opt : Option [ActorRef ] }
195195
196- sealed trait ForbiddenCommandDuringSplice extends Command
197- sealed trait ForbiddenCommandDuringQuiescence extends Command
196+ sealed trait ForbiddenCommandDuringQuiescenceNegotiation extends Command
197+ sealed trait ForbiddenCommandWhenQuiescent extends Command
198198
199- final case class CMD_ADD_HTLC (replyTo : ActorRef , amount : MilliSatoshi , paymentHash : ByteVector32 , cltvExpiry : CltvExpiry , onion : OnionRoutingPacket , nextBlindingKey_opt : Option [PublicKey ], confidence : Double , origin : Origin .Hot , commit : Boolean = false ) extends HasReplyToCommand with ForbiddenCommandDuringSplice with ForbiddenCommandDuringQuiescence
200- sealed trait HtlcSettlementCommand extends HasOptionalReplyToCommand with ForbiddenCommandDuringSplice with ForbiddenCommandDuringQuiescence { def id : Long }
199+ final case class CMD_ADD_HTLC (replyTo : ActorRef , amount : MilliSatoshi , paymentHash : ByteVector32 , cltvExpiry : CltvExpiry , onion : OnionRoutingPacket , nextBlindingKey_opt : Option [PublicKey ], confidence : Double , origin : Origin .Hot , commit : Boolean = false ) extends HasReplyToCommand with ForbiddenCommandDuringQuiescenceNegotiation with ForbiddenCommandWhenQuiescent
200+ sealed trait HtlcSettlementCommand extends HasOptionalReplyToCommand with ForbiddenCommandDuringQuiescenceNegotiation with ForbiddenCommandWhenQuiescent { def id : Long }
201201final case class CMD_FULFILL_HTLC (id : Long , r : ByteVector32 , commit : Boolean = false , replyTo_opt : Option [ActorRef ] = None ) extends HtlcSettlementCommand
202202final case class CMD_FAIL_HTLC (id : Long , reason : Either [ByteVector , FailureMessage ], delay_opt : Option [FiniteDuration ] = None , commit : Boolean = false , replyTo_opt : Option [ActorRef ] = None ) extends HtlcSettlementCommand
203203final case class CMD_FAIL_MALFORMED_HTLC (id : Long , onionHash : ByteVector32 , failureCode : Int , commit : Boolean = false , replyTo_opt : Option [ActorRef ] = None ) extends HtlcSettlementCommand
204- final case class CMD_UPDATE_FEE (feeratePerKw : FeeratePerKw , commit : Boolean = false , replyTo_opt : Option [ActorRef ] = None ) extends HasOptionalReplyToCommand with ForbiddenCommandDuringSplice with ForbiddenCommandDuringQuiescence
205- final case class CMD_SIGN (replyTo_opt : Option [ActorRef ] = None ) extends HasOptionalReplyToCommand with ForbiddenCommandDuringSplice
204+ final case class CMD_UPDATE_FEE (feeratePerKw : FeeratePerKw , commit : Boolean = false , replyTo_opt : Option [ActorRef ] = None ) extends HasOptionalReplyToCommand with ForbiddenCommandDuringQuiescenceNegotiation with ForbiddenCommandWhenQuiescent
205+ final case class CMD_SIGN (replyTo_opt : Option [ActorRef ] = None ) extends HasOptionalReplyToCommand with ForbiddenCommandWhenQuiescent
206206
207207final case class ClosingFees (preferred : Satoshi , min : Satoshi , max : Satoshi )
208208final case class ClosingFeerates (preferred : FeeratePerKw , min : FeeratePerKw , max : FeeratePerKw ) {
209209 def computeFees (closingTxWeight : Int ): ClosingFees = ClosingFees (weight2fee(preferred, closingTxWeight), weight2fee(min, closingTxWeight), weight2fee(max, closingTxWeight))
210210}
211211
212212sealed trait CloseCommand extends HasReplyToCommand
213- final case class CMD_CLOSE (replyTo : ActorRef , scriptPubKey : Option [ByteVector ], feerates : Option [ClosingFeerates ]) extends CloseCommand with ForbiddenCommandDuringSplice with ForbiddenCommandDuringQuiescence
213+ final case class CMD_CLOSE (replyTo : ActorRef , scriptPubKey : Option [ByteVector ], feerates : Option [ClosingFeerates ]) extends CloseCommand with ForbiddenCommandDuringQuiescenceNegotiation with ForbiddenCommandWhenQuiescent
214214final case class CMD_FORCECLOSE (replyTo : ActorRef ) extends CloseCommand
215215final case class CMD_BUMP_FORCE_CLOSE_FEE (replyTo : akka.actor.typed.ActorRef [CommandResponse [CMD_BUMP_FORCE_CLOSE_FEE ]], confirmationTarget : ConfirmationTarget ) extends Command
216216
217- final case class CMD_BUMP_FUNDING_FEE (replyTo : akka.actor.typed.ActorRef [CommandResponse [CMD_BUMP_FUNDING_FEE ]], targetFeerate : FeeratePerKw , fundingFeeBudget : Satoshi , lockTime : Long ) extends Command
217+ sealed trait ChannelFundingCommand extends Command {
218+ def replyTo : akka.actor.typed.ActorRef [CommandResponse [ChannelFundingCommand ]]
219+ }
218220case class SpliceIn (additionalLocalFunding : Satoshi , pushAmount : MilliSatoshi = 0 msat)
219221case class SpliceOut (amount : Satoshi , scriptPubKey : ByteVector )
220- final case class CMD_SPLICE (replyTo : akka.actor.typed.ActorRef [CommandResponse [CMD_SPLICE ]], spliceIn_opt : Option [SpliceIn ], spliceOut_opt : Option [SpliceOut ]) extends Command {
222+ final case class CMD_SPLICE (replyTo : akka.actor.typed.ActorRef [CommandResponse [ChannelFundingCommand ]], spliceIn_opt : Option [SpliceIn ], spliceOut_opt : Option [SpliceOut ]) extends ChannelFundingCommand {
221223 require(spliceIn_opt.isDefined || spliceOut_opt.isDefined, " there must be a splice-in or a splice-out" )
222224 val additionalLocalFunding : Satoshi = spliceIn_opt.map(_.additionalLocalFunding).getOrElse(0 sat)
223225 val pushAmount : MilliSatoshi = spliceIn_opt.map(_.pushAmount).getOrElse(0 msat)
224226 val spliceOutputs : List [TxOut ] = spliceOut_opt.toList.map(s => TxOut (s.amount, s.scriptPubKey))
225227}
228+ final case class CMD_BUMP_FUNDING_FEE (replyTo : akka.actor.typed.ActorRef [CommandResponse [ChannelFundingCommand ]], targetFeerate : FeeratePerKw , fundingFeeBudget : Satoshi , lockTime : Long ) extends ChannelFundingCommand
226229final case class CMD_UPDATE_RELAY_FEE (replyTo : ActorRef , feeBase : MilliSatoshi , feeProportionalMillionths : Long ) extends HasReplyToCommand
227230final case class CMD_GET_CHANNEL_STATE (replyTo : ActorRef ) extends HasReplyToCommand
228231final case class CMD_GET_CHANNEL_DATA (replyTo : ActorRef ) extends HasReplyToCommand
@@ -456,42 +459,61 @@ object RemoteFundingStatus {
456459 case object Locked extends RemoteFundingStatus
457460}
458461
459- sealed trait RbfStatus
460- object RbfStatus {
461- case object NoRbf extends RbfStatus
462- case class RbfRequested (cmd : CMD_BUMP_FUNDING_FEE ) extends RbfStatus
463- case class RbfInProgress (cmd_opt : Option [CMD_BUMP_FUNDING_FEE ], rbf : typed.ActorRef [InteractiveTxBuilder .Command ], remoteCommitSig : Option [CommitSig ]) extends RbfStatus
464- case class RbfWaitingForSigs (signingSession : InteractiveTxSigningSession .WaitingForSigs ) extends RbfStatus
465- case object RbfAborted extends RbfStatus
462+ sealed trait DualFundingStatus
463+ object DualFundingStatus {
464+ /** We're waiting for one of the funding transactions to confirm. */
465+ case object WaitingForConfirmations extends DualFundingStatus
466+ /** We told our peer we want to RBF the funding transaction. */
467+ case class RbfRequested (cmd : CMD_BUMP_FUNDING_FEE ) extends DualFundingStatus
468+ /** We both agreed to RBF and are building the new funding transaction. */
469+ case class RbfInProgress (cmd_opt : Option [CMD_BUMP_FUNDING_FEE ], rbf : typed.ActorRef [InteractiveTxBuilder .Command ], remoteCommitSig : Option [CommitSig ]) extends DualFundingStatus
470+ /** A new funding transaction has been negotiated, we're exchanging signatures. */
471+ case class RbfWaitingForSigs (signingSession : InteractiveTxSigningSession .WaitingForSigs ) extends DualFundingStatus
472+ /** The RBF attempt was aborted by us, we're waiting for our peer to ack. */
473+ case object RbfAborted extends DualFundingStatus
466474}
467475
468- sealed trait SpliceStatus
469476/** We're waiting for the channel to be quiescent. */
470- sealed trait QuiescenceNegotiation extends SpliceStatus
477+ sealed trait QuiescenceNegotiation
471478object QuiescenceNegotiation {
472479 sealed trait Initiator extends QuiescenceNegotiation
480+ object Initiator {
481+ /** We stop sending new updates and wait for our updates to be added to the local and remote commitments. */
482+ case object QuiescenceRequested extends Initiator
483+ /** Our updates have been added to the local and remote commitments, we wait for our peer to do the same. */
484+ case class SentStfu (stfu : Stfu ) extends Initiator
485+ }
486+
473487 sealed trait NonInitiator extends QuiescenceNegotiation
488+ object NonInitiator {
489+ /** Our peer has asked us to stop sending new updates and wait for our updates to be added to the local and remote commitments. */
490+ case class ReceivedStfu (stfu : Stfu ) extends NonInitiator
491+ }
492+ }
493+
494+ sealed trait SpliceStatus {
495+ def isNegotiatingQuiescence : Boolean = this .isInstanceOf [SpliceStatus .NegotiatingQuiescence ]
496+ def isQuiescent : Boolean = this match {
497+ case SpliceStatus .NoSplice | _ : SpliceStatus .NegotiatingQuiescence => false
498+ case _ => true
499+ }
474500}
475- /** The channel is quiescent and a splice attempt was initiated. */
476- sealed trait QuiescentSpliceStatus extends SpliceStatus
477501object SpliceStatus {
478502 case object NoSplice extends SpliceStatus
479- /** We stop sending new updates and wait for our updates to be added to the local and remote commitments. */
480- case class QuiescenceRequested (splice : CMD_SPLICE ) extends QuiescenceNegotiation .Initiator
481- /** Our updates have been added to the local and remote commitments, we wait for our peer to do the same. */
482- case class InitiatorQuiescent (splice : CMD_SPLICE ) extends QuiescenceNegotiation .Initiator
483- /** Our peer has asked us to stop sending new updates and wait for our updates to be added to the local and remote commitments. */
484- case class ReceivedStfu (stfu : Stfu ) extends QuiescenceNegotiation .NonInitiator
485- /** Our updates have been added to the local and remote commitments, we wait for our peer to use the now quiescent channel. */
486- case object NonInitiatorQuiescent extends QuiescentSpliceStatus
503+ /** We're trying to quiesce the channel in order to negotiate a splice. */
504+ case class NegotiatingQuiescence (cmd_opt : Option [ChannelFundingCommand ], status : QuiescenceNegotiation ) extends SpliceStatus
505+ /** The channel is quiescent, we wait for our peer to send splice_init or tx_init_rbf. */
506+ case object NonInitiatorQuiescent extends SpliceStatus
487507 /** We told our peer we want to splice funds in the channel. */
488- case class SpliceRequested (cmd : CMD_SPLICE , init : SpliceInit ) extends QuiescentSpliceStatus
489- /** We both agreed to splice and are building the splice transaction. */
490- case class SpliceInProgress (cmd_opt : Option [CMD_SPLICE ], sessionId : ByteVector32 , splice : typed.ActorRef [InteractiveTxBuilder .Command ], remoteCommitSig : Option [CommitSig ]) extends QuiescentSpliceStatus
508+ case class SpliceRequested (cmd : CMD_SPLICE , init : SpliceInit ) extends SpliceStatus
509+ /** We told our peer we want to RBF the latest splice transaction. */
510+ case class RbfRequested (cmd : CMD_BUMP_FUNDING_FEE , rbf : TxInitRbf ) extends SpliceStatus
511+ /** We both agreed to splice/rbf and are building the corresponding transaction. */
512+ case class SpliceInProgress (cmd_opt : Option [ChannelFundingCommand ], sessionId : ByteVector32 , splice : typed.ActorRef [InteractiveTxBuilder .Command ], remoteCommitSig : Option [CommitSig ]) extends SpliceStatus
491513 /** The splice transaction has been negotiated, we're exchanging signatures. */
492- case class SpliceWaitingForSigs (signingSession : InteractiveTxSigningSession .WaitingForSigs ) extends QuiescentSpliceStatus
514+ case class SpliceWaitingForSigs (signingSession : InteractiveTxSigningSession .WaitingForSigs ) extends SpliceStatus
493515 /** The splice attempt was aborted by us, we're waiting for our peer to ack. */
494- case object SpliceAborted extends QuiescentSpliceStatus
516+ case object SpliceAborted extends SpliceStatus
495517}
496518
497519sealed trait ChannelData extends PossiblyHarmful {
@@ -585,7 +607,7 @@ final case class DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments: Commitments,
585607 remotePushAmount : MilliSatoshi ,
586608 waitingSince : BlockHeight , // how long have we been waiting for a funding tx to confirm
587609 lastChecked : BlockHeight , // last time we checked if the channel was double-spent
588- rbfStatus : RbfStatus ,
610+ status : DualFundingStatus ,
589611 deferred : Option [ChannelReady ]) extends ChannelDataWithCommitments {
590612 def allFundingTxs : Seq [DualFundedUnconfirmedFundingTx ] = commitments.active.map(_.localFundingStatus).collect { case fundingTx : DualFundedUnconfirmedFundingTx => fundingTx }
591613 def latestFundingTx : DualFundedUnconfirmedFundingTx = commitments.latest.localFundingStatus.asInstanceOf [DualFundedUnconfirmedFundingTx ]
@@ -600,7 +622,10 @@ final case class DATA_NORMAL(commitments: Commitments,
600622 localShutdown : Option [Shutdown ],
601623 remoteShutdown : Option [Shutdown ],
602624 closingFeerates : Option [ClosingFeerates ],
603- spliceStatus : SpliceStatus ) extends ChannelDataWithCommitments
625+ spliceStatus : SpliceStatus ) extends ChannelDataWithCommitments {
626+ val isNegotiatingQuiescence : Boolean = spliceStatus.isNegotiatingQuiescence
627+ val isQuiescent : Boolean = spliceStatus.isQuiescent
628+ }
604629final case class DATA_SHUTDOWN (commitments : Commitments , localShutdown : Shutdown , remoteShutdown : Shutdown , closingFeerates : Option [ClosingFeerates ]) extends ChannelDataWithCommitments
605630final case class DATA_NEGOTIATING (commitments : Commitments ,
606631 localShutdown : Shutdown , remoteShutdown : Shutdown ,
0 commit comments