Skip to content

Commit 8876ef1

Browse files
authored
Update features early on reconnection (#3310)
Otherwise some upgrade paths may fail.
1 parent befdcd5 commit 8876ef1

2 files changed

Lines changed: 55 additions & 55 deletions

File tree

eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ object Helpers {
4949
/**
5050
* We update local/global features at reconnection
5151
*/
52-
def updateFeatures(data: PersistentChannelData, localInit: Init, remoteInit: Init): PersistentChannelData = {
53-
data match {
52+
def updateFeatures[T <: PersistentChannelData](data: T, localInit: Init, remoteInit: Init): T = {
53+
(data match {
5454
case d: DATA_WAIT_FOR_FUNDING_CONFIRMED => d.copy(commitments = d.commitments.updateInitFeatures(localInit, remoteInit))
5555
case d: DATA_WAIT_FOR_DUAL_FUNDING_SIGNED => d.copy(channelParams = d.channelParams.updateFeatures(localInit, remoteInit))
5656
case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.copy(commitments = d.commitments.updateInitFeatures(localInit, remoteInit))
@@ -62,7 +62,7 @@ object Helpers {
6262
case d: DATA_NEGOTIATING_SIMPLE => d.copy(commitments = d.commitments.updateInitFeatures(localInit, remoteInit))
6363
case d: DATA_CLOSING => d.copy(commitments = d.commitments.updateInitFeatures(localInit, remoteInit))
6464
case d: DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT => d.copy(commitments = d.commitments.updateInitFeatures(localInit, remoteInit))
65-
}
65+
}).asInstanceOf[T]
6666
}
6767

6868
def updateCommitments(data: ChannelDataWithCommitments, commitments: Commitments): PersistentChannelData = {

eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2416,102 +2416,104 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall
24162416

24172417
case Event(INPUT_RECONNECTED(r, localInit, remoteInit), d: DATA_WAIT_FOR_DUAL_FUNDING_SIGNED) =>
24182418
activeConnection = r
2419+
val d1 = Helpers.updateFeatures(d, localInit, remoteInit)
24192420
val myFirstPerCommitmentPoint = channelKeys.commitmentPoint(0)
2420-
val nextFundingTlv = if (d.channelParams.useLegacySpliceProtocol) {
2421-
Set[ChannelReestablishTlv](ChannelReestablishTlv.ExperimentalNextFundingTlv(d.signingSession.fundingTxId))
2421+
val nextFundingTlv = if (d1.channelParams.useLegacySpliceProtocol) {
2422+
Set[ChannelReestablishTlv](ChannelReestablishTlv.ExperimentalNextFundingTlv(d1.signingSession.fundingTxId))
24222423
} else {
2423-
Set[ChannelReestablishTlv](ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(d.signingSession.fundingTxId, d.signingSession.retransmitRemoteCommitSig))
2424+
Set[ChannelReestablishTlv](ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(d1.signingSession.fundingTxId, d1.signingSession.retransmitRemoteCommitSig))
24242425
}
2425-
val nonceTlvs = d.signingSession.fundingParams.commitmentFormat match {
2426+
val nonceTlvs = d1.signingSession.fundingParams.commitmentFormat match {
24262427
case _: SegwitV0CommitmentFormat => Set.empty
24272428
case _: SimpleTaprootChannelCommitmentFormat =>
24282429
val localFundingKey = channelKeys.fundingKey(0)
2429-
val remoteFundingPubKey = d.signingSession.fundingParams.remoteFundingPubKey
2430-
val currentCommitNonce_opt = d.signingSession.localCommit match {
2431-
case Left(_) => Some(NonceGenerator.verificationNonce(d.signingSession.fundingTxId, localFundingKey, remoteFundingPubKey, 0))
2430+
val remoteFundingPubKey = d1.signingSession.fundingParams.remoteFundingPubKey
2431+
val currentCommitNonce_opt = d1.signingSession.localCommit match {
2432+
case Left(_) => Some(NonceGenerator.verificationNonce(d1.signingSession.fundingTxId, localFundingKey, remoteFundingPubKey, 0))
24322433
case Right(_) => None
24332434
}
2434-
val nextCommitNonce = NonceGenerator.verificationNonce(d.signingSession.fundingTxId, localFundingKey, remoteFundingPubKey, 1)
2435+
val nextCommitNonce = NonceGenerator.verificationNonce(d1.signingSession.fundingTxId, localFundingKey, remoteFundingPubKey, 1)
24352436
Set(
2436-
Some(ChannelReestablishTlv.NextLocalNoncesTlv(List(d.signingSession.fundingTxId -> nextCommitNonce.publicNonce))),
2437+
Some(ChannelReestablishTlv.NextLocalNoncesTlv(List(d1.signingSession.fundingTxId -> nextCommitNonce.publicNonce))),
24372438
currentCommitNonce_opt.map(n => ChannelReestablishTlv.CurrentCommitNonceTlv(n.publicNonce)),
24382439
).flatten[ChannelReestablishTlv]
24392440
}
24402441
val channelReestablish = ChannelReestablish(
2441-
channelId = d.channelId,
2442-
nextLocalCommitmentNumber = d.signingSession.nextLocalCommitmentNumber(d.channelParams.useLegacySpliceProtocol),
2442+
channelId = d1.channelId,
2443+
nextLocalCommitmentNumber = d1.signingSession.nextLocalCommitmentNumber(d1.channelParams.useLegacySpliceProtocol),
24432444
nextRemoteRevocationNumber = 0,
24442445
yourLastPerCommitmentSecret = PrivateKey(ByteVector32.Zeroes),
24452446
myCurrentPerCommitmentPoint = myFirstPerCommitmentPoint,
24462447
TlvStream(nextFundingTlv ++ nonceTlvs),
24472448
)
2448-
val d1 = Helpers.updateFeatures(d, localInit, remoteInit)
24492449
goto(SYNCING) using d1 sending channelReestablish
24502450

24512451
case Event(INPUT_RECONNECTED(r, localInit, remoteInit), d: ChannelDataWithCommitments) =>
24522452
activeConnection = r
2453-
val remotePerCommitmentSecrets = d.commitments.remotePerCommitmentSecrets
2453+
// we update local/remote connection-local global/local features, we don't persist it right now
2454+
val d1 = Helpers.updateFeatures(d, localInit, remoteInit)
2455+
val remotePerCommitmentSecrets = d1.commitments.remotePerCommitmentSecrets
24542456
val yourLastPerCommitmentSecret = remotePerCommitmentSecrets.lastIndex.flatMap(remotePerCommitmentSecrets.getHash).getOrElse(ByteVector32.Zeroes)
2455-
val myCurrentPerCommitmentPoint = channelKeys.commitmentPoint(d.commitments.localCommitIndex)
2456-
// TODO: replace by d.commitments.localCommitIndex + 1 when removing support for the legacy splice protocol.
2457-
val nextLocalCommitmentNumber = d match {
2458-
case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match {
2459-
case DualFundingStatus.RbfWaitingForSigs(status) => status.nextLocalCommitmentNumber(d.channelParams.useLegacySpliceProtocol)
2460-
case _ => d.commitments.localCommitIndex + 1
2457+
val myCurrentPerCommitmentPoint = channelKeys.commitmentPoint(d1.commitments.localCommitIndex)
2458+
// TODO: replace by d1.commitments.localCommitIndex + 1 when removing support for the legacy splice protocol.
2459+
val nextLocalCommitmentNumber = d1 match {
2460+
case d1: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d1.status match {
2461+
case DualFundingStatus.RbfWaitingForSigs(status) => status.nextLocalCommitmentNumber(d1.channelParams.useLegacySpliceProtocol)
2462+
case _ => d1.commitments.localCommitIndex + 1
24612463
}
2462-
case d: DATA_NORMAL => d.spliceStatus match {
2463-
case SpliceStatus.SpliceWaitingForSigs(status) => status.nextLocalCommitmentNumber(d.channelParams.useLegacySpliceProtocol)
2464-
case _ => d.commitments.localCommitIndex + 1
2464+
case d1: DATA_NORMAL => d1.spliceStatus match {
2465+
case SpliceStatus.SpliceWaitingForSigs(status) => status.nextLocalCommitmentNumber(d1.channelParams.useLegacySpliceProtocol)
2466+
case _ => d1.commitments.localCommitIndex + 1
24652467
}
2466-
case _ => d.commitments.localCommitIndex + 1
2468+
case _ => d1.commitments.localCommitIndex + 1
24672469
}
24682470
// If we disconnected while signing a funding transaction, we may need our peer to (re)transmit their tx_signatures and commit_sig.
2469-
val rbfTlv: Set[ChannelReestablishTlv] = if (d.channelParams.useLegacySpliceProtocol) {
2470-
d match {
2471-
case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match {
2471+
val rbfTlv: Set[ChannelReestablishTlv] = if (d1.channelParams.useLegacySpliceProtocol) {
2472+
d1 match {
2473+
case d1: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d1.status match {
24722474
case DualFundingStatus.RbfWaitingForSigs(status) => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(status.fundingTx.txId))
2473-
case _ => d.latestFundingTx.sharedTx match {
2474-
case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(d.latestFundingTx.sharedTx.txId))
2475+
case _ => d1.latestFundingTx.sharedTx match {
2476+
case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(d1.latestFundingTx.sharedTx.txId))
24752477
case _: InteractiveTxBuilder.FullySignedSharedTransaction => Set.empty
24762478
}
24772479
}
2478-
case d: DATA_NORMAL => d.spliceStatus match {
2480+
case d1: DATA_NORMAL => d1.spliceStatus match {
24792481
case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(status.fundingTx.txId))
2480-
case _ => d.commitments.latest.localFundingStatus match {
2482+
case _ => d1.commitments.latest.localFundingStatus match {
24812483
case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _, _) => Set(ChannelReestablishTlv.ExperimentalNextFundingTlv(fundingTx.txId))
24822484
case _ => Set.empty
24832485
}
24842486
}
24852487
case _ => Set.empty
24862488
}
24872489
} else {
2488-
d match {
2489-
case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match {
2490+
d1 match {
2491+
case d1: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d1.status match {
24902492
case DualFundingStatus.RbfWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(status.fundingTx.txId, status.retransmitRemoteCommitSig))
2491-
case _ => d.latestFundingTx.sharedTx match {
2492-
case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(d.latestFundingTx.sharedTx.txId, retransmitCommitSig = false))
2493+
case _ => d1.latestFundingTx.sharedTx match {
2494+
case _: InteractiveTxBuilder.PartiallySignedSharedTransaction => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(d1.latestFundingTx.sharedTx.txId, retransmitCommitSig = false))
24932495
case _: InteractiveTxBuilder.FullySignedSharedTransaction => Set.empty
24942496
}
24952497
}
2496-
case d: DATA_NORMAL => d.spliceStatus match {
2498+
case d1: DATA_NORMAL => d1.spliceStatus match {
24972499
case SpliceStatus.SpliceWaitingForSigs(status) => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(status.fundingTx.txId, status.retransmitRemoteCommitSig))
2498-
case _ => d.commitments.latest.localFundingStatus match {
2500+
case _ => d1.commitments.latest.localFundingStatus match {
24992501
case LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx: PartiallySignedSharedTransaction, _, _, _) => Set(ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asNextFunding(fundingTx.txId, retransmitCommitSig = false))
25002502
case _ => Set.empty
25012503
}
25022504
}
25032505
case _ => Set.empty
25042506
}
25052507
}
2506-
val lastFundingLockedTlvs: Set[ChannelReestablishTlv] = if (d.channelParams.useLegacySpliceProtocol) {
2507-
val myCurrentFundingLocked_opt = d.commitments.lastLocalLocked_opt.map(c => ChannelReestablishTlv.ExperimentalMyCurrentFundingLockedTlv(c.fundingTxId))
2508-
val yourLastFundingLocked_opt = d.commitments.lastRemoteLocked_opt.map(c => ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asExperimentalYourLastFundingLocked(c.fundingTxId))
2508+
val lastFundingLockedTlvs: Set[ChannelReestablishTlv] = if (d1.channelParams.useLegacySpliceProtocol) {
2509+
val myCurrentFundingLocked_opt = d1.commitments.lastLocalLocked_opt.map(c => ChannelReestablishTlv.ExperimentalMyCurrentFundingLockedTlv(c.fundingTxId))
2510+
val yourLastFundingLocked_opt = d1.commitments.lastRemoteLocked_opt.map(c => ChannelReestablishTlv.NextFundingOrExperimentalYourLastFundingLockedTlv.asExperimentalYourLastFundingLocked(c.fundingTxId))
25092511
myCurrentFundingLocked_opt.toSet ++ yourLastFundingLocked_opt.toSet
2510-
} else if (d.channelParams.remoteParams.initFeatures.hasFeature(Features.Splicing)) {
2511-
d.commitments.lastLocalLocked_opt.map(c => {
2512+
} else if (d1.channelParams.remoteParams.initFeatures.hasFeature(Features.Splicing)) {
2513+
d1.commitments.lastLocalLocked_opt.map(c => {
25122514
// We ask our peer to retransmit their announcement_signatures if we haven't already announced that splice.
2513-
val retransmitAnnSigs = d match {
2514-
case d: DATA_NORMAL if d.commitments.announceChannel => !d.lastAnnouncedFundingTxId_opt.contains(c.fundingTxId)
2515+
val retransmitAnnSigs = d1 match {
2516+
case d1: DATA_NORMAL if d1.commitments.announceChannel => !d1.lastAnnouncedFundingTxId_opt.contains(c.fundingTxId)
25152517
case _ => false
25162518
}
25172519
ChannelReestablishTlv.MyCurrentFundingLockedTlv(c.fundingTxId, retransmitAnnSigs)
@@ -2521,23 +2523,23 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall
25212523
}
25222524

25232525
// We send our verification nonces for all active commitments.
2524-
val nextCommitNonces: Map[TxId, IndividualNonce] = d.commitments.active.flatMap(c => {
2526+
val nextCommitNonces: Map[TxId, IndividualNonce] = d1.commitments.active.flatMap(c => {
25252527
c.commitmentFormat match {
25262528
case _: SegwitV0CommitmentFormat => None
25272529
case _: SimpleTaprootChannelCommitmentFormat =>
25282530
val localFundingKey = channelKeys.fundingKey(c.fundingTxIndex)
2529-
Some(c.fundingTxId -> NonceGenerator.verificationNonce(c.fundingTxId, localFundingKey, c.remoteFundingPubKey, d.commitments.localCommitIndex + 1).publicNonce)
2531+
Some(c.fundingTxId -> NonceGenerator.verificationNonce(c.fundingTxId, localFundingKey, c.remoteFundingPubKey, d1.commitments.localCommitIndex + 1).publicNonce)
25302532
}
25312533
}).toMap
25322534
// If an interactive-tx session hasn't been fully signed, we also need to include the corresponding nonces.
2533-
val (interactiveTxCurrentCommitNonce_opt, interactiveTxNextCommitNonce): (Option[IndividualNonce], Map[TxId, IndividualNonce]) = d match {
2534-
case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d.status match {
2535+
val (interactiveTxCurrentCommitNonce_opt, interactiveTxNextCommitNonce): (Option[IndividualNonce], Map[TxId, IndividualNonce]) = d1 match {
2536+
case d1: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED => d1.status match {
25352537
case DualFundingStatus.RbfWaitingForSigs(signingSession) if signingSession.fundingParams.commitmentFormat.isInstanceOf[TaprootCommitmentFormat] =>
25362538
val nextCommitNonce = Map(signingSession.fundingTxId -> signingSession.nextCommitNonce(channelKeys).publicNonce)
25372539
(signingSession.currentCommitNonce_opt(channelKeys).map(_.publicNonce), nextCommitNonce)
25382540
case _ => (None, Map.empty)
25392541
}
2540-
case d: DATA_NORMAL => d.spliceStatus match {
2542+
case d1: DATA_NORMAL => d1.spliceStatus match {
25412543
case SpliceStatus.SpliceWaitingForSigs(signingSession) if signingSession.fundingParams.commitmentFormat.isInstanceOf[TaprootCommitmentFormat] =>
25422544
val nextCommitNonce = Map(signingSession.fundingTxId -> signingSession.nextCommitNonce(channelKeys).publicNonce)
25432545
(signingSession.currentCommitNonce_opt(channelKeys).map(_.publicNonce), nextCommitNonce)
@@ -2551,15 +2553,13 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall
25512553
).flatten
25522554

25532555
val channelReestablish = ChannelReestablish(
2554-
channelId = d.channelId,
2556+
channelId = d1.channelId,
25552557
nextLocalCommitmentNumber = nextLocalCommitmentNumber,
2556-
nextRemoteRevocationNumber = d.commitments.remoteCommitIndex,
2558+
nextRemoteRevocationNumber = d1.commitments.remoteCommitIndex,
25572559
yourLastPerCommitmentSecret = PrivateKey(yourLastPerCommitmentSecret),
25582560
myCurrentPerCommitmentPoint = myCurrentPerCommitmentPoint,
25592561
tlvStream = TlvStream(rbfTlv ++ lastFundingLockedTlvs ++ nonceTlvs)
25602562
)
2561-
// we update local/remote connection-local global/local features, we don't persist it right now
2562-
val d1 = Helpers.updateFeatures(d, localInit, remoteInit)
25632563
goto(SYNCING) using d1 sending channelReestablish
25642564

25652565
case Event(ProcessCurrentBlockHeight(c), d: ChannelDataWithCommitments) => handleNewBlock(c, d)

0 commit comments

Comments
 (0)