Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions eclair-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,18 @@ eclair {
12 = 110000
36 = 50000
72 = 20000
144 = 15000
}
}

// number of blocks to target when computing fees for each transaction type, possible values are: 1, 2, 6, 12, 36, 72, 144
fee-targets {
funding = 6 // target for the funding transaction
commitment = 2 // target for the commitment transaction (used in force-close scenario)
mutual-close = 6 // target for the mutual close transaction
claim-main = 6 // target for the claim main transaction (tx that spends main channel output back to wallet)
}

min-feerate = 3 // minimum feerate in satoshis per byte
smooth-feerate-window = 6 // 1 = no smoothing

Expand Down
14 changes: 10 additions & 4 deletions eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import java.io.File
import java.net.InetSocketAddress
import java.nio.file.Files
import java.util.concurrent.TimeUnit

import com.typesafe.config.{Config, ConfigFactory}
import fr.acinq.bitcoin.Crypto.PublicKey
import fr.acinq.bitcoin.{Block, ByteVector32}
Expand All @@ -30,9 +29,9 @@ import fr.acinq.eclair.crypto.KeyManager
import fr.acinq.eclair.db._
import fr.acinq.eclair.router.RouterConf
import fr.acinq.eclair.tor.Socks5ProxyParams
import fr.acinq.eclair.transactions.Transactions.FeeTargets
import fr.acinq.eclair.wire.{Color, NodeAddress}
import scodec.bits.ByteVector

import scala.collection.JavaConversions._
import scala.concurrent.duration.FiniteDuration

