Skip to content

Commit

Permalink
Back to using Relayer as source for usable balances, rename API to …
Browse files Browse the repository at this point in the history
…better reflect what it does
  • Loading branch information
anton committed Jun 11, 2019
1 parent 818199e commit e0ab3f7
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 20 deletions.
6 changes: 5 additions & 1 deletion eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
Expand Up @@ -27,15 +27,17 @@ import fr.acinq.eclair.channel.Register.{Forward, ForwardShortId}
import fr.acinq.eclair.channel._
import fr.acinq.eclair.db.{IncomingPayment, NetworkFee, OutgoingPayment, Stats}
import fr.acinq.eclair.io.Peer.{GetPeerInfo, PeerInfo}
import fr.acinq.eclair.io.{NodeURI, Peer, Switchboard}
import fr.acinq.eclair.io.{NodeURI, Peer}
import fr.acinq.eclair.payment.PaymentLifecycle._
import fr.acinq.eclair.router.{ChannelDesc, RouteRequest, RouteResponse, Router}
import scodec.bits.ByteVector

import scala.concurrent.Future
import scala.concurrent.duration._
import fr.acinq.eclair.payment.{PaymentReceived, PaymentRelayed, PaymentRequest, PaymentSent}
import fr.acinq.eclair.wire.{ChannelAnnouncement, ChannelUpdate, NodeAddress, NodeAnnouncement}
import TimestampQueryFilters._
import fr.acinq.eclair.payment.Relayer.OutgoingChannel

case class GetInfoResponse(nodeId: PublicKey, alias: String, chainHash: ByteVector32, blockHeight: Int, publicAddresses: Seq[NodeAddress])

Expand Down Expand Up @@ -105,6 +107,7 @@ trait Eclair {

def getInfoResponse()(implicit timeout: Timeout): Future[GetInfoResponse]

def usableBalances()(implicit timeout: Timeout): Future[Iterable[OutgoingChannel]]
}

class EclairImpl(appKit: Kit) extends Eclair {
Expand Down Expand Up @@ -269,4 +272,5 @@ class EclairImpl(appKit: Kit) extends Eclair {
publicAddresses = appKit.nodeParams.publicAddresses)
)

