@@ -26,7 +26,7 @@ import fr.acinq.eclair.channel.fund.{InteractiveTxBuilder, InteractiveTxSigningS
26
26
import fr .acinq .eclair .io .Peer
27
27
import fr .acinq .eclair .transactions .CommitmentSpec
28
28
import 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 }
30
30
import fr .acinq .eclair .{Alias , BlockHeight , CltvExpiry , CltvExpiryDelta , Features , InitFeature , MilliSatoshi , MilliSatoshiLong , RealShortChannelId , TimestampMilli , UInt64 }
31
31
import scodec .bits .ByteVector
32
32
@@ -193,36 +193,39 @@ sealed trait Command extends PossiblyHarmful
193
193
sealed trait HasReplyToCommand extends Command { def replyTo : ActorRef }
194
194
sealed trait HasOptionalReplyToCommand extends Command { def replyTo_opt : Option [ActorRef ] }
195
195
196
- sealed trait ForbiddenCommandDuringSplice extends Command
197
- sealed trait ForbiddenCommandDuringQuiescence extends Command
196
+ sealed trait ForbiddenCommandDuringQuiescenceNegotiation extends Command
197
+ sealed trait ForbiddenCommandWhenQuiescent extends Command
198
198
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 }
201
201
final case class CMD_FULFILL_HTLC (id : Long , r : ByteVector32 , commit : Boolean = false , replyTo_opt : Option [ActorRef ] = None ) extends HtlcSettlementCommand
202
202
final 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
203
203
final 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
206
206
207
207
final case class ClosingFees (preferred : Satoshi , min : Satoshi , max : Satoshi )
208
208
final case class ClosingFeerates (preferred : FeeratePerKw , min : FeeratePerKw , max : FeeratePerKw ) {
209
209
def computeFees (closingTxWeight : Int ): ClosingFees = ClosingFees (weight2fee(preferred, closingTxWeight), weight2fee(min, closingTxWeight), weight2fee(max, closingTxWeight))
210
210
}
211
211
212
212
sealed 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
214
214
final case class CMD_FORCECLOSE (replyTo : ActorRef ) extends CloseCommand
215
215
final case class CMD_BUMP_FORCE_CLOSE_FEE (replyTo : akka.actor.typed.ActorRef [CommandResponse [CMD_BUMP_FORCE_CLOSE_FEE ]], confirmationTarget : ConfirmationTarget ) extends Command
216
216
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
+ }
218
220
case class SpliceIn (additionalLocalFunding : Satoshi , pushAmount : MilliSatoshi = 0 msat)
219
221
case 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 {
221
223
require(spliceIn_opt.isDefined || spliceOut_opt.isDefined, " there must be a splice-in or a splice-out" )
222
224
val additionalLocalFunding : Satoshi = spliceIn_opt.map(_.additionalLocalFunding).getOrElse(0 sat)
223
225
val pushAmount : MilliSatoshi = spliceIn_opt.map(_.pushAmount).getOrElse(0 msat)
224
226
val spliceOutputs : List [TxOut ] = spliceOut_opt.toList.map(s => TxOut (s.amount, s.scriptPubKey))
225
227
}
228
+ final case class CMD_BUMP_FUNDING_FEE (replyTo : akka.actor.typed.ActorRef [CommandResponse [ChannelFundingCommand ]], targetFeerate : FeeratePerKw , fundingFeeBudget : Satoshi , lockTime : Long ) extends ChannelFundingCommand
226
229
final case class CMD_UPDATE_RELAY_FEE (replyTo : ActorRef , feeBase : MilliSatoshi , feeProportionalMillionths : Long ) extends HasReplyToCommand
227
230
final case class CMD_GET_CHANNEL_STATE (replyTo : ActorRef ) extends HasReplyToCommand
228
231
final case class CMD_GET_CHANNEL_DATA (replyTo : ActorRef ) extends HasReplyToCommand
@@ -456,42 +459,61 @@ object RemoteFundingStatus {
456
459
case object Locked extends RemoteFundingStatus
457
460
}
458
461
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
466
474
}
467
475
468
- sealed trait SpliceStatus
469
476
/** We're waiting for the channel to be quiescent. */
470
- sealed trait QuiescenceNegotiation extends SpliceStatus
477
+ sealed trait QuiescenceNegotiation
471
478
object QuiescenceNegotiation {
472
479
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
+
473
487
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
+ }
474
500
}
475
- /** The channel is quiescent and a splice attempt was initiated. */
476
- sealed trait QuiescentSpliceStatus extends SpliceStatus
477
501
object SpliceStatus {
478
502
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
487
507
/** 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
491
513
/** 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
493
515
/** 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
495
517
}
496
518
497
519
sealed trait ChannelData extends PossiblyHarmful {
@@ -585,7 +607,7 @@ final case class DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments: Commitments,
585
607
remotePushAmount : MilliSatoshi ,
586
608
waitingSince : BlockHeight , // how long have we been waiting for a funding tx to confirm
587
609
lastChecked : BlockHeight , // last time we checked if the channel was double-spent
588
- rbfStatus : RbfStatus ,
610
+ status : DualFundingStatus ,
589
611
deferred : Option [ChannelReady ]) extends ChannelDataWithCommitments {
590
612
def allFundingTxs : Seq [DualFundedUnconfirmedFundingTx ] = commitments.active.map(_.localFundingStatus).collect { case fundingTx : DualFundedUnconfirmedFundingTx => fundingTx }
591
613
def latestFundingTx : DualFundedUnconfirmedFundingTx = commitments.latest.localFundingStatus.asInstanceOf [DualFundedUnconfirmedFundingTx ]
@@ -600,7 +622,10 @@ final case class DATA_NORMAL(commitments: Commitments,
600
622
localShutdown : Option [Shutdown ],
601
623
remoteShutdown : Option [Shutdown ],
602
624
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
+ }
604
629
final case class DATA_SHUTDOWN (commitments : Commitments , localShutdown : Shutdown , remoteShutdown : Shutdown , closingFeerates : Option [ClosingFeerates ]) extends ChannelDataWithCommitments
605
630
final case class DATA_NEGOTIATING (commitments : Commitments ,
606
631
localShutdown : Shutdown , remoteShutdown : Shutdown ,
0 commit comments