Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4293514
Use feeEstimator in NodeParams with custom confirmationTarget
araspitzu Jul 19, 2019
5f4ee9a
Introduce FeeConf object and config block for confirmation targets, r…
araspitzu Jul 5, 2019
527499b
Use a custom confirmation target for commitment transaction
araspitzu Jul 8, 2019
dade6fd
Use a custom confirmation target for funding transaction
araspitzu Jul 8, 2019
3e4ad7a
Use custom confirmation target for mutual close transaction
araspitzu Jul 19, 2019
214494b
Use custom confirmation target for claim transactions
araspitzu Jul 19, 2019
de55d92
Add confirmation target block 144
araspitzu Jul 20, 2019
83763ef
Fix bitgo fee provider test
araspitzu Jul 20, 2019
7ec7e3a
Add copyright header to FeeEstimator.scala
araspitzu Jul 20, 2019
f0649dd
Reorg parametres order, pass `FeeEstimator` from Setup, move `FeeTarg…
araspitzu Jul 22, 2019
a04eed8
Formatting
araspitzu Jul 23, 2019
45100ad
Update eclair-core/src/main/resources/reference.conf
araspitzu Jul 23, 2019
7e31ebb
Use underlyingActor to access `NodeParams` and feeEstimator during test
araspitzu Jul 23, 2019
c66b3b8
Change position order of `receiveFee` parameters
araspitzu Jul 23, 2019
d577d07
Merge branch 'master' into custom_confirmation_target
araspitzu Jul 23, 2019
1c21959
Use feeEstimator from underlyingActor
araspitzu Jul 23, 2019
b652fb6
Group together on-chain fees related configurations
araspitzu Jul 23, 2019
4cf6359
Use helper functions to get 'OnChainFeeConf' during test
araspitzu Jul 23, 2019
a75a931
Use block target = 12 as default for claim transactions
araspitzu Jul 23, 2019
f768ec5
Move default-feerates configuration block inside on-chain-fees, renaming
araspitzu Jul 24, 2019
9da4996
Remove helper methods in favor of pimp pattern
araspitzu Jul 24, 2019
e16763d
Merge branch 'master' into custom_confirmation_target
araspitzu Jul 24, 2019
5db1271
Rename default-feerates section, remove blank line
araspitzu Jul 24, 2019
d240dfe
Move `OnChainFeeConf` to FeeEstimator.scala
araspitzu Jul 24, 2019
419bf60
When computing the first mutual-closing fee use the minimum between t…
araspitzu Jul 24, 2019
f350b87
Do not compare confirmation targets when choosing a 'firstClosingFee'…
araspitzu Jul 25, 2019
8f1bcc0
Move `OnChainFeeConf` value close to other on-chain fee related value
araspitzu Jul 25, 2019
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
42 changes: 26 additions & 16 deletions eclair-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,6 @@ eclair {
zmqtx = "tcp://127.0.0.1:29000"
}

default-feerates { // those are in satoshis per kilobyte
delay-blocks {
1 = 210000
2 = 180000
6 = 150000
12 = 110000
36 = 50000
72 = 20000
}
}
min-feerate = 3 // minimum feerate in satoshis per byte
smooth-feerate-window = 6 // 1 = no smoothing

Expand Down Expand Up @@ -77,13 +67,33 @@ eclair {
fee-base-msat = 1000
fee-proportional-millionths = 100 // fee charged per transferred satoshi in millionths of a satoshi (100 = 0.01%)

// maximum local vs remote feerate mismatch; 1.0 means 100%
// actual check is abs((local feerate - remote fee rate) / (local fee rate + remote fee rate)/2) > fee rate mismatch
max-feerate-mismatch = 1.56 // will allow remote fee rates up to 8x bigger or smaller than our local fee rate
on-chain-fees {
Comment thread
pm47 marked this conversation as resolved.
default-feerates { // those are per target block, in satoshis per kilobyte
1 = 210000
2 = 180000
6 = 150000
12 = 110000
36 = 50000
72 = 20000
144 = 15000
}

// funder will send an UpdateFee message if the difference between current commitment fee and actual current network fee is greater
// than this ratio.
update-fee_min-diff-ratio = 0.1
// number of blocks to target when computing fees for each transaction type
target-blocks {
funding = 6 // target for the funding transaction
commitment = 2 // target for the commitment transaction (used in force-close scenario) *do not change this unless you know what you are doing*
mutual-close = 12 // target for the mutual close transaction
claim-main = 12 // target for the claim main transaction (tx that spends main channel output back to wallet)
}

// maximum local vs remote feerate mismatch; 1.0 means 100%
// actual check is abs((local feerate - remote fee rate) / (local fee rate + remote fee rate)/2) > fee rate mismatch
max-feerate-mismatch = 1.56 // will allow remote fee rates up to 8x bigger or smaller than our local fee rate

// funder will send an UpdateFee message if the difference between current commitment fee and actual current network fee is greater
// than this ratio.
update-fee-min-diff-ratio = 0.1
}

revocation-timeout = 20 seconds // after sending a commit_sig, we will wait for at most that duration before disconnecting

Expand Down
25 changes: 17 additions & 8 deletions eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import java.util.concurrent.TimeUnit
import com.typesafe.config.{Config, ConfigFactory}
import fr.acinq.bitcoin.Crypto.PublicKey
import fr.acinq.bitcoin.{Block, ByteVector32}
import fr.acinq.eclair.NodeParams.WatcherType
import fr.acinq.eclair.NodeParams.{WatcherType}
import fr.acinq.eclair.blockchain.fee.{FeeEstimator, FeeTargets, OnChainFeeConf}
import fr.acinq.eclair.channel.Channel
import fr.acinq.eclair.crypto.KeyManager
import fr.acinq.eclair.db._
Expand All @@ -47,6 +48,7 @@ case class NodeParams(keyManager: KeyManager,
localFeatures: ByteVector,
overrideFeatures: Map[PublicKey, (ByteVector, ByteVector)],
dustLimitSatoshis: Long,
onChainFeeConf: OnChainFeeConf,
maxHtlcValueInFlightMsat: UInt64,
maxAcceptedHtlcs: Int,
expiryDeltaBlocks: Int,
Expand All @@ -55,7 +57,6 @@ case class NodeParams(keyManager: KeyManager,
toRemoteDelayBlocks: Int,
maxToLocalDelayBlocks: Int,
minDepthBlocks: Int,
smartfeeNBlocks: Int,
feeBaseMsat: Int,
feeProportionalMillionth: Int,
reserveToFundingRatio: Double,
Expand All @@ -65,8 +66,6 @@ case class NodeParams(keyManager: KeyManager,
pingInterval: FiniteDuration,
pingTimeout: FiniteDuration,
pingDisconnect: Boolean,
maxFeerateMismatch: Double,
updateFeeMinDiffRatio: Double,
autoReconnect: Boolean,
initialRandomReconnectDelay: FiniteDuration,
maxReconnectInterval: FiniteDuration,
Expand Down Expand Up @@ -125,7 +124,7 @@ object NodeParams {
}
}

def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases): NodeParams = {
def makeNodeParams(config: Config, keyManager: KeyManager, torAddress_opt: Option[NodeAddress], database: Databases, feeEstimator: FeeEstimator): NodeParams = {

val chain = config.getString("chain")
val chainHash = makeChainHash(chain)
Expand Down Expand Up @@ -181,6 +180,13 @@ object NodeParams {
.toList
.map(ip => NodeAddress.fromParts(ip, config.getInt("server.port")).get) ++ torAddress_opt

val feeTargets = FeeTargets(
fundingBlockTarget = config.getInt("on-chain-fees.target-blocks.funding"),
commitmentBlockTarget = config.getInt("on-chain-fees.target-blocks.commitment"),
mutualCloseBlockTarget = config.getInt("on-chain-fees.target-blocks.mutual-close"),
claimMainBlockTarget = config.getInt("on-chain-fees.target-blocks.claim-main")
)

NodeParams(
keyManager = keyManager,
alias = nodeAlias,
Expand All @@ -190,6 +196,12 @@ object NodeParams {
localFeatures = ByteVector.fromValidHex(config.getString("local-features")),
overrideFeatures = overrideFeatures,
dustLimitSatoshis = dustLimitSatoshis,
onChainFeeConf = OnChainFeeConf(
feeTargets = feeTargets,
feeEstimator = feeEstimator,
maxFeerateMismatch = config.getDouble("on-chain-fees.max-feerate-mismatch"),
updateFeeMinDiffRatio = config.getDouble("on-chain-fees.update-fee-min-diff-ratio")
),
maxHtlcValueInFlightMsat = UInt64(config.getLong("max-htlc-value-in-flight-msat")),
maxAcceptedHtlcs = maxAcceptedHtlcs,
expiryDeltaBlocks = expiryDeltaBlocks,
Expand All @@ -198,7 +210,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 @@ -208,8 +219,6 @@ 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"),
maxFeerateMismatch = config.getDouble("max-feerate-mismatch"),
updateFeeMinDiffRatio = config.getDouble("update-fee_min-diff-ratio"),
autoReconnect = config.getBoolean("auto-reconnect"),
initialRandomReconnectDelay = FiniteDuration(config.getDuration("initial-random-reconnect-delay").getSeconds, TimeUnit.SECONDS),
maxReconnectInterval = FiniteDuration(config.getDuration("max-reconnect-interval").getSeconds, TimeUnit.SECONDS),
Expand Down
20 changes: 13 additions & 7 deletions eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ class Setup(datadir: File,
case None => Databases.sqliteJDBC(chaindir)
}

val nodeParams = NodeParams.makeNodeParams(config, keyManager, initTor(), database)
val feeEstimator = new FeeEstimator {
override def getFeeratePerKb(target: Int): Long = Globals.feeratesPerKB.get().feePerBlock(target)
override def getFeeratePerKw(target: Int): Long = Globals.feeratesPerKw.get().feePerBlock(target)
}

val nodeParams = NodeParams.makeNodeParams(config, keyManager, initTor(), database, feeEstimator)

val serverBindingAddress = new InetSocketAddress(
config.getString("server.binding-ip"),
Expand Down Expand Up @@ -183,12 +188,13 @@ class Setup(datadir: File,

defaultFeerates = {
val confDefaultFeerates = FeeratesPerKB(
block_1 = config.getLong("default-feerates.delay-blocks.1"),
blocks_2 = config.getLong("default-feerates.delay-blocks.2"),
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")
block_1 = config.getLong("on-chain-fees.default-feerates.1"),
blocks_2 = config.getLong("on-chain-fees.default-feerates.2"),
blocks_6 = config.getLong("on-chain-fees.default-feerates.6"),
blocks_12 = config.getLong("on-chain-fees.default-feerates.12"),
blocks_36 = config.getLong("on-chain-fees.default-feerates.36"),
blocks_72 = config.getLong("on-chain-fees.default-feerates.72"),
blocks_144 = config.getLong("on-chain-fees.default-feerates.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
@@ -0,0 +1,29 @@
/*
* Copyright 2019 ACINQ SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package fr.acinq.eclair.blockchain.fee

trait FeeEstimator {

def getFeeratePerKb(target: Int) : Long

def getFeeratePerKw(target: Int) : Long

Comment thread
sstone marked this conversation as resolved.
}

case class FeeTargets(fundingBlockTarget: Int, commitmentBlockTarget: Int, mutualCloseBlockTarget: Int, claimMainBlockTarget: Int)

case class OnChainFeeConf(feeTargets: FeeTargets, feeEstimator: FeeEstimator, maxFeerateMismatch: Double, updateFeeMinDiffRatio: Double)
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,33 @@ 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) {
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")
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 && blocks_144 > 0, "all feerates must be strictly greater than 0")

def feePerBlock(target: Int) = target match {
Comment thread
pm47 marked this conversation as resolved.
case 1 => block_1
case 2 => blocks_2
case t if t <= 6 => blocks_6
case t if t <= 12 => blocks_12
case t if t <= 36 => blocks_36
case t if t <= 72 => blocks_72
case _ => blocks_144
}
}

// 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) {
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")
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 && blocks_144 > 0, "all feerates must be strictly greater than 0")

def feePerBlock(target: Int) = target match {
case 1 => block_1
case 2 => blocks_2
case t if t <= 6 => blocks_6
case t if t <= 12 => blocks_12
case t if t <= 36 => blocks_36
case t if t <= 72 => blocks_72
case _ => blocks_144
}
}

object FeeratesPerKw {
Expand All @@ -46,7 +66,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 +81,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