diff --git a/docs/release-notes/eclair-vnext.md b/docs/release-notes/eclair-vnext.md index 8abe2c1514..93b8feb33e 100644 --- a/docs/release-notes/eclair-vnext.md +++ b/docs/release-notes/eclair-vnext.md @@ -4,6 +4,28 @@ ## Major changes +### Taproot Channels (without announcements) + +This release adds support for taproot channels, as specified in [the BOLTs](https://github.com/lightning/bolts/pull/995). +Taproot channels improve privacy and cost less on-chain fees by using musig2 for the channel output. +This release is fully compatible with the `lnd` implementation of taproot channels. + +We don't support public taproot channels yet, as the gossip mechanism for this isn't finalized yet. +It is thus only possible to open "private" (unannounced) taproot channels. +You may follow progress on the specification for public taproot channels [here](https://github.com/lightning/bolts/pull/1059). + +This feature is active by default. To disable it, add the following to your `eclair.conf`: + +```conf +eclair.features.option_simple_taproot = disabled +``` + +To open a taproot channel with a node that supports the `option_simple_taproot` feature, use the following command: + +```sh +$ eclair-cli open --nodeId= --fundingSatoshis= --channelType=simple_taproot_channel --announceChannel=false +``` + ### Remove support for non-anchor channels We remove the code used to support legacy channels that don't use anchor outputs or taproot. diff --git a/eclair-core/src/main/resources/reference.conf b/eclair-core/src/main/resources/reference.conf index 2e456cfb5d..989088b157 100644 --- a/eclair-core/src/main/resources/reference.conf +++ b/eclair-core/src/main/resources/reference.conf @@ -88,6 +88,7 @@ eclair { option_zeroconf = disabled keysend = disabled option_simple_close = optional + option_simple_taproot = optional trampoline_payment_prototype = disabled async_payment_prototype = disabled on_the_fly_funding = disabled diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala index 12e5127208..f5bcad84a2 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala @@ -312,6 +312,11 @@ object Features { val mandatory = 60 } + case object SimpleTaprootChannels extends Feature with InitFeature with NodeFeature with ChannelTypeFeature { + val rfcName = "option_simple_taproot" + val mandatory = 80 + } + case object PhoenixZeroReserve extends Feature with InitFeature with ChannelTypeFeature with PermanentChannelFeature { val rfcName = "phoenix_zero_reserve" val mandatory = 128 @@ -351,11 +356,6 @@ object Features { val mandatory = 564 } - case object SimpleTaprootChannelsStaging extends Feature with InitFeature with NodeFeature with ChannelTypeFeature { - val rfcName = "option_simple_taproot_staging" - val mandatory = 180 - } - /** * Activate this feature to provide on-the-fly funding to remote nodes, as specified in bLIP 36: https://github.com/lightning/blips/blob/master/blip-0036.md. * TODO: add NodeFeature once bLIP is merged. @@ -399,8 +399,8 @@ object Features { ZeroConf, KeySend, SimpleClose, + SimpleTaprootChannels, SimpleTaprootChannelsPhoenix, - SimpleTaprootChannelsStaging, WakeUpNotificationClient, TrampolinePaymentPrototype, AsyncPaymentPrototype, @@ -421,6 +421,7 @@ object Features { TrampolinePaymentPrototype -> (PaymentSecret :: Nil), KeySend -> (VariableLengthOnion :: Nil), SimpleClose -> (ShutdownAnySegwit :: Nil), + SimpleTaprootChannels -> (ChannelType :: SimpleClose :: Nil), SimpleTaprootChannelsPhoenix -> (ChannelType :: SimpleClose :: Nil), AsyncPaymentPrototype -> (TrampolinePaymentPrototype :: Nil), OnTheFlyFunding -> (SplicePrototype :: Nil), diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala index be25030aec..1ed1d6a168 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala @@ -131,7 +131,7 @@ case class NodeParams(nodeKeyManager: NodeKeyManager, // We use the most likely commitment format, even though there is no guarantee that this is the one that will be used. val commitmentFormat = if (Features.canUseFeature(localFeatures, remoteFeatures, Features.SimpleTaprootChannelsPhoenix)) { PhoenixSimpleTaprootChannelCommitmentFormat - } else if (Features.canUseFeature(localFeatures, remoteFeatures, Features.SimpleTaprootChannelsStaging)) { + } else if (Features.canUseFeature(localFeatures, remoteFeatures, Features.SimpleTaprootChannels)) { ZeroFeeHtlcTxSimpleTaprootChannelCommitmentFormat } else { ZeroFeeHtlcTxAnchorOutputsCommitmentFormat diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelFeatures.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelFeatures.scala index 04fda872af..5d2f9112b0 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelFeatures.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelFeatures.scala @@ -95,14 +95,14 @@ object ChannelTypes { override def commitmentFormat: CommitmentFormat = ZeroFeeHtlcTxAnchorOutputsCommitmentFormat override def toString: String = s"anchor_outputs_zero_fee_htlc_tx${if (scidAlias) "+scid_alias" else ""}${if (zeroConf) "+zeroconf" else ""}" } - case class SimpleTaprootChannelsStaging(scidAlias: Boolean = false, zeroConf: Boolean = false) extends SupportedChannelType { + case class SimpleTaprootChannel(scidAlias: Boolean = false, zeroConf: Boolean = false) extends SupportedChannelType { override def features: Set[ChannelTypeFeature] = Set( if (scidAlias) Some(Features.ScidAlias) else None, if (zeroConf) Some(Features.ZeroConf) else None, - Some(Features.SimpleTaprootChannelsStaging), + Some(Features.SimpleTaprootChannels), ).flatten override def commitmentFormat: CommitmentFormat = ZeroFeeHtlcTxSimpleTaprootChannelCommitmentFormat - override def toString: String = s"simple_taproot_channel_staging${if (scidAlias) "+scid_alias" else ""}${if (zeroConf) "+zeroconf" else ""}" + override def toString: String = s"simple_taproot_channel${if (scidAlias) "+scid_alias" else ""}${if (zeroConf) "+zeroconf" else ""}" } case class UnsupportedChannelType(featureBits: Features[InitFeature]) extends ChannelType { @@ -127,10 +127,10 @@ object ChannelTypes { AnchorOutputsZeroFeeHtlcTx(zeroConf = true), AnchorOutputsZeroFeeHtlcTx(scidAlias = true), AnchorOutputsZeroFeeHtlcTx(scidAlias = true, zeroConf = true), - SimpleTaprootChannelsStaging(), - SimpleTaprootChannelsStaging(zeroConf = true), - SimpleTaprootChannelsStaging(scidAlias = true), - SimpleTaprootChannelsStaging(scidAlias = true, zeroConf = true), + SimpleTaprootChannel(), + SimpleTaprootChannel(zeroConf = true), + SimpleTaprootChannel(scidAlias = true), + SimpleTaprootChannel(scidAlias = true, zeroConf = true), SimpleTaprootChannelsPhoenix, ).map { channelType => Features(channelType.features.map(_ -> FeatureSupport.Mandatory).toMap) -> channelType @@ -150,7 +150,9 @@ object ChannelTypes { /** Returns our preferred channel type for public channels, if supported by our peer. */ def preferredForPublicChannels(localFeatures: Features[InitFeature], remoteFeatures: Features[InitFeature]): Option[SupportedChannelType] = { - if (Features.canUseFeature(localFeatures, remoteFeatures, Features.AnchorOutputsZeroFeeHtlcTx)) { + if (Features.canUseFeature(localFeatures, remoteFeatures, Features.SimpleTaprootChannels)) { + Some(SimpleTaprootChannel(scidAlias = Features.canUseFeature(localFeatures, remoteFeatures, Features.ScidAlias))) + } else if (Features.canUseFeature(localFeatures, remoteFeatures, Features.AnchorOutputsZeroFeeHtlcTx)) { Some(AnchorOutputsZeroFeeHtlcTx(scidAlias = Features.canUseFeature(localFeatures, remoteFeatures, Features.ScidAlias))) } else { None diff --git a/eclair-core/src/test/resources/bolt3-tx-test-vectors-simple-taproot-commitment-format.json b/eclair-core/src/test/resources/bolt3-tx-test-vectors-simple-taproot-commitment-format.json new file mode 100644 index 0000000000..6de7141396 --- /dev/null +++ b/eclair-core/src/test/resources/bolt3-tx-test-vectors-simple-taproot-commitment-format.json @@ -0,0 +1,309 @@ +{ + "params": { + "seed": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "funding_amount_satoshis": 10000000, + "dust_limit_satoshis": 354, + "csv_delay": 144, + "commit_height": 42, + "nums_point": "02dca094751109d0bd055d03565874e8276dd53e926b44e3bd1bb6bf4bc130a279", + "keys": { + "local_funding_privkey": "20ae2d254ab29afd3dcbf8744a5b88d06070f55a4bd5532483a093ac4db91277", + "local_funding_pubkey": "03b7203dec7c13896b6ff1f58b24f84458c441720a12b5a57426397e22f0a8c78b", + "remote_funding_privkey": "f0c5500a9dbd7cdcd46ced7bdeb937d4dcbf90f9b9357626e7ee54ab024c3df0", + "remote_funding_pubkey": "02956e6845a6f346f97c5e028c0f8ab38a76b0124fd7184deab60f682b3e657fdb", + "local_payment_basepoint_secret": "277975b5b081a9cbc4834e066d7bb494e4fde4f7637257dd3d312a0ae7cb7754", + "local_payment_basepoint": "03955b6085296cbd2447a1dde0f7e273e19b83e83de1814993b1517aaf193b7f33", + "remote_payment_basepoint_secret": "f1cd3a5ca44b52baf4eacb849fbf06e75aace97477b8bfe31d2b814dbbb562b1", + "remote_payment_basepoint": "03595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9", + "local_delayed_payment_basepoint_secret": "83ccf0b638c514db5ebefdc6cbf901505e2bb20edb2bb7248ce1a51523325f9b", + "local_delayed_payment_basepoint": "02ae68d8ff4c59864c03a42bbff6c07f9ae18047e0daa9bc40d07c410f9a0f7899", + "remote_revocation_basepoint_secret": "36c4175b91cff9731a63d1472b5b1c4cf3e7b688e87d5fb806b2e8350484e68d", + "remote_revocation_basepoint": "02c354121ef71922b5cb32fa685c08ac0014b558f96e28f383c45eb28b7da264c3", + "local_htlc_basepoint_secret": "786eb5024e4851bea3ddc6e40036c81b1efcf50eeed440eedefe5245bde6fc14", + "local_htlc_basepoint": "033ce88bf3c8333e242996964ac91ee7cd945bfe4c49668ea10f3211f3d418fbc8", + "remote_htlc_basepoint_secret": "51c9b6cf8279def85e3925bc8f16fc0ff100ee7b03ce7c954149ca29c834b684", + "remote_htlc_basepoint": "02932dfbf6737001e3c516696ae3dcd323fd91a01ce7898f7f91ab98eebacc323e", + "local_per_commit_secret": "037b507180b3985cea6396d6a70987cea11ccd05fde49e943a3ea0fe56ee33ed", + "local_per_commit_point": "02a0f5a09017c1dec2d30dd54a25dc4037fc5a2aa3832ee3c7b58f3a88a0836287", + "derived_local_delayed_pubkey": "0315ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05", + "derived_revocation_pubkey": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "derived_local_htlc_pubkey": "0271e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739e", + "derived_remote_htlc_pubkey": "032deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47d", + "derived_remote_payment_pubkey": "03595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9" + } + }, + "scripts": { + "funding": { + "funding_tx_hex": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000018096980000000000225120d0ebb4909d563a7ae1213fddede4ae54132fba0ef0b97ee3f8469191fecd348e00000000", + "combined_key": "d0ebb4909d563a7ae1213fddede4ae54132fba0ef0b97ee3f8469191fecd348e", + "pkscript": "5120d0ebb4909d563a7ae1213fddede4ae54132fba0ef0b97ee3f8469191fecd348e" + }, + "to_local": { + "scripts": { + "revocation": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c057520d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0ac", + "settle": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05ad029000b2" + }, + "leaf_hashes": { + "revocation": "8fcd64d212bbbf1bcec2360bbf229963240d05992fc2efb482fe6dca85b9469a", + "settle": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62" + }, + "tapscript_root": "b8b76c2e893ca785072f0d7393e35d5bd72adf8b7ff2a53538aa664378a38a36", + "internal_key": "02dca094751109d0bd055d03565874e8276dd53e926b44e3bd1bb6bf4bc130a279", + "output_key": "023e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff3", + "pkscript": "51203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff3" + }, + "to_remote": { + "scripts": { + "settle": "20595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9ad51b2" + }, + "leaf_hashes": { + "settle": "63ce35b16eb8f8687293d5a88c1d8ada3236843b79ca315fe9dd7c47f30f2bc9" + }, + "tapscript_root": "63ce35b16eb8f8687293d5a88c1d8ada3236843b79ca315fe9dd7c47f30f2bc9", + "internal_key": "02dca094751109d0bd055d03565874e8276dd53e926b44e3bd1bb6bf4bc130a279", + "output_key": "023609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec30174408", + "pkscript": "51203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec30174408" + }, + "local_anchor": { + "scripts": { + "sweep": "60b2" + }, + "leaf_hashes": { + "sweep": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912" + }, + "tapscript_root": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912", + "internal_key": "0315ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05", + "output_key": "02f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344e", + "pkscript": "5120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344e" + }, + "remote_anchor": { + "scripts": { + "sweep": "60b2" + }, + "leaf_hashes": { + "sweep": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912" + }, + "tapscript_root": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912", + "internal_key": "03595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9", + "output_key": "021249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac4", + "pkscript": "51201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac4" + }, + "offered_htlc_local_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad51b2", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac" + }, + "leaf_hashes": { + "success": "cd4b7ba74d132998f2bcea85f76082f5018e614c86f27f2631b6569c4914320f", + "timeout": "dd0bd08b3df902c399f5493a682f6c50c476c89e233ba454e89a234d2d16ffe3" + }, + "tapscript_root": "f36c8bd45002c5264cfce9944211e7bc6ea974a6b90cf99a87812d18acf28a2a", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "033e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0", + "pkscript": "51203e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0" + }, + "offered_htlc_remote_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad51b2", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac" + }, + "leaf_hashes": { + "success": "cd4b7ba74d132998f2bcea85f76082f5018e614c86f27f2631b6569c4914320f", + "timeout": "dd0bd08b3df902c399f5493a682f6c50c476c89e233ba454e89a234d2d16ffe3" + }, + "tapscript_root": "f36c8bd45002c5264cfce9944211e7bc6ea974a6b90cf99a87812d18acf28a2a", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "033e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0", + "pkscript": "51203e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0" + }, + "accepted_htlc_local_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739eac", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead51b26902f401b1" + }, + "leaf_hashes": { + "success": "69192ca730d4480044ade8741b8bd0845a32880aebaf58bc6f9186f8d2be8cbf", + "timeout": "4da43c795365bf757ed1e9656d12ea744b4cf52b01719a3ea94e6569115623f0" + }, + "tapscript_root": "1a990caa4bb0ed41ceb19e7466fcea5d9b31e3da968f348f6223201c5831d0a3", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "029aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea", + "pkscript": "51209aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea" + }, + "accepted_htlc_remote_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739eac", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead51b26902f401b1" + }, + "leaf_hashes": { + "success": "69192ca730d4480044ade8741b8bd0845a32880aebaf58bc6f9186f8d2be8cbf", + "timeout": "4da43c795365bf757ed1e9656d12ea744b4cf52b01719a3ea94e6569115623f0" + }, + "tapscript_root": "1a990caa4bb0ed41ceb19e7466fcea5d9b31e3da968f348f6223201c5831d0a3", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "029aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea", + "pkscript": "51209aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea" + }, + "second_level_htlc_success": { + "scripts": { + "success": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05ad029000b2" + }, + "leaf_hashes": { + "success": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62" + }, + "tapscript_root": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "02df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0", + "pkscript": "5120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0" + }, + "second_level_htlc_timeout": { + "scripts": { + "success": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05ad029000b2" + }, + "leaf_hashes": { + "success": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62" + }, + "tapscript_root": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "02df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0", + "pkscript": "5120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0" + } + }, + "transactions": [ + { + "name": "simple commitment tx with no HTLCs", + "local_balance_msat": 7000000000, + "remote_balance_msat": 3000000000, + "fee_per_kw": 15000, + "htlcs": null, + "remote_partial_sig": "3006020100020100", + "expected_commitment_tx_hex": "020000000001015474cba49124ab0c4327c244bb2907059585c4af3fa5f3469701534120fec0170000000000c5fe1780044a010000000000002251201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac44a01000000000000225120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344ec0c62d00000000002251203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec3017440874946a00000000002251203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff30140a4a9eb512a2f4094efdd2c566f1f20cc8a6e2c307a4a44cc3f9fea7fa147dd7038f1b048aa43fa0b4009175c1c37c37b96c01058541f9e1b61110fce4e831d9f55dc1920", + "htlc_descs": null + }, + { + "name": "commitment tx with five HTLCs untrimmed", + "local_balance_msat": 6988000000, + "remote_balance_msat": 3000000000, + "fee_per_kw": 644, + "htlcs": [ + { + "incoming": true, + "amount_msat": 1000000, + "expiry": 500, + "preimage": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "incoming": true, + "amount_msat": 2000000, + "expiry": 501, + "preimage": "0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "incoming": false, + "amount_msat": 2000000, + "expiry": 502, + "preimage": "0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "incoming": false, + "amount_msat": 3000000, + "expiry": 503, + "preimage": "0303030303030303030303030303030303030303030303030303030303030303" + }, + { + "incoming": true, + "amount_msat": 4000000, + "expiry": 504, + "preimage": "0404040404040404040404040404040404040404040404040404040404040404" + } + ], + "remote_partial_sig": "3006020100020100", + "expected_commitment_tx_hex": "020000000001015474cba49124ab0c4327c244bb2907059585c4af3fa5f3469701534120fec0170000000000c5fe1780094a010000000000002251201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac44a01000000000000225120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344ee8030000000000002251209ce82cd1b1f6f975049d58019a7145a3ec9680079969cf929d7d2c4bc9b30637d0070000000000002251208937f8afbc80cf4ba773f1adc3d63ea26259f80f5a3ba622211906d2e7e6e23dd007000000000000225120bf9ae94dda9b5b88485cc67a966ec946b237d19626916dee034b789ebd7fd5fcb80b0000000000002251208fe2e1306e414e896dfd879475b5c1a6a01d4e79b32c0544aa185ccb73c392aaa00f000000000000225120d93389ba5cdde8570d3ba73487ff7fc9f8c3816645009e42110fe5239f5a3e62c0c62d00000000002251203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec30174408b3996a00000000002251203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff301409dfe3b178022d975e4b86bd1f04bccfc7576363dbaf58f2ac682136ad89cbeb1a1d07eca1e0bc547b5c5c1133214565e5dfdc230bc7d4736aa7e1be3fb8269d355dc1920", + "htlc_descs": [ + { + "remote_partial_sig_hex": "ba244e80d7043172804bd1b8c8fc26328b4ca0379611892c9d311ac97802af6849541cac18f51071d9aa57dceb7bdfa72544cbab6527e7a47bf1e9507dc51683", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f02000000000100000001e803000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541ba244e80d7043172804bd1b8c8fc26328b4ca0379611892c9d311ac97802af6849541cac18f51071d9aa57dceb7bdfa72544cbab6527e7a47bf1e9507dc516838340f75d8a3d94db2d5aaefc4949b3c10fe2163ebd953b636b6488cc2fe9a988bd6b966fc0904557044510b6650bc624bdfa0298e3bb18c4f403996e0a46bdf37b720020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0e5e8fd071b9ade6367122afbd8acacc1a6727ddb6d478612af30827590027e0300000000" + }, + { + "remote_partial_sig_hex": "790f2e9c117c83c3a0c207dfa9cbfe8a955717854e96e966f428dbce816a408c3434839e522031064f0cb3ebb15c8c030d20dc5859a0c99a78a5f795d32b693f", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f03000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541790f2e9c117c83c3a0c207dfa9cbfe8a955717854e96e966f428dbce816a408c3434839e522031064f0cb3ebb15c8c030d20dc5859a0c99a78a5f795d32b693f8340f417b7b78b52f00a2c76586c3555b66cc87207fdf2995db255d232d9bfdad33bc1e8ee80898c4c2e6c9856158999abe762bfd6d17933dec9b6d522dc3b9fec3b0020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0127d1790461eff920f14ba7cff2093c44b8a83e6f0a959fa60e04cf8c435cf4b00000000" + }, + { + "remote_partial_sig_hex": "aa6d10a611d9d34fb22e02aa9d1cce2b85cd10f16651fa67e415a787e0a9d2f14eb5845c4e1990af4dac7d4d865d3da7afd049cbded334f46f174e8474a16e12", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f04000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba004410967aa040669318987029fba55410f9a43c4dd57da9e3a60e74b83a35abea76e813fbbdaa8baae38e096a6b7718d75838cb33e264814678823f55ee6fb9cdd0f8340c52f017d42f140311c33a8bb94329f77f40245880b6ecc736735056c581fc7ceaad686deb2fe4359f257defa175fc4ce07558825500c1ef8d25ead5ac495d5b0442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a040b30263c4d7cd1fa6544e8bc8cd9efe857d7b5fd691c958936c3a2e0df2232ef6010000" + }, + { + "remote_partial_sig_hex": "81dd0918b0e01f4c1f701a5689f3c5c076bf71d4f365f21b67707527c9e71fe40e0c6fee2f3e46ee297d542e883f5ba5004b53b04cda060b6f99d3a8b2c3f488", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f05000000000100000001b80b000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00441aa6d10a611d9d34fb22e02aa9d1cce2b85cd10f16651fa67e415a787e0a9d2f14eb5845c4e1990af4dac7d4d865d3da7afd049cbded334f46f174e8474a16e1283403c03b026ef105fe37ec3710fe2b81844531cfb080ad3b7290c7045c6ffa29e3d60a680ce9f539e4b89b37e5818545efbf2a94cb0c1b893c4a4a6b65703b137b9442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a064c44563d1bd58fa25c5c3ca7303c75849b6b3d91bf2e28f27068db4319b4c2ff7010000" + }, + { + "remote_partial_sig_hex": "0967aa040669318987029fba55410f9a43c4dd57da9e3a60e74b83a35abea76e813fbbdaa8baae38e096a6b7718d75838cb33e264814678823f55ee6fb9cdd0f", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f06000000000100000001a00f000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0054181dd0918b0e01f4c1f701a5689f3c5c076bf71d4f365f21b67707527c9e71fe40e0c6fee2f3e46ee297d542e883f5ba5004b53b04cda060b6f99d3a8b2c3f48883409c3edb75f915ab9573cd44d9500e630fb6c2388c21733be54bce3824e66df526bf73df2206ccb8fbd125a4f0025e5bae8ecd7ea586d62ff341cead78c0e2528b0020000000000000000000000000000000000000000000000000000000000000000041c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a06c3390c812b2596986592f02c7f22e4f857fb553805ff9ac1c2bda361c47c3fb00000000" + } + ] + }, + { + "name": "commitment tx with some HTLCs trimmed", + "local_balance_msat": 6988000000, + "remote_balance_msat": 3000000000, + "fee_per_kw": 100000, + "dust_limit_satoshis": 546, + "htlcs": [ + { + "incoming": true, + "amount_msat": 1000000, + "expiry": 500, + "preimage": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "incoming": true, + "amount_msat": 2000000, + "expiry": 501, + "preimage": "0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "incoming": false, + "amount_msat": 2000000, + "expiry": 502, + "preimage": "0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "incoming": false, + "amount_msat": 3000000, + "expiry": 503, + "preimage": "0303030303030303030303030303030303030303030303030303030303030303" + }, + { + "incoming": true, + "amount_msat": 4000000, + "expiry": 504, + "preimage": "0404040404040404040404040404040404040404040404040404040404040404" + } + ], + "remote_partial_sig": "3006020100020100", + "expected_commitment_tx_hex": "020000000001015474cba49124ab0c4327c244bb2907059585c4af3fa5f3469701534120fec0170000000000c5fe1780094a010000000000002251201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac44a01000000000000225120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344ee8030000000000002251209ce82cd1b1f6f975049d58019a7145a3ec9680079969cf929d7d2c4bc9b30637d0070000000000002251208937f8afbc80cf4ba773f1adc3d63ea26259f80f5a3ba622211906d2e7e6e23dd007000000000000225120bf9ae94dda9b5b88485cc67a966ec946b237d19626916dee034b789ebd7fd5fcb80b0000000000002251208fe2e1306e414e896dfd879475b5c1a6a01d4e79b32c0544aa185ccb73c392aaa00f000000000000225120d93389ba5cdde8570d3ba73487ff7fc9f8c3816645009e42110fe5239f5a3e62c0c62d00000000002251203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec301744083cd46700000000002251203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff30140c06828b729b180dc98cefecaa42f05215016a0b5a3232ce86773b5fc08bedc1112ff1ceddb9fa7dd0740f1641d80114630017badc95f32480a15e435ed569d6555dc1920", + "htlc_descs": [ + { + "remote_partial_sig_hex": "f96a7376f50c3a2ee763bbeec232798458c50a8a6fab0333275c169f113d6ae8a5b37b61a9fc2eecbd0a0493418a1a8dd48fd5d161a410a57970f72a97fcee6f", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51502000000000100000001e803000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541f96a7376f50c3a2ee763bbeec232798458c50a8a6fab0333275c169f113d6ae8a5b37b61a9fc2eecbd0a0493418a1a8dd48fd5d161a410a57970f72a97fcee6f834036b2363b0f0f478a564a88052a9a7df89d00d18a449bb9f17c527a4049f6abd4f7e851b7294360613a01d1480726617cf754b3f26a28d45c44ea1abe7b317aa20020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0e5e8fd071b9ade6367122afbd8acacc1a6727ddb6d478612af30827590027e0300000000" + }, + { + "remote_partial_sig_hex": "1e82f5cfb5d2a87418d1ca3cc3abf9f18198692aba1a31ced763a8a9ed0ecd4252fd2996b89089aa69958cf2f41dda83d04d8d5644443de32b6e614105e833fc", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51503000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba005411e82f5cfb5d2a87418d1ca3cc3abf9f18198692aba1a31ced763a8a9ed0ecd4252fd2996b89089aa69958cf2f41dda83d04d8d5644443de32b6e614105e833fc83402ff61ab8f640fe9f9ef159b0e2a9fc17d0b4d15da59eed6b44fdff55e80d3b3d45aea7362cae2dfb2ae1c92a7d87790fce1e8cc157edadb9882823bfe299bca90020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0127d1790461eff920f14ba7cff2093c44b8a83e6f0a959fa60e04cf8c435cf4b00000000" + }, + { + "remote_partial_sig_hex": "d1fc7f73da9f09780568db36b9d1d5b0555be656ac2913beeffc1a48105a9e7aefe36d83cfeba66df106f65e81a5d5bae078d3f103da7e855b9f244d3a9df538", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51504000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba004417fe6ed9d80a0d3e7c315ac36c6ec234f510515bd2b1812b54da0e93a75a5ce4fce67839dfebca8746d94d343e2610bc92c22c9f4bcf637de461dd6fa0acb768f83407635f668f41362106a98c94ff0cdf66f9a8a57a141240096a1d5bb5a8531e91381a24b48c2c86010cb68891a17aca616e6e476dab53890ef63374e2cfa0929d9442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a040b30263c4d7cd1fa6544e8bc8cd9efe857d7b5fd691c958936c3a2e0df2232ef6010000" + }, + { + "remote_partial_sig_hex": "754bcd14983ecb5a864ce03f1f1a6f986e7d23bd0fa92505929a5595cf56199a3a520cd56bd15f6b28f78f148e3eff5df7a3336a9f05396b5f4a67ac3e2ed747", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51505000000000100000001b80b000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00441d1fc7f73da9f09780568db36b9d1d5b0555be656ac2913beeffc1a48105a9e7aefe36d83cfeba66df106f65e81a5d5bae078d3f103da7e855b9f244d3a9df53883407f6bd7945f87d3a6a6f3700d756757e2cd03a897d8e01145fa2217d2741f3422776ef1f8b337e9f3f78a29060bedea63a29e574764a49a25acef1d8fe0b50370442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a064c44563d1bd58fa25c5c3ca7303c75849b6b3d91bf2e28f27068db4319b4c2ff7010000" + }, + { + "remote_partial_sig_hex": "7fe6ed9d80a0d3e7c315ac36c6ec234f510515bd2b1812b54da0e93a75a5ce4fce67839dfebca8746d94d343e2610bc92c22c9f4bcf637de461dd6fa0acb768f", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51506000000000100000001a00f000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541754bcd14983ecb5a864ce03f1f1a6f986e7d23bd0fa92505929a5595cf56199a3a520cd56bd15f6b28f78f148e3eff5df7a3336a9f05396b5f4a67ac3e2ed747834016f15c4e15363903022afa572110909661a5b6da439507d49980585a7a2c4a23c91cae4a9c20ebc5a4051d47ed7e9a5c087f31f981652b5bc4e4018bb58e1f9f0020000000000000000000000000000000000000000000000000000000000000000041c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a06c3390c812b2596986592f02c7f22e4f857fb553805ff9ac1c2bda361c47c3fb00000000" + } + ] + } + ] +} \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala index 758a43afdd..944c196176 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala @@ -480,7 +480,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val targetFeerate = FeeratePerKw(2500 sat) val fundingA = 150_000 sat val utxosA = Seq(80_000 sat, 120_000 sat) - withFixture(ChannelTypes.SimpleTaprootChannelsStaging(), fundingA, utxosA, 0 sat, Nil, targetFeerate, 660 sat, 0, RequireConfirmedInputs(forLocal = false, forRemote = false)) { f => + withFixture(ChannelTypes.SimpleTaprootChannel(), fundingA, utxosA, 0 sat, Nil, targetFeerate, 660 sat, 0, RequireConfirmedInputs(forLocal = false, forRemote = false)) { f => import f._ alice ! Start(alice2bob.ref) @@ -1997,7 +1997,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val utxosA = Seq(340_000 sat, 40_000 sat, 35_000 sat) val fundingB1 = 80_000 sat val utxosB = Seq(290_000 sat, 20_000 sat, 15_000 sat) - withFixture(ChannelTypes.SimpleTaprootChannelsStaging(), fundingA1, utxosA, fundingB1, utxosB, targetFeerate, 660 sat, 0, RequireConfirmedInputs(forLocal = false, forRemote = false)) { f => + withFixture(ChannelTypes.SimpleTaprootChannel(), fundingA1, utxosA, fundingB1, utxosB, targetFeerate, 660 sat, 0, RequireConfirmedInputs(forLocal = false, forRemote = false)) { f => import f._ val probe = TestProbe() @@ -2385,7 +2385,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit } test("invalid tx_signatures (missing shared input signature, taproot)") { - testTxSignaturesMissingSharedInputSigs(ChannelTypes.SimpleTaprootChannelsStaging()) + testTxSignaturesMissingSharedInputSigs(ChannelTypes.SimpleTaprootChannel()) } test("invalid commitment index") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala index 331e089b45..630fcde8b1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala @@ -263,8 +263,8 @@ trait ChannelStateTestsBase extends Assertions with Eventually { .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.DualFunding))(_.updated(Features.DualFunding, FeatureSupport.Optional)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.SimpleClose))(_.updated(Features.SimpleClose, FeatureSupport.Optional)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.AnchorOutputsPhoenix))(_.removed(Features.AnchorOutputsZeroFeeHtlcTx).updated(Features.AnchorOutputs, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaprootPhoenix))(_.removed(Features.SimpleTaprootChannelsStaging).updated(Features.SimpleTaprootChannelsPhoenix, FeatureSupport.Optional).updated(Features.PhoenixZeroReserve, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaproot))(_.updated(Features.SimpleTaprootChannelsStaging, FeatureSupport.Optional)) + .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaproot))(_.updated(Features.SimpleTaprootChannels, FeatureSupport.Optional)) + .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaprootPhoenix))(_.removed(Features.SimpleTaprootChannels).updated(Features.SimpleTaprootChannelsPhoenix, FeatureSupport.Optional).updated(Features.PhoenixZeroReserve, FeatureSupport.Optional)) ) val nodeParamsB1 = nodeParamsB.copy(features = nodeParamsB.features .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.DisableWumbo))(_.removed(Features.Wumbo)) @@ -275,8 +275,8 @@ trait ChannelStateTestsBase extends Assertions with Eventually { .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.SimpleClose))(_.updated(Features.SimpleClose, FeatureSupport.Optional)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.DisableSplice))(_.removed(Features.SplicePrototype)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.AnchorOutputsPhoenix))(_.removed(Features.AnchorOutputsZeroFeeHtlcTx).updated(Features.AnchorOutputs, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaprootPhoenix))(_.removed(Features.SimpleTaprootChannelsStaging).updated(Features.SimpleTaprootChannelsPhoenix, FeatureSupport.Optional).updated(Features.PhoenixZeroReserve, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaproot))(_.updated(Features.SimpleTaprootChannelsStaging, FeatureSupport.Optional)) + .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaproot))(_.updated(Features.SimpleTaprootChannels, FeatureSupport.Optional)) + .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.OptionSimpleTaprootPhoenix))(_.removed(Features.SimpleTaprootChannels).updated(Features.SimpleTaprootChannelsPhoenix, FeatureSupport.Optional).updated(Features.PhoenixZeroReserve, FeatureSupport.Optional)) ) (nodeParamsA1, nodeParamsB1) } @@ -287,8 +287,8 @@ trait ChannelStateTestsBase extends Assertions with Eventually { val scidAlias = canUse(Features.ScidAlias) && !announceChannel // alias feature is incompatible with public channel val zeroConf = canUse(Features.ZeroConf) - if (canUse(Features.SimpleTaprootChannelsStaging)) { - ChannelTypes.SimpleTaprootChannelsStaging(scidAlias, zeroConf) + if (canUse(Features.SimpleTaprootChannels)) { + ChannelTypes.SimpleTaprootChannel(scidAlias, zeroConf) } else if (canUse(Features.SimpleTaprootChannelsPhoenix)) { ChannelTypes.SimpleTaprootChannelsPhoenix } else if (canUse(Features.AnchorOutputsZeroFeeHtlcTx)) { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala index 3248890918..84054ed739 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala @@ -78,7 +78,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui test("recv OpenChannel (simple taproot channels)", Tag(ChannelStateTestsTags.OptionSimpleTaproot)) { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - assert(open.channelType_opt.contains(ChannelTypes.SimpleTaprootChannelsStaging())) + assert(open.channelType_opt.contains(ChannelTypes.SimpleTaprootChannel())) alice2bob.forward(bob) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].commitmentFormat == ZeroFeeHtlcTxSimpleTaprootChannelCommitmentFormat) @@ -88,7 +88,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui test("recv OpenChannel (simple taproot channels, missing nonce)", Tag(ChannelStateTestsTags.OptionSimpleTaproot)) { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - assert(open.channelType_opt.contains(ChannelTypes.SimpleTaprootChannelsStaging())) + assert(open.channelType_opt.contains(ChannelTypes.SimpleTaprootChannel())) assert(open.commitNonce_opt.isDefined) alice2bob.forward(bob, open.copy(tlvStream = open.tlvStream.copy(records = open.tlvStream.records.filterNot(_.isInstanceOf[ChannelTlv.NextLocalNonceTlv])))) val error = bob2alice.expectMsgType[Error] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala index 57f24f17bd..70aef1a323 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala @@ -18,17 +18,20 @@ package fr.acinq.eclair.transactions import fr.acinq.bitcoin.ScriptFlags import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, Satoshi, SatoshiLong, Script, Transaction} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction} import fr.acinq.eclair.blockchain.fee.FeeratePerKw -import fr.acinq.eclair.crypto.keymanager.{ChannelKeys, LocalCommitmentKeys, RemoteCommitmentKeys} -import fr.acinq.eclair.reputation.Reputation +import fr.acinq.eclair.crypto.NonceGenerator +import fr.acinq.eclair.crypto.keymanager.{ChannelKeys, CommitmentPublicKeys, LocalCommitmentKeys, RemoteCommitmentKeys} import fr.acinq.eclair.transactions.Transactions._ import fr.acinq.eclair.wire.protocol.UpdateAddHtlc import fr.acinq.eclair.{ChannelTypeFeature, CltvExpiry, CltvExpiryDelta, Features, MilliSatoshi, MilliSatoshiLong, TestConstants} import grizzled.slf4j.Logging +import org.json4s.DefaultFormats +import org.json4s.jackson.JsonMethods import org.scalatest.funsuite.AnyFunSuite import scodec.bits._ +import java.io.File import scala.io.Source trait TestVectorsSpec extends AnyFunSuite with Logging { @@ -455,3 +458,159 @@ class AnchorOutputsZeroFeeHtlcTxTestVectorSpec extends TestVectorsSpec { override def channelFeatures: Set[ChannelTypeFeature] = Set(Features.StaticRemoteKey, Features.AnchorOutputsZeroFeeHtlcTx) // @formatter:on } + +class SimpleTaprootCommitmentsTestVectorSpec extends AnyFunSuite { + + implicit val formats: DefaultFormats.type = DefaultFormats + + case class TestFixture(params: TestParams, scripts: TestScripts, transactions: Seq[TestVector]) { + val fundingTx: Transaction = Transaction.read(scripts.funding.funding_tx_hex) + val fundingInfo: RedeemInfo = makeFundingScript( + params.keys.localFundingKey.publicKey, + params.keys.remoteFundingKey.publicKey, + ZeroFeeHtlcTxSimpleTaprootChannelCommitmentFormat + ) + val commitInput: InputInfo = makeFundingInputInfo( + fundingTx.txid, + 0, + Satoshi(params.funding_amount_satoshis), + params.keys.localFundingKey.publicKey, + params.keys.remoteFundingKey.publicKey, + ZeroFeeHtlcTxSimpleTaprootChannelCommitmentFormat + ) + } + + case class TestParams(seed: String, + funding_amount_satoshis: Long, + dust_limit_satoshis: Long, + csv_delay: Int, + commit_height: Long, + nums_point: String, + keys: TestKeys) { + val dustLimit: Satoshi = Satoshi(dust_limit_satoshis) + val toSelfDelay: CltvExpiryDelta = CltvExpiryDelta(csv_delay) + // Private keys used to generate and sign our local commitment transaction and HTLC transactions. + val localKeys: LocalCommitmentKeys = LocalCommitmentKeys( + ourDelayedPaymentKey = ChannelKeys.derivePerCommitmentKey(PrivateKey(ByteVector.fromValidHex(keys.local_delayed_payment_basepoint_secret)), PublicKey(ByteVector.fromValidHex(keys.local_per_commit_point))), + theirPaymentPublicKey = PrivateKey(ByteVector.fromValidHex(keys.remote_payment_basepoint_secret)).publicKey, + ourPaymentBasePoint = PrivateKey(ByteVector.fromValidHex(keys.local_payment_basepoint_secret)).publicKey, + ourHtlcKey = ChannelKeys.derivePerCommitmentKey(PrivateKey(ByteVector.fromValidHex(keys.local_htlc_basepoint_secret)), PublicKey(ByteVector.fromValidHex(keys.local_per_commit_point))), + theirHtlcPublicKey = ChannelKeys.remotePerCommitmentPublicKey(PrivateKey(ByteVector.fromValidHex(keys.remote_htlc_basepoint_secret)).publicKey, PublicKey(ByteVector.fromValidHex(keys.local_per_commit_point))), + revocationPublicKey = ChannelKeys.revocationPublicKey(PublicKey(ByteVector.fromValidHex(keys.remote_revocation_basepoint)), PublicKey(ByteVector.fromValidHex(keys.local_per_commit_point))) + ) + // Keys used to sign our HTLC transactions by the remote peer. + val remoteKeys: RemoteCommitmentKeys = RemoteCommitmentKeys( + ourPaymentKey = PrivateKey(ByteVector.fromValidHex(keys.remote_payment_basepoint_secret)), + theirDelayedPaymentPublicKey = localKeys.ourDelayedPaymentKey.publicKey, + ourPaymentBasePoint = PrivateKey(ByteVector.fromValidHex(keys.remote_payment_basepoint_secret)).publicKey, + ourHtlcKey = ChannelKeys.derivePerCommitmentKey(PrivateKey(ByteVector.fromValidHex(keys.remote_htlc_basepoint_secret)), PublicKey(ByteVector.fromValidHex(keys.local_per_commit_point))), + theirHtlcPublicKey = localKeys.ourHtlcKey.publicKey, + revocationPublicKey = localKeys.revocationPublicKey + ) + } + + case class TestKeys(local_funding_privkey: String, + local_funding_pubkey: String, + remote_funding_privkey: String, + remote_funding_pubkey: String, + local_payment_basepoint_secret: String, + local_payment_basepoint: String, + remote_payment_basepoint_secret: String, + remote_payment_basepoint: String, + local_delayed_payment_basepoint_secret: String, + local_delayed_payment_basepoint: String, + remote_revocation_basepoint_secret: String, + remote_revocation_basepoint: String, + local_htlc_basepoint_secret: String, + local_htlc_basepoint: String, + remote_htlc_basepoint_secret: String, + remote_htlc_basepoint: String, + local_per_commit_secret: String, + local_per_commit_point: String, + derived_local_delayed_pubkey: String, + derived_revocation_pubkey: String, + derived_local_htlc_pubkey: String, + derived_remote_htlc_pubkey: String, + derived_remote_payment_pubkey: String) { + val localFundingKey: PrivateKey = PrivateKey(ByteVector.fromValidHex(local_funding_privkey)) + val remoteFundingKey: PrivateKey = PrivateKey(ByteVector.fromValidHex(remote_funding_privkey)) + } + + case class TestScripts(funding: TestFundingTx) + + case class TestFundingTx(funding_tx_hex: String) + + case class TestVector(name: String, + local_balance_msat: Long, + remote_balance_msat: Long, + fee_per_kw: Long, + htlcs: Seq[TestHtlc], + remote_partial_sig: String, + expected_commitment_tx_hex: String, + htlc_descs: Seq[TestHtlcTx]) { + val spec = CommitmentSpec( + htlcs = htlcs.zipWithIndex.map { + case (htlc, i) if htlc.incoming => IncomingHtlc(htlc.withId(i)) + case (htlc, i) => OutgoingHtlc(htlc.withId(i)) + }.toSet, + commitTxFeerate = FeeratePerKw(Satoshi(fee_per_kw)), + toLocal = MilliSatoshi(local_balance_msat), + toRemote = MilliSatoshi(remote_balance_msat), + ) + } + + case class TestHtlc(incoming: Boolean, amount_msat: Long, expiry: Long, preimage: String) { + def withId(id: Long): UpdateAddHtlc = UpdateAddHtlc(ByteVector32.Zeroes, id, MilliSatoshi(amount_msat), Crypto.sha256(ByteVector32.fromValidHex(preimage)), CltvExpiry(expiry), TestConstants.emptyOnionPacket, None, accountable = false, None) + } + + case class TestHtlcTx(remote_partial_sig_hex: String, resolution_tx_hex: String) + + test("simple-taproot-commitments (Bolt3 reference test vector)") { + val src = Source.fromFile(new File(getClass.getResource("/bolt3-tx-test-vectors-simple-taproot-commitment-format.json").getFile)) + val f = JsonMethods.parse(src.mkString).extract[TestFixture] + src.close() + import f._ + import f.params._ + + // We verify that keys are generated correctly. + assert(localKeys.publicKeys == CommitmentPublicKeys( + localDelayedPaymentPublicKey = PublicKey(ByteVector.fromValidHex(keys.derived_local_delayed_pubkey)), + remotePaymentPublicKey = PublicKey(ByteVector.fromValidHex(keys.derived_remote_payment_pubkey)), + localHtlcPublicKey = PublicKey(ByteVector.fromValidHex(keys.derived_local_htlc_pubkey)), + remoteHtlcPublicKey = PublicKey(ByteVector.fromValidHex(keys.derived_remote_htlc_pubkey)), + revocationPublicKey = PublicKey(ByteVector.fromValidHex(keys.derived_revocation_pubkey)), + )) + + transactions.foreach(t => { + // We verify that commitment transactions match. + val outputs = makeCommitTxOutputs(keys.localFundingKey.publicKey, keys.remoteFundingKey.publicKey, localKeys.publicKeys, payCommitTxFees = true, dustLimit, toSelfDelay, t.spec, ZeroFeeHtlcTxSimpleTaprootChannelCommitmentFormat) + val txInfo = makeCommitTx(commitInput, commit_height, localKeys.ourPaymentBasePoint, remoteKeys.ourPaymentBasePoint, localIsChannelOpener = true, outputs) + val localNonce = NonceGenerator.verificationNonce(fundingTx.txid, keys.localFundingKey, keys.remoteFundingKey.publicKey, commit_height) + val remoteNonce = NonceGenerator.signingNonce(keys.remoteFundingKey.publicKey, keys.localFundingKey.publicKey, fundingTx.txid) + val localSig = txInfo.partialSign(keys.localFundingKey, keys.remoteFundingKey.publicKey, localNonce, Seq(localNonce.publicNonce, remoteNonce.publicNonce)).toOption.get + val remoteSig = txInfo.partialSign(keys.remoteFundingKey, keys.localFundingKey.publicKey, remoteNonce, Seq(localNonce.publicNonce, remoteNonce.publicNonce)).toOption.get + val commitTx = txInfo.aggregateSigs(keys.localFundingKey.publicKey, keys.remoteFundingKey.publicKey, localSig, remoteSig).toOption.get + Transaction.correctlySpends(commitTx, Seq(fundingTx), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) + // TODO: we need to figure out how the signature from the test vector was generated. + val expectedCommitTx = Transaction.read(t.expected_commitment_tx_hex) + assert(commitTx.updateWitness(0, ScriptWitness.empty).toString() == expectedCommitTx.updateWitness(0, ScriptWitness.empty).toString()) + // We verify that HTLC transactions match. + val unsignedHtlcTxs = makeHtlcTxs(commitTx, outputs, ZeroFeeHtlcTxSimpleTaprootChannelCommitmentFormat) + assert(unsignedHtlcTxs.size == t.htlc_descs.size) + assert(unsignedHtlcTxs.map(_.input.outPoint) == t.htlc_descs.map(d => Transaction.read(d.resolution_tx_hex).txIn.head.outPoint)) + val preimages = t.htlcs.map(htlc => Crypto.sha256(ByteVector.fromValidHex(htlc.preimage)) -> ByteVector32.fromValidHex(htlc.preimage)).toMap + unsignedHtlcTxs.zip(t.htlc_descs).foreach { case (unsignedHtlcTx, desc) => + assert(unsignedHtlcTx.tx == Transaction.read(desc.resolution_tx_hex).updateWitness(0, ScriptWitness.empty)) + val remoteSig = ByteVector64.fromValidHex(desc.remote_partial_sig_hex) + assert(unsignedHtlcTx.checkRemoteSig(localKeys, remoteSig)) + val signedTx = unsignedHtlcTx match { + case htlcTx: UnsignedHtlcSuccessTx => htlcTx.addRemoteSig(localKeys, remoteSig, preimages(htlcTx.paymentHash)).sign() + case htlcTx: UnsignedHtlcTimeoutTx => htlcTx.addRemoteSig(localKeys, remoteSig).sign() + } + Transaction.correctlySpends(signedTx, Seq(commitTx), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) + assert(signedTx.toString() == desc.resolution_tx_hex) + } + }) + } + +} \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala index 2d6cf5d52b..20aa5a05ac 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala @@ -304,7 +304,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { defaultEncoded ++ hex"0000" ++ hex"0107 04400000101000" -> defaultOpen.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty), ChannelTlv.ChannelTypeTlv(ChannelTypes.AnchorOutputs(scidAlias = true, zeroConf = true)))), defaultEncoded ++ hex"0000" ++ hex"0107 04400000401000" -> defaultOpen.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty), ChannelTlv.ChannelTypeTlv(ChannelTypes.AnchorOutputsZeroFeeHtlcTx(scidAlias = true, zeroConf = true)))), // taproot channel type + nonce - defaultEncoded ++ hex"0000" ++ hex"01 17 1000000000000000000000000000000000400000000000" ++ hex"04 42 2062534ccb3be5a8997843f3b6bc530a94cbc60eceb538674ceedd62d8be07f2dfa5df6acf3ded7444268d56925bb2c33afe71a55f4fa88f3985451a681415930f6b" -> defaultOpen.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty), ChannelTlv.ChannelTypeTlv(ChannelTypes.SimpleTaprootChannelsStaging(scidAlias = true)), ChannelTlv.NextLocalNonceTlv(nonce))) + defaultEncoded ++ hex"0000" ++ hex"01 0b 0100000000400000000000" ++ hex"04 42 2062534ccb3be5a8997843f3b6bc530a94cbc60eceb538674ceedd62d8be07f2dfa5df6acf3ded7444268d56925bb2c33afe71a55f4fa88f3985451a681415930f6b" -> defaultOpen.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty), ChannelTlv.ChannelTypeTlv(ChannelTypes.SimpleTaprootChannel(scidAlias = true)), ChannelTlv.NextLocalNonceTlv(nonce))) ) for ((encoded, expected) <- testCases) { @@ -378,7 +378,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { defaultEncoded ++ hex"0000" -> defaultAccept.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty))), // empty upfront_shutdown_script defaultEncoded ++ hex"0000" ++ hex"0100" -> defaultAccept.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty), ChannelTlv.ChannelTypeTlv(ChannelTypes.UnsupportedChannelType(Features.empty)))), // empty upfront_shutdown_script with channel type defaultEncoded ++ hex"0004 01abcdef" -> defaultAccept.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(hex"01abcdef"))), // non-empty upfront_shutdown_script - defaultEncoded ++ hex"0000" ++ hex"01 17 1000000000000000000000000000000000000000000000" ++ hex"04 42 2062534ccb3be5a8997843f3b6bc530a94cbc60eceb538674ceedd62d8be07f2dfa5df6acf3ded7444268d56925bb2c33afe71a55f4fa88f3985451a681415930f6b" -> defaultAccept.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty), ChannelTlv.ChannelTypeTlv(ChannelTypes.SimpleTaprootChannelsStaging()), ChannelTlv.NextLocalNonceTlv(nonce))), // empty upfront_shutdown_script with taproot channel type and nonce + defaultEncoded ++ hex"0000" ++ hex"01 0b 0100000000000000000000" ++ hex"04 42 2062534ccb3be5a8997843f3b6bc530a94cbc60eceb538674ceedd62d8be07f2dfa5df6acf3ded7444268d56925bb2c33afe71a55f4fa88f3985451a681415930f6b" -> defaultAccept.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty), ChannelTlv.ChannelTypeTlv(ChannelTypes.SimpleTaprootChannel()), ChannelTlv.NextLocalNonceTlv(nonce))), // empty upfront_shutdown_script with taproot channel type and nonce defaultEncoded ++ hex"0004 01abcdef" ++ hex"0103401000" -> defaultAccept.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(hex"01abcdef"), ChannelTlv.ChannelTypeTlv(ChannelTypes.AnchorOutputsZeroFeeHtlcTx()))), // non-empty upfront_shutdown_script with channel type defaultEncoded ++ hex"0000 0302002a 050102" -> defaultAccept.copy(tlvStream = TlvStream(Set[AcceptChannelTlv](ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty)), Set(GenericTlv(UInt64(3), hex"002a"), GenericTlv(UInt64(5), hex"02")))), // empty upfront_shutdown_script + unknown odd tlv records defaultEncoded ++ hex"0002 1234 0303010203" -> defaultAccept.copy(tlvStream = TlvStream(Set[AcceptChannelTlv](ChannelTlv.UpfrontShutdownScriptTlv(hex"1234")), Set(GenericTlv(UInt64(3), hex"010203")))), // non-empty upfront_shutdown_script + unknown odd tlv records diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala index d598dc2f97..f45501a107 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala @@ -37,10 +37,10 @@ trait Channel { ChannelTypes.AnchorOutputsZeroFeeHtlcTx(zeroConf = true), ChannelTypes.AnchorOutputsZeroFeeHtlcTx(scidAlias = true), ChannelTypes.AnchorOutputsZeroFeeHtlcTx(scidAlias = true, zeroConf = true), - ChannelTypes.SimpleTaprootChannelsStaging(), - ChannelTypes.SimpleTaprootChannelsStaging(zeroConf = true), - ChannelTypes.SimpleTaprootChannelsStaging(scidAlias = true), - ChannelTypes.SimpleTaprootChannelsStaging(scidAlias = true, zeroConf = true), + ChannelTypes.SimpleTaprootChannel(), + ChannelTypes.SimpleTaprootChannel(zeroConf = true), + ChannelTypes.SimpleTaprootChannel(scidAlias = true), + ChannelTypes.SimpleTaprootChannel(scidAlias = true, zeroConf = true) ).map(ct => ct.toString -> ct).toMap // we use the toString method as name in the api val open: Route = postRequest("open") { implicit t =>