diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt index f624ea4d7..a7b8fba07 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt @@ -23,7 +23,6 @@ import fr.acinq.lightning.payment.* import fr.acinq.lightning.serialization.channel.Encryption.from import fr.acinq.lightning.serialization.channel.Encryption.fromEncryptedPeerStorage import fr.acinq.lightning.serialization.channel.Serialization.PeerStorageDeserializationResult -import fr.acinq.lightning.serialization.channel.Serialization.DeserializationResult import fr.acinq.lightning.transactions.Scripts import fr.acinq.lightning.transactions.Transactions import fr.acinq.lightning.utils.* @@ -1249,40 +1248,6 @@ class Peer( logger.warning { "received unwanted peer storage" } } } - is ChannelReestablish -> { - val backup: DeserializationResult? = msg.legacyChannelData.takeIf { !it.isEmpty() }?.let { channelData -> - PersistedChannelState - .from(nodeParams.nodePrivateKey, channelData) - .onFailure { logger.warning(it) { "unreadable backup" } } - .getOrNull() - } - val state: ChannelState? = when { - backup == null -> _channels[msg.channelId] - backup is DeserializationResult.UnknownVersion -> { - logger.warning { "peer sent a reestablish with a backup generated by a more recent version 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) - null - } - backup is DeserializationResult.Success && backup.state.channelId == msg.channelId -> { - maybeRestoreBackup(backup.state) - } - else -> { - logger.warning { "peer sent a reestablish with a backup for a different channel" } - _channels[msg.channelId] - } - } - if (state == null) { - logger.warning { "peer sent a reestablish for an unknown channel with no or undecipherable backup" } - peerConnection?.send(Error(msg.channelId, "unknown channel")) - } else { - val (state1, actions1) = state.process(ChannelCommand.MessageReceived(msg)) - processActions(msg.channelId, peerConnection, actions1, state1) - _channels = _channels + (msg.channelId to state1) - } - } is HasTemporaryChannelId -> { _channels[msg.temporaryChannelId]?.let { state -> logger.info { "received ${msg::class.simpleName} for temporary channel ${msg.temporaryChannelId}" } diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/serialization/channel/Encryption.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/serialization/channel/Encryption.kt index f4029b1e6..79b367952 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/serialization/channel/Encryption.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/serialization/channel/Encryption.kt @@ -10,7 +10,6 @@ import fr.acinq.lightning.logging.MDCLogger import fr.acinq.lightning.serialization.InputExtensions.readCollection import fr.acinq.lightning.serialization.InputExtensions.readDelimitedByteArray import fr.acinq.lightning.utils.toByteVector -import fr.acinq.lightning.wire.EncryptedChannelData import fr.acinq.lightning.wire.EncryptedPeerStorage /** @@ -34,27 +33,6 @@ object Encryption { return ChaCha20Poly1305.decrypt(key.toByteArray(), nonce.toByteArray(), ciphertext.toByteArray(), ByteArray(0), tag.toByteArray()) } - /** - * Convenience method that builds an [EncryptedChannelData] from a [PersistedChannelState] - */ - fun EncryptedChannelData.Companion.from(key: PrivateKey, state: PersistedChannelState): EncryptedChannelData { - val bin = Serialization.serialize(state) - val encrypted = encrypt(key.value, bin) - // we copy the first 2 bytes as meta-info on the serialization version - val data = bin.copyOfRange(0, 2) + encrypted - return EncryptedChannelData(data.toByteVector()) - } - - /** - * Convenience method that decrypts and deserializes a [PersistedChannelState] from an [EncryptedChannelData] - */ - fun PersistedChannelState.Companion.from(key: PrivateKey, encryptedChannelData: EncryptedChannelData): Result { - // we first assume that channel data is prefixed by 2 bytes of serialization meta-info - return runCatching { decrypt(key.value, encryptedChannelData.data.drop(2).toByteArray()) } - .recoverCatching { decrypt(key.value, encryptedChannelData.data.toByteArray()) } - .map { Serialization.deserialize(it) } - } - /** * Convenience method that builds an [EncryptedPeerStorage] from a list of [PersistedChannelState] */ diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt index 2bccdbe96..4e8777d2a 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/ChannelTlv.kt @@ -170,7 +170,7 @@ sealed class ChannelReestablishTlv : Tlv { } } - // Legacy TLV needed to deserialize old backups + /** Legacy TLV needed to deserialize old backups */ data class ChannelData(val ecb: EncryptedChannelData) : ChannelReestablishTlv() { override val tag: Long get() = ChannelData.tag override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) @@ -183,7 +183,7 @@ sealed class ChannelReestablishTlv : Tlv { } sealed class ShutdownTlv : Tlv { - // Legacy TLV needed to deserialize old backups + /** Legacy TLV needed to deserialize old backups */ data class ChannelData(val ecb: EncryptedChannelData) : ShutdownTlv() { override val tag: Long get() = ChannelData.tag override fun write(out: Output) = LightningCodecs.writeBytes(ecb.data, out) diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt index d0853eaca..434296834 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt @@ -156,18 +156,8 @@ interface HasChainHash : LightningMessage { interface ForbiddenMessageDuringSplice : LightningMessage -/** - * Legacy format to backup channel state. - * It is only kept to restore old channels. New backups now use EncryptedPeerStorage. - */ +/** Legacy format for channel backup, needed to deserialize old backups */ data class EncryptedChannelData(val data: ByteVector) { - /** We don't want to log the encrypted channel backups, they take a lot of space. We only keep the first bytes to help correlate mobile/server backups. */ - override fun toString(): String { - val bytes = data.take(min(data.size(), 10)) - return if (bytes.isEmpty()) "" else "$bytes (truncated)" - } - - fun isEmpty(): Boolean = data.isEmpty() companion object { val empty: EncryptedChannelData = EncryptedChannelData(ByteVector.empty) @@ -1329,8 +1319,6 @@ data class ChannelReestablish( override val type: Long get() = ChannelReestablish.type val nextFundingTxId: TxId? = tlvStream.get()?.txId - // Legacy channel backup present only on old inactive channels, will be replaced by peer storage next time this channel data is updated. - val legacyChannelData: EncryptedChannelData get() = tlvStream.get()?.ecb ?: EncryptedChannelData.empty override fun write(out: Output) { LightningCodecs.writeBytes(channelId, out) diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/LegacyWaitForFundingConfirmedTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/LegacyWaitForFundingConfirmedTestsCommon.kt deleted file mode 100644 index bdbaca8da..000000000 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/LegacyWaitForFundingConfirmedTestsCommon.kt +++ /dev/null @@ -1,74 +0,0 @@ -package fr.acinq.lightning.channel.states - -import fr.acinq.bitcoin.ByteVector -import fr.acinq.bitcoin.ByteVector32 -import fr.acinq.bitcoin.PrivateKey -import fr.acinq.bitcoin.Transaction -import fr.acinq.lightning.Lightning.randomKey -import fr.acinq.lightning.blockchain.WatchConfirmed -import fr.acinq.lightning.blockchain.WatchConfirmedTriggered -import fr.acinq.lightning.blockchain.fee.OnChainFeerates -import fr.acinq.lightning.channel.* -import fr.acinq.lightning.logging.MDCLogger -import fr.acinq.lightning.serialization.channel.Encryption.from -import fr.acinq.lightning.tests.TestConstants -import fr.acinq.lightning.tests.utils.testLoggerFactory -import fr.acinq.lightning.utils.value -import fr.acinq.lightning.wire.ChannelReady -import fr.acinq.lightning.wire.ChannelReestablish -import fr.acinq.lightning.wire.EncryptedChannelData -import fr.acinq.lightning.wire.Init -import kotlinx.coroutines.flow.MutableStateFlow -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertIs -import kotlin.test.assertTrue - -class LegacyWaitForFundingConfirmedTestsCommon { - @Test - fun `restore legacy channel`() { - // This data was generated with lightning-kmp v1.1.0 - val waitForFundingConfirmed = ByteVector.fromHex( - "1908557d740ca5f84607133a624cc2dc68ee86b669f953f950ecefcdb5895ea4d35f5b48095693a87f699eeb2e3e1639bff3df2c760a68ee6d5016266c8901e458e38cb43621197b6f410b3f87518a154b29caa86c17ca32b8c6c82c7d200c06c286cd60c6acb4ee04336484a50e6e44f197ddd3781568138bb40a2928cc279e136c6cff9d34405e3a4498846463ab60597f8900847dc1f874e03003c57d2ba5df52e65407f1ec1a09bf2d94b8f77b09632a722d5b67f60279c303b1cd05e3bceacc01482215b2afaa50d2703089c9cc0fb3aa2ae820b198bb841f51c97e845ed64ac96da96fac4bc396ac30d42348b52856386e594872da3db594c361143d22a9ee797dbea03783ba7437145d2713f39d831ab862f265fca41f0b574edc9b5cd2e7859cb05586276e378f5e3437af680b1276d8a8c7b44a8fd5c087899bf69e3cad48e71a21b1496230c1a3636cccd9919166434ee5b34c55f2cfaf640ae75c834ce5d4d944f46439053b73b9f421356635720b9bda92ffe9f46fd6b0d3e25ce487bffbbf3fe067457cb3baa0462033d7d753d4fcfb224ca3ab6da32e77c3610bc22c8c1017a5cb6c0403a4001a0ef54560fd9491f709dce538e67e7a4635532e4cc21969c8ff1201cf4ab651c457043552a621c3d315e50c59793ebf70d0809dda738bd3f29cc92d42c5c391c7411f4b2fff991c7b3a2a72e36acb59703e2ae2630f94c3c7fd92a9b4ea33e3d85961abce3512fa6fb0140eb6930ba02db6b12a362bdf745b223b0c930a0e82049304e7d018b8d8bc9f7b2e3e03b27a68a6dcf158d16e79b2090d4fcd2e2cc74a0f7de3034e1868cee1ad6f850bf0dd7728bf47a057fa443ff89214653ee56e146f3f16bc4dbcf52e16a173a14c806d54a55743ca39cf04f29895f667de344d26482d51f8c158e8805582272c231f856fd4481a3ed497eb9f9d05c9ba29dffb061356a78bae245626add2c669909d1b32d932b3cb25633647f819cb5c154ace541af17da8736e6ec817c9a1ceb4f4d3168776175ac3a0cb3365bab51a84be269f6d4257b4e48d69202536fe58646f61bf0eb403b656edcc5bd5a6a939c9f2c8adaa600d823408ef31450a0cd5e325264945db439032647367e476b9d02d4377c14ea49e7ff5ed08c9162d148233d6f325668ad4583632a3cbbf812316569856743caee4e4a39c9f90ebef4f610d36a866c5a2063f725e6c29f7b677c7ada795a44530bea415d630d3b21c4cc81954ca8cfe36cfbbdcffa02124cdd277b8c856d5299b9b2aafe682b27e9a12fb03a6fbcab59d1f4f26d5acab518a9bed3c25aebae08aa8f819ebd9908cc516edb9870094b83161dc77a1647c43ae0561ad4db359c7318da6cc8437d31cc610b1c43458ff32e3cf0e701369b3927eb4a163140cf75d63c2729d4852d20c26f59bafe84d30ee3e3ace84b9bd393433d42145db1011c865653247762ad8dea3520d832214219cd0ccff9dbd3959b59b02c30b6d02393f1369e108a99f953fbc4502bff31b59d5238170d5d0d1af201e8c208ffcd5c7d40d5b3c069335c0d7d677390ad925a2cca9c3877108cb2a6101ffbd31d7444672c912f6637c521cd7edb799252290242bc22e5b1a6e61dd72989c776a61648145a21f41d779ed45b6435907e917b990d4b67a9b717713f925afe8849f6c6cd9d54a328c2df7cfd51deb40a09a87a866da84cf0b48bb72f442ef2c4be5bd1b6b4cdaa7d6bd0891d1591933657e498d0021a69dbe58619ccbeed9a53d785f36dca57866df09f293610fa9ab333521f2f072398d3c34a2f1293d71903f5dee7458607a3d3750bc98778ef7f1d894bbee254d8546dc4a073ea1626ac69b025a513bdc28fde81cec9c176569d382cdfaf7115d09fb4943229ee15188a6b8625dafbd5b68669e7ccee85765cbff685c9b35ef54fac07f082ee6359c4fad518fe88258de68a053029724429e42690f8258625ac9a5de155bfc19c10da6254f9d712c787be74930cce228d74f672dfd775ef47764a4d563864abac6e0707a7cbd7a5eed72236a19a2f4d1eeb021a90a58bc849435c7cd9a398c46402d23e6c9982ebdef1dd0b04418090b50efa483ad7655ef5b081fb42f1410168a519d88243e15a856c4d595b620972c7b50d696488e9535b20178492a0f4df6b4d5c57698dafda3d156e8113732175b19c722dd3681ca15df187625517ec6f5e074fe63864d46be96405913f2b90ea5fe6771d1312b44617e7a8af69d6ebdcd88744b0136d375b49abda272fdb97cee6574d589dae485afddd08f2f9610c7671a7e2ad8f9fe3f6664f4f1aa259bfca3f8f369e572fa4fe420af65e215a86146f198111da3660146baae91a3d91dacf68c7920d005b2f3b240919be972e06295f74e0c2bff325b3980f7ba7ee3057da3cd5a78396e8ea0f52a35f951cc85ddf3fbbd55d6af038c7c6ec468bfbd415a456c85ab0acdb01cf7cc2d6bb9c97bb903d67ec88f9371ba00014cd0f600dfa81fe25db9bc9d2bc0906670a208a700d2b9042966c0aef95bf0993bb85f7f8ab94e8b3c3803fb7b5fdf2fd40ca7dd7eca2ecc7dee5257bc57a8054f59113f5ad3a0e77e5eb281968ab0959cea7af88d7c2f7f8e01474c2cfd5cfaab9157616002579b3a50a3e3425deecbf10a2007caa5c4ba0ff80891f4b4620964c1a90d9a9f04676d6d3773ea69b97b98a6c1efadd16d920c71fa42d26d5c54b940da5b948a61bf194373fe63d2d11c61b72abfd4798c4098ad8ee9cc905ffa86e9f8a9db9b7edebb1b9fd0385e24efe6a8d85b3b87c255397f6f9cf6173f03023a2280a9b1a00d776ceaaadfd184aa3d404d5a0ef5f8e1309c1c13de8d417870ffd8d2c97cd0e6a504cb4558b766726ea86279af776ae731db0d7f7beebd246198d3ab7f8d54a5dd74af6effcdd424b1b924eedd2f76cf777c8ecce1ac70d35f75a541cb76a06db6fbcb5e43cc19c36e85968e856500a12179fb45ee111f3e9b0ebe4c626b60843c03fa16faa75bbc2b6fab92e30dad7516680b02d349cf0c15153ab6af22eb7c8cefefaf8056a32e0f2c05ee1584226a74c04f9005ec884add4a18d5420dd252a37eeb3a15827c3315f46bacd4707c01d62fb2e474618dc289ce3be7e4da3e511120da4cd5630a96a31a08f220ba5328e92f06bd3fa738f7e08dea5c569454f66f9ec1606cf292e3f751af2b9d1b71f6c91a171ff52a2656f0b5dc4024507e0eabac730dfc642c14882de8c851f1a7e4705349c210b15b2a20859c004fe9c40a02405e6dcbe3364f827bc0c82270336cd08cc40790cd6b867e35997992d93188ee90e6984e108ca8503268cb81e27b2224706ab0a54dee215a29243f6f58a5e6d80b5de048e3ef905ab25f756b6462c2e59e4ae5742f06d24ee0333ec9a8485f9b0e48d23d9dfa494279cc84f4bb7971d69b3b46802481e4c8bdce37e9717bf57ac5eed94e941f0fcd7565b829dbcb52932792dceefb85a0e22c5da57a23c9fc52a581dc0189c1a9c33801fb97154a609686f740953536611b2f007b0b866646174c1dbc2ac3035edf1a24ab88438fed501287b84204f1a07cbadbdd1f30b53cef251becfcfeea5ef767df19b49e3dec15860e14a58e26988ce541bde95a417c3850f9f8fc290baade17eacb2d408193da1077de4053ccd1d07ac1f2d276a5c62980ca749498f86cf29284b2d8cd600d402ee21fd18a96d87b9415f713b1589e4e46ff4b24861f05660dbabfec82b8635fc253e23c1c70a4f26fe5b9ff87b88693f92f82f57b9ee7a9b6e232983f077b7d1904a123275e150ae4edd9c9bc9738ff4da1e053e334ceb7db7cc0810d9a17afbc86a3e10749bf21eca931e740195c1dc3e8ac9914a7e788da00d654a831f6c44b518011a8f428bccf9ebb35f3e52292126555bca5450df067b061d6062df822d17360bed60433358f9321817b51ef8ed3db203dabb6386e13279e17bd62ba1e688dc724b61e52dba54a57a933efa52f9451e2f71eddbc1f457c476bba1f6fe5ad58456c9af72b6620b54b3f4250c7e62c00992073089e0740489108dcfb66b179cf1dea40e0c253d5b414a35c681472f2ca22c9b8eab39cdce0b46873ac073b5a1819852492706f8d9c00bc54d4add581f441993be20f9c6b79067a214e650adb581db6055d97e8372f9bf5a71769abd6470630ad4fa4eae935d54c24a0a6e38c36475777a0d7a3a4ec9f2a2f6f2bd51830f91be09f3a51cbc238c33352e24e79fd809963b00d5ccd9091425ab221fbb315ea5916e005a8287114266674283624425bcefd0208088cdba34893d4a6f0652b02e61cbf7af17d18347d07ae7032fb4106865529fa419f3f2a4bb33e3f571903844bdfb70587c7c2653630f43a60e88e26d992255bf8c21062b972a6b7351b56b173bdde9a4495dc467ea98eec9d81cecb0b6d264f1b1786d974ffe61d7cc88be65cf6d1f3016444ca7b20e8f0bae9d599149ceda1720b6f96494205c88318d296d85445514267f2692a3b4060db5d28ea878b2aff099ef1ab912152589c8d5c865c79037369a1041af18b26dd5f674dce4713c4f741a516f2abdd28793dea949fc3a9a9d34cd9ce5f46e94ab32f38c06757e2e0bc7cbd6a63dce7bf99cbf6e4543c88ac323ef5101bbd43230c8c8bd5fb46ee1299be0b343aeeea62c5611663389b3773e795b8b6a4067d9f72f2dc0f0f3ce8ba95bdee2c2527ff98ec099ab70668ba8db8b5d7f877cc5b003c3a48fdbff5468a5592e741696dcfb2f3e52fbb7bc44ef4cc80151d9535f431a4f48156185e80f2b967fd5d18ae289b9534b2a8d891166e44e106c37c9e458fa19818bba7949e754e3db17bb1b43731e7a24d4b060601e63a0f1e49eb85c0924b481b8f8ae0520b2f7b8d362bde86bf13f07baa08c45217b5cecffd0042fb617bf36d17484c6272029a70fc2dc9bb95cb510cb679de804bbb0d68ef10dc0a8cfc0f165cf3ae3c2aafc192b2bed799b68276de8cccc146db52446edd7c61cdaf792271705386f77bb0a37bd25018f6da625eee685866d55724a358b4091f85d2e3a1d36b4439a06c3ce7fd0c8b93849a001de77db477e7d2ca967ddd1d26c8ca80e79e82e74dda777ea190295f73106485be6256c61c87df637105a421d61272882072ced3cd029310dfd24f1a32b6817d329df706a19d5e3eb4be3d79bb8fe77264" - ) - val state = PersistedChannelState.from(TestConstants.Bob.nodeParams.nodePrivateKey, EncryptedChannelData(waitForFundingConfirmed)).getOrNull()!!.value - assertIs(state) - val fundingTx = Transaction.read("020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0140420f0000000000220020f9aafa9be1212d0d373760c279f3817f9be707d674cae5f38bb31c1fd85c202900000000") - assertEquals(state.commitments.latest.fundingTxId, fundingTx.txid) - val ctx = ChannelContext( - StaticParams(TestConstants.Bob.nodeParams, TestConstants.Alice.nodeParams.nodeId), - TestConstants.defaultBlockHeight, - MutableStateFlow(OnChainFeerates(TestConstants.feeratePerKw, TestConstants.feeratePerKw, TestConstants.feeratePerKw, TestConstants.feeratePerKw)), - MDCLogger(testLoggerFactory.newLogger("ChannelState")) - ) - val (state1, actions1) = LNChannel(ctx, WaitForInit).process(ChannelCommand.Init.Restore(state)) - assertIs>(state1) - assertEquals(actions1.size, 1) - val watchConfirmed = actions1.findWatch() - assertEquals(watchConfirmed.event, WatchConfirmed.ChannelFundingDepthOk) - assertEquals(watchConfirmed.txId, fundingTx.txid) - // Reconnect to our peer. - val localInit = Init(state.commitments.params.localParams.features) - val remoteInit = Init(state.commitments.params.remoteParams.features) - val (state2, actions2) = state1.process(ChannelCommand.Connected(localInit, remoteInit)) - assertIs>(state2) - assertTrue(actions2.isEmpty()) - val channelReestablish = ChannelReestablish( - state.channelId, - state.commitments.remoteCommitIndex + 1, - state.commitments.localCommitIndex, - PrivateKey(ByteVector32.Zeroes), - randomKey().publicKey() - ) - val (state3, actions3) = state2.process(ChannelCommand.MessageReceived(channelReestablish)) - assertEquals(state, state3.state) - assertEquals(actions3.size, 1) - actions3.hasOutgoingMessage() - // The funding tx confirms. - val (state4, actions4) = state3.process(ChannelCommand.WatchReceived(WatchConfirmedTriggered(state.channelId, watchConfirmed.event, 1105, 3, fundingTx))) - assertIs>(state4) - assertEquals(actions4.size, 2) - actions4.hasOutgoingMessage() - actions4.has() - } -} \ No newline at end of file diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/LegacyWaitForFundingLockedTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/LegacyWaitForFundingLockedTestsCommon.kt deleted file mode 100644 index 2522109bd..000000000 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/LegacyWaitForFundingLockedTestsCommon.kt +++ /dev/null @@ -1,73 +0,0 @@ -package fr.acinq.lightning.channel.states - -import fr.acinq.bitcoin.ByteVector -import fr.acinq.bitcoin.ByteVector32 -import fr.acinq.bitcoin.PrivateKey -import fr.acinq.bitcoin.Transaction -import fr.acinq.lightning.Lightning.randomKey -import fr.acinq.lightning.blockchain.WatchConfirmed -import fr.acinq.lightning.blockchain.fee.OnChainFeerates -import fr.acinq.lightning.channel.* -import fr.acinq.lightning.logging.MDCLogger -import fr.acinq.lightning.serialization.channel.Encryption.from -import fr.acinq.lightning.tests.TestConstants -import fr.acinq.lightning.tests.utils.testLoggerFactory -import fr.acinq.lightning.utils.value -import fr.acinq.lightning.wire.ChannelReady -import fr.acinq.lightning.wire.ChannelReestablish -import fr.acinq.lightning.wire.EncryptedChannelData -import fr.acinq.lightning.wire.Init -import kotlinx.coroutines.flow.MutableStateFlow -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertIs -import kotlin.test.assertTrue - -class LegacyWaitForFundingLockedTestsCommon { - @Test - fun `restore legacy channel`() { - // This data was generated with lightning-kmp v1.1.0 - val waitForFundingLocked = ByteVector.fromHex( - "d236a18c976d566711632eec6c9aef3eeac1494e188e16fe6950e40969c6320549eac3c8845c7c3cb7f3cba5675fc5f694322b8b823f27e913ffb90a7589e9841751470e293ce7ce37bd6c32a958e9050cc93a76e6cccc925ab50e1c328171404a17609dc407ef93805197ac59cc3793ff6f171604ff5eb2ec4e9b3391611a3a49e94994268a3939a0272b0efad40848105bbd6284092d801ddc19ea0cc7cc25d21de905492b0155ee6790b050fb19804f502d81a0b643eeadc327f4347cd85f67cc990830aa9ae9eb698b47eaaef4344ea36162f028887f3872e1ecae8fbd59f55f8443ee8340ff62e2368fc7414b7a650011ac943e184184b20efb937a05d6255e4deb8eb93479f6a7b8834bbbbf96e2effe58497b8e1015520101ccc412ba4c88676fd985e922f7d2e400cca8ffc5f2c4d3b646f5e2ef7a78c6377a7b684fc99816c6433ef01edd887b5ae03c7c538599a44f157f851757ec167845c00b74995b3dd534df7f9a94f20835c0ed8b571935a2614412bf6374b92ff0b1676ca11b2ead8ce3b477066d8b6a96f58ff155c9868190071a48ece842df32451e5a68b3ca559d8972e1a471d00b5906d48fa8a9a4d450a5f3eca192daa1a45cf5d5b9f65216becc0a0876d1f4081fecad201a99442406bad01319c4b4220076d0f6ee1b11d31ab1c47e8954f6b5a2468ad17b89088bba828c2f24ccfc9a011e6d25b050c78a685e96f7e56896b2eafe34e0399f5703cc35c1f65112506625bae00b1e2ac6dcef6e8245bea7e888b98369107929185e1fad0b97c4f00b28d50b30c1ef7fd33e51f1dcc32cf88bb575b23ce04e9c4f927a6fbb0a8a027ba81977cfcca8f3b6684c74c5ba7c8efc72b3844f5fc503f60eb1a8b3e45edbc16708b570e33ffe3e01f427e77b37d4dc95742149ea57e5e0c7abd78a7b8b39e64bd035d14ebe370d9eee4952fcaab6a1f0713dae2e8dd67eb99fed580147172ab465aba5ea5968adf017c7b158fcde85694c32adadd96f5a9e19e73a1abd8ba388fd764129186e883df7c581c076e3996772b78cd730042fa040c0728e6b5da87e080c088ac490bbe8bba226f2b28c20d8c5407f0291668b1dfabfab276cc02f4c0bbe3c950a1b8d7b47f8b04e180e5bf9c46d05775c6662762e17ecf561ca3f72af7cad4131508bd979c2505b0d37c2de7a826b64f77c41fe24b2d16182b2f8836900aeef83b8e7841cb408963eed0162e173a7846207a27f8b178dffd3c8ee8ac2e98e6f08e420a1b8baa3d2532c51bf47b72e1624f8a1032adf06099179425dbb78d394da9dbd5e2b0b3bb23b27b53a0adc139a092d6e8a04cabcba004e3de7f4a8ac716bf1b9b040e6d13ac186d2a9d4ed4d2876ae1c98ee50569cf73e780306af6b28961f6213fbcf3f0e692e4bd77b7da5ae73146090f4efc4b6a2d9e906f13e9781b6e888fa90d14a16117383981017a974c86ddbb367667ce4a672abc45555139548957b2f21ca155a91697944f2f5aa8caabe93b98015a43cbb68ef26962d3e83110434c93287bbd36d5f513a23960cd923a0a07c4705537e8a6afb36d8459cfb3963144dd1431869eaa93c02774ddb3da8aca8599997a7b4dcb53033e3d5f9ed62cc9af49abef77483145913c067428b87c3f1149269029e19fe8027baf15c0830cc731124021372c56be2fb031a83d6f2594ddb534245052cd06caa90315e3cf1e45e9f3773b2a20302cc39ba83a743bb428d8bc7b2db8bc93ac8c48938f06f9e5d41f4d1c4ed9de149b797bf339bd77301c899b76910c8cd8333d48d365aee1af80eaa994bf18ce04b0c59931a97c64724dcf01a8372a807efa0b5bf8f8cc00396c3bbb5d5ce0bc8cf8bc98f0734b9c8c030ffe3e9fa71c9807d9417862cfb6740658e01978170b4f7ad314f0fbe0987206579ec65a5d1e57b9a43523104c507ced68624ff440642be208ca3eb655a8d068dc74f12ed334092d086b7a83bef03d2e756ae0c839024c505265ff20ba06def8f928a9072ee72adea0cd5694b524b15e436e5e8b88022f5c4b00a1cb1bd3a4cfc1ec02142349c1292f4236b7c18383162ea4d50132dbc46e528b092e8fb7b436415d6f4d2b23017c59f9243aef6411a22744c0cb7497e1af3dc7964cbb5d1dc478d9be64d01719cb8e2017d4354ca3b373bf7756e3f0f54ef93cb5eb56e80720d6a7b1e687010f2a76bd9ae8003c25a2e6cf99450bc067cda702ba3dd35a848bfd6da2c57f8784e6165043228118c4dc1b06d2dbfddea813074a4a1813b16b75dd0e55066545378c33a8cabe0069488a90a0891f433241131d94ee85d76cdf9bdc59fac4ddb305512c566eaf33c5bef4516395b3639750d5eb0988e09ed2d46eb593e1912f9667cbabd816eb600e98e37263cf48dbf5cb306caf02f62a5a43fe2e797ea491cc0d5d60bd15aa455611e1ed5df96ba76a7facec2fcb81918c254f61ac87c9d398cea5f1d81dd594eb94583fd9481ef38531dfa7d159ec59af5b7eaf95c4e3025e84e5b348c38486fa2570ae9b2deea38f267581c4eaaee3d4b7fcb68899c9363d0e880a5d7cd76702c9c549bed92f4c2c0d900453f2b6e36cc174e69ad65d775258bc46f2cc003768788f9b9aa3892890ce704301c78d9f84c7499442d64866849187ed43b5f68def04f9ed345d915055794e4e36f0b775027bd8a11ebbf2e2690f96c6058bf0709c612d6ff762ba40804bc03655a6e535545a07392842ee4bd802c4f44ac93e13601f047f1790fb2b3c16c30833a8b104824b99758e058218ed1d15abd3044e3b690eda2d5a360be6508a3cd1133f68a9693ecbf24da8999c6eec2fd6d5322953d3c6e608d5a2186e2ea56fc046b7e029acce56828c665d3b9b760418e6401edb636116a5ac867791620bb13dfeed4a28536217dd0c81fddf6d0166d7cd45d57f362e40df68bb279e16075d764963339129e39c44816dffe423441b2c964246e6c5e26cb220258ef88cf696e48c10781eb834903c584af0bb5d5cac591dbc2354ea57a7535b989e431b9e3bc301a8d08cb127b97a5e8dc732d274fb413a5d6e69811e1bd5eb77db27c1f85d221325b06a078688493a13de832e5be50ac514153cd9a582e3edef18751aa30d153717ab580fb12a6b3d704dc953b5b06b4f45bbc177f2a91ae084cfc28e2dd8dc7a1e05240e80995d3afc3ab8f4ed80e769a842e6eaeb0ad5a6868f6634632358afdf1ee51f3b1b4e4a7b2550c63a287f5033767a2683f81d206f938120c86afabc95a625b641bd883cfde6fc8555fca3681f130bfe3287284e93e2072b83fdbb9b3198744d5040a5fff3753a9bc9aaeca1938cec63bb342845af692701b8acc4433308f4a75672a5deb6e52b97d64024b1b2fd7fe44c057569991f53d4fb60b0501d7ac7cc7971a67ced33da1c049c364fea91af91469de4e72a51efb11ec6b1ac5cde7e1290a8c389289f991e7c44013f62bd941a6fe2b1ba901f17d7b9d3d1ca9ecce7c017c3aebc117971a57c261dfc8bde79320fa25139b76a5c67cbd432e0bb8afda88d2e7741cb7359211bc78ccd0358ffff7e803eacb6b373468705579bacd73c748219c2749801a3515993eaf77c749935adb9a5730ee88428cad6d856a918c58ab199ad653899c3fe598ff2171f24cfcbdc16f8ed7e5ce1f04db7f541827b335eac929fb01443783f68152f8044636c78b35413f6d900a2d1115d5c960a943b88ed96c28e2ba10ae5b878be89094194bd94eb104d5be699b1778deeafa7ba7c7ae5ddd3c79487a56532f66d9a1dcc63dcb67209997d5587ea8f99921d1e500c8ddab5db2556ea329f73e0a38224652394ae5eb9384b87e14f42d0ed178667d19569142d7fd712246529d59ec54f9375358bc7c4d4d018106be268d0d83a8ff447403377845036f69440ef2c975eeb98142e1735000d85c3b8a53225c90c6008ed0751263ac2f72e6a5e2dfb8c52a88e93e23b13c39ce8d1c45a673c4ee5b33e9e4b03c58eb9a34003728201e917e2ae2336cc0127862c0d657bada3e371bf67fc63197658b55597ac0a3cad1ad2fb3ef7836a7a120e79f7ef7944be3f47da92f84ac2b2b856efd151605429235db5ca4d0d42f206af47243d70f71cc3d0f497f286f195fb264b16793e27e9d3010628f464fdb0ec4dcb433c52396107e8710e6d537161f6b78dcd2a89a8d6f335e2284741e3a0f3da06104a7c500e5f724112d5492434bd39d643418f20abbde6dc5a8cfbca7ac6d6ac9beb8bf97422bf0284dab19e94e8e7645952a6cd7370e1e49178ad2192bd00cbadc3668fa37e989c7713a9a655e7bec12f59a5ee1d9282e4a58bec73cd338c363919c062a2b8aaee5176a3580e1cb731b3a7150ce78ebcc5944e22a0ef0e13f11c81ec8b934402a497cde5bf4f658ccd93a6c9d0779157994eac86ea8a596b7746af85911b13ede1c6e12d92615fff12deb0348f8e712999ab4e8f2e0390c1867fbe642672e8e9588db48624859731e9ce3fa12ef43c35b8392a966167c068e24f6a838552e592ac8e0bc75363215e2ad801fbff53f1ad8f4eca7c67cd6d5576ab239ec7902735f2ae7287c37bf97501610541f7bae47edf2d91a3fe2dbb410d26a832ede200f5a9dade21664ea5a3b58f1467575a3238b0faaceab0827e237b1325d0ba54a2898179527e7b506ce21f298e8871988f8d66d2d6415de2b31b9d0cea349242e994b012d7986fa3c2ae34fb49e8bf448fbb4e0cf35bfcb553e74a259b33fb286b1cc9da883409857514f29f741267f0120481c0f85ccf571808dbf56268f9f33a381cf9a4418d8b6bfc4e64ef18c02e3276d479e84d7021407acd446564103dfb53e62789b21253fd6b3142ab79e0fa7f64b34074dba79815d67d9eaa48974b0a17d03e56bad2dec8ba5f0641cd1d0a92138f6cc1ce44cb1576144ce69ad2955b3b704ab31f581b5429a34fea915654d9ee688415e3e044344b4ae4593db8febb189748d59bf0aa8f28083929a0abe88dd3c238bfd8a145fdc8bacacf71a906ed99af62b2876286dae6f4729f9edbe32767c7b7f3c42a7f24afbbfa776122eb6d52af6af609415a5b11a15719641a6381650639845420ff929f1233363a26be1165d777e2b0a6d5e4e978f7dbb" - ) - val state = PersistedChannelState.from(TestConstants.Bob.nodeParams.nodePrivateKey, EncryptedChannelData(waitForFundingLocked)).getOrNull()!!.value - assertIs(state) - val fundingTx = Transaction.read("020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0140420f0000000000220020f9aafa9be1212d0d373760c279f3817f9be707d674cae5f38bb31c1fd85c202900000000") - assertEquals(state.commitments.latest.fundingTxId, fundingTx.txid) - val ctx = ChannelContext( - StaticParams(TestConstants.Bob.nodeParams, TestConstants.Alice.nodeParams.nodeId), - TestConstants.defaultBlockHeight, - MutableStateFlow(OnChainFeerates(TestConstants.feeratePerKw, TestConstants.feeratePerKw, TestConstants.feeratePerKw, TestConstants.feeratePerKw)), - MDCLogger(testLoggerFactory.newLogger("ChannelState")) - ) - val (state1, actions1) = LNChannel(ctx, WaitForInit).process(ChannelCommand.Init.Restore(state)) - assertIs>(state1) - assertEquals(actions1.size, 1) - val watchConfirmed = actions1.findWatch() - assertEquals(watchConfirmed.event, WatchConfirmed.ChannelFundingDepthOk) - assertEquals(watchConfirmed.txId, fundingTx.txid) - // Reconnect to our peer. - val localInit = Init(state.commitments.params.localParams.features) - val remoteInit = Init(state.commitments.params.remoteParams.features) - val (state2, actions2) = state1.process(ChannelCommand.Connected(localInit, remoteInit)) - assertIs>(state2) - assertTrue(actions2.isEmpty()) - val channelReestablish = ChannelReestablish( - state.channelId, - state.commitments.remoteCommitIndex + 1, - state.commitments.localCommitIndex, - PrivateKey(ByteVector32.Zeroes), - randomKey().publicKey() - ) - val (state3, actions3) = state2.process(ChannelCommand.MessageReceived(channelReestablish)) - assertEquals(state, state3.state) - assertEquals(actions3.size, 2) - actions3.hasOutgoingMessage() - actions3.hasOutgoingMessage() - // Our peer sends us funding_locked. - val (state4, actions4) = state3.process(ChannelCommand.MessageReceived(ChannelReady(state.channelId, randomKey().publicKey()))) - assertIs>(state4) - assertEquals(actions4.size, 2) - actions4.has() - } -} \ No newline at end of file diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/CompatibilityTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/CompatibilityTestsCommon.kt index 214f06849..a8756b026 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/CompatibilityTestsCommon.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/CompatibilityTestsCommon.kt @@ -11,6 +11,7 @@ import fr.acinq.lightning.channel.ChannelType import fr.acinq.lightning.channel.LNChannel import fr.acinq.lightning.channel.findOutgoingMessage import fr.acinq.lightning.channel.states.Normal +import fr.acinq.lightning.channel.states.PersistedChannelState import fr.acinq.lightning.channel.states.WaitForChannelReady import fr.acinq.lightning.channel.states.WaitForFundingConfirmed import fr.acinq.lightning.channel.states.WaitForFundingConfirmedTestsCommon @@ -19,7 +20,7 @@ import fr.acinq.lightning.tests.TestConstants import fr.acinq.lightning.utils.UUID import fr.acinq.lightning.utils.msat import fr.acinq.lightning.wire.ChannelReady -import fr.acinq.lightning.wire.EncryptedChannelData +import fr.acinq.lightning.wire.EncryptedPeerStorage import fr.acinq.lightning.wire.UpdateAddHtlc import kotlin.test.assertEquals import kotlin.test.assertIs @@ -31,14 +32,14 @@ class CompatibilityTestsCommon { // generate test data val (alice, bob, fundingTx) = WaitForFundingConfirmedTestsCommon.init(ChannelType.SupportedChannelType.AnchorOutputs) println("funding_tx: ${Transaction.write(fundingTx).byteVector().toHex()}") - val bin = EncryptedChannelData.from(TestConstants.Bob.nodeParams.nodePrivateKey, bob.state) + val bin = EncryptedPeerStorage.from(TestConstants.Bob.nodeParams.nodePrivateKey, listOf(bob.state)) println("wait_for_funding_confirmed: ${bin.data}") val (bob1, actionsBob) = bob.process(ChannelCommand.WatchReceived(WatchConfirmedTriggered(bob.channelId, WatchConfirmed.ChannelFundingDepthOk, 42, 0, fundingTx))) val channelReady = actionsBob.findOutgoingMessage() assertIs>(bob1) - val bin1 = EncryptedChannelData.from(TestConstants.Bob.nodeParams.nodePrivateKey, bob1.state) + val bin1 = EncryptedPeerStorage.from(TestConstants.Bob.nodeParams.nodePrivateKey, listOf(bob1.state)) println("wait_for_channel_ready: ${bin1.data}") val (alice1, actionsAlice) = alice.process(ChannelCommand.MessageReceived(channelReady)) @@ -51,7 +52,7 @@ class CompatibilityTestsCommon { val (bob2, _) = bob1.process(ChannelCommand.MessageReceived(channelReadyAlice)) assertIs>(bob2) - val bin2 = EncryptedChannelData.from(TestConstants.Bob.nodeParams.nodePrivateKey, bob2.state) + val bin2 = EncryptedPeerStorage.from(TestConstants.Bob.nodeParams.nodePrivateKey, listOf(bob2.state)) println("normal: ${bin2.data}") val add1 = ChannelCommand.Htlc.Add( @@ -80,7 +81,7 @@ class CompatibilityTestsCommon { assertIs>(bob6) - val bin3 = EncryptedChannelData.from(TestConstants.Bob.nodeParams.nodePrivateKey, bob6.state) + val bin3 = EncryptedPeerStorage.from(TestConstants.Bob.nodeParams.nodePrivateKey, listOf(bob6.state)) println("normal_with_htlcs: ${bin3.data}") } } \ No newline at end of file diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/StateSerializationTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/StateSerializationTestsCommon.kt index 16930a201..21d445802 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/StateSerializationTestsCommon.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/serialization/channel/StateSerializationTestsCommon.kt @@ -29,7 +29,6 @@ import fr.acinq.lightning.tests.utils.runSuspendTest import fr.acinq.lightning.utils.msat import fr.acinq.lightning.utils.sat import fr.acinq.lightning.utils.value -import fr.acinq.lightning.wire.EncryptedChannelData import fr.acinq.lightning.wire.EncryptedPeerStorage import fr.acinq.secp256k1.Hex import kotlin.test.* @@ -48,19 +47,6 @@ class StateSerializationTestsCommon : LightningTestSuite() { assertEquals(bob.state, check1) } - @Test - fun `encrypt - decrypt normal state`() { - val (alice, bob) = TestsHelper.reachNormal() - val priv = randomKey() - val bytes = EncryptedChannelData.from(priv, alice.state) - val check = PersistedChannelState.from(priv, bytes).getOrNull()!!.value - assertEquals(alice.state, check) - - val bytes1 = EncryptedChannelData.from(priv, bob.state) - val check1 = PersistedChannelState.from(priv, bytes1).getOrNull()!!.value - assertEquals(bob.state, check1) - } - @Test fun `backward compatibility test`() { val bin = Hex.decode( diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt index 95f3a9028..2b68908b6 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt @@ -746,10 +746,10 @@ 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, TlvStream(setOf(ChannelReestablishTlv.ChannelData(EncryptedChannelData(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"))))), + Hex.decode("0088") + channelId.toByteArray() + Hex.decode("0001020304050607 0809aabbccddeeff") + key.value.toByteArray() + point.value.toByteArray() to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream()), + 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() to ChannelReestablish(channelId, 0x01020304050607L, 0x0809aabbccddeeffL, key, point, TlvStream()), + 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"))))), // 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 2b012a") to TxSignatures(channelId, TxId(txHash), listOf(), TlvStream(setOf(), setOf(GenericTlv(43, ByteVector("2a"))))),