override def usableBalances()(implicit timeout: Timeout): Future[Iterable[OutgoingChannel]] = (appKit.relayer ? 'usableBalances).mapTo[Iterable[OutgoingChannel]]
}
3 changes: 3 additions & 0 deletions eclair-core/src/main/scala/fr/acinq/eclair/api/Service.scala
Expand Up @@ -281,6 +281,9 @@ trait Service extends ExtraDirectives with Logging {
} ~
path("channelstats") {
complete(eclairApi.channelStats())
} ~
path("usablebalances") {
complete(eclairApi.usableBalances())
}
} ~ get {
path("ws") {
Expand Down
Expand Up @@ -40,6 +40,7 @@ case class PublishableTxs(commitTx: CommitTx, htlcTxsAndSigs: List[HtlcTxAndSigs
case class LocalCommit(index: Long, spec: CommitmentSpec, publishableTxs: PublishableTxs)
case class RemoteCommit(index: Long, spec: CommitmentSpec, txid: ByteVector32, remotePerCommitmentPoint: Point)
case class WaitingForRevocation(nextRemoteCommit: RemoteCommit, sent: CommitSig, sentAfterLocalCommitIndex: Long, reSignAsap: Boolean = false)
case class UsableBalances(localMsat: Long, remoteMsat: Long, isPublic: Boolean)
// @formatter:on

/**
Expand Down Expand Up @@ -71,12 +72,14 @@ case class Commitments(localParams: LocalParams, remoteParams: RemoteParams,

def addRemoteProposal(proposal: UpdateMessage): Commitments = Commitments.addRemoteProposal(this, proposal)

def announceChannel: Boolean = (channelFlags & 0x01) != 0
val announceChannel: Boolean = (channelFlags & 0x01) != 0

def availableBalanceForSendMsat: Long = {
def usableBalances: UsableBalances = {
val reduced = CommitmentSpec.reduce(remoteCommit.spec, remoteChanges.acked, localChanges.proposed)
val feesMsat = if (localParams.isFunder) Transactions.commitTxFee(Satoshi(remoteParams.dustLimitSatoshis), reduced).amount * 1000 else 0
reduced.toRemoteMsat - remoteParams.channelReserveSatoshis * 1000 - feesMsat
val commitTxFee = Transactions.commitTxFee(Satoshi(remoteParams.dustLimitSatoshis), reduced).amount * 1000
val localBalance = reduced.toRemoteMsat - remoteParams.channelReserveSatoshis * 1000 - { if (localParams.isFunder) commitTxFee else 0 }
val remoteBalance = reduced.toLocalMsat - localParams.channelReserveSatoshis * 1000 - { if (localParams.isFunder) 0 else commitTxFee }
UsableBalances(localMsat = localBalance, remoteMsat = remoteBalance, isPublic = announceChannel)
}
}

Expand Down
13 changes: 8 additions & 5 deletions eclair-core/src/main/scala/fr/acinq/eclair/payment/Relayer.scala
Expand Up @@ -70,17 +70,20 @@ class Relayer(nodeParams: NodeParams, register: ActorRef, paymentHandler: ActorR

def main(channelUpdates: Map[ShortChannelId, OutgoingChannel], node2channels: mutable.HashMap[PublicKey, mutable.Set[ShortChannelId]] with mutable.MultiMap[PublicKey, ShortChannelId]): Receive = {

case 'usableBalances =>
sender ! channelUpdates.values

case LocalChannelUpdate(_, channelId, shortChannelId, remoteNodeId, _, channelUpdate, commitments) =>
log.debug(s"updating local channel info for channelId=$channelId shortChannelId=$shortChannelId remoteNodeId=$remoteNodeId channelUpdate={} commitments={}", channelUpdate, commitments)
context become main(channelUpdates + (channelUpdate.shortChannelId -> OutgoingChannel(remoteNodeId, channelUpdate, commitments.availableBalanceForSendMsat)), node2channels.addBinding(remoteNodeId, channelUpdate.shortChannelId))
context become main(channelUpdates + (channelUpdate.shortChannelId -> OutgoingChannel(remoteNodeId, channelUpdate, commitments.usableBalances)), node2channels.addBinding(remoteNodeId, channelUpdate.shortChannelId))

case LocalChannelDown(_, channelId, shortChannelId, remoteNodeId) =>
log.debug(s"removed local channel info for channelId=$channelId shortChannelId=$shortChannelId")
context become main(channelUpdates - shortChannelId, node2channels.removeBinding(remoteNodeId, shortChannelId))

case AvailableBalanceChanged(_, _, shortChannelId, _, commitments) =>
val channelUpdates1 = channelUpdates.get(shortChannelId) match {
case Some(c: OutgoingChannel) => channelUpdates + (shortChannelId -> c.copy(availableBalanceMsat = commitments.availableBalanceForSendMsat))
case Some(c: OutgoingChannel) => channelUpdates + (shortChannelId -> c.copy(usableBalances = commitments.usableBalances))
case None => channelUpdates // we only consider the balance if we have the channel_update
}
context become main(channelUpdates1, node2channels)
Expand Down Expand Up @@ -197,7 +200,7 @@ class Relayer(nodeParams: NodeParams, register: ActorRef, paymentHandler: ActorR
object Relayer {
def props(nodeParams: NodeParams, register: ActorRef, paymentHandler: ActorRef) = Props(classOf[Relayer], nodeParams, register, paymentHandler)

case class OutgoingChannel(nextNodeId: PublicKey, channelUpdate: ChannelUpdate, availableBalanceMsat: Long)
case class OutgoingChannel(nextNodeId: PublicKey, channelUpdate: ChannelUpdate, usableBalances: UsableBalances)

// @formatter:off
sealed trait NextPayload
Expand Down Expand Up @@ -302,10 +305,10 @@ object Relayer {
val channelInfo_opt = channelUpdates.get(shortChannelId)
val channelUpdate_opt = channelInfo_opt.map(_.channelUpdate)
val relayResult = relayOrFail(relayPayload, channelUpdate_opt)
log.debug(s"candidate channel for htlc #${add.id} paymentHash=${add.paymentHash}: shortChannelId={} balanceMsat={} channelUpdate={} relayResult={}", shortChannelId, channelInfo_opt.map(_.availableBalanceMsat).getOrElse(""), channelUpdate_opt.getOrElse(""), relayResult)
log.debug(s"candidate channel for htlc #${add.id} paymentHash=${add.paymentHash}: shortChannelId={} balanceMsat={} channelUpdate={} relayResult={}", shortChannelId, channelInfo_opt.map(_.usableBalances.localMsat).getOrElse(""), channelUpdate_opt.getOrElse(""), relayResult)
(shortChannelId, channelInfo_opt, relayResult)
}
.collect { case (shortChannelId, Some(channelInfo), Right(_)) => (shortChannelId, channelInfo.availableBalanceMsat) }
.collect { case (shortChannelId, Some(channelInfo), Right(_)) => (shortChannelId, channelInfo.usableBalances.localMsat) }
.filter(_._2 > relayPayload.payload.amtToForward) // we only keep channels that have enough balance to handle this payment
.toList // needed for ordering
.sortBy(_._2) // we want to use the channel with the lowest available balance that can process the payment
Expand Down
Expand Up @@ -103,7 +103,7 @@ trait StateTestsHelperMethods extends TestKitBase {
bob2blockchain.expectMsgType[WatchConfirmed] // deeply buried
awaitCond(alice.stateName == NORMAL)
awaitCond(bob.stateName == NORMAL)
assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSendMsat == pushMsat - TestConstants.Alice.channelParams.channelReserveSatoshis * 1000)
assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.usableBalances.localMsat == pushMsat - TestConstants.Alice.channelParams.channelReserveSatoshis * 1000)
// x2 because alice and bob share the same relayer
channelUpdateListener.expectMsgType[LocalChannelUpdate]
channelUpdateListener.expectMsgType[LocalChannelUpdate]
Expand Down
Expand Up @@ -18,7 +18,7 @@ package fr.acinq.eclair.payment

import fr.acinq.bitcoin.Block
import fr.acinq.bitcoin.Crypto.PublicKey
import fr.acinq.eclair.channel.{AddHtlcFailed, CMD_ADD_HTLC, CMD_FAIL_HTLC}
import fr.acinq.eclair.channel.{AddHtlcFailed, UsableBalances, CMD_ADD_HTLC, CMD_FAIL_HTLC}
import fr.acinq.eclair.crypto.Sphinx
import fr.acinq.eclair.payment.Relayer.{OutgoingChannel, RelayPayload}
import fr.acinq.eclair.router.Announcements
Expand Down Expand Up @@ -81,11 +81,11 @@ class ChannelSelectionSpec extends FunSuite {
val channelUpdate = dummyUpdate(ShortChannelId(12345), 10, 100, 1000, 100, 10000000, true)

val channelUpdates = Map(
ShortChannelId(11111) -> OutgoingChannel(a, channelUpdate, 100000000),
ShortChannelId(12345) -> OutgoingChannel(a, channelUpdate, 20000000),
ShortChannelId(22222) -> OutgoingChannel(a, channelUpdate, 10000000),
ShortChannelId(33333) -> OutgoingChannel(a, channelUpdate, 100000),
ShortChannelId(44444) -> OutgoingChannel(b, channelUpdate, 1000000)
ShortChannelId(11111) -> OutgoingChannel(a, channelUpdate, UsableBalances(100000000, 0, isPublic = true)),
ShortChannelId(12345) -> OutgoingChannel(a, channelUpdate, UsableBalances(20000000, 0, isPublic = true)),
ShortChannelId(22222) -> OutgoingChannel(a, channelUpdate, UsableBalances(10000000, 0, isPublic = false)),
ShortChannelId(33333) -> OutgoingChannel(a, channelUpdate, UsableBalances(100000, 0, isPublic = false)),
ShortChannelId(44444) -> OutgoingChannel(b, channelUpdate, UsableBalances(1000000, 0, isPublic = true))
)

val node2channels = new mutable.HashMap[PublicKey, mutable.Set[ShortChannelId]] with mutable.MultiMap[PublicKey, ShortChannelId]
Expand Down
Expand Up @@ -58,9 +58,8 @@ class RelayerSpec extends TestkitBaseClass {
val channelId_ab = randomBytes32
val channelId_bc = randomBytes32

def makeCommitments(channelId: ByteVector32, availableBalanceMsat: Long = 50000000L) = new Commitments(null, null, 0.toByte, null, null,
null, null, 0, 0, Map.empty, null, null, null, channelId) {
override def availableBalanceForSendMsat: Long = availableBalanceMsat
def makeCommitments(channelId: ByteVector32, availableBalanceMsat: Long = 50000000L) = new Commitments(null, null, 0.toByte, null, null, null, null, 0, 0, Map.empty, null, null, null, channelId) {
override def usableBalances: UsableBalances = UsableBalances(availableBalanceMsat, 0, isPublic = true)
}

test("relay an htlc-add") { f =>
Expand Down

0 comments on commit e0ab3f7

Please sign in to comment.