1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-24 06:47:46 +01:00

add node fees to htlc amounts

This commit is contained in:
sstone 2016-08-11 17:14:50 +02:00
parent 3146c2d68a
commit 293f1c930a
5 changed files with 43 additions and 5 deletions

View file

@ -18,6 +18,8 @@ eclair {
} }
commit-fee = 50000 commit-fee = 50000
closing-fee = 10000 closing-fee = 10000
base-fee = 546000
proportional-fee = 10
payment-handler = "local" payment-handler = "local"
} }
akka { akka {

View file

@ -29,7 +29,8 @@ object Globals {
val default_mindepth = 3 val default_mindepth = 3
val commit_fee = config.getInt("eclair.commit-fee") val commit_fee = config.getInt("eclair.commit-fee")
val closing_fee = config.getInt("eclair.closing-fee") val closing_fee = config.getInt("eclair.closing-fee")
val base_fee = config.getInt("eclair.base-fee")
val proportional_fee = config.getInt("eclair.proportional-fee")
val default_anchor_amount = 1000000 val default_anchor_amount = 1000000
//def newChannelParameters = OurChannelParams(default_locktime, commit_priv, final_priv, default_mindepth, commit_fee, "sha-seed".getBytes(), None) //def newChannelParameters = OurChannelParams(default_locktime, commit_priv, final_priv, default_mindepth, commit_fee, "sha-seed".getBytes(), None)

View file

@ -125,4 +125,13 @@ package object eclair {
def computeFee(feeRate: Long, numberOfHtlcs: Int): Long = { def computeFee(feeRate: Long, numberOfHtlcs: Int): Long = {
Math.floorDiv((338 + 32 * numberOfHtlcs) * feeRate, 2000) * 2 Math.floorDiv((338 + 32 * numberOfHtlcs) * feeRate, 2000) * 2
} }
/**
*
* @param base fixed fee
* @param proportional proportional fee
* @param msat amount in millisatoshi
* @return the fee (in msat) that a node should be paid to forward an HTLC of 'amount' millisatoshis
*/
def nodeFee(base: Long, proportional: Long, msat: Long): Long = base + (proportional * msat) / 1000000
} }

View file

@ -77,10 +77,14 @@ class IRCRouter(bitcoinClient: ExtendedBitcoinClient) extends Actor with ActorLo
Boot.system.actorSelection(Register.actorPathToNodeId(next)) Boot.system.actorSelection(Register.actorPathToNodeId(next))
.resolveOne(2 seconds) .resolveOne(2 seconds)
.map { channel => .map { channel =>
// TODO : no fees! // build a route
val r = lightning.route(others.map(n => route_step(c.amountMsat, next = Next.Bitcoin(n))) :+ route_step(0, next = route_step.Next.End(true))) val r = buildRoute(c.amountMsat, others)
// apply fee
val amountMsat = r.steps(0).amount
val fee = nodeFee(Globals.base_fee, Globals.proportional_fee, amountMsat).toInt
// TODO : expiry is not correctly calculated // TODO : expiry is not correctly calculated
channel ! CMD_ADD_HTLC(c.amountMsat, c.h, locktime(Blocks(blockCount.toInt + 100 + r.steps.size - 1)), r, commit = true) channel ! CMD_ADD_HTLC(amountMsat + fee, c.h, locktime(Blocks(blockCount.toInt + 100 + r.steps.size - 1)), r, commit = true)
s ! channel s ! channel
} }
}) onFailure { }) onFailure {
@ -115,11 +119,23 @@ object IRCRouter {
} }
case None => throw new RuntimeException("route not found") case None => throw new RuntimeException("route not found")
} }
} }
def findRoute(myNodeId: BinaryData, targetNodeId: BinaryData, channels: Map[BinaryData, ChannelDesc])(implicit ec: ExecutionContext): Future[Seq[BinaryData]] = Future { def findRoute(myNodeId: BinaryData, targetNodeId: BinaryData, channels: Map[BinaryData, ChannelDesc])(implicit ec: ExecutionContext): Future[Seq[BinaryData]] = Future {
findRouteDijkstra(myNodeId, targetNodeId, channels) findRouteDijkstra(myNodeId, targetNodeId, channels)
} }
def buildRoute(finalAmountMsat: Int, nodeIds: Seq[BinaryData]) : lightning.route = {
// FIXME: use actual fee parameters that are specific to each node
def fee(amountMsat: Int) = nodeFee(Globals.base_fee, Globals.proportional_fee, amountMsat).toInt
var amountMsat = finalAmountMsat
val steps = nodeIds.reverse.map(nodeId => {
val step = route_step(amountMsat, next = Next.Bitcoin(nodeId))
amountMsat = amountMsat + fee(amountMsat)
step
})
lightning.route(steps.reverse :+ route_step(0, next = route_step.Next.End(true)))
}
} }

View file

@ -2,6 +2,7 @@ package fr.acinq.eclair
import fr.acinq.bitcoin.BinaryData import fr.acinq.bitcoin.BinaryData
import fr.acinq.eclair.router.{ChannelDesc, IRCRouter} import fr.acinq.eclair.router.{ChannelDesc, IRCRouter}
import lightning.route_step
import org.jgrapht.alg.DijkstraShortestPath import org.jgrapht.alg.DijkstraShortestPath
import org.jgrapht.graph.{DefaultEdge, SimpleGraph} import org.jgrapht.graph.{DefaultEdge, SimpleGraph}
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -79,4 +80,13 @@ class RouterSpec extends FunSuite {
} }
} }
test("compute fees") {
val nodeIds = Seq(BinaryData("00"), BinaryData("01"), BinaryData("02"))
val amountMsat = 1000000
val route = IRCRouter.buildRoute(amountMsat, nodeIds)
assert(route.steps.length == 4 && route.steps.last == route_step(0, next = route_step.Next.End(true)))
assert(route.steps(2).amount == amountMsat)
assert(route.steps.dropRight(1).map(_.next.bitcoin.get.key).map(bytestring2bin) == nodeIds)
assert(route.steps(0).amount - route.steps(1).amount == nodeFee(Globals.base_fee, Globals.proportional_fee, route.steps(1).amount))
}
} }