Expand All @@ -54,7 +53,6 @@ case class NodeParams(keyManager: KeyManager,
toRemoteDelayBlocks: Int,
maxToLocalDelayBlocks: Int,
minDepthBlocks: Int,
smartfeeNBlocks: Int,
feeBaseMsat: Int,
feeProportionalMillionth: Int,
reserveToFundingRatio: Double,
Expand All @@ -64,6 +62,7 @@ case class NodeParams(keyManager: KeyManager,
pingInterval: FiniteDuration,
pingTimeout: FiniteDuration,
pingDisconnect: Boolean,
feeTargets: FeeTargets,
maxFeerateMismatch: Double,
updateFeeMinDiffRatio: Double,
autoReconnect: Boolean,
Expand Down Expand Up @@ -176,6 +175,13 @@ object NodeParams {
.toList
.map(ip => NodeAddress.fromParts(ip, config.getInt("server.port")).get) ++ torAddress_opt

val feeTargets = FeeTargets(
fundingBlockTarget = config.getInt("fee-targets.funding"),
commitmentBlockTarget = config.getInt("fee-targets.commitment"),
mutualCloseBlockTarget = config.getInt("fee-targets.mutual-close"),
claimMainBlockTarget = config.getInt("fee-targets.claim-main")
)

NodeParams(
keyManager = keyManager,
alias = nodeAlias,
Expand All @@ -192,7 +198,6 @@ object NodeParams {
toRemoteDelayBlocks = config.getInt("to-remote-delay-blocks"),
maxToLocalDelayBlocks = config.getInt("max-to-local-delay-blocks"),
minDepthBlocks = config.getInt("mindepth-blocks"),
smartfeeNBlocks = 3,
feeBaseMsat = config.getInt("fee-base-msat"),
feeProportionalMillionth = config.getInt("fee-proportional-millionths"),
reserveToFundingRatio = config.getDouble("reserve-to-funding-ratio"),
Expand All @@ -202,6 +207,7 @@ object NodeParams {
pingInterval = FiniteDuration(config.getDuration("ping-interval").getSeconds, TimeUnit.SECONDS),
pingTimeout = FiniteDuration(config.getDuration("ping-timeout").getSeconds, TimeUnit.SECONDS),
pingDisconnect = config.getBoolean("ping-disconnect"),
feeTargets = feeTargets,
maxFeerateMismatch = config.getDouble("max-feerate-mismatch"),
updateFeeMinDiffRatio = config.getDouble("update-fee_min-diff-ratio"),
autoReconnect = config.getBoolean("auto-reconnect"),
Expand Down
3 changes: 2 additions & 1 deletion eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ class Setup(datadir: File,
blocks_6 = config.getLong("default-feerates.delay-blocks.6"),
blocks_12 = config.getLong("default-feerates.delay-blocks.12"),
blocks_36 = config.getLong("default-feerates.delay-blocks.36"),
blocks_72 = config.getLong("default-feerates.delay-blocks.72")
blocks_72 = config.getLong("default-feerates.delay-blocks.72"),
blocks_144 = config.getLong("default-feerates.delay-blocks.144")
)
Globals.feeratesPerKB.set(confDefaultFeerates)
Globals.feeratesPerKw.set(FeeratesPerKw(confDefaultFeerates))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ class BitcoinCoreFeeProvider(rpcClient: BitcoinJsonRPCClient, defaultFeerates: F
blocks_12 <- estimateSmartFee(12)
blocks_36 <- estimateSmartFee(36)
blocks_72 <- estimateSmartFee(72)
blocks_144 <- estimateSmartFee(144)
} yield FeeratesPerKB(
block_1 = if (block_1 > 0) block_1 else defaultFeerates.block_1,
blocks_2 = if (blocks_2 > 0) blocks_2 else defaultFeerates.blocks_2,
blocks_6 = if (blocks_6 > 0) blocks_6 else defaultFeerates.blocks_6,
blocks_12 = if (blocks_12 > 0) blocks_12 else defaultFeerates.blocks_12,
blocks_36 = if (blocks_36 > 0) blocks_36 else defaultFeerates.blocks_36,
blocks_72 = if (blocks_72 > 0) blocks_72 else defaultFeerates.blocks_72)
blocks_72 = if (blocks_72 > 0) blocks_72 else defaultFeerates.blocks_72,
blocks_144 = if (blocks_144 > 0) blocks_144 else defaultFeerates.blocks_144)
}

object BitcoinCoreFeeProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ object BitgoFeeProvider {
blocks_6 = extractFeerate(feeRanges, 6),
blocks_12 = extractFeerate(feeRanges, 12),
blocks_36 = extractFeerate(feeRanges, 36),
blocks_72 = extractFeerate(feeRanges, 72))
blocks_72 = extractFeerate(feeRanges, 72),
blocks_144 = extractFeerate(feeRanges, 144))

}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ object EarnDotComFeeProvider {
blocks_6 = extractFeerate(feeRanges, 6),
blocks_12 = extractFeerate(feeRanges, 12),
blocks_36 = extractFeerate(feeRanges, 36),
blocks_72 = extractFeerate(feeRanges, 72))
blocks_72 = extractFeerate(feeRanges, 72),
blocks_144 = extractFeerate(feeRanges, 144))

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,25 @@ trait FeeProvider {
}

// stores fee rate in satoshi/kb (1 kb = 1000 bytes)
case class FeeratesPerKB(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long) {
case class FeeratesPerKB(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long, blocks_144: Long) {
require(block_1 > 0 && blocks_2 > 0 && blocks_6 > 0 && blocks_12 > 0 && blocks_36 > 0 && blocks_72 > 0, "all feerates must be strictly greater than 0")
}

// stores fee rate in satoshi/kw (1 kw = 1000 weight units)
case class FeeratesPerKw(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long) {
case class FeeratesPerKw(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long, blocks_144: Long) {
require(block_1 > 0 && blocks_2 > 0 && blocks_6 > 0 && blocks_12 > 0 && blocks_36 > 0 && blocks_72 > 0, "all feerates must be strictly greater than 0")

def getRatePerBlock(blockTarget: Int): Long = blockTarget match {
case 1 => block_1
case 2 => blocks_2
case 6 => blocks_6
case 12 => blocks_12
case 36 => blocks_36
case 72 => blocks_72
case 144 => blocks_144
case _ => throw new IllegalArgumentException(s"can't choose ratePerBlock=$blockTarget")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about:

  def getRatePerBlock(blockTarget: Int): Long = blockTarget match {
    case i if i <=1 => block_1
    case i if i <= 2 => blocks_2
    case i if i <= 6 => blocks_6
    case i if i <= 12 => blocks_12
    case i if i <= 36 => blocks_36
    case i if i <= 72 => blocks_72
    case _ => blocks_144
}

A bit more lax to reduce support requests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like silently choosing a different feerate for the user, this can result in unexpected delays. The current block of code is wrong though (it would fail for blockTarget = 144).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 5195614 fixes the problem but it does not introduce lax behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather agree with @pm47 here: onchain fee estimation is very unreliable and it gets worse as the confirmation target goes up, so forcing users to use arbitrary targets seems a bit too strict.
I think we should be able to accept any confirmation target and convert it to a feerate

}

}

object FeeratesPerKw {
Expand All @@ -46,7 +58,8 @@ object FeeratesPerKw {
blocks_6 = feerateKB2Kw(feerates.blocks_6),
blocks_12 = feerateKB2Kw(feerates.blocks_12),
blocks_36 = feerateKB2Kw(feerates.blocks_36),
blocks_72 = feerateKB2Kw(feerates.blocks_72))
blocks_72 = feerateKB2Kw(feerates.blocks_72),
blocks_144 = feerateKB2Kw(feerates.blocks_144))

/**
* Used in tests
Expand All @@ -60,6 +73,7 @@ object FeeratesPerKw {
blocks_6 = feeratePerKw,
blocks_12 = feeratePerKw,
blocks_36 = feeratePerKw,
blocks_72 = feeratePerKw)
blocks_72 = feeratePerKw,
blocks_144 = feeratePerKw)
}

Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ object SmoothFeeProvider {
blocks_6 = avg(rates.map(_.blocks_6)),
blocks_12 = avg(rates.map(_.blocks_12)),
blocks_36 = avg(rates.map(_.blocks_36)),
blocks_72 = avg(rates.map(_.blocks_72)))
blocks_72 = avg(rates.map(_.blocks_72)),
blocks_144 = avg(rates.map(_.blocks_144)))
}
Loading