Skip to content

Commit

Permalink
make OnChainConf static
Browse files Browse the repository at this point in the history
  • Loading branch information
pm47 committed Jun 16, 2023
1 parent 300d17c commit b8f334e
Show file tree
Hide file tree
Showing 19 changed files with 181 additions and 179 deletions.
8 changes: 7 additions & 1 deletion eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,
channelKeyManager: ChannelKeyManager,
instanceId: UUID, // a unique instance ID regenerated after each restart
private val blockHeight: AtomicLong,
private val feerates: AtomicReference[FeeratesPerKw],
alias: String,
color: Color,
publicAddresses: List[NodeAddress],
Expand Down Expand Up @@ -97,6 +98,11 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,

def currentBlockHeight: BlockHeight = BlockHeight(blockHeight.get)

def currentFeerates: FeeratesPerKw = feerates.get()

/** Only to be used in tests. */
def setFeerates(value: FeeratesPerKw) = feerates.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()
}
Expand Down Expand Up @@ -462,6 +468,7 @@ object NodeParams extends Logging {
channelKeyManager = channelKeyManager,
instanceId = instanceId,
blockHeight = blockHeight,
feerates = feerates,
alias = nodeAlias,
color = Color(color(0), color(1), color(2)),
publicAddresses = addresses,
Expand Down Expand Up @@ -500,7 +507,6 @@ object NodeParams extends Logging {
remoteRbfLimits = Channel.RemoteRbfLimits(config.getInt("channel.funding.remote-rbf-limits.max-attempts"), config.getInt("channel.funding.remote-rbf-limits.attempt-delta-blocks"))
),
onChainFeeConf = OnChainFeeConf(
feerates = feerates,
feeTargets = feeTargets,
safeUtxosThreshold = config.getInt("on-chain-fees.safe-utxos-threshold"),
spendAnchorWithoutHtlcs = config.getBoolean("on-chain-fees.spend-anchor-without-htlcs"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import fr.acinq.eclair.BlockHeight
import fr.acinq.eclair.channel.{ChannelTypes, SupportedChannelType}
import fr.acinq.eclair.transactions.Transactions

import java.util.concurrent.atomic.AtomicReference

// @formatter:off
sealed trait ConfirmationPriority {
def getFeerate(feerates: FeeratesPerKw): FeeratePerKw = this match {
Expand Down Expand Up @@ -71,17 +69,15 @@ case class FeerateTolerance(ratioLow: Double, ratioHigh: Double, anchorOutputMax
}
}

case class OnChainFeeConf(feerates: AtomicReference[FeeratesPerKw], feeTargets: FeeTargets, safeUtxosThreshold: Int, spendAnchorWithoutHtlcs: Boolean, closeOnOfflineMismatch: Boolean, updateFeeMinDiffRatio: Double, private val defaultFeerateTolerance: FeerateTolerance, private val perNodeFeerateTolerance: Map[PublicKey, FeerateTolerance]) {

def currentFeerates: FeeratesPerKw = feerates.get()
case class OnChainFeeConf(feeTargets: FeeTargets, safeUtxosThreshold: Int, spendAnchorWithoutHtlcs: Boolean, closeOnOfflineMismatch: Boolean, updateFeeMinDiffRatio: Double, private val defaultFeerateTolerance: FeerateTolerance, private val perNodeFeerateTolerance: Map[PublicKey, FeerateTolerance]) {

def feerateToleranceFor(nodeId: PublicKey): FeerateTolerance = perNodeFeerateTolerance.getOrElse(nodeId, defaultFeerateTolerance)

/** To avoid spamming our peers with fee updates every time there's a small variation, we only update the fee when the difference exceeds a given ratio. */
def shouldUpdateFee(currentFeeratePerKw: FeeratePerKw, nextFeeratePerKw: FeeratePerKw): Boolean =
currentFeeratePerKw.toLong == 0 || Math.abs((currentFeeratePerKw.toLong - nextFeeratePerKw.toLong).toDouble / currentFeeratePerKw.toLong) > updateFeeMinDiffRatio

def getFundingFeerate(): FeeratePerKw = feeTargets.funding.getFeerate(currentFeerates)
def getFundingFeerate(feerates: FeeratesPerKw): FeeratePerKw = feeTargets.funding.getFeerate(feerates)

/**
* Get the feerate that should apply to a channel commitment transaction:
Expand All @@ -92,9 +88,9 @@ case class OnChainFeeConf(feerates: AtomicReference[FeeratesPerKw], feeTargets:
* @param channelType channel type
* @param currentFeerates_opt if provided, will be used to compute the most up-to-date network fee, otherwise we rely on the fee estimator
*/
def getCommitmentFeerate(remoteNodeId: PublicKey, channelType: SupportedChannelType, channelCapacity: Satoshi): FeeratePerKw = {
val networkFeerate = currentFeerates.blocks_2
val networkMinFee = currentFeerates.mempoolMinFee
def getCommitmentFeerate(feerates: FeeratesPerKw, remoteNodeId: PublicKey, channelType: SupportedChannelType, channelCapacity: Satoshi): FeeratePerKw = {
val networkFeerate = feerates.blocks_2
val networkMinFee = feerates.mempoolMinFee

channelType.commitmentFormat match {
case Transactions.DefaultCommitmentFormat => networkFeerate
Expand All @@ -105,5 +101,5 @@ case class OnChainFeeConf(feerates: AtomicReference[FeeratesPerKw], feeTargets:
}
}

def getClosingFeerate(): FeeratePerKw = feeTargets.closing.getFeerate(currentFeerates)
def getClosingFeerate(feerates: FeeratesPerKw): FeeratePerKw = feeTargets.closing.getFeerate(feerates)
}
Original file line number Diff line number Diff line change
Expand Up @@ -411,11 +411,11 @@ case class Commitment(fundingTxIndex: Long,
localCommit.spec.htlcs.collect(DirectedHtlc.incoming).filter(nearlyExpired)
}

def canSendAdd(amount: MilliSatoshi, params: ChannelParams, changes: CommitmentChanges, feeConf: OnChainFeeConf): Either[ChannelException, Unit] = {
def canSendAdd(amount: MilliSatoshi, params: ChannelParams, changes: CommitmentChanges, feerates: FeeratesPerKw, feeConf: OnChainFeeConf): Either[ChannelException, Unit] = {
// we allowed mismatches between our feerates and our remote's as long as commitments didn't contain any HTLC at risk
// we need to verify that we're not disagreeing on feerates anymore before offering new HTLCs
// NB: there may be a pending update_fee that hasn't been applied yet that needs to be taken into account
val localFeeratePerKw = feeConf.getCommitmentFeerate(params.remoteNodeId, params.channelType, capacity)
val localFeeratePerKw = feeConf.getCommitmentFeerate(feerates, params.remoteNodeId, params.channelType, capacity)
val remoteFeeratePerKw = localCommit.spec.commitTxFeerate +: changes.remoteChanges.all.collect { case f: UpdateFee => f.feeratePerKw }
remoteFeeratePerKw.find(feerate => feeConf.feerateToleranceFor(params.remoteNodeId).isFeeDiffTooHigh(params.channelType, localFeeratePerKw, feerate)) match {
case Some(feerate) => return Left(FeerateTooDifferent(params.channelId, localFeeratePerKw = localFeeratePerKw, remoteFeeratePerKw = feerate))
Expand Down Expand Up @@ -475,11 +475,11 @@ case class Commitment(fundingTxIndex: Long,
Right(())
}

def canReceiveAdd(amount: MilliSatoshi, params: ChannelParams, changes: CommitmentChanges, feeConf: OnChainFeeConf): Either[ChannelException, Unit] = {
def canReceiveAdd(amount: MilliSatoshi, params: ChannelParams, changes: CommitmentChanges, feerates: FeeratesPerKw, feeConf: OnChainFeeConf): Either[ChannelException, Unit] = {
// we allowed mismatches between our feerates and our remote's as long as commitments didn't contain any HTLC at risk
// we need to verify that we're not disagreeing on feerates anymore before accepting new HTLCs
// NB: there may be a pending update_fee that hasn't been applied yet that needs to be taken into account
val localFeeratePerKw = feeConf.getCommitmentFeerate(params.remoteNodeId, params.channelType, capacity)
val localFeeratePerKw = feeConf.getCommitmentFeerate(feerates, params.remoteNodeId, params.channelType, capacity)
val remoteFeeratePerKw = localCommit.spec.commitTxFeerate +: changes.remoteChanges.all.collect { case f: UpdateFee => f.feeratePerKw }
remoteFeeratePerKw.find(feerate => feeConf.feerateToleranceFor(params.remoteNodeId).isFeeDiffTooHigh(params.channelType, localFeeratePerKw, feerate)) match {
case Some(feerate) => return Left(FeerateTooDifferent(params.channelId, localFeeratePerKw = localFeeratePerKw, remoteFeeratePerKw = feerate))
Expand Down Expand Up @@ -551,8 +551,8 @@ case class Commitment(fundingTxIndex: Long,
Right(())
}

def canReceiveFee(targetFeerate: FeeratePerKw, params: ChannelParams, changes: CommitmentChanges, feeConf: OnChainFeeConf): Either[ChannelException, Unit] = {
val localFeeratePerKw = feeConf.getCommitmentFeerate(params.remoteNodeId, params.channelType, capacity)
def canReceiveFee(targetFeerate: FeeratePerKw, params: ChannelParams, changes: CommitmentChanges, feerates: FeeratesPerKw, feeConf: OnChainFeeConf): Either[ChannelException, Unit] = {
val localFeeratePerKw = feeConf.getCommitmentFeerate(feerates, params.remoteNodeId, params.channelType, capacity)
if (feeConf.feerateToleranceFor(params.remoteNodeId).isFeeDiffTooHigh(params.channelType, localFeeratePerKw, targetFeerate) && hasPendingOrProposedHtlcs(changes)) {
return Left(FeerateTooDifferent(params.channelId, localFeeratePerKw = localFeeratePerKw, remoteFeeratePerKw = targetFeerate))
} else {
Expand Down Expand Up @@ -809,7 +809,7 @@ case class Commitments(params: ChannelParams,
* @param cmd add HTLC command
* @return either Left(failure, error message) where failure is a failure message (see BOLT #4 and the Failure Message class) or Right(new commitments, updateAddHtlc)
*/
def sendAdd(cmd: CMD_ADD_HTLC, currentHeight: BlockHeight, channelConf: ChannelConf, feeConf: OnChainFeeConf): Either[ChannelException, (Commitments, UpdateAddHtlc)] = {
def sendAdd(cmd: CMD_ADD_HTLC, currentHeight: BlockHeight, channelConf: ChannelConf, feerates: FeeratesPerKw, feeConf: OnChainFeeConf): Either[ChannelException, (Commitments, UpdateAddHtlc)] = {
// we must ensure we're not relaying htlcs that are already expired, otherwise the downstream channel will instantly close
// NB: we add a 3 blocks safety to reduce the probability of running into this when our bitcoin node is slightly outdated
val minExpiry = CltvExpiry(currentHeight + 3)
Expand All @@ -833,12 +833,12 @@ case class Commitments(params: ChannelParams,
val changes1 = changes.addLocalProposal(add).copy(localNextHtlcId = changes.localNextHtlcId + 1)
val originChannels1 = originChannels + (add.id -> cmd.origin)
// we verify that this htlc is allowed in every active commitment
active.map(_.canSendAdd(add.amountMsat, params, changes1, feeConf))
active.map(_.canSendAdd(add.amountMsat, params, changes1, feerates, feeConf))
.collectFirst { case Left(f) => Left(f) }
.getOrElse(Right(copy(changes = changes1, originChannels = originChannels1), add))
}

def receiveAdd(add: UpdateAddHtlc, feeConf: OnChainFeeConf): Either[ChannelException, Commitments] = {
def receiveAdd(add: UpdateAddHtlc, feerates: FeeratesPerKw, feeConf: OnChainFeeConf): Either[ChannelException, Commitments] = {
if (add.id != changes.remoteNextHtlcId) {
return Left(UnexpectedHtlcId(channelId, expected = changes.remoteNextHtlcId, actual = add.id))
}
Expand All @@ -851,7 +851,7 @@ case class Commitments(params: ChannelParams,

val changes1 = changes.addRemoteProposal(add).copy(remoteNextHtlcId = changes.remoteNextHtlcId + 1)
// we verify that this htlc is allowed in every active commitment
active.map(_.canReceiveAdd(add.amountMsat, params, changes1, feeConf))
active.map(_.canReceiveAdd(add.amountMsat, params, changes1, feerates, feeConf))
.collectFirst { case Left(f) => Left(f) }
.getOrElse(Right(copy(changes = changes1)))
}
Expand Down Expand Up @@ -946,18 +946,18 @@ case class Commitments(params: ChannelParams,
}
}

def receiveFee(fee: UpdateFee, feeConf: OnChainFeeConf)(implicit log: LoggingAdapter): Either[ChannelException, Commitments] = {
def receiveFee(fee: UpdateFee, feerates: FeeratesPerKw, feeConf: OnChainFeeConf)(implicit log: LoggingAdapter): Either[ChannelException, Commitments] = {
if (params.localParams.isInitiator) {
Left(NonInitiatorCannotSendUpdateFee(channelId))
} else if (fee.feeratePerKw < FeeratePerKw.MinimumFeeratePerKw) {
Left(FeerateTooSmall(channelId, remoteFeeratePerKw = fee.feeratePerKw))
} else {
Metrics.RemoteFeeratePerKw.withoutTags().record(fee.feeratePerKw.toLong)
val localFeeratePerKw = feeConf.getCommitmentFeerate(params.remoteNodeId, params.channelType, active.head.capacity)
val localFeeratePerKw = feeConf.getCommitmentFeerate(feerates, params.remoteNodeId, params.channelType, active.head.capacity)
log.info("remote feeratePerKw={}, local feeratePerKw={}, ratio={}", fee.feeratePerKw, localFeeratePerKw, fee.feeratePerKw.toLong.toDouble / localFeeratePerKw.toLong)
// update_fee replace each other, so we can remove previous ones
val changes1 = changes.copy(remoteChanges = changes.remoteChanges.copy(proposed = changes.remoteChanges.proposed.filterNot(_.isInstanceOf[UpdateFee]) :+ fee))
active.map(_.canReceiveFee(fee.feeratePerKw, params, changes1, feeConf))
active.map(_.canReceiveFee(fee.feeratePerKw, params, changes1, feerates, feeConf))
.collectFirst { case Left(f) => Left(f) }
.getOrElse(Right(copy(changes = changes1)))
}
Expand Down
Loading

0 comments on commit b8f334e

Please sign in to comment.