diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala b/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala index bacd948555..53603d453a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala @@ -34,15 +34,13 @@ object DBChecker extends Logging { def checkChannelsDB(nodeParams: NodeParams): Seq[PersistentChannelData] = { Try(nodeParams.db.channels.listLocalChannels()) match { case Success(channels) => - channels.foreach { + channels.collect { case data: ChannelDataWithCommitments => val channelKeys = nodeParams.channelKeyManager.channelKeys(data.channelParams.channelConfig, data.channelParams.localParams.fundingKeyPath) - if (!data.commitments.validateSeed(channelKeys)) { - throw InvalidChannelSeedException(data.channelId) - } - case _ => () + data.setChannelKeys(channelKeys) + data + case data => data } - channels case Failure(t) => throw IncompatibleDBException(t) } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala index 548ae9497f..6a3bf520ad 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala @@ -23,12 +23,13 @@ import fr.acinq.eclair.blockchain.fee.{ConfirmationTarget, FeeratePerKw} import fr.acinq.eclair.channel.Helpers.Closing import fr.acinq.eclair.channel.fund.InteractiveTxBuilder._ import fr.acinq.eclair.channel.fund.{InteractiveTxBuilder, InteractiveTxSigningSession} +import fr.acinq.eclair.crypto.keymanager.ChannelKeys import fr.acinq.eclair.io.Peer import fr.acinq.eclair.reputation.Reputation import fr.acinq.eclair.transactions.CommitmentSpec import fr.acinq.eclair.transactions.Transactions._ import fr.acinq.eclair.wire.protocol.{ChannelAnnouncement, ChannelReady, ChannelReestablish, ChannelUpdate, ClosingSigned, CommitSig, FailureReason, FundingCreated, FundingSigned, Init, LiquidityAds, OnionRoutingPacket, OpenChannel, OpenDualFundedChannel, Shutdown, SpliceInit, Stfu, TxInitRbf, TxSignatures, UpdateAddHtlc, UpdateFailHtlc, UpdateFailMalformedHtlc, UpdateFulfillHtlc} -import fr.acinq.eclair.{Alias, BlockHeight, CltvExpiry, CltvExpiryDelta, Features, InitFeature, MilliSatoshi, MilliSatoshiLong, RealShortChannelId, TimestampMilli, UInt64} +import fr.acinq.eclair.{Alias, BlockHeight, CltvExpiry, CltvExpiryDelta, Features, InitFeature, InvalidChannelSeedException, MilliSatoshi, MilliSatoshiLong, RealShortChannelId, TimestampMilli, UInt64} import scodec.bits.ByteVector import java.util.UUID @@ -549,17 +550,30 @@ case object Nothing extends TransientChannelData { sealed trait PersistentChannelData extends ChannelData { def remoteNodeId: PublicKey def channelParams: ChannelParams + // channel keys are never persisted or serialized + @transient private var channelKeys_opt: Option[ChannelKeys] = None + def validateChannelKeys(channelKeys: ChannelKeys): Boolean + def setChannelKeys(channelKeys: ChannelKeys): Unit = { + if (!validateChannelKeys(channelKeys)) { + throw InvalidChannelSeedException(channelId) + } + channelKeys_opt = Some(channelKeys) + } + def getChannelKeys: Option[ChannelKeys] = channelKeys_opt } sealed trait ChannelDataWithoutCommitments extends PersistentChannelData { val channelId: ByteVector32 = channelParams.channelId val remoteNodeId: PublicKey = channelParams.remoteNodeId def channelParams: ChannelParams + override def validateChannelKeys(channelKeys: ChannelKeys): Boolean = true } + sealed trait ChannelDataWithCommitments extends PersistentChannelData { val channelId: ByteVector32 = commitments.channelId val remoteNodeId: PublicKey = commitments.remoteNodeId val channelParams: ChannelParams = commitments.channelParams def commitments: Commitments + override def validateChannelKeys(channelKeys: ChannelKeys): Boolean = commitments.validateSeed(channelKeys) } sealed trait ClosedData extends ChannelData diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index 63b373fb79..75cd98e99b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -83,7 +83,7 @@ class Peer(val nodeParams: NodeParams, case Event(init: Init, _) => pendingOnTheFlyFunding = init.pendingOnTheFlyFunding val channels = init.storedChannels.map { state => - val channelKeys = nodeParams.channelKeyManager.channelKeys(state.channelParams.channelConfig, state.channelParams.localParams.fundingKeyPath) + val channelKeys = state.getChannelKeys.getOrElse(nodeParams.channelKeyManager.channelKeys(state.channelParams.channelConfig, state.channelParams.localParams.fundingKeyPath)) val channel = spawnChannel(channelKeys) channel ! INPUT_RESTORED(state) FinalChannelId(state.channelId) -> channel diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala index 9236f0430b..895630c6d4 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala @@ -429,7 +429,7 @@ object PostRestartHtlcCleaner { case Some(_: Closing.MutualClose) => Set.empty case None => Set.empty } - val channelKeys = nodeParams.channelKeyManager.channelKeys(d.commitments.channelParams.channelConfig, d.commitments.localChannelParams.fundingKeyPath) + val channelKeys = d.getChannelKeys.getOrElse(nodeParams.channelKeyManager.channelKeys(d.commitments.channelParams.channelConfig, d.commitments.localChannelParams.fundingKeyPath)) val timedOutHtlcs: Set[Long] = (closingType_opt match { case Some(c: Closing.LocalClose) => confirmedTxs.flatMap(tx => Closing.trimmedOrTimedOutHtlcs(channelKeys, d.commitments.latest, c.localCommit, tx)) case Some(c: Closing.RemoteClose) => confirmedTxs.flatMap(tx => Closing.trimmedOrTimedOutHtlcs(channelKeys, d.commitments.latest, c.remoteCommit, tx))