Skip to content

Commit

Permalink
Remove messages relay
Browse files Browse the repository at this point in the history
  • Loading branch information
thomash-acinq committed Nov 8, 2021
1 parent 316e7b5 commit 58857c3
Show file tree
Hide file tree
Showing 5 changed files with 6 additions and 75 deletions.
4 changes: 0 additions & 4 deletions docs/release-notes/eclair-vnext.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ Node operators should watch this file very regularly.
An event is also sent to the event stream for every such notification.
This lets plugins notify the node operator via external systems (push notifications, email, etc).

### Initial support for onion messages

Eclair now supports the feature `option_onion_messages`. If this feature is enabled, eclair will relay onion messages, initiating or receiving onion messages is not supported yet.

### API changes

#### Timestamps
Expand Down
43 changes: 4 additions & 39 deletions eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ import fr.acinq.eclair.blockchain.{OnChainAddressGenerator, OnChainChannelFunder
import fr.acinq.eclair.channel._
import fr.acinq.eclair.io.Monitoring.Metrics
import fr.acinq.eclair.io.PeerConnection.KillReason
import fr.acinq.eclair.message.OnionMessages
import fr.acinq.eclair.remote.EclairInternalsSerializer.RemoteTypes
import fr.acinq.eclair.wire.protocol
import fr.acinq.eclair.wire.protocol.{Error, HasChannelId, HasTemporaryChannelId, LightningMessage, NodeAddress, OnionMessage, RoutingMessage, UnknownMessage, Warning}
import fr.acinq.eclair.wire.protocol.{Error, HasChannelId, HasTemporaryChannelId, LightningMessage, NodeAddress, RoutingMessage, UnknownMessage, Warning}
import scodec.bits.ByteVector

import java.net.InetSocketAddress
Expand Down Expand Up @@ -66,7 +65,7 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, wallet: OnChainA
FinalChannelId(state.channelId) -> channel
}.toMap

goto(DISCONNECTED) using DisconnectedData(channels, None) // when we restart, we will attempt to reconnect right away, but then we'll wait
goto(DISCONNECTED) using DisconnectedData(channels) // when we restart, we will attempt to reconnect right away, but then we'll wait
}

when(DISCONNECTED) {
Expand All @@ -75,7 +74,6 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, wallet: OnChainA
stay()

case Event(connectionReady: PeerConnection.ConnectionReady, d: DisconnectedData) =>
d.messageToRelay.foreach(msg => self ! Peer.SendOnionMessage(remoteNodeId, msg))
gotoConnected(connectionReady, d.channels.map { case (k: ChannelId, v) => (k, v) })

case Event(Terminated(actor), d: DisconnectedData) if d.channels.exists(_._2 == actor) =>
Expand All @@ -96,19 +94,6 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, wallet: OnChainA
stay() using d.copy(channels = d.channels + (FinalChannelId(channelId) -> channel))

case Event(_: LightningMessage, _) => stay() // we probably just got disconnected and that's the last messages we received

case Event(Peer.SendOnionMessage(toNodeId, msg), d: DisconnectedData) if toNodeId == remoteNodeId =>
// We may drop a previous messageToRelay but that's fine. If we receive several messages to relay while trying to connect, we're probably getting spammed.
stay() using d.copy(messageToRelay = Some(msg))

case Event(_ : PeerConnection.ConnectionResult.Failure, d: DisconnectedData) =>
if (d.channels.isEmpty) {
// we don't have any channel with this peer and we can't connect to it so we just drop it
stopPeer()
} else {
stay() using d.copy(messageToRelay = None)
}

}

when(CONNECTED) {
Expand Down Expand Up @@ -238,7 +223,7 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, wallet: OnChainA
stopPeer()
} else {
d.channels.values.toSet[ActorRef].foreach(_ ! INPUT_DISCONNECTED) // we deduplicate with toSet because there might be two entries per channel (tmp id and final id)
goto(DISCONNECTED) using DisconnectedData(d.channels.collect { case (k: FinalChannelId, v) => (k, v) }, None)
goto(DISCONNECTED) using DisconnectedData(d.channels.collect { case (k: FinalChannelId, v) => (k, v) })
}

case Event(Terminated(actor), d: ConnectedData) if d.channels.values.toSet.contains(actor) =>
Expand All @@ -258,20 +243,6 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, wallet: OnChainA
d.channels.values.toSet[ActorRef].foreach(_ ! INPUT_DISCONNECTED) // we deduplicate with toSet because there might be two entries per channel (tmp id and final id)
gotoConnected(connectionReady, d.channels)

case Event(msg: OnionMessage, _: ConnectedData) =>
if (nodeParams.features.hasFeature(Features.OnionMessages)) {
OnionMessages.process(nodeParams.privateKey, msg) match {
case OnionMessages.DropMessage(reason) => log.debug(s"dropping message from ${remoteNodeId.value.toHex}: ${reason.toString}")
case OnionMessages.RelayMessage(nextNodeId, dataToRelay) => context.parent ! Peer.SendOnionMessage(nextNodeId, dataToRelay)
case msg: OnionMessages.ReceiveMessage => log.info(s"received message from ${remoteNodeId.value.toHex}: $msg")
}
}
stay()

case Event(Peer.SendOnionMessage(toNodeId, msg), d: ConnectedData) if toNodeId == remoteNodeId =>
d.peerConnection ! msg
stay()

