Skip to content

Commit

Permalink
Filter out non-standard channels from channelInfo API (#2107)
Browse files Browse the repository at this point in the history
This change makes it possible for a non-standard channel to reply
with `CommandFailure` which in turn will be filtered out in `channelsInfo`.

The reason is that currently hosted channels have to return something
to make the whole API call succeed and whatever they return would
break external tools which only expect standard channel formats.
  • Loading branch information
akumaigorodski committed Dec 15, 2021
1 parent 8ff7dc7 commit 7e7de53
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 16 deletions.
27 changes: 15 additions & 12 deletions eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ trait Eclair {

def channelsInfo(toRemoteNode_opt: Option[PublicKey])(implicit timeout: Timeout): Future[Iterable[RES_GETINFO]]

def channelInfo(channel: ApiTypes.ChannelIdentifier)(implicit timeout: Timeout): Future[RES_GETINFO]
def channelInfo(channel: ApiTypes.ChannelIdentifier)(implicit timeout: Timeout): Future[CommandResponse[CMD_GETINFO]]

def peers()(implicit timeout: Timeout): Future[Iterable[PeerInfo]]

Expand Down Expand Up @@ -212,19 +212,22 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging {
.map(_.filter(n => nodeIds_opt.forall(_.contains(n.nodeId))))
}

override def channelsInfo(toRemoteNode_opt: Option[PublicKey])(implicit timeout: Timeout): Future[Iterable[RES_GETINFO]] = toRemoteNode_opt match {
case Some(pk) => for {
channelIds <- (appKit.register ? Symbol("channelsTo")).mapTo[Map[ByteVector32, PublicKey]].map(_.filter(_._2 == pk).keys)
channels <- Future.sequence(channelIds.map(channelId => sendToChannel[CMD_GETINFO, RES_GETINFO](Left(channelId), CMD_GETINFO(ActorRef.noSender))))
} yield channels
case None => for {
channelIds <- (appKit.register ? Symbol("channels")).mapTo[Map[ByteVector32, ActorRef]].map(_.keys)
channels <- Future.sequence(channelIds.map(channelId => sendToChannel[CMD_GETINFO, RES_GETINFO](Left(channelId), CMD_GETINFO(ActorRef.noSender))))
} yield channels
override def channelsInfo(toRemoteNode_opt: Option[PublicKey])(implicit timeout: Timeout): Future[Iterable[RES_GETINFO]] = {
val futureResponse = toRemoteNode_opt match {
case Some(pk) => (appKit.register ? Symbol("channelsTo")).mapTo[Map[ByteVector32, PublicKey]].map(_.filter(_._2 == pk).keys)
case None => (appKit.register ? Symbol("channels")).mapTo[Map[ByteVector32, ActorRef]].map(_.keys)
}

for {
channelIds <- futureResponse
channels <- Future.sequence(channelIds.map(channelId => sendToChannel[CMD_GETINFO, CommandResponse[CMD_GETINFO]](Left(channelId), CMD_GETINFO(ActorRef.noSender))))
} yield channels.collect {
case properResponse: RES_GETINFO => properResponse
}
}

override def channelInfo(channel: ApiTypes.ChannelIdentifier)(implicit timeout: Timeout): Future[RES_GETINFO] = {
sendToChannel[CMD_GETINFO, RES_GETINFO](channel, CMD_GETINFO(ActorRef.noSender))
override def channelInfo(channel: ApiTypes.ChannelIdentifier)(implicit timeout: Timeout): Future[CommandResponse[CMD_GETINFO]] = {
sendToChannel[CMD_GETINFO, CommandResponse[CMD_GETINFO]](channel, CMD_GETINFO(ActorRef.noSender))
}

override def allChannels()(implicit timeout: Timeout): Future[Iterable[ChannelDesc]] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I
assert(verifiedMessage.publicKey !== kit.nodeParams.nodeId)
}

test("get channel info (all channels)") { f =>
test("get channel info (filtered channels)") { f =>
import f._

val eclair = new EclairImpl(kit)
Expand All @@ -468,8 +468,8 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I

val c1 = register.expectMsgType[Register.Forward[CMD_GETINFO]]
register.reply(RES_GETINFO(map(c1.channelId), c1.channelId, NORMAL, ChannelCodecsSpec.normal))
val c2 = register.expectMsgType[Register.Forward[CMD_GETINFO]]
register.reply(RES_GETINFO(map(c2.channelId), c2.channelId, NORMAL, ChannelCodecsSpec.normal))
register.expectMsgType[Register.Forward[CMD_GETINFO]]
register.reply(RES_FAILURE(CMD_GETINFO(ActorRef.noSender), new IllegalArgumentException("Non-standard channel")))
val c3 = register.expectMsgType[Register.Forward[CMD_GETINFO]]
register.reply(RES_GETINFO(map(c3.channelId), c3.channelId, NORMAL, ChannelCodecsSpec.normal))
register.expectNoMessage()
Expand All @@ -478,7 +478,6 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I

assert(res.value.get.get.toSet === Set(
RES_GETINFO(a, a1, NORMAL, ChannelCodecsSpec.normal),
RES_GETINFO(a, a2, NORMAL, ChannelCodecsSpec.normal),
RES_GETINFO(b, b1, NORMAL, ChannelCodecsSpec.normal),
))
}
Expand Down

0 comments on commit 7e7de53

Please sign in to comment.