Correctly handle unknown flags in `channel_update` (#3341)
What changed, and why it matters
This commit fixes a bug in how Eclair handled unknown flag bits in Lightning 'channel_update' messages. Previously, the software silently cleared any flag bits it did not recognize when re-encoding a message before forwarding it. Because those flag bits are part of the signed data, clearing them made the digital signature invalid. The fix now preserves all unknown flag bits through a decode-encode round trip, so older Eclair nodes can still correctly relay future channel updates that use newly defined flags.
Treat this as a protocol-forward-compatibility and denial-of-service-prevention fix. Nodes running the old code would drop or propagate invalid channel updates once future BOLT specifications define new flag bits, so upgrading is recommended. Review whether any persisted channel-update data decoded under the old codec lost unknown bits and may need re-validation from the network.
Security signals we found
Signature invalidation through lossy codec round-trip
Unknown protocol flag bits silently zeroed before forwarding
Future protocol compatibility / forward-compatibility fix
BOLT 7 channel_update message handling
Test added for unknown flags preserving signature validity
Evidence from the diff
The patch changes the codec definitions for ChannelUpdate.MessageFlags and ChannelUpdate.ChannelFlags. Before, the codecs used ignore(N) for the upper six bits of each one-byte flag field, which dropped unknown bits on decode. On re-encode those bits were written as 0, altering the signed payload and breaking the ECDSA signature. The new codecs explicitly decode all eight bits into named flag fields (flag2..flag7) and re-encode them unchanged. Companion case classes and JSON serializers are updated to store and output the extra bits. New tests verify that a channel_update with unknown message and channel flags set still validates and round-trips with its signature intact.
Changed components
eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scalaeclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scalaChannelUpdate messageFlagsCodec and channelFlagsCodecChannelUpdate.MessageFlags and ChannelUpdate.ChannelFlags case classesJSON serialization of channel update flagsInspect captured patch +118 / −17
### eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecs.scala
@@ -335,12 +335,12 @@ object LightningMessageCodecs {
("signature" | bytes64) ::
nodeAnnouncementWitnessCodec).as[NodeAnnouncement]
- val messageFlagsCodec = ("messageFlags" | (ignore(6) :: bool :: constant(bin"1"))).as[ChannelUpdate.MessageFlags]
+ val messageFlagsCodec = ("messageFlags" | (bool :: bool :: bool :: bool :: bool :: bool :: bool :: constant(bin"1"))).as[ChannelUpdate.MessageFlags]
val reverseBool: Codec[Boolean] = bool.xmap[Boolean](b => !b, b => !b)
- /** BOLT 7 defines a 'disable' bit and a 'direction' bit, but it's easier to understand if we take the reverse. */
- val channelFlagsCodec = ("channelFlags" | (ignore(6) :: reverseBool :: reverseBool)).as[ChannelUpdate.ChannelFlags]
+ /** BOLT 7 defines a 'disable' bit (position 1) and a 'direction' bit (position 0), but it's easier to understand if we take the reverse. */
+ val channelFlagsCodec = ("channelFlags" | (bool :: bool :: bool :: bool :: bool :: bool :: reverseBool :: reverseBool)).as[ChannelUpdate.ChannelFlags]
val channelUpdateChecksumCodec =
("chainHash" | blockHash) ::
### eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala
@@ -778,13 +778,19 @@ case class ChannelUpdate(signature: ByteVector64,
}
object ChannelUpdate {
- case class MessageFlags(dontForward: Boolean)
+ case class MessageFlags(flag7: Boolean, flag6: Boolean, flag5: Boolean, flag4: Boolean, flag3: Boolean, flag2: Boolean, dontForward: Boolean)
- case class ChannelFlags(isEnabled: Boolean, isNode1: Boolean)
+ object MessageFlags {
+ def apply(dontForward: Boolean): MessageFlags = MessageFlags(flag7 = false, flag6 = false, flag5 = false, flag4 = false, flag3 = false, flag2 = false, dontForward)
+ }
+
+ case class ChannelFlags(flag7: Boolean, flag6: Boolean, flag5: Boolean, flag4: Boolean, flag3: Boolean, flag2: Boolean, isEnabled: Boolean, isNode1: Boolean)
object ChannelFlags {
/** for tests */
- val DUMMY: ChannelFlags = ChannelFlags(isEnabled = true, isNode1 = true)
+ val DUMMY: ChannelFlags = ChannelFlags(flag7 = false, flag6 = false, flag5 = false, flag4 = false, flag3 = false, flag2 = false, isEnabled = true, isNode1 = true)
+
+ def apply(isEnabled: Boolean, isNode1: Boolean): ChannelFlags = ChannelFlags(flag7 = false, flag6 = false, flag5 = false, flag4 = false, flag3 = false, flag2 = false, isEnabled = isEnabled, isNode1 = isNode1)
}
}
### eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced-splice/data.json
@@ -264,9 +264,21 @@
"unix" : 1757058126
},
"messageFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"dontForward" : false
},
"channelFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"isEnabled" : true,
"isNode1" : true
},
### eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/announced/data.json
@@ -162,9 +162,21 @@
"unix" : 1757057800
},
"messageFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"dontForward" : false
},
"channelFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"isEnabled" : true,
"isNode1" : true
},
### eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/fundee/data.json
@@ -170,9 +170,21 @@
"unix" : 1757057697
},
"messageFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"dontForward" : true
},
"channelFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"isEnabled" : true,
"isNode1" : false
},
### eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/funder/data.json
@@ -301,9 +301,21 @@
"unix" : 1757057504
},
"messageFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"dontForward" : true
},
"channelFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"isEnabled" : true,
"isNode1" : true
},
### eclair-core/src/test/resources/nonreg/codecs/050006-DATA_NORMAL/splice-commitment-upgrade/data.json
@@ -301,9 +301,21 @@
"unix" : 1757057979
},
"messageFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"dontForward" : true
},
"channelFlags" : {
+ "flag7" : false,
+ "flag6" : false,
+ "flag5" : false,
+ "flag4" : false,
+ "flag3" : false,
+ "flag2" : false,
"isEnabled" : true,
"isNode1" : true
},
### eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala
@@ -239,8 +239,25 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat
| "chainHash": "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f",
| "shortChannelId": "0x0x0",
| "timestamp": { "iso": "1970-01-01T00:00:00Z", "unix": 0 },
- | "messageFlags": { "dontForward": false },
- | "channelFlags": { "isEnabled": true, "isNode1": true },
+ | "messageFlags": {
+ | "flag7" : false,
+ | "flag6" : false,
+ | "flag5" : false,
+ | "flag4" : false,
+ | "flag3" : false,
+ | "flag2" : false,
+ | "dontForward": false
+ | },
+ | "channelFlags": {
+ | "flag7" : false,
+ | "flag6" : false,
+ | "flag5" : false,
+ | "flag4" : false,
+ | "flag3" : false,
+ | "flag2" : false,
+ | "isEnabled": true,
+ | "isNode1": true
+ | },
| "cltvExpiryDelta": 12,
| "htlcMinimumMsat": 1,
| "feeBaseMsat": 100,
### eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala
@@ -781,27 +781,45 @@ class LightningMessageCodecsSpec extends AnyFunSuite {
}
test("reject channel_update without htlc_maximum_msat") {
- // {"signature":"12540b6a236e21932622d61432f52913d9442cc09a1057c386119a286153f8681c66d2a0f17d32505ba71bb37c8edcfa9c11e151b2b38dae98b825eff1c040b3","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"558351x1422x1","timestamp":{"iso":"2020-03-12T17:58:06Z","unix":1584035886},"channelFlags":{"isEnabled":true,"isNode1":true},"cltvExpiryDelta":144,"htlcMinimumMsat":1000,"feeBaseMsat":1000,"feeProportionalMillionths":2}
val bin = hex"12540b6a236e21932622d61432f52913d9442cc09a1057c386119a286153f8681c66d2a0f17d32505ba71bb37c8edcfa9c11e151b2b38dae98b825eff1c040b36fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000008850f00058e00015e6a782e0000009000000000000003e8000003e800000002"
assert(channelUpdateCodec.decode(bin.bits).isFailure)
}
+ test("support channel_update with unknown message and channel flags") {
+ val bin = hex"01027d939649ea0bc83acecef6d7d68df32367d91232df3fc5457faa322aece323f61bf6e580b8c184f9e2546621c6d9ad2c657165b6ff2e2db767a9ccdad6b355ff06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0eaa720004dd00006a72ff233588002400000000000000010000000a000000960000000005f5e100"
+ val nodeId = PublicKey(hex"03884feff6e19f6c5153502bb19282cea0e57d68e172a2b97d8a89ddd88cbcdbbe")
+ val update = lightningMessageCodec.decode(bin.bits).require.value.asInstanceOf[ChannelUpdate]
+ assert(Announcements.checkSig(update, nodeId))
+ // Some unknown flags are set.
+ assert(update.messageFlags.flag5)
+ assert(update.messageFlags.flag4)
+ assert(update.messageFlags.flag2)
+ assert(update.channelFlags.flag7)
+ assert(update.channelFlags.flag3)
+ // The signature is still correct after an encoding round-trip.
+ assert(bin == lightningMessageCodec.encode(update).require.bytes)
+ assert(Announcements.checkSig(lightningMessageCodec.decode(lightningMessageCodec.encode(update).require).require.value.asInstanceOf[ChannelUpdate], nodeId))
+ }
+
test("non-regression on channel_update") {
val bins = Map(
hex"3b6bb4872825450ff29d0b46f5835751329b0394a10ac792e4ba2a23b4f17bcc4e5834d1424787830be0ee3d22ac99e674d121f25d19ed931aaabb8ed0eec0fb6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000086a4e000a9700016137e9e9010200900000000000000001000003e800000001000000001dcd6500" ->
- """{"signature":"3b6bb4872825450ff29d0b46f5835751329b0394a10ac792e4ba2a23b4f17bcc4e5834d1424787830be0ee3d22ac99e674d121f25d19ed931aaabb8ed0eec0fb","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"551502x2711x1","timestamp":{"iso":"2021-09-07T22:38:33Z","unix":1631054313},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":false,"isNode1":true},"cltvExpiryDelta":144,"htlcMinimumMsat":1,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":500000000,"tlvStream":{}}""",
+ """{"signature":"3b6bb4872825450ff29d0b46f5835751329b0394a10ac792e4ba2a23b4f17bcc4e5834d1424787830be0ee3d22ac99e674d121f25d19ed931aaabb8ed0eec0fb","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"551502x2711x1","timestamp":{"iso":"2021-09-07T22:38:33Z","unix":1631054313},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":false,"isNode1":true},"cltvExpiryDelta":144,"htlcMinimumMsat":1,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":500000000,"tlvStream":{}}""",
hex"8efb98c939aba422a1f2ccd3e05e5471be41c54ac5d7cb27b9aaaecea45f3abb363907644c44b385d83ef6b577061847396d6d3464e4f1fa9e779395e36703ef6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000a79dd00098800006137f9ba0100002800000000000003e800000000000003e800000000938580c0" ->
- """{"signature":"8efb98c939aba422a1f2ccd3e05e5471be41c54ac5d7cb27b9aaaecea45f3abb363907644c44b385d83ef6b577061847396d6d3464e4f1fa9e779395e36703ef","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"686557x2440x0","timestamp":{"iso":"2021-09-07T23:46:02Z","unix":1631058362},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":true,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":0,"feeProportionalMillionths":1000,"htlcMaximumMsat":2475000000,"tlvStream":{}}""",
+ """{"signature":"8efb98c939aba422a1f2ccd3e05e5471be41c54ac5d7cb27b9aaaecea45f3abb363907644c44b385d83ef6b577061847396d6d3464e4f1fa9e779395e36703ef","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"686557x2440x0","timestamp":{"iso":"2021-09-07T23:46:02Z","unix":1631058362},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":true,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":0,"feeProportionalMillionths":1000,"htlcMaximumMsat":2475000000,"tlvStream":{}}""",
hex"b212e4d88a5ce3201ec34160d90a07eeb0601207d7d53bcf2b8f99b21146d7eb00d6a5b4b80b878eac0d25c2209eda05c913851730a65260c943fec8956cb22e6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000a48ce0006900000613792e40100002800000000000003e8000003e8000000010000000056d35b20" ->
- """{"signature":"b212e4d88a5ce3201ec34160d90a07eeb0601207d7d53bcf2b8f99b21146d7eb00d6a5b4b80b878eac0d25c2209eda05c913851730a65260c943fec8956cb22e","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"673998x1680x0","timestamp":{"iso":"2021-09-07T16:27:16Z","unix":1631032036},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":true,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":1456692000,"tlvStream":{}}""",
+ """{"signature":"b212e4d88a5ce3201ec34160d90a07eeb0601207d7d53bcf2b8f99b21146d7eb00d6a5b4b80b878eac0d25c2209eda05c913851730a65260c943fec8956cb22e","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"673998x1680x0","timestamp":{"iso":"2021-09-07T16:27:16Z","unix":1631032036},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":true,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":1456692000,"tlvStream":{}}""",
hex"29396591aee1bfd292193b4329d24eb9f57ddb143f303d029ae004113a7402af015c721ddc3e5d2e36cc67c92af3bdcd22d55eaf1e532503f9972207b226984f6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000096f010006ea000061375a440102002800000000000003e8000003e800000001000000024e160300" ->
- """{"signature":"29396591aee1bfd292193b4329d24eb9f57ddb143f303d029ae004113a7402af015c721ddc3e5d2e36cc67c92af3bdcd22d55eaf1e532503f9972207b226984f","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"618241x1770x0","timestamp":{"iso":"2021-09-07T12:25:40Z","unix":1631017540},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":false,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":9900000000,"tlvStream":{}}""",
+ """{"signature":"29396591aee1bfd292193b4329d24eb9f57ddb143f303d029ae004113a7402af015c721ddc3e5d2e36cc67c92af3bdcd22d55eaf1e532503f9972207b226984f","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"618241x1770x0","timestamp":{"iso":"2021-09-07T12:25:40Z","unix":1631017540},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":false,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":9900000000,"tlvStream":{}}""",
hex"3c6de66a61f2b8803537a2d92e7b82db1b44eac664ed6b7f5c7b5360b21d7ce32e5238e98d54701fe6d5b9109b2a2d875878a12d254eb6d651843b787f1ba5de6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000a921f0003fc000461386d9e0100002800000000000003e8000003e80000000100000000ec08ce00" ->
- """{"signature":"3c6de66a61f2b8803537a2d92e7b82db1b44eac664ed6b7f5c7b5360b21d7ce32e5238e98d54701fe6d5b9109b2a2d875878a12d254eb6d651843b787f1ba5de","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"692767x1020x4","timestamp":{"iso":"2021-09-08T08:00:30Z","unix":1631088030},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":true,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":3960000000,"tlvStream":{}}""",
+ """{"signature":"3c6de66a61f2b8803537a2d92e7b82db1b44eac664ed6b7f5c7b5360b21d7ce32e5238e98d54701fe6d5b9109b2a2d875878a12d254eb6d651843b787f1ba5de","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"692767x1020x4","timestamp":{"iso":"2021-09-08T08:00:30Z","unix":1631088030},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":true,"isNode1":true},"cltvExpiryDelta":40,"htlcMinimumMsat":1000,"feeBaseMsat":1000,"feeProportionalMillionths":1,"htlcMaximumMsat":3960000000,"tlvStream":{}}""",
hex"180de159377d68ecc3b327594bfb7408374811f3c98b5982af1520802796025a1430a6049294ebc0030518cc9b56a574c38c316122cb674f972734d7054d0b546fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000868f200029a00006137935701030028000000000000000000000001000002bc0000000001c9c380" ->
- """{"signature":"180de159377d68ecc3b327594bfb7408374811f3c98b5982af1520802796025a1430a6049294ebc0030518cc9b56a574c38c316122cb674f972734d7054d0b54","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"551154x666x0","timestamp":{"iso":"2021-09-07T16:29:11Z","unix":1631032151},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":false,"isNode1":false},"cltvExpiryDelta":40,"htlcMinimumMsat":0,"feeBaseMsat":1,"feeProportionalMillionths":700,"htlcMaximumMsat":30000000,"tlvStream":{}}""",
+ """{"signature":"180de159377d68ecc3b327594bfb7408374811f3c98b5982af1520802796025a1430a6049294ebc0030518cc9b56a574c38c316122cb674f972734d7054d0b54","chainHash":"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000","shortChannelId":"551154x666x0","timestamp":{"iso":"2021-09-07T16:29:11Z","unix":1631032151},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":false,"isNode1":false},"cltvExpiryDelta":40,"htlcMinimumMsat":0,"feeBaseMsat":1,"feeProportionalMillionths":700,"htlcMaximumMsat":30000000,"tlvStream":{}}""",
hex"cb6aacede86c15cb64f2513e357e1fe2384dd17b8e613608dfdca48cf884043c3431faaccc1e2417cbe938213686efe15e0d0549c75bb66c1675a4909e8e60ee06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000000000000023162ea9b1f03010024000000000000003200000064000000fa0000000002faf080" ->
- """{"signature":"cb6aacede86c15cb64f2513e357e1fe2384dd17b8e613608dfdca48cf884043c3431faaccc1e2417cbe938213686efe15e0d0549c75bb66c1675a4909e8e60ee","chainHash":"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f","shortChannelId":"0x0x561","timestamp":{"iso":"2022-08-03T15:58:23Z","unix":1659542303},"messageFlags":{"dontForward":true},"channelFlags":{"isEnabled":true,"isNode1":false},"cltvExpiryDelta":36,"htlcMinimumMsat":50,"feeBaseMsat":100,"feeProportionalMillionths":250,"htlcMaximumMsat":50000000,"tlvStream":{}}"""
+ """{"signature":"cb6aacede86c15cb64f2513e357e1fe2384dd17b8e613608dfdca48cf884043c3431faaccc1e2417cbe938213686efe15e0d0549c75bb66c1675a4909e8e60ee","chainHash":"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f","shortChannelId":"0x0x561","timestamp":{"iso":"2022-08-03T15:58:23Z","unix":1659542303},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":true},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":true,"isNode1":false},"cltvExpiryDelta":36,"htlcMinimumMsat":50,"feeBaseMsat":100,"feeProportionalMillionths":250,"htlcMaximumMsat":50000000,"tlvStream":{}}""",
+ // We are forward-compatible with message and channel flags that we don't understand:
+ hex"7d939649ea0bc83acecef6d7d68df32367d91232df3fc5457faa322aece323f61bf6e580b8c184f9e2546621c6d9ad2c657165b6ff2e2db767a9ccdad6b355ff06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0eaa720004dd00006a72ff233588002400000000000000010000000a000000960000000005f5e100" ->
+ """{"signature":"7d939649ea0bc83acecef6d7d68df32367d91232df3fc5457faa322aece323f61bf6e580b8c184f9e2546621c6d9ad2c657165b6ff2e2db767a9ccdad6b355ff","chainHash":"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f","shortChannelId":"961138x1245x0","timestamp":{"iso":"2026-08-05T09:15:15Z","unix":1785921315},"messageFlags":{"flag7":false,"flag6":false,"flag5":true,"flag4":true,"flag3":false,"flag2":true,"dontForward":false},"channelFlags":{"flag7":true,"flag6":false,"flag5":false,"flag4":false,"flag3":true,"flag2":false,"isEnabled":true,"isNode1":true},"cltvExpiryDelta":36,"htlcMinimumMsat":1,"feeBaseMsat":10,"feeProportionalMillionths":150,"htlcMaximumMsat":100000000,"tlvStream":{}}"""
)
for ((bin, ref) <- bins) {
val decoded = channelUpdateCodec.decode(bin.bits).require
### eclair-node/src/test/resources/api/findroute-full
@@ -1 +1 @@
-{"routes":[{"amount":456,"hops":[{"nodeId":"03007e67dc5a8fd2b2ef21cb310ab6359ddb51f3f86a8b79b8b1e23bc3a6ea150a","nextNodeId":"026105f6cb4862810be989385d16f04b0f748f6f2a14040338b1a534d45b4be1c1","source":{"type":"announcement","channelUpdate":{"signature":"92cf3f12e161391986eb2cd7106ddab41a23c734f8f1ed120fb64f4b91f98f690ecf930388e62965f8aefbf1adafcd25a572669a125396dcfb83615208754679","chainHash":"024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2","shortChannelId":"1x2x3","timestamp":{"iso":"1970-01-01T00:00:00Z","unix":0},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":true,"isNode1":true},"cltvExpiryDelta":0,"htlcMinimumMsat":1,"feeBaseMsat":1,"feeProportionalMillionths":1,"htlcMaximumMsat":20000000,"tlvStream":{}}}},{"nodeId":"026105f6cb4862810be989385d16f04b0f748f6f2a14040338b1a534d45b4be1c1","nextNodeId":"038cfa2b5857843ee90cff91b06f692c0d8fe201921ee6387aee901d64f43699f0","source":{"type":"announcement","channelUpdate":{"signature":"92cf3f12e161391986eb2cd7106ddab41a23c734f8f1ed120fb64f4b91f98f690ecf930388e62965f8aefbf1adafcd25a572669a125396dcfb83615208754679","chainHash":"024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2","shortChannelId":"1x2x4","timestamp":{"iso":"1970-01-01T00:00:00Z","unix":0},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":true,"isNode1":true},"cltvExpiryDelta":0,"htlcMinimumMsat":1,"feeBaseMsat":1,"feeProportionalMillionths":1,"htlcMaximumMsat":20000000,"tlvStream":{}}}},{"nodeId":"038cfa2b5857843ee90cff91b06f692c0d8fe201921ee6387aee901d64f43699f0","nextNodeId":"02be60276e294c6921240daae33a361d214d02578656df0e74c61a09c3196e51df","source":{"type":"announcement","channelUpdate":{"signature":"92cf3f12e161391986eb2cd7106ddab41a23c734f8f1ed120fb64f4b91f98f690ecf930388e62965f8aefbf1adafcd25a572669a125396dcfb83615208754679","chainHash":"024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2","shortChannelId":"1x2x5","timestamp":{"iso":"1970-01-01T00:00:00Z","unix":0},"messageFlags":{"dontForward":false},"channelFlags":{"isEnabled":true,"isNode1":true},"cltvExpiryDelta":0,"htlcMinimumMsat":1,"feeBaseMsat":1,"feeProportionalMillionths":1,"htlcMaximumMsat":20000000,"tlvStream":{}}}}],"fee":2}]}
\ No newline at end of file
+{"routes":[{"amount":456,"hops":[{"nodeId":"03007e67dc5a8fd2b2ef21cb310ab6359ddb51f3f86a8b79b8b1e23bc3a6ea150a","nextNodeId":"026105f6cb4862810be989385d16f04b0f748f6f2a14040338b1a534d45b4be1c1","source":{"type":"announcement","channelUpdate":{"signature":"92cf3f12e161391986eb2cd7106ddab41a23c734f8f1ed120fb64f4b91f98f690ecf930388e62965f8aefbf1adafcd25a572669a125396dcfb83615208754679","chainHash":"024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2","shortChannelId":"1x2x3","timestamp":{"iso":"1970-01-01T00:00:00Z","unix":0},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":true,"isNode1":true},"cltvExpiryDelta":0,"htlcMinimumMsat":1,"feeBaseMsat":1,"feeProportionalMillionths":1,"htlcMaximumMsat":20000000,"tlvStream":{}}}},{"nodeId":"026105f6cb4862810be989385d16f04b0f748f6f2a14040338b1a534d45b4be1c1","nextNodeId":"038cfa2b5857843ee90cff91b06f692c0d8fe201921ee6387aee901d64f43699f0","source":{"type":"announcement","channelUpdate":{"signature":"92cf3f12e161391986eb2cd7106ddab41a23c734f8f1ed120fb64f4b91f98f690ecf930388e62965f8aefbf1adafcd25a572669a125396dcfb83615208754679","chainHash":"024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2","shortChannelId":"1x2x4","timestamp":{"iso":"1970-01-01T00:00:00Z","unix":0},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":true,"isNode1":true},"cltvExpiryDelta":0,"htlcMinimumMsat":1,"feeBaseMsat":1,"feeProportionalMillionths":1,"htlcMaximumMsat":20000000,"tlvStream":{}}}},{"nodeId":"038cfa2b5857843ee90cff91b06f692c0d8fe201921ee6387aee901d64f43699f0","nextNodeId":"02be60276e294c6921240daae33a361d214d02578656df0e74c61a09c3196e51df","source":{"type":"announcement","channelUpdate":{"signature":"92cf3f12e161391986eb2cd7106ddab41a23c734f8f1ed120fb64f4b91f98f690ecf930388e62965f8aefbf1adafcd25a572669a125396dcfb83615208754679","chainHash":"024b7b3626554c44dcc2454ee3812458bfa68d9fced466edfab470844cb7ffe2","shortChannelId":"1x2x5","timestamp":{"iso":"1970-01-01T00:00:00Z","unix":0},"messageFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"dontForward":false},"channelFlags":{"flag7":false,"flag6":false,"flag5":false,"flag4":false,"flag3":false,"flag2":false,"isEnabled":true,"isNode1":true},"cltvExpiryDelta":0,"htlcMinimumMsat":1,"feeBaseMsat":1,"feeProportionalMillionths":1,"htlcMaximumMsat":20000000,"tlvStream":{}}}}],"fee":2}]}
\ No newline at end of fileWhy this scored 64/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.