case Event(unknownMsg: UnknownMessage, d: ConnectedData) if nodeParams.pluginMessageTags.contains(unknownMsg.tag) =>
context.system.eventStream.publish(UnknownMessageReceived(self, remoteNodeId, unknownMsg, d.connectionInfo))
stay()
Expand Down Expand Up @@ -436,14 +407,10 @@ object Peer {
def channels: Map[_ <: ChannelId, ActorRef] // will be overridden by Map[FinalChannelId, ActorRef] or Map[ChannelId, ActorRef]
}
case object Nothing extends Data { override def channels = Map.empty }

case class DisconnectedData(channels: Map[FinalChannelId, ActorRef], messageToRelay: Option[OnionMessage]) extends Data

case class DisconnectedData(channels: Map[FinalChannelId, ActorRef]) extends Data
case class ConnectedData(address: InetSocketAddress, peerConnection: ActorRef, localInit: protocol.Init, remoteInit: protocol.Init, channels: Map[ChannelId, ActorRef]) extends Data {
val connectionInfo: ConnectionInfo = ConnectionInfo(address, peerConnection, localInit, remoteInit)

def localFeatures: Features = localInit.features

def remoteFeatures: Features = remoteInit.features
}

Expand All @@ -460,8 +427,6 @@ object Peer {
def apply(uri: NodeURI): Connect = new Connect(uri.nodeId, Some(uri.address))
}

case class SendOnionMessage(nodeId: PublicKey, message: OnionMessage) extends PossiblyHarmful

case class Disconnect(nodeId: PublicKey) extends PossiblyHarmful
case class OpenChannel(remoteNodeId: PublicKey, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, channelType_opt: Option[SupportedChannelType], fundingTxFeeratePerKw_opt: Option[FeeratePerKw], channelFlags: Option[Byte], timeout_opt: Option[Timeout]) extends PossiblyHarmful {
require(pushMsat <= fundingSatoshis, s"pushMsat must be less or equal to fundingSatoshis")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ class Switchboard(nodeParams: NodeParams, peerFactory: Switchboard.PeerFactory)
case None => sender() ! Status.Failure(new RuntimeException("peer not found"))
}

case s@Peer.SendOnionMessage(nodeId, _) =>
val peer = createOrGetPeer(nodeId, offlineChannels = Set.empty)
peer.tell(Peer.Connect(nodeId, None), peer)
peer forward s

case o: Peer.OpenChannel =>
getPeer(o.remoteNodeId) match {
case Some(peer) => peer forward o
Expand Down
25 changes: 0 additions & 25 deletions eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -457,31 +457,6 @@ class PeerSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Paralle
assert(peerInfo2.channels === 2)
}

test("relay message with new peer") { f =>
import f._
val msg0 = OnionMessage(PublicKey(hex"02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619"), OnionRoutingPacket(1, hex"032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991", hex"baba", ByteVector32(hex"0000000000000000000000000000000000000000000000000000000000000000")))
val msg1 = OnionMessage(PublicKey(hex"0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"), OnionRoutingPacket(1, hex"0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7", hex"fefe", ByteVector32(hex"0000000000000000000000000000000000000000000000000000000000000000")))
val msg2 = OnionMessage(PublicKey(hex"027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007"), OnionRoutingPacket(1, hex"02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f", hex"c0c0", ByteVector32(hex"0000000000000000000000000000000000000000000000000000000000000000")))
peer ! Peer.Init(Set.empty)

peer.tell(Peer.Connect(remoteNodeId, None), peer)
peer ! SendOnionMessage(remoteNodeId, msg0)

peer.tell(Peer.Connect(remoteNodeId, None), peer)
peer ! SendOnionMessage(remoteNodeId, msg1)

peer ! PeerConnection.ConnectionReady(peerConnection.ref, remoteNodeId, fakeIPAddress.socketAddress, outgoing = true, protocol.Init(peer.underlyingActor.nodeParams.features), protocol.Init(Bob.nodeParams.features))

val msgSent0 = peerConnection.expectMsgType[OnionMessage]
assert(msgSent0 === msg1)

peer.tell(Peer.Connect(remoteNodeId, None), peer)
peer ! SendOnionMessage(remoteNodeId, msg2)

val msgSent1 = peerConnection.expectMsgType[OnionMessage]
assert(msgSent1 === msg2)
}

}

object PeerSpec {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ReconnectionTaskSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike
private val channels = Map(Peer.FinalChannelId(randomBytes32()) -> system.deadLetters)

private val PeerNothingData = Peer.Nothing
private val PeerDisconnectedData = Peer.DisconnectedData(channels, None)
private val PeerDisconnectedData = Peer.DisconnectedData(channels)
private val PeerConnectedData = Peer.ConnectedData(fakeIPAddress.socketAddress, system.deadLetters, null, null, channels.map { case (k: ChannelId, v) => (k, v) })

case class FixtureParam(nodeParams: NodeParams, remoteNodeId: PublicKey, reconnectionTask: TestFSMRef[ReconnectionTask.State, ReconnectionTask.Data, ReconnectionTask], monitor: TestProbe)
Expand Down Expand Up @@ -77,7 +77,7 @@ class ReconnectionTaskSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike
import f._

val peer = TestProbe()
peer.send(reconnectionTask, Peer.Transition(PeerNothingData, Peer.DisconnectedData(Map.empty, None)))
peer.send(reconnectionTask, Peer.Transition(PeerNothingData, Peer.DisconnectedData(Map.empty)))
monitor.expectNoMessage()
}

Expand Down

0 comments on commit 58857c3

Please sign in to comment.