From 4300e7b651b934a5e0605d8a0319308894164936 Mon Sep 17 00:00:00 2001 From: Fabrice Drouin Date: Mon, 7 Oct 2019 17:08:22 +0200 Subject: [PATCH] Activate extended channel range queries (#1165) * Activate extended channel range queries By default we now set the `gossip_queries_ex` feature bit. We also change how we compare feature bits, and will use channel queries (or extended queries) only if the corresponding feature bit is set in both local and remote init messages. --- eclair-core/src/main/resources/reference.conf | 2 +- .../main/scala/fr/acinq/eclair/Features.scala | 3 ++ .../main/scala/fr/acinq/eclair/io/Peer.scala | 44 +++++++++---------- .../scala/fr/acinq/eclair/TestConstants.scala | 2 +- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/eclair-core/src/main/resources/reference.conf b/eclair-core/src/main/resources/reference.conf index 8f441fe41..0d3187793 100644 --- a/eclair-core/src/main/resources/reference.conf +++ b/eclair-core/src/main/resources/reference.conf @@ -36,7 +36,7 @@ eclair { node-color = "49daaa" global-features = "0200" // variable_length_onion - local-features = "8a" // initial_routing_sync + option_data_loss_protect + option_channel_range_queries + local-features = "088a" // initial_routing_sync + option_data_loss_protect + option_channel_range_queries + option_channel_range_queries_ex override-features = [ // optional per-node features # { # nodeid = "02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 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 145961614..8fc1b2790 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala @@ -32,6 +32,9 @@ object Features { val CHANNEL_RANGE_QUERIES_BIT_MANDATORY = 6 val CHANNEL_RANGE_QUERIES_BIT_OPTIONAL = 7 + val CHANNEL_RANGE_QUERIES_EX_BIT_MANDATORY = 10 + val CHANNEL_RANGE_QUERIES_EX_BIT_OPTIONAL = 11 + val VARIABLE_LENGTH_ONION_MANDATORY = 8 val VARIABLE_LENGTH_ONION_OPTIONAL = 9 diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index bad45c068..0aee107c9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -23,7 +23,7 @@ import akka.event.Logging.MDC import akka.util.Timeout import com.google.common.net.HostAndPort import fr.acinq.bitcoin.Crypto.PublicKey -import fr.acinq.bitcoin.{Block, ByteVector32, DeterministicWallet, Satoshi} +import fr.acinq.bitcoin.{ByteVector32, DeterministicWallet, Satoshi} import fr.acinq.eclair.blockchain.EclairWallet import fr.acinq.eclair.channel._ import fr.acinq.eclair.crypto.TransportHandler @@ -132,38 +132,36 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, authenticator: A when(INITIALIZING) { case Event(remoteInit: wire.Init, d: InitializingData) => d.transport ! TransportHandler.ReadAck(remoteInit) - val remoteHasInitialRoutingSync = Features.hasFeature(remoteInit.localFeatures, Features.INITIAL_ROUTING_SYNC_BIT_OPTIONAL) - val remoteHasChannelRangeQueriesOptional = Features.hasFeature(remoteInit.localFeatures, Features.CHANNEL_RANGE_QUERIES_BIT_OPTIONAL) - val remoteHasChannelRangeQueriesMandatory = Features.hasFeature(remoteInit.localFeatures, Features.CHANNEL_RANGE_QUERIES_BIT_MANDATORY) + log.info(s"peer is using globalFeatures=${remoteInit.globalFeatures.toBin} and localFeatures=${remoteInit.localFeatures.toBin}") - log.info(s"$remoteNodeId has features: initialRoutingSync=$remoteHasInitialRoutingSync channelRangeQueriesOptional=$remoteHasChannelRangeQueriesOptional channelRangeQueriesMandatory=$remoteHasChannelRangeQueriesMandatory") + if (Features.areSupported(remoteInit.localFeatures)) { d.origin_opt.foreach(origin => origin ! "connected") - if (remoteHasInitialRoutingSync) { - if (remoteHasChannelRangeQueriesOptional || remoteHasChannelRangeQueriesMandatory) { - // if they support channel queries we do nothing, they will send us their filters - log.info("peer has set initial routing sync and supports channel range queries, we do nothing (they will send us a query)") - } else { - // "old" nodes, do as before - log.info("peer requested a full routing table dump") - router ! GetRoutingState - } - } - if (remoteHasChannelRangeQueriesOptional || remoteHasChannelRangeQueriesMandatory) { - // if they support channel queries, always ask for their filter - // TODO: for now we do not activate extended queries on mainnet - val flags_opt = nodeParams.chainHash match { - case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash => - Some(QueryChannelRangeTlv.QueryFlags(QueryChannelRangeTlv.QueryFlags.WANT_ALL)) - case _ => None - } + import Features._ + + def hasLocalFeature(bit: Int) = Features.hasFeature(d.localInit.localFeatures, bit) + + def hasRemoteFeature(bit: Int) = Features.hasFeature(remoteInit.localFeatures, bit) + + val canUseChannelRangeQueries = (hasLocalFeature(CHANNEL_RANGE_QUERIES_BIT_OPTIONAL) || hasLocalFeature(CHANNEL_RANGE_QUERIES_BIT_MANDATORY)) && (hasRemoteFeature(CHANNEL_RANGE_QUERIES_BIT_OPTIONAL) || hasRemoteFeature(CHANNEL_RANGE_QUERIES_BIT_MANDATORY)) + + val canUseChannelRangeQueriesEx = (hasLocalFeature(CHANNEL_RANGE_QUERIES_EX_BIT_OPTIONAL) || hasLocalFeature(CHANNEL_RANGE_QUERIES_EX_BIT_MANDATORY)) && (hasRemoteFeature(CHANNEL_RANGE_QUERIES_EX_BIT_OPTIONAL) || hasRemoteFeature(CHANNEL_RANGE_QUERIES_EX_BIT_MANDATORY)) + + if (canUseChannelRangeQueries || canUseChannelRangeQueriesEx) { + // if they support channel queries we don't send routing info yet, if they want it they will query us + // we will query them, using extended queries if supported + val flags_opt = if (canUseChannelRangeQueriesEx) Some(QueryChannelRangeTlv.QueryFlags(QueryChannelRangeTlv.QueryFlags.WANT_ALL)) else None if (nodeParams.syncWhitelist.isEmpty || nodeParams.syncWhitelist.contains(remoteNodeId)) { log.info(s"sending sync channel range query with flags_opt=$flags_opt") router ! SendChannelQuery(remoteNodeId, d.transport, flags_opt = flags_opt) } else { log.info("not syncing with this peer") } + } else if (hasRemoteFeature(INITIAL_ROUTING_SYNC_BIT_OPTIONAL)) { + // "old" nodes, do as before + log.info("peer requested a full routing table dump") + router ! GetRoutingState } // let's bring existing/requested channels online diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index 757f37f36..f68d3575e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -71,7 +71,7 @@ object TestConstants { color = Color(1, 2, 3), publicAddresses = NodeAddress.fromParts("localhost", 9731).get :: Nil, globalFeatures = globalFeatures, - localFeatures = ByteVector(0), + localFeatures = ByteVector.fromValidHex("088a"), overrideFeatures = Map.empty, syncWhitelist = Set.empty, dustLimit = 1100 sat,