From fdeb3ce7e13c5d9cfc1b73e208b6d2e8a1eec61f Mon Sep 17 00:00:00 2001 From: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> Date: Mon, 15 Feb 2021 17:05:48 +0100 Subject: [PATCH] Correctly set gossip sync_complete (#1668) We are restoring the previous behavior of using the `sync_complete` field to signal the end of a `channel_range_query` sync. The first step is to correctly set that field, before we can read it and interpret it to mark the end of sync. See https://github.com/lightningnetwork/lightning-rfc/pull/826 --- .../scala/fr/acinq/eclair/router/Sync.scala | 16 +++--- .../eclair/wire/LightningMessageTypes.scala | 25 +++------ .../router/ChannelRangeQueriesSpec.scala | 53 +++++++++---------- .../acinq/eclair/router/RoutingSyncSpec.scala | 4 +- 4 files changed, 44 insertions(+), 54 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala index 725ecf74f6..cd97db6495 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala @@ -80,8 +80,9 @@ object Sync { log.info("replying with {} items for range=({}, {})", shortChannelIds.size, q.firstBlockNum, q.numberOfBlocks) val chunks = split(shortChannelIds, q.firstBlockNum, q.numberOfBlocks, routerConf.channelRangeChunkSize) Metrics.QueryChannelRange.Replies.withoutTags().record(chunks.size) - chunks.foreach { chunk => - val reply = buildReplyChannelRange(chunk, q.chainHash, routerConf.encodingType, q.queryFlags_opt, channels) + chunks.zipWithIndex.foreach { case (chunk, i) => + val syncComplete = i == chunks.size - 1 + val reply = buildReplyChannelRange(chunk, syncComplete, q.chainHash, routerConf.encodingType, q.queryFlags_opt, channels) origin.peerConnection ! reply Metrics.ReplyChannelRange.Blocks.withTag(Tags.Direction, Tags.Directions.Outgoing).record(reply.numberOfBlocks) Metrics.ReplyChannelRange.ShortChannelIds.withTag(Tags.Direction, Tags.Directions.Outgoing).record(reply.shortChannelIds.array.size) @@ -392,12 +393,13 @@ object Sync { case class ShortChannelIdsChunk(firstBlock: Long, numBlocks: Long, shortChannelIds: List[ShortChannelId]) { /** - * * @param maximumSize maximum size of the short channel ids list * @return a chunk with at most `maximumSize` ids */ - def enforceMaximumSize(maximumSize: Int) = { - if (shortChannelIds.size <= maximumSize) this else { + def enforceMaximumSize(maximumSize: Int): ShortChannelIdsChunk = { + if (shortChannelIds.size <= maximumSize) { + this + } else { // we use a random offset here, so even if shortChannelIds.size is much bigger than maximumSize (which should // not happen) peers will eventually receive info about all channels in this chunk val offset = Random.nextInt(shortChannelIds.size - maximumSize + 1) @@ -480,7 +482,7 @@ object Sync { * @param channels channels map * @return a ReplyChannelRange object */ - def buildReplyChannelRange(chunk: ShortChannelIdsChunk, chainHash: ByteVector32, defaultEncoding: EncodingType, queryFlags_opt: Option[QueryChannelRangeTlv.QueryFlags], channels: SortedMap[ShortChannelId, PublicChannel]): ReplyChannelRange = { + def buildReplyChannelRange(chunk: ShortChannelIdsChunk, syncComplete: Boolean, chainHash: ByteVector32, defaultEncoding: EncodingType, queryFlags_opt: Option[QueryChannelRangeTlv.QueryFlags], channels: SortedMap[ShortChannelId, PublicChannel]): ReplyChannelRange = { val encoding = if (chunk.shortChannelIds.isEmpty) EncodingType.UNCOMPRESSED else defaultEncoding val (timestamps, checksums) = queryFlags_opt match { case Some(extension) if extension.wantChecksums | extension.wantTimestamps => @@ -492,7 +494,7 @@ object Sync { case _ => (None, None) } ReplyChannelRange(chainHash, chunk.firstBlock, chunk.numBlocks, - complete = 1, + syncComplete = if (syncComplete) 1 else 0, shortChannelIds = EncodedShortChannelIds(encoding, chunk.shortChannelIds), timestamps = timestamps, checksums = checksums) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageTypes.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageTypes.scala index 56a7e23555..93b5cd7ef3 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageTypes.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageTypes.scala @@ -16,9 +16,6 @@ package fr.acinq.eclair.wire -import java.net.{Inet4Address, Inet6Address, InetAddress, InetSocketAddress} -import java.nio.charset.StandardCharsets - import com.google.common.base.Charsets import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Satoshi} @@ -27,6 +24,8 @@ import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, Features, MilliSatoshi, ShortChannelId, UInt64} import scodec.bits.ByteVector +import java.net.{Inet4Address, Inet6Address, InetAddress, InetSocketAddress} +import java.nio.charset.StandardCharsets import scala.util.Try /** @@ -246,27 +245,17 @@ case class EncodedShortChannelIds(encoding: EncodingType, array: List[ShortChann override def toString: String = s"EncodedShortChannelIds($encoding,${array.headOption.getOrElse("")}->${array.lastOption.getOrElse("")} size=${array.size})" } -case class QueryShortChannelIds(chainHash: ByteVector32, - shortChannelIds: EncodedShortChannelIds, - tlvStream: TlvStream[QueryShortChannelIdsTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash { +case class QueryShortChannelIds(chainHash: ByteVector32, shortChannelIds: EncodedShortChannelIds, tlvStream: TlvStream[QueryShortChannelIdsTlv] = TlvStream.empty) extends RoutingMessage with HasChainHash { val queryFlags_opt: Option[QueryShortChannelIdsTlv.EncodedQueryFlags] = tlvStream.get[QueryShortChannelIdsTlv.EncodedQueryFlags] } case class ReplyShortChannelIdsEnd(chainHash: ByteVector32, complete: Byte) extends RoutingMessage with HasChainHash -case class QueryChannelRange(chainHash: ByteVector32, - firstBlockNum: Long, - numberOfBlocks: Long, - tlvStream: TlvStream[QueryChannelRangeTlv] = TlvStream.empty) extends RoutingMessage { +case class QueryChannelRange(chainHash: ByteVector32, firstBlockNum: Long, numberOfBlocks: Long, tlvStream: TlvStream[QueryChannelRangeTlv] = TlvStream.empty) extends RoutingMessage { val queryFlags_opt: Option[QueryChannelRangeTlv.QueryFlags] = tlvStream.get[QueryChannelRangeTlv.QueryFlags] } -case class ReplyChannelRange(chainHash: ByteVector32, - firstBlockNum: Long, - numberOfBlocks: Long, - complete: Byte, - shortChannelIds: EncodedShortChannelIds, - tlvStream: TlvStream[ReplyChannelRangeTlv] = TlvStream.empty) extends RoutingMessage { +case class ReplyChannelRange(chainHash: ByteVector32, firstBlockNum: Long, numberOfBlocks: Long, syncComplete: Byte, shortChannelIds: EncodedShortChannelIds, tlvStream: TlvStream[ReplyChannelRangeTlv] = TlvStream.empty) extends RoutingMessage { val timestamps_opt: Option[ReplyChannelRangeTlv.EncodedTimestamps] = tlvStream.get[ReplyChannelRangeTlv.EncodedTimestamps] val checksums_opt: Option[ReplyChannelRangeTlv.EncodedChecksums] = tlvStream.get[ReplyChannelRangeTlv.EncodedChecksums] } @@ -275,13 +264,13 @@ object ReplyChannelRange { def apply(chainHash: ByteVector32, firstBlockNum: Long, numberOfBlocks: Long, - complete: Byte, + syncComplete: Byte, shortChannelIds: EncodedShortChannelIds, timestamps: Option[ReplyChannelRangeTlv.EncodedTimestamps], checksums: Option[ReplyChannelRangeTlv.EncodedChecksums]): ReplyChannelRange = { timestamps.foreach(ts => require(ts.timestamps.length == shortChannelIds.array.length)) checksums.foreach(cs => require(cs.checksums.length == shortChannelIds.array.length)) - new ReplyChannelRange(chainHash, firstBlockNum, numberOfBlocks, complete, shortChannelIds, TlvStream(timestamps.toList ::: checksums.toList)) + new ReplyChannelRange(chainHash, firstBlockNum, numberOfBlocks, syncComplete, shortChannelIds, TlvStream(timestamps.toList ::: checksums.toList)) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala index 1f07194f04..b5bdbf9eda 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala @@ -20,6 +20,7 @@ import fr.acinq.bitcoin.{Block, ByteVector32, SatoshiLong} import fr.acinq.eclair.router.Router.{ChannelMeta, PublicChannel} import fr.acinq.eclair.router.Sync._ import fr.acinq.eclair.wire.QueryChannelRangeTlv.QueryFlags +import fr.acinq.eclair.wire.QueryShortChannelIdsTlv.QueryFlagType._ import fr.acinq.eclair.wire.ReplyChannelRangeTlv._ import fr.acinq.eclair.wire.{EncodedShortChannelIds, EncodingType, ReplyChannelRange} import fr.acinq.eclair.{MilliSatoshiLong, ShortChannelId, randomKey} @@ -83,7 +84,6 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { } test("compute flag tests") { - val now = System.currentTimeMillis / 1000 val a = randomKey.publicKey @@ -96,7 +96,6 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { val d = randomKey.publicKey val cd = RouteCalculationSpec.makeChannel(451312L, c, d) val ucd1 = RouteCalculationSpec.makeUpdateShort(cd.shortChannelId, cd.nodeId1, cd.nodeId2, 0 msat, 0, timestamp = now) - val ucd2 = RouteCalculationSpec.makeUpdateShort(cd.shortChannelId, cd.nodeId2, cd.nodeId1, 0 msat, 0, timestamp = now) val e = randomKey.publicKey val f = randomKey.publicKey @@ -107,30 +106,28 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { cd.shortChannelId -> PublicChannel(cd, ByteVector32.Zeroes, 0 sat, Some(ucd1), None, None) ) - import fr.acinq.eclair.wire.QueryShortChannelIdsTlv.QueryFlagType._ - assert(getChannelDigestInfo(channels)(ab.shortChannelId) == (Timestamps(now, now), Checksums(1697591108L, 3692323747L))) // no extended info but we know the channel: we ask for the updates - assert(computeFlag(channels)(ab.shortChannelId, None, None, false) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2)) - assert(computeFlag(channels)(ab.shortChannelId, None, None, true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) + assert(computeFlag(channels)(ab.shortChannelId, None, None, includeNodeAnnouncements = false) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2)) + assert(computeFlag(channels)(ab.shortChannelId, None, None, includeNodeAnnouncements = true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) // same checksums, newer timestamps: we don't ask anything - assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now + 1)), Some(Checksums(1697591108L, 3692323747L)), true) === 0) + assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now + 1)), Some(Checksums(1697591108L, 3692323747L)), includeNodeAnnouncements = true) === 0) // different checksums, newer timestamps: we ask for the updates - assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now)), Some(Checksums(154654604, 3692323747L)), true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) - assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now, now + 1)), Some(Checksums(1697591108L, 45664546)), true) === (INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) - assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now + 1)), Some(Checksums(154654604, 45664546 + 6)), true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) + assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now)), Some(Checksums(154654604, 3692323747L)), includeNodeAnnouncements = true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) + assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now, now + 1)), Some(Checksums(1697591108L, 45664546)), includeNodeAnnouncements = true) === (INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) + assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now + 1)), Some(Checksums(154654604, 45664546 + 6)), includeNodeAnnouncements = true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) // different checksums, older timestamps: we don't ask anything - assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now - 1, now)), Some(Checksums(154654604, 3692323747L)), true) === 0) - assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now, now - 1)), Some(Checksums(1697591108L, 45664546)), true) === 0) - assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now - 1, now - 1)), Some(Checksums(154654604, 45664546)), true) === 0) + assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now - 1, now)), Some(Checksums(154654604, 3692323747L)), includeNodeAnnouncements = true) === 0) + assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now, now - 1)), Some(Checksums(1697591108L, 45664546)), includeNodeAnnouncements = true) === 0) + assert(computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now - 1, now - 1)), Some(Checksums(154654604, 45664546)), includeNodeAnnouncements = true) === 0) // missing channel update: we ask for it - assert(computeFlag(channels)(cd.shortChannelId, Some(Timestamps(now, now)), Some(Checksums(3297511804L, 3297511804L)), true) === (INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) + assert(computeFlag(channels)(cd.shortChannelId, Some(Timestamps(now, now)), Some(Checksums(3297511804L, 3297511804L)), includeNodeAnnouncements = true) === (INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) // unknown channel: we ask everything - assert(computeFlag(channels)(ef.shortChannelId, None, None, false) === (INCLUDE_CHANNEL_ANNOUNCEMENT | INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2)) - assert(computeFlag(channels)(ef.shortChannelId, None, None, true) === (INCLUDE_CHANNEL_ANNOUNCEMENT | INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) + assert(computeFlag(channels)(ef.shortChannelId, None, None, includeNodeAnnouncements = false) === (INCLUDE_CHANNEL_ANNOUNCEMENT | INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2)) + assert(computeFlag(channels)(ef.shortChannelId, None, None, includeNodeAnnouncements = true) === (INCLUDE_CHANNEL_ANNOUNCEMENT | INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) } def makeShortChannelIds(height: Int, count: Int): List[ShortChannelId] = { @@ -149,7 +146,7 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { output.toList } - def validate(chunk: ShortChannelIdsChunk) = { + def validate(chunk: ShortChannelIdsChunk): Unit = { require(chunk.shortChannelIds.forall(keep(chunk.firstBlock, chunk.numBlocks, _))) } @@ -326,9 +323,9 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { test("enforce maximum size of short channel lists") { - def makeChunk(startBlock: Int, count: Int) = ShortChannelIdsChunk(startBlock, count, makeShortChannelIds(startBlock, count)) + def makeChunk(startBlock: Int, count: Int): ShortChannelIdsChunk = ShortChannelIdsChunk(startBlock, count, makeShortChannelIds(startBlock, count)) - def validate(before: ShortChannelIdsChunk, after: ShortChannelIdsChunk) = { + def validate(before: ShortChannelIdsChunk, after: ShortChannelIdsChunk): Unit = { require(before.shortChannelIds.containsSlice(after.shortChannelIds)) require(after.shortChannelIds.size <= Sync.MAXIMUM_CHUNK_SIZE) } @@ -353,7 +350,7 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { { val chunks = collection.mutable.ArrayBuffer.empty[ShortChannelIdsChunk] // we select parameters to make sure that some chunks will have too many ids - for (i <- 0 until 100) chunks += makeChunk(0, Sync.MAXIMUM_CHUNK_SIZE - 500 + Random.nextInt(1000)) + for (_ <- 0 until 100) chunks += makeChunk(0, Sync.MAXIMUM_CHUNK_SIZE - 500 + Random.nextInt(1000)) val pruned = enforceMaximumSize(chunks.toList) validateChunks(chunks.toList, pruned) } @@ -361,20 +358,20 @@ class ChannelRangeQueriesSpec extends AnyFunSuite { test("do not encode empty lists as COMPRESSED_ZLIB") { { - val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, Some(QueryFlags(QueryFlags.WANT_ALL)), SortedMap()) - assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0L, 42L, 1.toByte, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), Some(EncodedTimestamps(EncodingType.UNCOMPRESSED, Nil)), Some(EncodedChecksums(Nil)))) + val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), syncComplete = true, Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, Some(QueryFlags(QueryFlags.WANT_ALL)), SortedMap()) + assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0, 42L, 1, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), Some(EncodedTimestamps(EncodingType.UNCOMPRESSED, Nil)), Some(EncodedChecksums(Nil)))) } { - val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, Some(QueryFlags(QueryFlags.WANT_TIMESTAMPS)), SortedMap()) - assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0L, 42L, 1.toByte, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), Some(EncodedTimestamps(EncodingType.UNCOMPRESSED, Nil)), None)) + val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), syncComplete = false, Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, Some(QueryFlags(QueryFlags.WANT_TIMESTAMPS)), SortedMap()) + assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0, 42L, 0, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), Some(EncodedTimestamps(EncodingType.UNCOMPRESSED, Nil)), None)) } { - val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, Some(QueryFlags(QueryFlags.WANT_CHECKSUMS)), SortedMap()) - assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0L, 42L, 1.toByte, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), None, Some(EncodedChecksums(Nil)))) + val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), syncComplete = false, Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, Some(QueryFlags(QueryFlags.WANT_CHECKSUMS)), SortedMap()) + assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0, 42L, 0, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), None, Some(EncodedChecksums(Nil)))) } { - val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, None, SortedMap()) - assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0L, 42L, 1.toByte, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), None, None)) + val reply = buildReplyChannelRange(ShortChannelIdsChunk(0, 42, Nil), syncComplete = true, Block.RegtestGenesisBlock.hash, EncodingType.COMPRESSED_ZLIB, None, SortedMap()) + assert(reply == ReplyChannelRange(Block.RegtestGenesisBlock.hash, 0, 42L, 1, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, Nil), None, None)) } } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala index 196b2e4ef1..e537803d7a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala @@ -92,6 +92,8 @@ class RoutingSyncSpec extends TestKitBaseClass with AnyFunSuiteLike with Paralle val rcrs = pipe.receiveWhile() { case rcr: ReplyChannelRange => rcr } + rcrs.dropRight(1).foreach(rcr => assert(rcr.syncComplete == 0)) + assert(rcrs.last.syncComplete == 1) pipe.expectMsgType[Data] rcrs.foreach(rcr => pipe.send(src, PeerRoutingMessage(pipe.ref, tgtId, rcr))) // then src will now query announcements @@ -297,7 +299,7 @@ class RoutingSyncSpec extends TestKitBaseClass with AnyFunSuiteLike with Paralle assert(!router.stateData.sync.contains(remoteNodeId)) // we didn't send a corresponding query_channel_range, but peer sends us a reply_channel_range - val unsolicitedBlocks = ReplyChannelRange(params.chainHash, 10, 5, 1, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, fakeRoutingInfo.take(5).keys.toList), None, None) + val unsolicitedBlocks = ReplyChannelRange(params.chainHash, 10, 5, 0, EncodedShortChannelIds(EncodingType.UNCOMPRESSED, fakeRoutingInfo.take(5).keys.toList), None, None) peerConnection.send(router, PeerRoutingMessage(peerConnection.ref, remoteNodeId, unsolicitedBlocks)) // it will be simply ignored