diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/MessageRelay.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/MessageRelay.scala index 1a21129421..2446ee0f87 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/MessageRelay.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/MessageRelay.scala @@ -137,6 +137,7 @@ private class MessageRelay(nodeParams: NodeParams, Behaviors.stopped } case EncodedNodeId.WithPublicKey.Plain(nodeId) => + println(policy) policy match { case RelayChannelsOnly => switchboard ! GetPeerInfo(context.messageAdapter(WrappedPeerInfo), prevNodeId) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala index 8f2fe0254c..684423d16d 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala @@ -185,6 +185,7 @@ class PeerConnection(keyPair: KeyPair, conf: PeerConnection.Conf, switchboard: A heartbeat { case Event(msg: OnionMessage, d: ConnectedData) => // we process onion messages separately as we want to rate limit them if (sender() == d.transport) { + println(s"${keyPair.pub.toHex.substring(2, 3)} <- ${d.remoteNodeId.toHex.substring(2, 3)}") d.transport ! TransportHandler.ReadAck(msg) if (incomingRateLimiter.tryAcquire()) { d.peer ! msg @@ -193,6 +194,7 @@ class PeerConnection(keyPair: KeyPair, conf: PeerConnection.Conf, switchboard: A Metrics.OnionMessagesThrottled.withTag(Tags.Direction, Tags.Directions.Incoming).increment() } } else { + println(s"${keyPair.pub.toHex.substring(2, 3)} -> ${d.remoteNodeId.toHex.substring(2, 3)}") if (outgoingRateLimiter.tryAcquire()) { d.transport forward msg Metrics.OnionMessagesProcessed.withTag(Tags.Direction, Tags.Directions.Outgoing).increment() diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/ReconnectionTask.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/ReconnectionTask.scala index 9d0b4ab662..ee128be6f3 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/ReconnectionTask.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/ReconnectionTask.scala @@ -129,6 +129,7 @@ class ReconnectionTask(nodeParams: NodeParams, remoteNodeId: PublicKey) extends case Event(TickReconnect, _) => stay() case Event(Peer.Connect(_, address_opt, replyTo, isPersistent), _) => + println(s"${nodeParams.alias} -> ${remoteNodeId.toHex.substring(2, 3)} connection isPersistent=$isPersistent") // manual connection requests happen completely independently of the automated reconnection process; // we initiate a connection but don't modify our state. // if we are already connecting/connected, the peer will kill any duplicate connections diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index 36043db74f..18d56ed664 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.integration import akka.actor.ActorSystem import akka.testkit.{TestKit, TestProbe} import com.typesafe.config.{Config, ConfigFactory} -import fr.acinq.bitcoin.scalacompat.Satoshi +import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} import fr.acinq.eclair.Features._ import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import fr.acinq.eclair.io.Peer.OpenChannelResponse @@ -28,7 +28,7 @@ import fr.acinq.eclair.payment.relay.Relayer.RelayFees import fr.acinq.eclair.router.Graph.PaymentWeightRatios import fr.acinq.eclair.router.RouteCalculation.ROUTE_MAX_LENGTH import fr.acinq.eclair.router.Router.{MultiPartParams, PathFindingConf, SearchBoundaries, NORMAL => _, State => _} -import fr.acinq.eclair.{BlockHeight, CltvExpiryDelta, Kit, MilliSatoshi, MilliSatoshiLong, Setup, TestKitBaseClass} +import fr.acinq.eclair.{BlockHeight, CltvExpiryDelta, Kit, MilliSatoshi, MilliSatoshiLong, Setup, TestKitBaseClass, randomBytes32} import grizzled.slf4j.Logging import org.json4s.{DefaultFormats, Formats} import org.scalatest.BeforeAndAfterAll @@ -145,14 +145,14 @@ abstract class IntegrationSpec extends TestKitBaseClass with BitcoindService wit super.afterAll() } - def instantiateEclairNode(name: String, config: Config): Unit = { + def instantiateEclairNode(name: String, config: Config, seed_opt: Option[ByteVector32] = None): Unit = { val datadir = new File(INTEGRATION_TMP_DIR, s"datadir-eclair-$name") datadir.mkdirs() if (useEclairSigner) { Files.writeString(datadir.toPath.resolve("eclair-signer.conf"), eclairSignerConf) } implicit val system: ActorSystem = ActorSystem(s"system-$name", config) - val setup = new Setup(datadir, pluginParams = Seq.empty) + val setup = new Setup(datadir, pluginParams = Seq.empty, seed_opt.map(s => Setup.Seeds(s, randomBytes32()))) val kit = Await.result(setup.bootstrap, 10 seconds) nodes = nodes + (name -> kit) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/MessageIntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/MessageIntegrationSpec.scala index 53fb435af5..d323bece5c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/MessageIntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/MessageIntegrationSpec.scala @@ -23,12 +23,13 @@ import akka.testkit.TestProbe import akka.util.Timeout import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.Transaction -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Satoshi} import fr.acinq.eclair.TestUtils.waitEventStreamSynced import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher.{Watch, WatchFundingConfirmed} import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient import fr.acinq.eclair.channel.{CMD_CLOSE, RES_SUCCESS, Register} +import fr.acinq.eclair.crypto.keymanager.LocalNodeKeyManager import fr.acinq.eclair.io.Switchboard import fr.acinq.eclair.message.OnionMessages import fr.acinq.eclair.message.OnionMessages.{IntermediateNode, Recipient, buildRoute} @@ -36,7 +37,7 @@ import fr.acinq.eclair.router.Router import fr.acinq.eclair.wire.protocol.OnionMessagePayloadTlv.ReplyPath import fr.acinq.eclair.wire.protocol.TlvCodecs.genericTlv import fr.acinq.eclair.wire.protocol.{GenericTlv, NodeAnnouncement} -import fr.acinq.eclair.{EclairImpl, EncodedNodeId, Features, MilliSatoshi, SendOnionMessageResponse, UInt64, randomBytes, randomKey} +import fr.acinq.eclair.{EclairImpl, EncodedNodeId, Features, MilliSatoshi, SendOnionMessageResponse, UInt64, randomBytes, randomBytes32, randomKey} import scodec.bits.{ByteVector, HexStringSyntax} import scala.concurrent.ExecutionContext.Implicits.global @@ -47,12 +48,12 @@ class MessageIntegrationSpec extends IntegrationSpec { implicit val timeout: Timeout = FiniteDuration(30, SECONDS) test("start eclair nodes") { - instantiateEclairNode("A", ConfigFactory.parseMap(Map("eclair.node-alias" -> "A", "eclair.server.port" -> 30700, "eclair.api.port" -> 30780, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "relay-all", "eclair.onion-messages.reply-timeout" -> "1 minute").asJava).withFallback(commonConfig)) - instantiateEclairNode("B", ConfigFactory.parseMap(Map("eclair.node-alias" -> "B", "eclair.server.port" -> 30701, "eclair.api.port" -> 30781, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "relay-all", "eclair.onion-messages.reply-timeout" -> "1 second").asJava).withFallback(commonConfig)) - instantiateEclairNode("C", ConfigFactory.parseMap(Map("eclair.node-alias" -> "C", "eclair.server.port" -> 30702, "eclair.api.port" -> 30782, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "relay-all").asJava).withFallback(commonConfig)) - instantiateEclairNode("D", ConfigFactory.parseMap(Map("eclair.node-alias" -> "D", "eclair.server.port" -> 30703, "eclair.api.port" -> 30783).asJava).withFallback(commonConfig)) - instantiateEclairNode("E", ConfigFactory.parseMap(Map("eclair.node-alias" -> "E", "eclair.server.port" -> 30704, "eclair.api.port" -> 30784, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "channels-only").asJava).withFallback(commonConfig)) - instantiateEclairNode("F", ConfigFactory.parseMap(Map("eclair.node-alias" -> "F", "eclair.server.port" -> 30705, "eclair.api.port" -> 30785, s"eclair.features.${Features.OnionMessages.rfcName}" -> "disabled").asJava).withFallback(commonConfig)) + instantiateEclairNode("A", ConfigFactory.parseMap(Map("eclair.node-alias" -> "A", "eclair.server.port" -> 30700, "eclair.api.port" -> 30780, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "relay-all", "eclair.onion-messages.reply-timeout" -> "1 minute").asJava).withFallback(commonConfig), Some(ByteVector32(hex"40e4f4f95f9967b8cc5f844e94936f7045ed3ab67e0db7951a8af0bcddb8abbb"))) + instantiateEclairNode("B", ConfigFactory.parseMap(Map("eclair.node-alias" -> "B", "eclair.server.port" -> 30701, "eclair.api.port" -> 30781, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "relay-all", "eclair.onion-messages.reply-timeout" -> "1 second").asJava).withFallback(commonConfig), Some(ByteVector32(hex"0c436bdc75a384126b86c0f65fee1a87ab16ef28397c3f38f6b165a13c969bba"))) + instantiateEclairNode("C", ConfigFactory.parseMap(Map("eclair.node-alias" -> "C", "eclair.server.port" -> 30702, "eclair.api.port" -> 30782, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "relay-all").asJava).withFallback(commonConfig), Some(ByteVector32(hex"de6614d459422d77df04571f62c7b73c1aae404e00f568af462d513303f54b46"))) + instantiateEclairNode("D", ConfigFactory.parseMap(Map("eclair.node-alias" -> "D", "eclair.server.port" -> 30703, "eclair.api.port" -> 30783).asJava).withFallback(commonConfig), Some(ByteVector32(hex"454e58503bec6b75430c3a5a738cc9329318969afd2a5d789bee3fa0b0327027"))) + instantiateEclairNode("E", ConfigFactory.parseMap(Map("eclair.node-alias" -> "E", "eclair.server.port" -> 30704, "eclair.api.port" -> 30784, s"eclair.features.${Features.OnionMessages.rfcName}" -> "optional", "eclair.onion-messages.relay-policy" -> "channels-only").asJava).withFallback(commonConfig), Some(ByteVector32(hex"e8faa9ac62d99f6362452c4d4decfdf826b0d47718550a10821d19a4d6382d43"))) + instantiateEclairNode("F", ConfigFactory.parseMap(Map("eclair.node-alias" -> "F", "eclair.server.port" -> 30705, "eclair.api.port" -> 30785, s"eclair.features.${Features.OnionMessages.rfcName}" -> "disabled").asJava).withFallback(commonConfig), Some(ByteVector32(hex"acc27975904e764e18d1261de40014a42a992fbacf9d9b2a333162993520bdca"))) } test("try to reach unknown node") { @@ -369,6 +370,9 @@ class MessageIntegrationSpec extends IntegrationSpec { val eventListener = TestProbe() nodes("C").system.eventStream.subscribe(eventListener.ref, classOf[OnionMessages.ReceiveMessage]) waitEventStreamSynced(nodes("C").system.eventStream) + println(".") + println(".") + println("=== automatically connect to known nodes ===") alice.sendOnionMessage(Some(nodes("B").nodeParams.nodeId :: Nil), Left(nodes("C").nodeParams.nodeId), expectsReply = false, hex"7300").pipeTo(probe.ref) assert(probe.expectMsgType[SendOnionMessageResponse].sent)