Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add recommended_feerates optional message #2860

Merged
merged 2 commits into from
Sep 24, 2024
Merged
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
6 changes: 3 additions & 3 deletions eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,9 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging {
override def sendOnChain(address: String, amount: Satoshi, confirmationTargetOrFeerate: Either[Long, FeeratePerByte]): Future[TxId] = {
val feeRate = confirmationTargetOrFeerate match {
case Left(blocks) =>
if (blocks < 3) appKit.nodeParams.currentFeerates.fast
else if (blocks > 6) appKit.nodeParams.currentFeerates.slow
else appKit.nodeParams.currentFeerates.medium
if (blocks < 3) appKit.nodeParams.currentBitcoinCoreFeerates.fast
else if (blocks > 6) appKit.nodeParams.currentBitcoinCoreFeerates.slow
else appKit.nodeParams.currentBitcoinCoreFeerates.medium
case Right(feeratePerByte) => FeeratePerKw(feeratePerByte)
}
appKit.wallet match {
Expand Down
34 changes: 28 additions & 6 deletions eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, Crypto, Satoshi, SatoshiLong}
import fr.acinq.eclair.Setup.Seeds
import fr.acinq.eclair.blockchain.fee._
import fr.acinq.eclair.channel.ChannelFlags
import fr.acinq.eclair.channel.fsm.Channel
import fr.acinq.eclair.channel.fsm.Channel.{BalanceThreshold, ChannelConf, UnhandledExceptionStrategy}
import fr.acinq.eclair.channel.{ChannelFlags, ChannelTypes}
import fr.acinq.eclair.crypto.Noise.KeyPair
import fr.acinq.eclair.crypto.keymanager.{ChannelKeyManager, NodeKeyManager, OnChainKeyManager}
import fr.acinq.eclair.db._
Expand All @@ -36,6 +36,7 @@ import fr.acinq.eclair.router.Graph.{HeuristicsConstants, WeightRatios}
import fr.acinq.eclair.router.Router._
import fr.acinq.eclair.router.{Graph, PathFindingExperimentConf}
import fr.acinq.eclair.tor.Socks5ProxyParams
import fr.acinq.eclair.transactions.Transactions
import fr.acinq.eclair.wire.protocol._
import grizzled.slf4j.Logging
import scodec.bits.ByteVector
Expand All @@ -57,7 +58,7 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,
onChainKeyManager_opt: Option[OnChainKeyManager],
instanceId: UUID, // a unique instance ID regenerated after each restart
private val blockHeight: AtomicLong,
private val feerates: AtomicReference[FeeratesPerKw],
private val bitcoinCoreFeerates: AtomicReference[FeeratesPerKw],
alias: String,
color: Color,
publicAddresses: List[NodeAddress],
Expand Down Expand Up @@ -102,13 +103,34 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,

def currentBlockHeight: BlockHeight = BlockHeight(blockHeight.get)

def currentFeerates: FeeratesPerKw = feerates.get()
def currentBitcoinCoreFeerates: FeeratesPerKw = bitcoinCoreFeerates.get()

/** Only to be used in tests. */
def setFeerates(value: FeeratesPerKw): Unit = feerates.set(value)
def setBitcoinCoreFeerates(value: FeeratesPerKw): Unit = bitcoinCoreFeerates.set(value)

/** Returns the features that should be used in our init message with the given peer. */
def initFeaturesFor(nodeId: PublicKey): Features[InitFeature] = overrideInitFeatures.getOrElse(nodeId, features).initFeatures()

/** Returns the feerates we'd like our peer to use when funding channels. */
def recommendedFeerates(remoteNodeId: PublicKey, localFeatures: Features[InitFeature], remoteFeatures: Features[InitFeature]): RecommendedFeerates = {
val feerateTolerance = onChainFeeConf.feerateToleranceFor(remoteNodeId)
val fundingFeerate = onChainFeeConf.getFundingFeerate(currentBitcoinCoreFeerates)
val fundingRange = RecommendedFeeratesTlv.FundingFeerateRange(
min = fundingFeerate * feerateTolerance.ratioLow,
max = fundingFeerate * feerateTolerance.ratioHigh,
)
pm47 marked this conversation as resolved.
Show resolved Hide resolved
// We use the most likely commitment format, even though there is no guarantee that this is the one that will be used.
val commitmentFormat = ChannelTypes.defaultFromFeatures(localFeatures, remoteFeatures, announceChannel = false).commitmentFormat
val commitmentFeerate = onChainFeeConf.getCommitmentFeerate(currentBitcoinCoreFeerates, remoteNodeId, commitmentFormat, channelConf.minFundingPrivateSatoshis)
val commitmentRange = RecommendedFeeratesTlv.CommitmentFeerateRange(
min = commitmentFeerate * feerateTolerance.ratioLow,
max = commitmentFormat match {
case Transactions.DefaultCommitmentFormat => commitmentFeerate * feerateTolerance.ratioHigh
case _: Transactions.AnchorOutputsCommitmentFormat => (commitmentFeerate * feerateTolerance.ratioHigh).max(feerateTolerance.anchorOutputMaxCommitFeerate)
},
)
RecommendedFeerates(chainHash, fundingFeerate, commitmentFeerate, TlvStream(fundingRange, commitmentRange))
}
}

case class PaymentFinalExpiryConf(min: CltvExpiryDelta, max: CltvExpiryDelta) {
Expand Down Expand Up @@ -219,7 +241,7 @@ object NodeParams extends Logging {

def makeNodeParams(config: Config, instanceId: UUID,
nodeKeyManager: NodeKeyManager, channelKeyManager: ChannelKeyManager, onChainKeyManager_opt: Option[OnChainKeyManager],
torAddress_opt: Option[NodeAddress], database: Databases, blockHeight: AtomicLong, feerates: AtomicReference[FeeratesPerKw],
torAddress_opt: Option[NodeAddress], database: Databases, blockHeight: AtomicLong, bitcoinCoreFeerates: AtomicReference[FeeratesPerKw],
pluginParams: Seq[PluginParams] = Nil): NodeParams = {
// check configuration for keys that have been renamed
val deprecatedKeyPaths = Map(
Expand Down Expand Up @@ -513,7 +535,7 @@ object NodeParams extends Logging {
onChainKeyManager_opt = onChainKeyManager_opt,
instanceId = instanceId,
blockHeight = blockHeight,
feerates = feerates,
bitcoinCoreFeerates = bitcoinCoreFeerates,
alias = nodeAlias,
color = Color(color(0), color(1), color(2)),
publicAddresses = addresses,
Expand Down
2 changes: 1 addition & 1 deletion eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class Setup(val datadir: File,
blockchain.Monitoring.Metrics.FeeratesPerByte.withTag(blockchain.Monitoring.Tags.Priority, blockchain.Monitoring.Tags.Priorities.Medium).update(feeratesPerKw.get.medium.toLong.toDouble)
blockchain.Monitoring.Metrics.FeeratesPerByte.withTag(blockchain.Monitoring.Tags.Priority, blockchain.Monitoring.Tags.Priorities.Fast).update(feeratesPerKw.get.fast.toLong.toDouble)
blockchain.Monitoring.Metrics.FeeratesPerByte.withTag(blockchain.Monitoring.Tags.Priority, blockchain.Monitoring.Tags.Priorities.Fastest).update(feeratesPerKw.get.fastest.toLong.toDouble)
system.eventStream.publish(CurrentFeerates(feeratesPerKw.get))
system.eventStream.publish(CurrentFeerates.BitcoinCore(feeratesPerKw.get))
logger.info(s"current feeratesPerKB=$feeratesPerKB feeratesPerKw=${feeratesPerKw.get}")
feeratesRetrieved.trySuccess(Done)
case Failure(exception) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,14 @@ case class NewTransaction(tx: Transaction) extends BlockchainEvent

case class CurrentBlockHeight(blockHeight: BlockHeight) extends BlockchainEvent

case class CurrentFeerates(feeratesPerKw: FeeratesPerKw) extends BlockchainEvent
sealed trait CurrentFeerates extends BlockchainEvent {
val feeratesPerKw: FeeratesPerKw
}

object CurrentFeerates {
//@formatter:off
case class BitcoinCore(feeratesPerKw: FeeratesPerKw) extends CurrentFeerates
//@formatter:on
}


Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ object Helpers {
val channelFeatures = ChannelFeatures(channelType, localFeatures, remoteFeatures, open.channelFlags.announceChannel)

// BOLT #2: The receiving node MUST fail the channel if: it considers feerate_per_kw too small for timely processing or unreasonably large.
val localFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentFeerates, remoteNodeId, channelFeatures.commitmentFormat, open.fundingSatoshis)
val localFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, channelFeatures.commitmentFormat, open.fundingSatoshis)
if (nodeParams.onChainFeeConf.feerateToleranceFor(remoteNodeId).isFeeDiffTooHigh(channelFeatures.commitmentFormat, localFeeratePerKw, open.feeratePerKw)) return Left(FeerateTooDifferent(open.temporaryChannelId, localFeeratePerKw, open.feeratePerKw))

// we don't check that the funder's amount for the initial commitment transaction is sufficient for full fee payment
Expand Down Expand Up @@ -166,7 +166,7 @@ object Helpers {
val channelFeatures = ChannelFeatures(channelType, localFeatures, remoteFeatures, open.channelFlags.announceChannel)

// BOLT #2: The receiving node MUST fail the channel if: it considers feerate_per_kw too small for timely processing or unreasonably large.
val localFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentFeerates, remoteNodeId, channelFeatures.commitmentFormat, open.fundingAmount)
val localFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, channelFeatures.commitmentFormat, open.fundingAmount)
if (nodeParams.onChainFeeConf.feerateToleranceFor(remoteNodeId).isFeeDiffTooHigh(channelFeatures.commitmentFormat, localFeeratePerKw, open.commitmentFeerate)) return Left(FeerateTooDifferent(open.temporaryChannelId, localFeeratePerKw, open.commitmentFeerate))

for {
Expand Down
Loading
Loading