diff --git a/src/commonMain/kotlin/fr/acinq/lightning/Features.kt b/src/commonMain/kotlin/fr/acinq/lightning/Features.kt index 3f834bc8f..595384231 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/Features.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/Features.kt @@ -133,6 +133,13 @@ sealed class Feature { override val scopes: Set get() = setOf(FeatureScope.Init, FeatureScope.Node) } + @Serializable + object ProvideStorage : Feature() { + override val rfcName get() = "option_provide_storage" + override val mandatory get() = 42 + override val scopes: Set get() = setOf(FeatureScope.Init, FeatureScope.Node) + } + @Serializable object ChannelType : Feature() { override val rfcName get() = "option_channel_type" @@ -224,22 +231,6 @@ sealed class Feature { override val scopes: Set get() = setOf(FeatureScope.Init, FeatureScope.Node) } - /** This feature bit should be activated when a node wants to send channel backups to their peers. */ - @Serializable - object ChannelBackupClient : Feature() { - override val rfcName get() = "channel_backup_client" - override val mandatory get() = 144 - override val scopes: Set get() = setOf(FeatureScope.Init) - } - - /** This feature bit should be activated when a node stores channel backups for their peers. */ - @Serializable - object ChannelBackupProvider : Feature() { - override val rfcName get() = "channel_backup_provider" - override val mandatory get() = 146 - override val scopes: Set get() = setOf(FeatureScope.Init, FeatureScope.Node) - } - // The version of trampoline enabled by this feature bit does not match the latest spec PR: once the spec is accepted, // we will introduce a new version of trampoline that will work in parallel to this one, until we can safely deprecate it. @Serializable @@ -337,6 +328,7 @@ data class Features(val activated: Map, val unknown: Se Feature.ShutdownAnySegwit, Feature.DualFunding, Feature.Quiescence, + Feature.ProvideStorage, Feature.ChannelType, Feature.PaymentMetadata, Feature.TrampolinePayment, @@ -349,8 +341,6 @@ data class Features(val activated: Map, val unknown: Se Feature.PayToOpenProvider, Feature.TrustedSwapInClient, Feature.TrustedSwapInProvider, - Feature.ChannelBackupClient, - Feature.ChannelBackupProvider, Feature.ExperimentalSplice, Feature.OnTheFlyFunding, Feature.FundingFeeCredit diff --git a/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt b/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt index 94f519965..5ea97b2fa 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt @@ -207,7 +207,6 @@ data class NodeParams( Feature.ExperimentalTrampolinePayment to FeatureSupport.Optional, Feature.ZeroReserveChannels to FeatureSupport.Optional, Feature.WakeUpNotificationClient to FeatureSupport.Optional, - Feature.ChannelBackupClient to FeatureSupport.Optional, Feature.ExperimentalSplice to FeatureSupport.Optional, Feature.OnTheFlyFunding to FeatureSupport.Optional, Feature.FundingFeeCredit to FeatureSupport.Optional, diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt index a094f456c..247dca70b 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/Commitments.kt @@ -566,7 +566,6 @@ data class Commitments( val payments: Map, // for outgoing htlcs, maps to paymentId val remoteNextCommitInfo: Either, // this one is tricky, it must be kept in sync with Commitment.nextRemoteCommit val remotePerCommitmentSecrets: ShaChain, - val remoteChannelData: EncryptedChannelData = EncryptedChannelData.empty ) { init { require(active.isNotEmpty()) { "there must be at least one active commitment" } @@ -794,7 +793,6 @@ data class Commitments( localChanges = changes.localChanges.copy(acked = emptyList()), remoteChanges = changes.remoteChanges.copy(proposed = emptyList(), acked = changes.remoteChanges.acked + changes.remoteChanges.proposed) ), - remoteChannelData = commits.last().channelData // the last message is the most recent ) return Either.Right(Pair(commitments1, revocation)) } @@ -849,7 +847,6 @@ data class Commitments( remoteNextCommitInfo = Either.Right(revocation.nextPerCommitmentPoint), remotePerCommitmentSecrets = remotePerCommitmentSecrets.addHash(revocation.perCommitmentSecret.value, 0xFFFFFFFFFFFFL - remoteCommitIndex), payments = payments1, - remoteChannelData = revocation.channelData ) return Either.Right(Pair(commitments1, actions.toList())) } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt index 3083829f0..4671a5d7c 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Channel.kt @@ -62,28 +62,12 @@ sealed class ChannelState { suspend fun ChannelContext.process(cmd: ChannelCommand): Pair> { return try { processInternal(cmd) - .let { (newState, actions) -> Pair(newState, newState.run { maybeAddBackupToMessages(actions) }) } .let { (newState, actions) -> Pair(newState, actions + onTransition(newState)) } } catch (t: Throwable) { handleLocalError(cmd, t) } } - /** Update outgoing messages to include an encrypted backup when necessary. */ - private fun ChannelContext.maybeAddBackupToMessages(actions: List): List = when { - this@ChannelState is PersistedChannelState && staticParams.nodeParams.features.hasFeature(Feature.ChannelBackupClient) -> actions.map { - when { - it is ChannelAction.Message.Send && it.message is TxSignatures -> it.copy(message = it.message.withChannelData(EncryptedChannelData.from(privateKey, this@ChannelState), logger)) - it is ChannelAction.Message.Send && it.message is CommitSig -> it.copy(message = it.message.withChannelData(EncryptedChannelData.from(privateKey, this@ChannelState), logger)) - it is ChannelAction.Message.Send && it.message is RevokeAndAck -> it.copy(message = it.message.withChannelData(EncryptedChannelData.from(privateKey, this@ChannelState), logger)) - it is ChannelAction.Message.Send && it.message is Shutdown -> it.copy(message = it.message.withChannelData(EncryptedChannelData.from(privateKey, this@ChannelState), logger)) - it is ChannelAction.Message.Send && it.message is ClosingSigned -> it.copy(message = it.message.withChannelData(EncryptedChannelData.from(privateKey, this@ChannelState), logger)) - else -> it - } - } - else -> actions - } - /** Add actions for some transitions */ private fun ChannelContext.onTransition(newState: ChannelState): List { val oldState = when (this@ChannelState) { @@ -301,7 +285,7 @@ sealed class ChannelState { sealed class PersistedChannelState : ChannelState() { abstract val channelId: ByteVector32 - internal fun ChannelContext.createChannelReestablish(): HasEncryptedChannelData = when (val state = this@PersistedChannelState) { + internal fun ChannelContext.createChannelReestablish(): ChannelReestablish = when (val state = this@PersistedChannelState) { is WaitForFundingSigned -> { val myFirstPerCommitmentPoint = keyManager.channelKeys(state.channelParams.localParams.fundingKeyPath).commitmentPoint(0) ChannelReestablish( @@ -311,7 +295,7 @@ sealed class PersistedChannelState : ChannelState() { yourLastCommitmentSecret = PrivateKey(ByteVector32.Zeroes), myCurrentPerCommitmentPoint = myFirstPerCommitmentPoint, TlvStream(ChannelReestablishTlv.NextFunding(state.signingSession.fundingTx.txId)) - ).withChannelData(state.remoteChannelData, logger) + ) } is ChannelStateWithCommitments -> { val yourLastPerCommitmentSecret = state.commitments.remotePerCommitmentSecrets.lastIndex?.let { state.commitments.remotePerCommitmentSecrets.getHash(it) } ?: ByteVector32.Zeroes @@ -329,7 +313,7 @@ sealed class PersistedChannelState : ChannelState() { yourLastCommitmentSecret = PrivateKey(yourLastPerCommitmentSecret), myCurrentPerCommitmentPoint = myCurrentPerCommitmentPoint, tlvStream = tlvs - ).withChannelData(state.commitments.remoteChannelData, logger) + ) } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Closing.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Closing.kt index be378bca1..6e2a40f7c 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Closing.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Closing.kt @@ -281,9 +281,6 @@ data class Closing( null -> Pair(closing1, listOf()) else -> { logger.info { "channel is now closed" } - if (closingType !is MutualClose) { - logger.debug { "last known remoteChannelData=${commitments.remoteChannelData}" } - } Pair(Closed(closing1), listOf(setClosingStatus(closingType))) } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Negotiating.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Negotiating.kt index 321f2062a..77403903f 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Negotiating.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Negotiating.kt @@ -89,7 +89,6 @@ data class Negotiating( closingTxProposed.last() + listOf(ClosingTxProposed(closingTx, closingSigned)) ) val nextState = this@Negotiating.copy( - commitments = commitments.copy(remoteChannelData = cmd.message.channelData), closingTxProposed = closingProposed1, bestUnpublishedClosingTx = signedClosingTx ) @@ -127,7 +126,6 @@ data class Negotiating( closingTxProposed.last() + listOf(ClosingTxProposed(closingTx, closingSigned)) ) val nextState = this@Negotiating.copy( - commitments = commitments.copy(remoteChannelData = cmd.message.channelData), closingTxProposed = closingProposed1, bestUnpublishedClosingTx = signedClosingTx ) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt index ad0e24621..48e3bd74f 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt @@ -178,7 +178,7 @@ data class Normal( logger.info { "waiting for tx_sigs" } Pair(this@Normal.copy(spliceStatus = spliceStatus.copy(session = signingSession1)), listOf()) } - is InteractiveTxSigningSessionAction.SendTxSigs -> sendSpliceTxSigs(spliceStatus.origins, action, spliceStatus.liquidityPurchase, cmd.message.channelData) + is InteractiveTxSigningSessionAction.SendTxSigs -> sendSpliceTxSigs(spliceStatus.origins, action, spliceStatus.liquidityPurchase) } } ignoreRetransmittedCommitSig(cmd.message) -> { @@ -298,7 +298,7 @@ data class Normal( } is Either.Right -> { // no, let's sign right away - val newState = this@Normal.copy(remoteShutdown = cmd.message, commitments = commitments.copy(remoteChannelData = cmd.message.channelData)) + val newState = this@Normal.copy(remoteShutdown = cmd.message) Pair(newState, listOf(ChannelAction.Message.SendToSelf(ChannelCommand.Commitment.Sign))) } } @@ -308,18 +308,17 @@ data class Normal( val actions = mutableListOf() val localShutdown = this@Normal.localShutdown ?: Shutdown(channelId, commitments.params.localParams.defaultFinalScriptPubKey) if (this@Normal.localShutdown == null) actions.add(ChannelAction.Message.Send(localShutdown)) - val commitments1 = commitments.copy(remoteChannelData = cmd.message.channelData) when { - commitments1.hasNoPendingHtlcsOrFeeUpdate() && paysClosingFees -> { + commitments.hasNoPendingHtlcsOrFeeUpdate() && paysClosingFees -> { val (closingTx, closingSigned) = Helpers.Closing.makeFirstClosingTx( channelKeys(), - commitments1.latest, + commitments.latest, localShutdown.scriptPubKey.toByteArray(), cmd.message.scriptPubKey.toByteArray(), closingFeerates ?: ClosingFeerates(currentOnChainFeerates().mutualCloseFeerate), ) val nextState = Negotiating( - commitments1, + commitments, localShutdown, cmd.message, listOf(listOf(ClosingTxProposed(closingTx, closingSigned))), @@ -329,14 +328,14 @@ data class Normal( actions.addAll(listOf(ChannelAction.Storage.StoreState(nextState), ChannelAction.Message.Send(closingSigned))) Pair(nextState, actions) } - commitments1.hasNoPendingHtlcsOrFeeUpdate() -> { - val nextState = Negotiating(commitments1, localShutdown, cmd.message, listOf(listOf()), null, closingFeerates) + commitments.hasNoPendingHtlcsOrFeeUpdate() -> { + val nextState = Negotiating(commitments, localShutdown, cmd.message, listOf(listOf()), null, closingFeerates) actions.add(ChannelAction.Storage.StoreState(nextState)) Pair(nextState, actions) } else -> { // there are some pending changes, we need to wait for them to be settled (fail/fulfill htlcs and sign fee updates) - val nextState = ShuttingDown(commitments1, localShutdown, cmd.message, closingFeerates) + val nextState = ShuttingDown(commitments, localShutdown, cmd.message, closingFeerates) actions.add(ChannelAction.Storage.StoreState(nextState)) Pair(nextState, actions) } @@ -670,7 +669,7 @@ data class Normal( } is Either.Right -> { val action: InteractiveTxSigningSessionAction.SendTxSigs = res.value - sendSpliceTxSigs(spliceStatus.origins, action, spliceStatus.liquidityPurchase, cmd.message.channelData) + sendSpliceTxSigs(spliceStatus.origins, action, spliceStatus.liquidityPurchase) } } } @@ -851,13 +850,12 @@ data class Normal( origins: List, action: InteractiveTxSigningSessionAction.SendTxSigs, liquidityPurchase: LiquidityAds.Purchase?, - remoteChannelData: EncryptedChannelData ): Pair> { logger.info { "sending tx_sigs" } // We watch for confirmation in all cases, to allow pruning outdated commitments when transactions confirm. val fundingMinDepth = Helpers.minDepthForFunding(staticParams.nodeParams, action.fundingTx.fundingParams.fundingAmount) val watchConfirmed = WatchConfirmed(channelId, action.commitment.fundingTxId, action.commitment.commitInput.txOut.publicKeyScript, fundingMinDepth.toLong(), BITCOIN_FUNDING_DEPTHOK) - val commitments = commitments.add(action.commitment).copy(remoteChannelData = remoteChannelData) + val commitments = commitments.add(action.commitment) val nextState = this@Normal.copy(commitments = commitments, spliceStatus = SpliceStatus.None) val actions = buildList { add(ChannelAction.Storage.StoreState(nextState)) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Offline.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Offline.kt index 10264fb9e..0b9af5faa 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Offline.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Offline.kt @@ -33,22 +33,14 @@ data class Offline(val state: PersistedChannelState) : ChannelState() { val channelReestablish = state.run { createChannelReestablish() } val actions = listOf(ChannelAction.Message.Send(channelReestablish)) val nextState = state.copy(channelParams = state.channelParams.updateFeatures(cmd.localInit, cmd.remoteInit)) - Pair(Syncing(nextState, channelReestablishSent = true), actions) + Pair(Syncing(nextState), actions) } is ChannelStateWithCommitments -> { logger.info { "syncing ${state::class}" } - val sendChannelReestablish = !staticParams.nodeParams.features.hasFeature(Feature.ChannelBackupClient) - val actions = buildList { - if (!sendChannelReestablish) { - // We wait for them to go first, which lets us restore from the latest backup if we've lost data. - logger.info { "waiting for their channel_reestablish message" } - } else { - val channelReestablish = state.run { createChannelReestablish() } - add(ChannelAction.Message.Send(channelReestablish)) - } - } + val channelReestablish = state.run { createChannelReestablish() } + val actions = listOf(ChannelAction.Message.Send(channelReestablish)) val nextState = state.updateCommitments(state.commitments.copy(params = state.commitments.params.updateFeatures(cmd.localInit, cmd.remoteInit))) - Pair(Syncing(nextState, channelReestablishSent = sendChannelReestablish), actions) + Pair(Syncing(nextState), actions) } } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt index a14f9e471..d87739e1c 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Syncing.kt @@ -9,7 +9,7 @@ import fr.acinq.lightning.crypto.KeyManager import fr.acinq.lightning.utils.toByteVector import fr.acinq.lightning.wire.* -data class Syncing(val state: PersistedChannelState, val channelReestablishSent: Boolean) : ChannelState() { +data class Syncing(val state: PersistedChannelState) : ChannelState() { val channelId = state.channelId @@ -257,13 +257,7 @@ data class Syncing(val state: PersistedChannelState, val channelReestablishSent: } is Closing, is Closed, is WaitForRemotePublishFutureCommitment -> unhandled(cmd) } - Pair(nextState, buildList { - if (!channelReestablishSent) { - val channelReestablish = state.run { createChannelReestablish() } - add(ChannelAction.Message.Send(channelReestablish)) - } - addAll(actions) - }) + Pair(nextState, actions) } is Error -> state.run { handleRemoteError(cmd.message) } else -> unhandled(cmd) @@ -292,7 +286,7 @@ data class Syncing(val state: PersistedChannelState, val channelReestablishSent: when (nextState) { is Closing -> Pair(nextState, actions) is Closed -> Pair(nextState, actions) - else -> Pair(Syncing(nextState, channelReestablishSent), actions) + else -> Pair(Syncing(nextState), actions) } } } @@ -328,7 +322,7 @@ data class Syncing(val state: PersistedChannelState, val channelReestablishSent: when (newState) { is Closing -> Pair(newState, actions) is Closed -> Pair(newState, actions) - else -> Pair(Syncing(newState, channelReestablishSent), actions) + else -> Pair(Syncing(newState), actions) } } is WaitForFundingSigned -> Pair(this@Syncing, listOf()) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt index 7667c4e68..777f2cff0 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmed.kt @@ -60,7 +60,7 @@ data class WaitForFundingConfirmed( } is Either.Right -> { val action: InteractiveTxSigningSessionAction.SendTxSigs = res.value - sendRbfTxSigs(action, cmd.message.channelData) + sendRbfTxSigs(action) } } } @@ -210,7 +210,7 @@ data class WaitForFundingConfirmed( } // No need to store their commit_sig, they will re-send it if we disconnect. InteractiveTxSigningSessionAction.WaitForTxSigs -> Pair(this@WaitForFundingConfirmed.copy(rbfStatus = rbfStatus.copy(session = signingSession1)), listOf()) - is InteractiveTxSigningSessionAction.SendTxSigs -> sendRbfTxSigs(action, cmd.message.channelData) + is InteractiveTxSigningSessionAction.SendTxSigs -> sendRbfTxSigs(action) } } else -> { @@ -302,13 +302,13 @@ data class WaitForFundingConfirmed( } } - private fun ChannelContext.sendRbfTxSigs(action: InteractiveTxSigningSessionAction.SendTxSigs, remoteChannelData: EncryptedChannelData): Pair> { + private fun ChannelContext.sendRbfTxSigs(action: InteractiveTxSigningSessionAction.SendTxSigs): Pair> { logger.info { "rbf funding tx created with txId=${action.fundingTx.txId}, ${action.fundingTx.sharedTx.tx.localInputs.size} local inputs, ${action.fundingTx.sharedTx.tx.remoteInputs.size} remote inputs, ${action.fundingTx.sharedTx.tx.localOutputs.size} local outputs and ${action.fundingTx.sharedTx.tx.remoteOutputs.size} remote outputs" } val fundingMinDepth = Helpers.minDepthForFunding(staticParams.nodeParams, action.fundingTx.fundingParams.fundingAmount) logger.info { "will wait for $fundingMinDepth confirmations" } val watchConfirmed = WatchConfirmed(channelId, action.commitment.fundingTxId, action.commitment.commitInput.txOut.publicKeyScript, fundingMinDepth.toLong(), BITCOIN_FUNDING_DEPTHOK) val nextState = WaitForFundingConfirmed( - commitments.add(action.commitment).copy(remoteChannelData = remoteChannelData), + commitments.add(action.commitment), waitingSinceBlock, deferred, RbfStatus.None diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt index 7e8ed19d9..189390d1f 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt @@ -41,7 +41,6 @@ data class WaitForFundingSigned( val remoteSecondPerCommitmentPoint: PublicKey, val liquidityPurchase: LiquidityAds.Purchase?, val channelOrigin: Origin?, - val remoteChannelData: EncryptedChannelData = EncryptedChannelData.empty ) : PersistedChannelState() { override val channelId: ByteVector32 = channelParams.channelId @@ -53,8 +52,8 @@ data class WaitForFundingSigned( when (action) { is InteractiveTxSigningSessionAction.AbortFundingAttempt -> handleLocalError(cmd, action.reason) // No need to store their commit_sig, they will re-send it if we disconnect. - InteractiveTxSigningSessionAction.WaitForTxSigs -> Pair(this@WaitForFundingSigned.copy(signingSession = signingSession1, remoteChannelData = cmd.message.channelData), listOf()) - is InteractiveTxSigningSessionAction.SendTxSigs -> sendTxSigs(action, cmd.message.channelData) + InteractiveTxSigningSessionAction.WaitForTxSigs -> Pair(this@WaitForFundingSigned.copy(signingSession = signingSession1), listOf()) + is InteractiveTxSigningSessionAction.SendTxSigs -> sendTxSigs(action) } } is TxSignatures -> { @@ -65,7 +64,7 @@ data class WaitForFundingSigned( } is Either.Right -> { val action: InteractiveTxSigningSessionAction.SendTxSigs = res.value - sendTxSigs(action, cmd.message.channelData) + sendTxSigs(action) } } } @@ -98,7 +97,7 @@ data class WaitForFundingSigned( } } - private fun ChannelContext.sendTxSigs(action: InteractiveTxSigningSessionAction.SendTxSigs, remoteChannelData: EncryptedChannelData): Pair> { + private fun ChannelContext.sendTxSigs(action: InteractiveTxSigningSessionAction.SendTxSigs): Pair> { logger.info { "funding tx created with txId=${action.fundingTx.txId}, ${action.fundingTx.sharedTx.tx.localInputs.size} local inputs, ${action.fundingTx.sharedTx.tx.remoteInputs.size} remote inputs, ${action.fundingTx.sharedTx.tx.localOutputs.size} local outputs and ${action.fundingTx.sharedTx.tx.remoteOutputs.size} remote outputs" } // We watch for confirmation in all cases, to allow pruning outdated commitments when transactions confirm. val fundingMinDepth = Helpers.minDepthForFunding(staticParams.nodeParams, action.fundingTx.fundingParams.fundingAmount) @@ -111,7 +110,6 @@ data class WaitForFundingSigned( payments = mapOf(), remoteNextCommitInfo = Either.Right(remoteSecondPerCommitmentPoint), remotePerCommitmentSecrets = ShaChain.init, - remoteChannelData = remoteChannelData ) val commonActions = buildList { action.fundingTx.signedTx?.let { add(ChannelAction.Blockchain.PublishTx(it, ChannelAction.Blockchain.PublishTx.Type.FundingTx)) } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt b/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt index ba7833d6e..aab565888 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt @@ -19,6 +19,7 @@ import fr.acinq.lightning.logging.MDCLogger import fr.acinq.lightning.logging.mdc import fr.acinq.lightning.logging.withMDC import fr.acinq.lightning.payment.* +import fr.acinq.lightning.serialization.Encryption import fr.acinq.lightning.serialization.Encryption.from import fr.acinq.lightning.serialization.Serialization.DeserializationResult import fr.acinq.lightning.transactions.Scripts @@ -254,6 +255,15 @@ class Peer( ) ) return state.run { ctx.process(cmd) } + .let { (state1, actions) -> + if (theirInit?.features?.hasFeature(Feature.ProvideStorage) == true && + state1 is PersistedChannelState && + actions.any { it is ChannelAction.Message.Send && it.message is UpdatesChannelData }) { + Pair(state1, actions + ChannelAction.Message.Send(PeerStorageStore(EncryptedChannelData.from(nodeParams.nodePrivateKey, state1)))) + } else { + Pair(state1, actions) + } + } .also { (state1, _) -> if (state1::class != state::class) { ctx.logger.info { "${state.stateName} -> ${state1.stateName}" } @@ -1088,14 +1098,12 @@ class Peer( processActions(msg.temporaryChannelId, peerConnection, actions1 + actions2) } } - is ChannelReestablish -> { - val local: ChannelState? = _channels[msg.channelId] - val backup: DeserializationResult? = msg.channelData.takeIf { !it.isEmpty() }?.let { channelData -> + is PeerStorageRetrieval -> { + val backup: DeserializationResult? = PersistedChannelState - .from(nodeParams.nodePrivateKey, channelData) + .from(nodeParams.nodePrivateKey, msg.ecd) .onFailure { logger.warning(it) { "unreadable backup" } } .getOrNull() - } suspend fun recoverChannel(recovered: PersistedChannelState) { db.channels.addOrUpdateChannel(recovered) @@ -1103,42 +1111,35 @@ class Peer( val state = WaitForInit val event1 = ChannelCommand.Init.Restore(recovered) val (state1, actions1) = state.process(event1) - processActions(msg.channelId, peerConnection, actions1) + processActions(recovered.channelId, peerConnection, actions1) val event2 = ChannelCommand.Connected(ourInit, theirInit!!) val (state2, actions2) = state1.process(event2) - processActions(msg.channelId, peerConnection, actions2) + processActions(recovered.channelId, peerConnection, actions2) - val event3 = ChannelCommand.MessageReceived(msg) - val (state3, actions3) = state2.process(event3) - processActions(msg.channelId, peerConnection, actions3) - _channels = _channels + (msg.channelId to state3) + _channels = _channels + (recovered.channelId to state2) } when { backup is DeserializationResult.UnknownVersion -> { - logger.warning { "peer sent a reestablish with a backup generated by a more recent of phoenix: version=${backup.version}." } + logger.warning { "peer sent a storage retrieval with a backup generated by a more recent of phoenix: version=${backup.version}." } // In this corner case, we do not want to return an error to the peer, because they will force-close and we will be unable to // do anything as we can't read the data. Best thing is to not answer, and tell the user to upgrade the app. logger.error { "need to upgrade your app!" } nodeParams._nodeEvents.emit(UpgradeRequired) } - local == null && backup == null -> { - logger.warning { "peer sent a reestablish for a unknown channel with no or undecipherable backup" } - peerConnection?.send(Error(msg.channelId, "unknown channel")) - } - local == null && backup is DeserializationResult.Success -> { - logger.warning { "recovering channel from peer backup" } - recoverChannel(backup.state) - } - local is Syncing && local.state is ChannelStateWithCommitments && backup is DeserializationResult.Success && backup.state is ChannelStateWithCommitments && backup.state.commitments.isMoreRecent(local.state.commitments) -> { - logger.warning { "recovering channel from peer backup (it is more recent)" } - recoverChannel(backup.state) - } - local is ChannelState -> { - val (state1, actions1) = local.process(ChannelCommand.MessageReceived(msg)) - processActions(msg.channelId, peerConnection, actions1) - _channels = _channels + (msg.channelId to state1) + backup is DeserializationResult.Success -> { + val local: ChannelState? = _channels[backup.state.channelId] + when { + local == null -> { + logger.warning { "recovering channel from peer backup" } + recoverChannel(backup.state) + } + local is Syncing && local.state is ChannelStateWithCommitments && backup.state is ChannelStateWithCommitments && backup.state.commitments.isMoreRecent(local.state.commitments) -> { + logger.warning { "recovering channel from peer backup (it is more recent)" } + recoverChannel(backup.state) + } + } } } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt b/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt index 20ba6aac0..ac49cca76 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt @@ -81,7 +81,6 @@ JsonSerializers.ChannelReadySerializer::class, JsonSerializers.ChannelReadyTlvShortChannelIdTlvSerializer::class, JsonSerializers.ClosingSignedTlvFeeRangeSerializer::class, - JsonSerializers.ShutdownTlvChannelDataSerializer::class, JsonSerializers.GenericTlvSerializer::class, JsonSerializers.TlvStreamSerializer::class, JsonSerializers.ShutdownTlvSerializer::class, @@ -207,7 +206,6 @@ object JsonSerializers { subclass(ChannelReadyTlv.ShortChannelIdTlv::class, ChannelReadyTlvShortChannelIdTlvSerializer) subclass(CommitSigTlv.AlternativeFeerateSigs::class, CommitSigTlvAlternativeFeerateSigsSerializer) subclass(CommitSigTlv.Batch::class, CommitSigTlvBatchSerializer) - subclass(ShutdownTlv.ChannelData::class, ShutdownTlvChannelDataSerializer) subclass(ClosingSignedTlv.FeeRange::class, ClosingSignedTlvFeeRangeSerializer) subclass(UpdateAddHtlcTlv.Blinding::class, UpdateAddHtlcTlvBlindingSerializer) } @@ -527,9 +525,6 @@ object JsonSerializers { @Serializer(forClass = ClosingSignedTlv.FeeRange::class) object ClosingSignedTlvFeeRangeSerializer - @Serializer(forClass = ShutdownTlv.ChannelData::class) - object ShutdownTlvChannelDataSerializer - @Serializer(forClass = ShutdownTlv::class) object ShutdownTlvSerializer diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt index 1ea499568..6e6a06da6 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/ChannelState.kt @@ -138,9 +138,6 @@ object ChannelReadyTlvShortChannelIdTlvSerializer @Serializer(forClass = ClosingSignedTlv.FeeRange::class) object ClosingSignedTlvFeeRangeSerializer -@Serializer(forClass = ShutdownTlv.ChannelData::class) -object ShutdownTlvChannelDataSerializer - @Serializer(forClass = ShutdownTlv::class) object ShutdownTlvSerializer @@ -403,7 +400,6 @@ internal data class Commitments( val commitInput: Transactions.InputInfo, val remotePerCommitmentSecrets: ShaChain, val channelId: ByteVector32, - val remoteChannelData: EncryptedChannelData = EncryptedChannelData.empty ) { fun export() = fr.acinq.lightning.channel.Commitments( fr.acinq.lightning.channel.ChannelParams( @@ -445,7 +441,6 @@ internal data class Commitments( payments, remoteNextCommitInfo.transform({ x -> fr.acinq.lightning.channel.WaitingForRevocation(x.sentAfterLocalCommitIndex) }, { y -> y }), remotePerCommitmentSecrets, - remoteChannelData ) } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/Serialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/Serialization.kt index 7099fc9c3..4a9fbe736 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/Serialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v2/Serialization.kt @@ -45,7 +45,6 @@ object Serialization { polymorphic(Tlv::class) { subclass(ChannelReadyTlvShortChannelIdTlvSerializer) subclass(ClosingSignedTlvFeeRangeSerializer) - subclass(ShutdownTlvChannelDataSerializer) subclass(GenericTlvSerializer) } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt index 1dc862ed1..fbda55dc4 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/ChannelState.kt @@ -138,9 +138,6 @@ object ChannelReadyTlvShortChannelIdTlvSerializer @Serializer(forClass = ClosingSignedTlv.FeeRange::class) object ClosingSignedTlvFeeRangeSerializer -@Serializer(forClass = ShutdownTlv.ChannelData::class) -object ShutdownTlvChannelDataSerializer - @Serializer(forClass = ShutdownTlv::class) object ShutdownTlvSerializer @@ -396,7 +393,6 @@ internal data class Commitments( val commitInput: Transactions.InputInfo, val remotePerCommitmentSecrets: ShaChain, val channelId: ByteVector32, - val remoteChannelData: EncryptedChannelData = EncryptedChannelData.empty ) { fun export() = fr.acinq.lightning.channel.Commitments( fr.acinq.lightning.channel.ChannelParams( @@ -438,7 +434,6 @@ internal data class Commitments( payments, remoteNextCommitInfo.transform({ x -> fr.acinq.lightning.channel.WaitingForRevocation(x.sentAfterLocalCommitIndex) }, { y -> y }), remotePerCommitmentSecrets, - remoteChannelData ) } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/Serialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/Serialization.kt index 6df2513f3..0aa5c1ac0 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/Serialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v3/Serialization.kt @@ -45,7 +45,6 @@ object Serialization { polymorphic(Tlv::class) { subclass(ChannelReadyTlvShortChannelIdTlvSerializer) subclass(ClosingSignedTlvFeeRangeSerializer) - subclass(ShutdownTlvChannelDataSerializer) subclass(GenericTlvSerializer) } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt index 5492af611..e90a6e4fd 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt @@ -669,8 +669,8 @@ object Deserialization { }.toMap(), lastIndex = readNullable { readNumber() } ) - val remoteChannelData = EncryptedChannelData(readDelimitedByteArray().toByteVector()) - return Commitments(params, changes, active, inactive, payments, remoteNextCommitInfo, remotePerCommitmentSecrets, remoteChannelData) + readDelimitedByteArray() // ignored legacy remoteChannelData + return Commitments(params, changes, active, inactive, payments, remoteNextCommitInfo, remotePerCommitmentSecrets) } private fun Input.readDirectedHtlc(): DirectedHtlc = when (val discriminator = read()) { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt index 637fdfc10..ad9bd8a8b 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt @@ -610,7 +610,7 @@ object Serialization { } writeNullable(lastIndex) { writeNumber(it) } } - writeDelimited(remoteChannelData.data.toByteArray()) + writeNumber(0) // ignored legacy remoteChannelData } private fun Output.writeDirectedHtlc(htlc: DirectedHtlc) = htlc.run { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt index 227c7c5e5..e6a381509 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt @@ -115,16 +115,6 @@ sealed class ChannelReadyTlv : Tlv { } sealed class CommitSigTlv : Tlv { - data class ChannelData(val ecb: EncryptedChannelData) : CommitSigTlv() { - override val tag: Long get() = ChannelData.tag - override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) - - companion object : TlvValueReader { - const val tag: Long = 0x47010000 - override fun read(input: Input): ChannelData = ChannelData(EncryptedChannelData(LightningCodecs.bytes(input, input.availableBytes).toByteVector())) - } - } - data class AlternativeFeerateSig(val feerate: FeeratePerKw, val sig: ByteVector64) /** @@ -167,17 +157,7 @@ sealed class CommitSigTlv : Tlv { } } -sealed class RevokeAndAckTlv : Tlv { - data class ChannelData(val ecb: EncryptedChannelData) : RevokeAndAckTlv() { - override val tag: Long get() = ChannelData.tag - override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) - - companion object : TlvValueReader { - const val tag: Long = 0x47010000 - override fun read(input: Input): ChannelData = ChannelData(EncryptedChannelData(LightningCodecs.bytes(input, input.availableBytes).toByteVector())) - } - } -} +sealed class RevokeAndAckTlv : Tlv sealed class ChannelReestablishTlv : Tlv { data class NextFunding(val txId: TxId) : ChannelReestablishTlv() { @@ -189,29 +169,9 @@ sealed class ChannelReestablishTlv : Tlv { override fun read(input: Input): NextFunding = NextFunding(TxId(LightningCodecs.txHash(input))) } } - - data class ChannelData(val ecb: EncryptedChannelData) : ChannelReestablishTlv() { - override val tag: Long get() = ChannelData.tag - override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) - - companion object : TlvValueReader { - const val tag: Long = 0x47010000 - override fun read(input: Input): ChannelData = ChannelData(EncryptedChannelData(LightningCodecs.bytes(input, input.availableBytes).toByteVector())) - } - } } -sealed class ShutdownTlv : Tlv { - data class ChannelData(val ecb: EncryptedChannelData) : ShutdownTlv() { - override val tag: Long get() = ChannelData.tag - override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) - - companion object : TlvValueReader { - const val tag: Long = 0x47010000 - override fun read(input: Input): ChannelData = ChannelData(EncryptedChannelData(LightningCodecs.bytes(input, input.availableBytes).toByteVector())) - } - } -} +sealed class ShutdownTlv : Tlv sealed class ClosingSignedTlv : Tlv { data class FeeRange(val min: Satoshi, val max: Satoshi) : ClosingSignedTlv() { @@ -227,14 +187,4 @@ sealed class ClosingSignedTlv : Tlv { override fun read(input: Input): FeeRange = FeeRange(Satoshi(LightningCodecs.u64(input)), Satoshi(LightningCodecs.u64(input))) } } - - data class ChannelData(val ecb: EncryptedChannelData) : ClosingSignedTlv() { - override val tag: Long get() = ChannelData.tag - override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) - - companion object : TlvValueReader { - const val tag: Long = 0x47010000 - override fun read(input: Input): ChannelData = ChannelData(EncryptedChannelData(LightningCodecs.bytes(input, input.availableBytes).toByteVector())) - } - } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt index b3c2e6f68..67a3f72f6 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt @@ -182,16 +182,6 @@ sealed class TxSignaturesTlv : Tlv { } } } - - data class ChannelData(val ecb: EncryptedChannelData) : TxSignaturesTlv() { - override val tag: Long get() = ChannelData.tag - override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) - - companion object : TlvValueReader { - const val tag: Long = 0x47010000 - override fun read(input: Input): ChannelData = ChannelData(EncryptedChannelData(LightningCodecs.bytes(input, input.availableBytes).toByteVector())) - } - } } sealed class TxInitRbfTlv : Tlv { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt index 608e0715e..3895860c5 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt @@ -95,6 +95,8 @@ interface LightningMessage { SpliceInit.type -> SpliceInit.read(stream) SpliceAck.type -> SpliceAck.read(stream) SpliceLocked.type -> SpliceLocked.read(stream) + PeerStorageStore.type -> PeerStorageStore.read(stream) + PeerStorageRetrieval.type -> PeerStorageRetrieval.read(stream) else -> UnknownMessage(code.toLong()) } } @@ -167,25 +169,7 @@ data class EncryptedChannelData(val data: ByteVector) { } } -interface HasEncryptedChannelData : HasChannelId { - val channelData: EncryptedChannelData - fun withNonEmptyChannelData(ecd: EncryptedChannelData): HasEncryptedChannelData - fun withChannelData(data: ByteVector, logger: MDCLogger? = null): HasEncryptedChannelData = withChannelData(EncryptedChannelData(data), logger) - fun withChannelData(ecd: EncryptedChannelData, logger: MDCLogger? = null): HasEncryptedChannelData { - // The maximum size for lightning messages is 65535 bytes, so we only include a channel backup when we have enough space available. - // Our peer needs to be able to send the backup back in their channel_reestablish message, and we don't know the size of that message. - // We use an upper bound of 60000 bytes, hoping that it will be enough to make it work in all cases. - val sizeWithoutBackup = write().size - return when { - ecd.isEmpty() -> this - ecd.data.size() + sizeWithoutBackup <= 60_000 -> withNonEmptyChannelData(ecd) - else -> { - logger?.warning { "c:${this.channelId} could not include encrypted backup in ${this::class.simpleName}: too large (${ecd.data.size()} bytes)" } - this - } - } - } -} +interface UpdatesChannelData : HasChannelId interface ChannelMessage @@ -491,7 +475,7 @@ data class TxSignatures( val txId: TxId, val witnesses: List, val tlvs: TlvStream = TlvStream.empty() -) : InteractiveTxMessage(), HasChannelId, HasEncryptedChannelData { +) : InteractiveTxMessage(), HasChannelId, UpdatesChannelData { constructor( channelId: ByteVector32, tx: Transaction, @@ -524,9 +508,6 @@ data class TxSignatures( val swapInUserPartialSigs: List = tlvs.get()?.psigs ?: listOf() val swapInServerPartialSigs: List = tlvs.get()?.psigs ?: listOf() - override val channelData: EncryptedChannelData get() = tlvs.get()?.ecb ?: EncryptedChannelData.empty - override fun withNonEmptyChannelData(ecd: EncryptedChannelData): TxSignatures = copy(tlvs = tlvs.addOrUpdate(TxSignaturesTlv.ChannelData(ecd))) - override fun write(out: Output) { LightningCodecs.writeBytes(channelId.toByteArray(), out) // Note that we encode the tx_hash instead of the tx_id to be consistent with other lightning messages. @@ -550,7 +531,6 @@ data class TxSignatures( TxSignaturesTlv.SwapInServerSigs.tag to TxSignaturesTlv.SwapInServerSigs.Companion as TlvValueReader, TxSignaturesTlv.SwapInUserPartialSigs.tag to TxSignaturesTlv.SwapInUserPartialSigs.Companion as TlvValueReader, TxSignaturesTlv.SwapInServerPartialSigs.tag to TxSignaturesTlv.SwapInServerPartialSigs.Companion as TlvValueReader, - TxSignaturesTlv.ChannelData.tag to TxSignaturesTlv.ChannelData.Companion as TlvValueReader, ) override fun read(input: Input): TxSignatures { @@ -1223,12 +1203,9 @@ data class CommitSig( val signature: ByteVector64, val htlcSignatures: List, val tlvStream: TlvStream = TlvStream.empty() -) : HtlcMessage, HasChannelId, HasEncryptedChannelData { +) : HtlcMessage, HasChannelId, UpdatesChannelData { override val type: Long get() = CommitSig.type - override val channelData: EncryptedChannelData get() = tlvStream.get()?.ecb ?: EncryptedChannelData.empty - override fun withNonEmptyChannelData(ecd: EncryptedChannelData): CommitSig = copy(tlvStream = tlvStream.addOrUpdate(CommitSigTlv.ChannelData(ecd))) - val alternativeFeerateSigs: List = tlvStream.get()?.sigs ?: listOf() val batchSize: Int = tlvStream.get()?.size ?: 1 @@ -1245,7 +1222,6 @@ data class CommitSig( @Suppress("UNCHECKED_CAST") val readers = mapOf( - CommitSigTlv.ChannelData.tag to CommitSigTlv.ChannelData.Companion as TlvValueReader, CommitSigTlv.AlternativeFeerateSigs.tag to CommitSigTlv.AlternativeFeerateSigs.Companion as TlvValueReader, CommitSigTlv.Batch.tag to CommitSigTlv.Batch.Companion as TlvValueReader, ) @@ -1268,12 +1244,9 @@ data class RevokeAndAck( val perCommitmentSecret: PrivateKey, val nextPerCommitmentPoint: PublicKey, val tlvStream: TlvStream = TlvStream.empty() -) : HtlcMessage, HasChannelId, HasEncryptedChannelData { +) : HtlcMessage, HasChannelId, UpdatesChannelData { override val type: Long get() = RevokeAndAck.type - override val channelData: EncryptedChannelData get() = tlvStream.get()?.ecb ?: EncryptedChannelData.empty - override fun withNonEmptyChannelData(ecd: EncryptedChannelData): RevokeAndAck = copy(tlvStream = tlvStream.addOrUpdate(RevokeAndAckTlv.ChannelData(ecd))) - override fun write(out: Output) { LightningCodecs.writeBytes(channelId, out) LightningCodecs.writeBytes(perCommitmentSecret.value, out) @@ -1285,7 +1258,7 @@ data class RevokeAndAck( const val type: Long = 133 @Suppress("UNCHECKED_CAST") - val readers = mapOf(RevokeAndAckTlv.ChannelData.tag to RevokeAndAckTlv.ChannelData.Companion as TlvValueReader) + val readers: Map> = mapOf() override fun read(input: Input): RevokeAndAck { return RevokeAndAck( @@ -1328,12 +1301,10 @@ data class ChannelReestablish( val yourLastCommitmentSecret: PrivateKey, val myCurrentPerCommitmentPoint: PublicKey, val tlvStream: TlvStream = TlvStream.empty() -) : HasChannelId, HasEncryptedChannelData { +) : HasChannelId { override val type: Long get() = ChannelReestablish.type val nextFundingTxId: TxId? = tlvStream.get()?.txId - override val channelData: EncryptedChannelData get() = tlvStream.get()?.ecb ?: EncryptedChannelData.empty - override fun withNonEmptyChannelData(ecd: EncryptedChannelData): ChannelReestablish = copy(tlvStream = tlvStream.addOrUpdate(ChannelReestablishTlv.ChannelData(ecd))) override fun write(out: Output) { LightningCodecs.writeBytes(channelId, out) @@ -1349,7 +1320,6 @@ data class ChannelReestablish( @Suppress("UNCHECKED_CAST") val readers = mapOf( - ChannelReestablishTlv.ChannelData.tag to ChannelReestablishTlv.ChannelData.Companion as TlvValueReader, ChannelReestablishTlv.NextFunding.tag to ChannelReestablishTlv.NextFunding.Companion as TlvValueReader, ) @@ -1545,12 +1515,9 @@ data class Shutdown( override val channelId: ByteVector32, val scriptPubKey: ByteVector, val tlvStream: TlvStream = TlvStream.empty() -) : ChannelMessage, HasChannelId, HasEncryptedChannelData, ForbiddenMessageDuringSplice { +) : ChannelMessage, HasChannelId, UpdatesChannelData, ForbiddenMessageDuringSplice { override val type: Long get() = Shutdown.type - override val channelData: EncryptedChannelData get() = tlvStream.get()?.ecb ?: EncryptedChannelData.empty - override fun withNonEmptyChannelData(ecd: EncryptedChannelData): Shutdown = copy(tlvStream = tlvStream.addOrUpdate(ShutdownTlv.ChannelData(ecd))) - override fun write(out: Output) { LightningCodecs.writeBytes(channelId, out) LightningCodecs.writeU16(scriptPubKey.size(), out) @@ -1562,7 +1529,7 @@ data class Shutdown( const val type: Long = 38 @Suppress("UNCHECKED_CAST") - val readers = mapOf(ShutdownTlv.ChannelData.tag to ShutdownTlv.ChannelData.Companion as TlvValueReader) + val readers: Map> = mapOf() override fun read(input: Input): Shutdown { return Shutdown( @@ -1579,12 +1546,9 @@ data class ClosingSigned( val feeSatoshis: Satoshi, val signature: ByteVector64, val tlvStream: TlvStream = TlvStream.empty() -) : ChannelMessage, HasChannelId, HasEncryptedChannelData { +) : ChannelMessage, HasChannelId, UpdatesChannelData { override val type: Long get() = ClosingSigned.type - override val channelData: EncryptedChannelData get() = tlvStream.get()?.ecb ?: EncryptedChannelData.empty - override fun withNonEmptyChannelData(ecd: EncryptedChannelData): ClosingSigned = copy(tlvStream = tlvStream.addOrUpdate(ClosingSignedTlv.ChannelData(ecd))) - override fun write(out: Output) { LightningCodecs.writeBytes(channelId, out) LightningCodecs.writeU64(feeSatoshis.toLong(), out) @@ -1598,7 +1562,6 @@ data class ClosingSigned( @Suppress("UNCHECKED_CAST") val readers = mapOf( ClosingSignedTlv.FeeRange.tag to ClosingSignedTlv.FeeRange.Companion as TlvValueReader, - ClosingSignedTlv.ChannelData.tag to ClosingSignedTlv.ChannelData.Companion as TlvValueReader ) override fun read(input: Input): ClosingSigned { @@ -1945,6 +1908,40 @@ data class RecommendedFeerates( } } +data class PeerStorageStore(val ecd: EncryptedChannelData) : LightningMessage { + override val type: Long get() = PeerStorageStore.type + + override fun write(out: Output) { + LightningCodecs.writeU16(ecd.data.size(), out) + LightningCodecs.writeBytes(ecd.data, out) + } + + companion object : LightningMessageReader { + const val type: Long = 7 + + override fun read(input: Input): PeerStorageStore { + return PeerStorageStore(EncryptedChannelData(LightningCodecs.bytes(input, LightningCodecs.u16(input)).toByteVector())) + } + } +} + +data class PeerStorageRetrieval(val ecd: EncryptedChannelData) : LightningMessage { + override val type: Long get() = PeerStorageRetrieval.type + + override fun write(out: Output) { + LightningCodecs.writeU16(ecd.data.size(), out) + LightningCodecs.writeBytes(ecd.data, out) + } + + companion object : LightningMessageReader { + const val type: Long = 9 + + override fun read(input: Input): PeerStorageRetrieval { + return PeerStorageRetrieval(EncryptedChannelData(LightningCodecs.bytes(input, LightningCodecs.u16(input)).toByteVector())) + } + } +} + data class UnknownMessage(override val type: Long) : LightningMessage { override fun write(out: Output) = TODO("Serialization of unknown messages is not implemented") } \ No newline at end of file diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt index 08c3e527d..a37299e0f 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ClosingTestsCommon.kt @@ -1176,7 +1176,7 @@ class ClosingTestsCommon : LightningTestSuite() { @Test fun `recv BITCOIN_TX_CONFIRMED -- future remote commit`() { - val (alice0, bob0) = reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = reachNormal() val (_, bobDisconnected) = run { // This HTLC will be fulfilled. val (nodes1, preimage, htlc) = addHtlc(25_000_000.msat, alice0, bob0) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NegotiatingTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NegotiatingTestsCommon.kt index c1226aaf8..48c064443 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NegotiatingTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NegotiatingTestsCommon.kt @@ -376,17 +376,6 @@ class NegotiatingTestsCommon : LightningTestSuite() { actions.findPublishTxs().contains(bob.commitments.latest.localCommit.publishableTxs.commitTx.tx) } - @Test - fun `recv ClosingSigned with encrypted channel data`() { - val (alice, bob, aliceCloseSig) = init() - assertTrue(alice.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupProvider)) - assertTrue(bob.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupClient)) - assertTrue(aliceCloseSig.channelData.isEmpty()) - val (_, actions1) = bob.process(ChannelCommand.MessageReceived(aliceCloseSig)) - val bobCloseSig = actions1.hasOutgoingMessage() - assertFalse(bobCloseSig.channelData.isEmpty()) - } - @Test fun `recv BITCOIN_FUNDING_SPENT -- counterparty's mutual close`() { // NB: we're not the initiator here diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt index bce65898d..94bc08559 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/NormalTestsCommon.kt @@ -724,35 +724,15 @@ class NormalTestsCommon : LightningTestSuite() { actions2.hasOutgoingMessage() } - @Test - fun `recv ChannelCommand_Sign -- channel backup + non-initiator`() { - val (alice, bob) = reachNormal() - assertTrue(alice.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupProvider)) - assertTrue(bob.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupClient)) - val (_, cmdAdd) = makeCmdAdd(50_000_000.msat, alice.staticParams.nodeParams.nodeId, alice.currentBlockHeight.toLong()) - val (bob1, actions) = bob.process(cmdAdd) - val add = actions.findOutgoingMessage() - val (alice1, _) = alice.process(ChannelCommand.MessageReceived(add)) - assertIs>(alice1) - assertTrue { alice1.state.commitments.changes.remoteChanges.proposed.contains(add) } - val (bob2, actions2) = bob1.process(ChannelCommand.Commitment.Sign) - val commitSig = actions2.findOutgoingMessage() - assertIs>(bob2) - val blob = EncryptedChannelData.from(bob.staticParams.nodeParams.nodePrivateKey, bob2.state) - assertEquals(blob, commitSig.channelData) - } - @Test fun `recv CommitSig -- one htlc received`() { - val (alice0, bob0) = reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = reachNormal() val (nodes0, _, htlc) = addHtlc(50_000_000.msat, alice0, bob0) val (alice1, bob1) = nodes0 assertIs>(bob1) val (_, bob2) = signAndRevack(alice1, bob1) - val (bob3, actions3) = bob2.process(ChannelCommand.Commitment.Sign) - val commitSig = actions3.findOutgoingMessage() - assertTrue(commitSig.channelData.isEmpty()) + val (bob3, _) = bob2.process(ChannelCommand.Commitment.Sign) assertIs>(bob3) assertTrue(bob3.commitments.latest.localCommit.spec.htlcs.incomings().any { it.id == htlc.id }) assertEquals(1, bob3.commitments.latest.localCommit.publishableTxs.htlcTxsAndSigs.size) @@ -986,34 +966,9 @@ class NormalTestsCommon : LightningTestSuite() { } } - @Test - fun `recv RevokeAndAck -- channel backup + non-initiator`() { - val (alice, bob) = reachNormal() - assertTrue(alice.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupProvider)) - assertTrue(bob.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupClient)) - val (_, cmdAdd) = makeCmdAdd(50_000_000.msat, alice.staticParams.nodeParams.nodeId, alice.currentBlockHeight.toLong()) - val (bob1, actions) = bob.process(cmdAdd) - val add = actions.findOutgoingMessage() - val (alice1, _) = alice.process(ChannelCommand.MessageReceived(add)) - assertIs>(alice1) - assertTrue(alice1.commitments.changes.remoteChanges.proposed.contains(add)) - val (bob2, actions2) = bob1.process(ChannelCommand.Commitment.Sign) - val commitSig = actions2.findOutgoingMessage() - val (alice2, actions3) = alice1.process(ChannelCommand.MessageReceived(commitSig)) - val revack = actions3.findOutgoingMessage() - val (bob3, _) = bob2.process(ChannelCommand.MessageReceived(revack)) - val (_, actions4) = alice2.process(ChannelCommand.Commitment.Sign) - val commitSig1 = actions4.findOutgoingMessage() - val (bob4, actions5) = bob3.process(ChannelCommand.MessageReceived(commitSig1)) - val revack1 = actions5.findOutgoingMessage() - assertIs>(bob4) - val blob = EncryptedChannelData.from(bob4.staticParams.nodeParams.nodePrivateKey, bob4.state) - assertEquals(blob, revack1.channelData) - } - @Test fun `recv RevokeAndAck -- one htlc sent`() { - val (alice0, bob0) = reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = reachNormal() val (alice1, bob1) = addHtlc(50_000_000.msat, alice0, bob0).first val (alice2, actionsAlice2) = alice1.process(ChannelCommand.Commitment.Sign) @@ -1022,7 +977,6 @@ class NormalTestsCommon : LightningTestSuite() { val commitSig = actionsAlice2.findOutgoingMessage() val (_, actionsBob2) = bob1.process(ChannelCommand.MessageReceived(commitSig)) val revokeAndAck = actionsBob2.findOutgoingMessage() - assertTrue(revokeAndAck.channelData.isEmpty()) val (alice3, _) = alice2.process(ChannelCommand.MessageReceived(revokeAndAck)) assertIs>(alice3) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/OfflineTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/OfflineTestsCommon.kt index 9761b524c..6e61a3bdc 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/OfflineTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/OfflineTestsCommon.kt @@ -22,7 +22,6 @@ class OfflineTestsCommon : LightningTestSuite() { val (alice, aliceCommitSig, bob, _) = WaitForFundingSignedTestsCommon.init( ChannelType.SupportedChannelType.AnchorOutputsZeroReserve, zeroConf = true, - bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient).initFeatures() ) val (bob1, actionsBob1) = bob.process(ChannelCommand.MessageReceived(aliceCommitSig)) assertIs(bob1.state) @@ -50,7 +49,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `handle disconnect - connect events -- no messages sent yet`() { - val (alice, bob) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient).initFeatures()) + val (alice, bob) = TestsHelper.reachNormal() val (alice1, bob1) = disconnect(alice, bob) val localInit = Init(alice.commitments.params.localParams.features.initFeatures()) @@ -92,7 +91,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `re-send update and sig after first commitment`() { val (alice0, bob0) = run { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() val cmdAdd = ChannelCommand.Htlc.Add(1_000_000.msat, ByteVector32.Zeroes, CltvExpiryDelta(144).toCltvExpiry(alice0.currentBlockHeight.toLong()), TestConstants.emptyOnionPacket, UUID.randomUUID()) val (alice1, actions1) = alice0.process(cmdAdd) val add = actions1.hasOutgoingMessage() @@ -160,7 +159,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `re-send lost revocation`() { val (alice0, bob0) = run { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() val cmdAdd = ChannelCommand.Htlc.Add(1_000_000.msat, ByteVector32.Zeroes, CltvExpiryDelta(144).toCltvExpiry(alice0.currentBlockHeight.toLong()), TestConstants.emptyOnionPacket, UUID.randomUUID()) val (alice1, actionsAlice1) = alice0.process(cmdAdd) val add = actionsAlice1.hasOutgoingMessage() @@ -224,7 +223,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `resume htlc settlement`() { val (alice0, bob0, revB) = run { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() val (nodes1, r1, htlc1) = TestsHelper.addHtlc(15_000_000.msat, bob0, alice0) val (bob1, alice1) = TestsHelper.crossSign(nodes1.first, nodes1.second) val (bob2, alice2) = TestsHelper.fulfillHtlc(htlc1.id, r1, bob1, alice1) @@ -283,7 +282,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `discover that we have a revoked commitment`() { val (alice, aliceOld, bob) = run { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() val (nodes1, r1, htlc1) = TestsHelper.addHtlc(250_000_000.msat, alice0, bob0) val (alice1, bob1) = TestsHelper.crossSign(nodes1.first, nodes1.second) val (nodes2, r2, htlc2) = TestsHelper.addHtlc(100_000_000.msat, alice1, bob1) @@ -349,7 +348,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `counterparty lies about having a more recent commitment and publishes current commitment`() { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() // The current state contains a pending htlc. val (alice1, bob1) = run { val (aliceTmp, bobTmp) = TestsHelper.addHtlc(250_000_000.msat, alice0, bob0).first @@ -401,7 +400,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `counterparty lies about having a more recent commitment and publishes revoked commitment`() { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() // We sign a new commitment to make sure the first one is revoked. val bobRevokedCommitTx = bob0.commitments.latest.localCommit.publishableTxs.commitTx.tx val (alice1, bob1) = run { @@ -455,7 +454,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `reprocess pending incoming htlcs after disconnection or wallet restart`() { val (alice, bob, htlcs) = run { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() val (aliceId, bobId) = Pair(alice0.staticParams.nodeParams.nodeId, bob0.staticParams.nodeParams.nodeId) val currentBlockHeight = alice0.currentBlockHeight.toLong() // We add some htlcs Alice ---> Bob @@ -512,7 +511,7 @@ class OfflineTestsCommon : LightningTestSuite() { @Test fun `reprocess pending incoming htlcs after disconnection or wallet restart -- htlc settlement signed by us`() { val (alice, bob, htlcs) = run { - val (alice0, bob0) = TestsHelper.reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = TestsHelper.reachNormal() val (aliceId, bobId) = Pair(alice0.staticParams.nodeParams.nodeId, bob0.staticParams.nodeParams.nodeId) val currentBlockHeight = alice0.currentBlockHeight.toLong() val preimage = randomBytes32() @@ -555,23 +554,6 @@ class OfflineTestsCommon : LightningTestSuite() { assertEquals(listOf(ChannelAction.ProcessIncomingHtlc(htlcs[2])), actionsBob.filterIsInstance()) } - @Test - fun `wait for their channel reestablish when using channel backup`() { - val (alice, bob) = TestsHelper.reachNormal() - assertTrue(bob.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupClient)) - val (alice1, bob1) = disconnect(alice, bob) - val localInit = Init(alice.commitments.params.localParams.features) - val remoteInit = Init(bob.commitments.params.localParams.features) - - val (alice2, actions) = alice1.process(ChannelCommand.Connected(localInit, remoteInit)) - assertIs(alice2.state) - actions.findOutgoingMessage() - val (bob2, actions1) = bob1.process(ChannelCommand.Connected(remoteInit, localInit)) - assertIs(bob2.state) - // Bob waits to receive Alice's channel reestablish before sending his own. - assertTrue(actions1.isEmpty()) - } - @Test fun `republish unconfirmed funding tx after restart`() { val (alice, bob, fundingTx) = WaitForFundingConfirmedTestsCommon.init(ChannelType.SupportedChannelType.AnchorOutputs) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ShutdownTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ShutdownTestsCommon.kt index 661444daf..1a1fd9f8d 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ShutdownTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/ShutdownTestsCommon.kt @@ -355,18 +355,6 @@ class ShutdownTestsCommon : LightningTestSuite() { actions1.hasOutgoingMessage() } - @Test - fun `recv Shutdown with encrypted channel data`() { - val (_, bob0) = reachNormal() - assertTrue(bob0.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupClient)) - assertFalse(bob0.commitments.params.channelFeatures.hasFeature(Feature.ChannelBackupClient)) // this isn't a permanent channel feature - val (bob1, actions1) = bob0.process(ChannelCommand.Close.MutualClose(null, null)) - assertIs>(bob1) - val blob = EncryptedChannelData.from(bob1.staticParams.nodeParams.nodePrivateKey, bob1.state) - val shutdown = actions1.findOutgoingMessage() - assertEquals(blob, shutdown.channelData) - } - @Test fun `recv Shutdown with non-initiator paying commit fees`() { val (alice, bob) = reachNormal(requestRemoteFunding = TestConstants.bobFundingAmount) @@ -549,7 +537,7 @@ class ShutdownTestsCommon : LightningTestSuite() { @Test fun `basic disconnection and reconnection`() { - val (alice0, bob0) = init(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice0, bob0) = init() val (alice1, bob1, reestablishes) = SyncingTestsCommon.disconnect(alice0, bob0) val (aliceReestablish, bobReestablish) = reestablishes val (alice2, actionsAlice2) = alice1.process(ChannelCommand.MessageReceived(bobReestablish)) @@ -600,8 +588,6 @@ class ShutdownTestsCommon : LightningTestSuite() { assertIs>(bob1) assertIs(alice2.state) assertIs(bob1.state) - if (alice2.state.commitments.params.channelFeatures.hasFeature(Feature.ChannelBackupClient)) assertFalse(shutdown.channelData.isEmpty()) - if (bob1.state.commitments.params.channelFeatures.hasFeature(Feature.ChannelBackupClient)) assertFalse(shutdown1.channelData.isEmpty()) return Pair(alice2, bob1) } } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt index e69527e5e..2734587dc 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SyncingTestsCommon.kt @@ -350,7 +350,7 @@ class SyncingTestsCommon : LightningTestSuite() { companion object { fun init(): Pair, LNChannel> { // NB: we disable channel backups to ensure Bob sends his channel_reestablish on reconnection. - val (alice, bob, _) = reachNormal(bobFeatures = TestConstants.Bob.nodeParams.features.remove(Feature.ChannelBackupClient)) + val (alice, bob, _) = reachNormal() return Pair(alice, bob) } @@ -390,7 +390,6 @@ class SyncingTestsCommon : LightningTestSuite() { val aliceInit = Init(alice1.commitments.params.localParams.features) val bobInit = Init(bob1.commitments.params.localParams.features) - assertFalse(bob1.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupClient)) val (alice2, actionsAlice2) = alice1.process(ChannelCommand.Connected(aliceInit, bobInit)) assertIs>(alice2) @@ -416,13 +415,11 @@ class SyncingTestsCommon : LightningTestSuite() { is ChannelStateWithCommitments -> alice.state.commitments.params.localParams.features } val aliceInit = Init(aliceFeatures) - assertTrue(aliceFeatures.hasFeature(Feature.ChannelBackupProvider)) val bobFeatures = when (bob.state) { is WaitForFundingSigned -> bob.state.channelParams.localParams.features is ChannelStateWithCommitments -> bob.state.commitments.params.localParams.features } val bobInit = Init(bobFeatures) - assertTrue(bobFeatures.hasFeature(Feature.ChannelBackupClient)) val (alice2, actionsAlice2) = alice1.process(ChannelCommand.Connected(aliceInit, bobInit)) assertIs>(alice2) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt index 51c66cc51..d7cbf64ac 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt @@ -402,9 +402,6 @@ class WaitForFundingConfirmedTestsCommon : LightningTestSuite() { assertIs(bob1.state) assertEquals(actionsBob1.findWatch().event, BITCOIN_FUNDING_DEPTHOK) val txSigsBob = actionsBob1.findOutgoingMessage() - if (bob.staticParams.nodeParams.features.hasFeature(Feature.ChannelBackupClient)) { - assertFalse(txSigsBob.channelData.isEmpty()) - } val (alice2, actionsAlice2) = alice1.process(ChannelCommand.MessageReceived(txSigsBob)) assertIs>(alice2) val fundingTxAlice = alice2.state.latestFundingTx.signedTx @@ -495,14 +492,10 @@ class WaitForFundingConfirmedTestsCommon : LightningTestSuite() { actionsBob3.has() val watchBob = actionsBob3.findWatch() val txSigsBob = actionsBob3.findOutgoingMessage() - if (bob.staticParams.nodeParams.features.hasFeature(Feature.ChannelBackupClient)) { - assertFalse(txSigsBob.channelData.isEmpty()) - } val (alice3, actionsAlice3) = alice2.process(ChannelCommand.MessageReceived(txSigsBob)) assertIs>(alice3) assertEquals(actionsAlice3.size, 4) val txSigsAlice = actionsAlice3.hasOutgoingMessage() - assertTrue(txSigsAlice.channelData.isEmpty()) val watchAlice = actionsAlice3.findWatch() actionsAlice3.has() val fundingTxAlice = actionsAlice3.find().tx diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt index f0e069a46..ce178e8d2 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt @@ -55,9 +55,7 @@ class WaitForFundingCreatedTestsCommon : LightningTestSuite() { val commitSigBob = actionsBob3.findOutgoingMessage() assertEquals(commitSigAlice.channelId, commitSigBob.channelId) assertTrue(commitSigAlice.htlcSignatures.isEmpty()) - assertTrue(commitSigAlice.channelData.isEmpty()) assertTrue(commitSigBob.htlcSignatures.isEmpty()) - assertFalse(commitSigBob.channelData.isEmpty()) actionsAlice2.has() actionsBob3.has() assertIs(alice2.state) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt index c8020305b..9143a83c5 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt @@ -34,7 +34,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { bob.process(ChannelCommand.MessageReceived(commitSigAlice)).also { (state, actions) -> assertIs(state.state) assertEquals(actions.size, 5) - actions.hasOutgoingMessage().also { assertFalse(it.channelData.isEmpty()) } + actions.hasOutgoingMessage() actions.findWatch().also { assertEquals(WatchConfirmed(state.channelId, commitInput.outPoint.txid, commitInput.txOut.publicKeyScript, 3, BITCOIN_FUNDING_DEPTHOK), it) } actions.find().also { assertEquals(TestConstants.bobFundingAmount.toMilliSatoshi(), it.amountReceived) } actions.has() @@ -56,7 +56,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { bob.process(ChannelCommand.MessageReceived(commitSigAlice)).also { (state, actions) -> assertIs(state.state) assertEquals(actions.size, 6) - actions.hasOutgoingMessage().also { assertFalse(it.channelData.isEmpty()) } + actions.hasOutgoingMessage() actions.hasOutgoingMessage().also { assertEquals(ShortChannelId.peerId(bob.staticParams.nodeParams.nodeId), it.alias) } actions.findWatch().also { assertEquals(state.commitments.latest.fundingTxId, it.txId) } actions.find().also { assertEquals(TestConstants.bobFundingAmount.toMilliSatoshi(), it.amountReceived) } @@ -85,7 +85,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { assertEquals(actions.size, 5) assertEquals(TestConstants.bobFundingAmount + purchase.fees.total, state.commitments.latest.localCommit.spec.toLocal.truncateToSatoshi()) assertEquals(TestConstants.aliceFundingAmount - purchase.fees.total, state.commitments.latest.localCommit.spec.toRemote.truncateToSatoshi()) - actions.hasOutgoingMessage().also { assertFalse(it.channelData.isEmpty()) } + actions.hasOutgoingMessage() actions.findWatch().also { assertEquals(BITCOIN_FUNDING_DEPTHOK, it.event) } actions.find().also { assertEquals((TestConstants.bobFundingAmount + purchase.fees.total).toMilliSatoshi(), it.amountReceived) } actions.has() @@ -148,7 +148,6 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { val (alice2, actionsAlice2) = alice1.process(ChannelCommand.MessageReceived(txSigsBob)) assertIs(alice2.state) assertEquals(6, actionsAlice2.size) - assertTrue(actionsAlice2.hasOutgoingMessage().channelData.isEmpty()) actionsAlice2.has() val watchConfirmedAlice = actionsAlice2.findWatch() assertEquals(WatchConfirmed(alice2.channelId, commitInput.outPoint.txid, commitInput.txOut.publicKeyScript, 3, BITCOIN_FUNDING_DEPTHOK), watchConfirmedAlice) @@ -175,7 +174,6 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { val (alice2, actionsAlice2) = alice1.process(ChannelCommand.MessageReceived(txSigsBob)) assertIs(alice2.state) assertEquals(8, actionsAlice2.size) - assertTrue(actionsAlice2.hasOutgoingMessage().channelData.isEmpty()) actionsAlice2.has() val watchConfirmedAlice = actionsAlice2.findWatch() assertEquals(WatchConfirmed(alice2.channelId, commitInput.outPoint.txid, commitInput.txOut.publicKeyScript, 3, BITCOIN_FUNDING_DEPTHOK), watchConfirmedAlice) @@ -204,7 +202,6 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { val (alice2, actionsAlice2) = alice1.process(ChannelCommand.MessageReceived(txSigsBob)) assertIs(alice2.state) assertEquals(7, actionsAlice2.size) - assertTrue(actionsAlice2.hasOutgoingMessage().channelData.isEmpty()) assertEquals(actionsAlice2.hasOutgoingMessage().alias, ShortChannelId.peerId(alice.staticParams.nodeParams.nodeId)) assertEquals(actionsAlice2.findWatch().txId, alice2.commitments.latest.fundingTxId) actionsAlice2.has() @@ -352,15 +349,11 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { assertIs>(alice2) assertIs(alice2.state) val commitSigAlice = actionsAlice2.findOutgoingMessage() - assertTrue(commitSigAlice.channelData.isEmpty()) actionsAlice2.has() val (bob3, actionsBob3) = bob2.process(ChannelCommand.MessageReceived(actionsAlice2.findOutgoingMessage())) assertIs>(bob3) assertIs(bob3.state) val commitSigBob = actionsBob3.findOutgoingMessage() - if (bob.staticParams.nodeParams.features.hasFeature(Feature.ChannelBackupClient)) { - assertFalse(commitSigBob.channelData.isEmpty()) - } actionsBob3.has() return Fixture(alice2, commitSigAlice, bob3, commitSigBob, walletAlice) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/io/peer/PeerTest.kt b/src/commonTest/kotlin/fr/acinq/lightning/io/peer/PeerTest.kt index 5bcba2e0d..b2951f9a5 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/io/peer/PeerTest.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/io/peer/PeerTest.kt @@ -1,6 +1,7 @@ package fr.acinq.lightning.io.peer import fr.acinq.bitcoin.Block +import fr.acinq.bitcoin.ByteVector import fr.acinq.bitcoin.ByteVector32 import fr.acinq.bitcoin.PrivateKey import fr.acinq.bitcoin.utils.Either @@ -305,7 +306,7 @@ class PeerTest : LightningTestSuite() { nextRemoteRevocationNumber = commitments.remoteCommitIndex, yourLastCommitmentSecret = PrivateKey(yourLastPerCommitmentSecret), myCurrentPerCommitmentPoint = myCurrentPerCommitmentPoint - ).withChannelData(commitments.remoteChannelData) + ) peer.send(MessageReceived(connectionId = 0, channelReestablish)) @@ -348,8 +349,8 @@ class PeerTest : LightningTestSuite() { // Simulate a reconnection with Alice. peer.send(MessageReceived(connectionId = 0, Init(features = alice0.staticParams.nodeParams.features))) + peer.send(MessageReceived(connectionId = 0, PeerStorageRetrieval(EncryptedChannelData(ByteVector.empty)))) val aliceReestablish = alice1.state.run { alice1.ctx.createChannelReestablish() } - assertFalse(aliceReestablish.channelData.isEmpty()) peer.send(MessageReceived(connectionId = 0, aliceReestablish)) // Wait until the channels are Syncing @@ -377,8 +378,8 @@ class PeerTest : LightningTestSuite() { // Simulate a reconnection with Alice. peer.send(MessageReceived(connectionId = 0, Init(features = alice0.staticParams.nodeParams.features))) + peer.send(MessageReceived(connectionId = 0, PeerStorageRetrieval(EncryptedChannelData(ByteVector.empty)))) val aliceReestablish = alice1.state.run { alice1.ctx.createChannelReestablish() } - assertFalse(aliceReestablish.channelData.isEmpty()) peer.send(MessageReceived(connectionId = 0, aliceReestablish)) // Wait until the channels are Syncing diff --git a/src/commonTest/kotlin/fr/acinq/lightning/serialization/StateSerializationTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/serialization/StateSerializationTestsCommon.kt index 5742b35eb..2682faef6 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/serialization/StateSerializationTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/serialization/StateSerializationTestsCommon.kt @@ -88,39 +88,6 @@ class StateSerializationTestsCommon : LightningTestSuite() { assertIs(res) } - @Test - fun `maximum number of HTLCs that is safe to use`() { - val (alice, bob) = TestsHelper.reachNormal() - assertTrue(bob.commitments.params.localParams.features.hasFeature(Feature.ChannelBackupClient)) - - tailrec fun addHtlcs(sender: LNChannel, receiver: LNChannel, amount: MilliSatoshi, count: Int): Pair, LNChannel> = if (count == 0) Pair(sender, receiver) else { - val (p, _) = TestsHelper.addHtlc(amount, sender, receiver) - val (alice1, bob1) = p - assertIs>(alice1) - assertIs>(bob1) - addHtlcs(alice1, bob1, amount, count - 1) - } - - fun commitSigSize(maxIncoming: Int, maxOutgoing: Int): Int { - val (alice1, bob1) = addHtlcs(alice, bob, MilliSatoshi(6000_000), maxOutgoing) - val (bob2, alice2) = addHtlcs(bob1, alice1, MilliSatoshi(6000_000), maxIncoming) - val (alice3, bob3) = crossSign(alice2, bob2) - - assertIs>(alice3) - assertIs>(bob3) - val (_, commitSig0, _, commitSig1) = SpliceTestsCommon.spliceInAndOutWithoutSigs(alice3, bob3, listOf(50_000.sat), 50_000.sat) - assertFalse(commitSig1.channelData.isEmpty()) - - val bina = LightningMessage.encode(commitSig0) - val binb = LightningMessage.encode(commitSig1) - return max(bina.size, binb.size) - } - - // with 5 incoming payments and 5 outgoing payments, we can still add our encrypted backup to commig_sig messages - // and stay below the 65k limit for a future channel_reestablish message of unknown size - assertTrue(commitSigSize(5, 5) < 60_000) - } - @Test fun `liquidity ads lease backwards compatibility`() { run { diff --git a/src/commonTest/kotlin/fr/acinq/lightning/tests/TestConstants.kt b/src/commonTest/kotlin/fr/acinq/lightning/tests/TestConstants.kt index 52aef868e..a3a5e82d9 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/tests/TestConstants.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/tests/TestConstants.kt @@ -80,7 +80,6 @@ object TestConstants { Feature.PaymentMetadata to FeatureSupport.Optional, Feature.ExperimentalTrampolinePayment to FeatureSupport.Optional, Feature.WakeUpNotificationProvider to FeatureSupport.Optional, - Feature.ChannelBackupProvider to FeatureSupport.Optional, Feature.ExperimentalSplice to FeatureSupport.Optional, Feature.OnTheFlyFunding to FeatureSupport.Optional, ), diff --git a/src/commonTest/kotlin/fr/acinq/lightning/tests/io/peer/builders.kt b/src/commonTest/kotlin/fr/acinq/lightning/tests/io/peer/builders.kt index 4b5274a7e..e0e972335 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/tests/io/peer/builders.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/tests/io/peer/builders.kt @@ -164,7 +164,7 @@ suspend fun CoroutineScope.newPeer( nextRemoteRevocationNumber = state.commitments.remoteCommitIndex, yourLastCommitmentSecret = PrivateKey(yourLastPerCommitmentSecret), myCurrentPerCommitmentPoint = myCurrentPerCommitmentPoint - ).withChannelData(state.commitments.remoteChannelData) + ) peer.send(MessageReceived(connection.id, channelReestablish)) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt index 45ba39bf2..9696b33bf 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt @@ -429,13 +429,9 @@ class LightningCodecsTestsCommon : LightningTestSuite() { CommitSigTlv.AlternativeFeerateSig(FeeratePerKw(500.sat), ByteVector64.fromValidHex("2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db252a2f914ea1fcbd580b80cdea60226f63288cd44bd84a8850c9189a24f08c7cc5")), CommitSigTlv.AlternativeFeerateSig(FeeratePerKw(750.sat), ByteVector64.fromValidHex("83a7a1a04141ac8ab2818f4a872ea86716ef9aac0852146bcdbc2cc49aecc985899a63513f41ed2502a321a4945689239d12bdab778c1a2e8bf7c3f19ec53b58")), ) - val backup = EncryptedChannelData(ByteVector.fromHex("fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c303a6680e79e30f050d4f32f1fb9d046cc6efb5ed4cc99eeedba6b2e89cbf838691")) val testCases = listOf( // @formatter:off - CommitSig(channelId, signature, listOf(), TlvStream(CommitSigTlv.ChannelData(backup))) to "00842dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db2505e06d9a8fdfbb3625051ff2e3cdf82679cc2268beee6905941d6dd8a067cd62711e04b119a836aa0eebe07545172cefb228860fea6c797178453a319169bed70000fe4701000041fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c303a6680e79e30f050d4f32f1fb9d046cc6efb5ed4cc99eeedba6b2e89cbf838691", - CommitSig(channelId, signature, listOf(), TlvStream(CommitSigTlv.ChannelData(backup), CommitSigTlv.AlternativeFeerateSigs(listOf()))) to "00842dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db2505e06d9a8fdfbb3625051ff2e3cdf82679cc2268beee6905941d6dd8a067cd62711e04b119a836aa0eebe07545172cefb228860fea6c797178453a319169bed70000fe4701000041fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c303a6680e79e30f050d4f32f1fb9d046cc6efb5ed4cc99eeedba6b2e89cbf838691fe470100010100", CommitSig(channelId, signature, listOf(), TlvStream(CommitSigTlv.AlternativeFeerateSigs(alternateSigs))) to "00842dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db2505e06d9a8fdfbb3625051ff2e3cdf82679cc2268beee6905941d6dd8a067cd62711e04b119a836aa0eebe07545172cefb228860fea6c797178453a319169bed70000fe47010001cd03000000fdc49269a9baa73a5ec44b63bdcaabf9c7c6477f72866b822f8502e5c989aa3562fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c3000001f42dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db252a2f914ea1fcbd580b80cdea60226f63288cd44bd84a8850c9189a24f08c7cc5000002ee83a7a1a04141ac8ab2818f4a872ea86716ef9aac0852146bcdbc2cc49aecc985899a63513f41ed2502a321a4945689239d12bdab778c1a2e8bf7c3f19ec53b58", - CommitSig(channelId, signature, listOf(), TlvStream(CommitSigTlv.ChannelData(backup), CommitSigTlv.AlternativeFeerateSigs(alternateSigs))) to "00842dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db2505e06d9a8fdfbb3625051ff2e3cdf82679cc2268beee6905941d6dd8a067cd62711e04b119a836aa0eebe07545172cefb228860fea6c797178453a319169bed70000fe4701000041fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c303a6680e79e30f050d4f32f1fb9d046cc6efb5ed4cc99eeedba6b2e89cbf838691fe47010001cd03000000fdc49269a9baa73a5ec44b63bdcaabf9c7c6477f72866b822f8502e5c989aa3562fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c3000001f42dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db252a2f914ea1fcbd580b80cdea60226f63288cd44bd84a8850c9189a24f08c7cc5000002ee83a7a1a04141ac8ab2818f4a872ea86716ef9aac0852146bcdbc2cc49aecc985899a63513f41ed2502a321a4945689239d12bdab778c1a2e8bf7c3f19ec53b58", // @formatter:on ) testCases.forEach { (commitSig, bin) -> @@ -744,43 +740,22 @@ class LightningCodecsTestsCommon : LightningTestSuite() { // channel_reestablish Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point), Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("01 02 0102") to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(setOf(), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("fe47010000 00") to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(ChannelReestablishTlv.ChannelData(EncryptedChannelData.empty))), - Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("01 02 0102") + Hex.decode("fe47010000 00") to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(setOf(ChannelReestablishTlv.ChannelData(EncryptedChannelData(ByteVector.empty))), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("fe47010000 07 bbbbbbbbbbbbbb") to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point).withChannelData(ByteVector("bbbbbbbbbbbbbb")), - Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("01 02 0102") + Hex.decode("fe47010000 07 bbbbbbbbbbbbbb") to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream(setOf(ChannelReestablishTlv.ChannelData(EncryptedChannelData(ByteVector("bbbbbbbbbbbbbb")))), setOf(GenericTlv(1, ByteVector("0102"))))), // tx_signatures Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000") to TxSignatures(channelId, TxId(txHash), listOf()), - Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000 fe47010000 00") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(TxSignaturesTlv.ChannelData(EncryptedChannelData.empty))), - Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000 fe47010000 04 deadbeef") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(TxSignaturesTlv.ChannelData(EncryptedChannelData(ByteVector("deadbeef"))))), - Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000 2b012a fe47010000 04 deadbeef") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(setOf(TxSignaturesTlv.ChannelData(EncryptedChannelData(ByteVector("deadbeef")))), setOf(GenericTlv(43, ByteVector("2a"))))), + Hex.decode("0047") + channelId.toByteArray() + txHash.value.toByteArray() + Hex.decode("0000 2b012a") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(setOf(), setOf(GenericTlv(43, ByteVector("2a"))))), // commit_sig Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000") to CommitSig(channelId, signature, listOf()), Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000") + Hex.decode("01 02 0102") to CommitSig(channelId, signature, listOf(), TlvStream(setOf(), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000 fe47010000 00") to CommitSig(channelId, signature, listOf(), TlvStream(CommitSigTlv.ChannelData(EncryptedChannelData.empty))), - Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000 01020102 fe47010000 00") to CommitSig(channelId, signature, listOf(), TlvStream(setOf(CommitSigTlv.ChannelData(EncryptedChannelData.empty)), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000 fe47010000 07 cccccccccccccc") to CommitSig(channelId, signature, listOf()).withChannelData(ByteVector("cccccccccccccc")), - Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000 01020102 fe47010000 07 cccccccccccccc") to CommitSig(channelId, signature, listOf(), TlvStream(setOf(CommitSigTlv.ChannelData(EncryptedChannelData(ByteVector("cccccccccccccc")))), setOf(GenericTlv(1, ByteVector("0102"))))), + Hex.decode("0084") + channelId.toByteArray() + signature.toByteArray() + Hex.decode("0000 01020102") to CommitSig(channelId, signature, listOf(), TlvStream(setOf(), setOf(GenericTlv(1, ByteVector("0102"))))), // revoke_and_ack Hex.decode("0085") + channelId.toByteArray() + key.value.toByteArray() + point.value.toByteArray() to RevokeAndAck(channelId, key, point), Hex.decode("0085") + channelId.toByteArray() + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("01 02 0102") to RevokeAndAck(channelId, key, point, TlvStream(setOf(), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0085") + channelId.toByteArray() + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("fe47010000 00") to RevokeAndAck(channelId, key, point, TlvStream(RevokeAndAckTlv.ChannelData(EncryptedChannelData.empty))), - Hex.decode("0085") + channelId.toByteArray() + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("01 02 0102") + Hex.decode("fe47010000 00") to RevokeAndAck(channelId, key, point, TlvStream(setOf(RevokeAndAckTlv.ChannelData(EncryptedChannelData.empty)), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0085") + channelId.toByteArray() + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("fe47010000 07 cccccccccccccc") to RevokeAndAck(channelId, key, point).withChannelData(ByteVector("cccccccccccccc")), - Hex.decode("0085") + channelId.toByteArray() + key.value.toByteArray() + point.value.toByteArray() + Hex.decode("01 02 0102") + Hex.decode("fe47010000 07 cccccccccccccc") to RevokeAndAck(channelId, key, point, TlvStream(setOf(RevokeAndAckTlv.ChannelData(EncryptedChannelData(ByteVector("cccccccccccccc")))), setOf(GenericTlv(1, ByteVector("0102"))))), // shutdown Hex.decode("0026") + channelId.toByteArray() + Hex.decode("002a") + randomData to Shutdown(channelId, randomData.toByteVector()), Hex.decode("0026") + channelId.toByteArray() + Hex.decode("002a") + randomData + Hex.decode("01 02 0102") to Shutdown(channelId, randomData.toByteVector(), TlvStream(setOf(), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0026") + channelId.toByteArray() + Hex.decode("002a") + randomData + Hex.decode("fe47010000 00") to Shutdown(channelId, randomData.toByteVector(), TlvStream(ShutdownTlv.ChannelData(EncryptedChannelData.empty))), - Hex.decode("0026") + channelId.toByteArray() + Hex.decode("002a") + randomData + Hex.decode("01 02 0102") + Hex.decode("fe47010000 00") to Shutdown(channelId, randomData.toByteVector(), TlvStream(setOf(ShutdownTlv.ChannelData(EncryptedChannelData.empty)), setOf(GenericTlv(1, ByteVector("0102"))))), - Hex.decode("0026") + channelId.toByteArray() + Hex.decode("002a") + randomData + Hex.decode("fe47010000 07 cccccccccccccc") to Shutdown(channelId, randomData.toByteVector()).withChannelData(ByteVector("cccccccccccccc")), - Hex.decode("0026") + channelId.toByteArray() + Hex.decode("002a") + randomData + Hex.decode("01 02 0102") + Hex.decode("fe47010000 07 cccccccccccccc") to Shutdown(channelId, randomData.toByteVector(), TlvStream(setOf(ShutdownTlv.ChannelData(EncryptedChannelData(ByteVector("cccccccccccccc")))), setOf(GenericTlv(1, ByteVector("0102"))))), // closing_signed Hex.decode("0027") + channelId.toByteArray() + Hex.decode("00000000075bcd15") + signature.toByteArray() to ClosingSigned(channelId, 123456789.sat, signature), Hex.decode("0027") + channelId.toByteArray() + Hex.decode("00000000075bcd15") + signature.toByteArray() + Hex.decode("03 02 0102") to ClosingSigned(channelId, 123456789.sat, signature, TlvStream(setOf(), setOf(GenericTlv(3, ByteVector("0102"))))), - Hex.decode("0027") + channelId.toByteArray() + Hex.decode("00000000075bcd15") + signature.toByteArray() + Hex.decode("fe47010000 00") to ClosingSigned(channelId, 123456789.sat, signature, TlvStream(ClosingSignedTlv.ChannelData(EncryptedChannelData.empty))), - Hex.decode("0027") + channelId.toByteArray() + Hex.decode("00000000075bcd15") + signature.toByteArray() + Hex.decode("03 02 0102") + Hex.decode("fe47010000 00") to ClosingSigned(channelId, 123456789.sat, signature, TlvStream(setOf(ClosingSignedTlv.ChannelData(EncryptedChannelData.empty)), setOf(GenericTlv(3, ByteVector("0102"))))), - Hex.decode("0027") + channelId.toByteArray() + Hex.decode("00000000075bcd15") + signature.toByteArray() + Hex.decode("fe47010000 07 cccccccccccccc") to ClosingSigned(channelId, 123456789.sat, signature).withChannelData(ByteVector("cccccccccccccc")), - Hex.decode("0027") + channelId.toByteArray() + Hex.decode("00000000075bcd15") + signature.toByteArray() + Hex.decode("03 02 0102") + Hex.decode("fe47010000 07 cccccccccccccc") to ClosingSigned(channelId, 123456789.sat, signature, TlvStream(setOf(ClosingSignedTlv.ChannelData(EncryptedChannelData(ByteVector("cccccccccccccc")))), setOf(GenericTlv(3, ByteVector("0102"))))) ) // @formatter:on @@ -792,34 +767,6 @@ class LightningCodecsTestsCommon : LightningTestSuite() { } } - @Test - fun `skip backup channel data when too large`() { - // We omit the channel backup when it risks overflowing the lightning message. - val belowLimit = EncryptedChannelData(ByteVector(ByteArray(59500) { 42 })) - val aboveLimit = EncryptedChannelData(ByteVector(ByteArray(60000) { 42 })) - val messages = listOf( - ChannelReestablish(randomBytes32(), 0, 0, randomKey(), randomKey().publicKey()), - TxSignatures(randomBytes32(), TxId(randomBytes32()), listOf()), - CommitSig(randomBytes32(), randomBytes64(), listOf()), - RevokeAndAck(randomBytes32(), randomKey(), randomKey().publicKey()), - Shutdown(randomBytes32(), ByteVector("deadbeef")), - ClosingSigned(randomBytes32(), 0.sat, randomBytes64()), - ) - messages.forEach { - assertEquals(it.withChannelData(belowLimit).channelData, belowLimit) - assertTrue(it.withChannelData(aboveLimit).channelData.isEmpty()) - } - } - - @Test - fun `skip backup channel data when message is too large`() { - val channelData = EncryptedChannelData(ByteVector(ByteArray(59500) { 42 })) - val smallCommit = CommitSig(randomBytes32(), randomBytes64(), listOf()) - assertEquals(smallCommit.withChannelData(channelData).channelData, channelData) - val largeCommit = CommitSig(randomBytes32(), randomBytes64(), List(50) { randomBytes64() }) - assertTrue(largeCommit.withChannelData(channelData).channelData.isEmpty()) - } - @Test fun `encode - decode on-the-fly funding messages`() { val channelId = ByteVector32("c11b8fbd682b3c6ee11f9d7268e22bb5887cd4d3bf3338bfcc340583f685733c")