Skip to content

Commit fa985da

Browse files
authored
Reject unreasonably low splice feerate (#2657)
We let the initiator pick the feerate, but it must at least meet some sanity requirements.
1 parent 55a985a commit fa985da

File tree

2 files changed

+21
-5
lines changed

2 files changed

+21
-5
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -827,9 +827,15 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
827827
case Event(msg: SpliceInit, d: DATA_NORMAL) =>
828828
d.spliceStatus match {
829829
case SpliceStatus.NoSplice =>
830-
if (d.commitments.isIdle) {
830+
if (!d.commitments.isIdle) {
831+
log.info("rejecting splice request: channel not idle")
832+
stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceRequest(d.channelId).getMessage)
833+
} else if (msg.feerate < nodeParams.onChainFeeConf.feeEstimator.getMempoolMinFeeratePerKw()) {
834+
log.info("rejecting splice request: feerate too low")
835+
stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceRequest(d.channelId).getMessage)
836+
} else {
831837
log.info(s"accepting splice with remote.in.amount=${msg.fundingContribution} remote.in.push=${msg.pushAmount}")
832-
val parentCommitment = d.commitments.latest.commitment
838+
val parentCommitment = d.commitments.latest.commitment
833839
val spliceAck = SpliceAck(d.channelId,
834840
fundingContribution = 0.sat, // only remote contributes to the splice
835841
fundingPubKey = keyManager.fundingPublicKey(d.commitments.params.localParams.fundingKeyPath, parentCommitment.fundingTxIndex + 1).publicKey,
@@ -858,9 +864,6 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
858864
))
859865
txBuilder ! InteractiveTxBuilder.Start(self)
860866
stay() using d.copy(spliceStatus = SpliceStatus.SpliceInProgress(cmd_opt = None, splice = txBuilder, remoteCommitSig = None)) sending spliceAck
861-
} else {
862-
log.info("rejecting splice request, channel not idle or not compatible")
863-
stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceRequest(d.channelId).getMessage)
864867
}
865868
case SpliceStatus.SpliceAborted =>
866869
log.info("rejecting splice attempt: our previous tx_abort was not acked")

eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import akka.testkit.{TestFSMRef, TestProbe}
2222
import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, Transaction}
2323
import fr.acinq.eclair._
2424
import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._
25+
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
2526
import fr.acinq.eclair.channel.Helpers.Closing.{LocalClose, RemoteClose, RevokedClose}
2627
import fr.acinq.eclair.channel.LocalFundingStatus.DualFundedUnconfirmedFundingTx
2728
import fr.acinq.eclair.channel._
@@ -169,6 +170,18 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
169170
sender.expectMsgType[RES_FAILURE[_, _]]
170171
}
171172

173+
test("recv CMD_SPLICE (splice-in, feerate too low)") { f =>
174+
import f._
175+
176+
val sender = TestProbe()
177+
val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(500_000 sat)), spliceOut_opt = None)
178+
alice ! cmd
179+
// we tweak the feerate
180+
val spliceInit = alice2bob.expectMsgType[SpliceInit].copy(feerate = FeeratePerKw(100.sat))
181+
alice2bob.forward(bob, spliceInit)
182+
bob2alice.expectMsgType[TxAbort]
183+
}
184+
172185
test("recv CMD_SPLICE (splice-in + splice-out)") { f =>
173186
import f._
174187

0 commit comments

Comments
 (0)