Skip to content

Commit deccda6

Browse files
committed
Add detailed error message when splice feerate is incorrect
This can be helpful when troubleshooting cross-compatibility issues. Replaces #2911.
1 parent 2a3d7d7 commit deccda6

File tree

4 files changed

+6
-5
lines changed

4 files changed

+6
-5
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelExceptions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ case class UnexpectedFundingSignatures (override val channelId: Byte
8282
case class InvalidFundingFeerate (override val channelId: ByteVector32, targetFeerate: FeeratePerKw, actualFeerate: FeeratePerKw) extends ChannelException(channelId, s"invalid funding feerate: target=$targetFeerate actual=$actualFeerate")
8383
case class InvalidFundingSignature (override val channelId: ByteVector32, txId_opt: Option[TxId]) extends ChannelException(channelId, s"invalid funding signature: txId=${txId_opt.map(_.toString()).getOrElse("n/a")}")
8484
case class InvalidRbfFeerate (override val channelId: ByteVector32, proposed: FeeratePerKw, expected: FeeratePerKw) extends ChannelException(channelId, s"invalid rbf attempt: the feerate must be at least $expected, you proposed $proposed")
85+
case class InvalidSpliceFeerate (override val channelId: ByteVector32, proposed: FeeratePerKw, expected: FeeratePerKw) extends ChannelException(channelId, s"invalid splice request: the feerate must be at least $expected, you proposed $proposed")
8586
case class InvalidSpliceRequest (override val channelId: ByteVector32) extends ChannelException(channelId, "invalid splice request")
8687
case class InvalidRbfAlreadyInProgress (override val channelId: ByteVector32) extends ChannelException(channelId, "invalid rbf attempt: the current rbf attempt must be completed or aborted first")
8788
case class InvalidSpliceAlreadyInProgress (override val channelId: ByteVector32) extends ChannelException(channelId, "invalid splice attempt: the current splice attempt must be completed or aborted first")

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -946,8 +946,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
946946
log.info("rejecting splice request: channel not quiescent")
947947
stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceNotQuiescent(d.channelId).getMessage)
948948
} else if (msg.feerate < nodeParams.currentBitcoinCoreFeerates.minimum) {
949-
log.info("rejecting splice request: feerate too low")
950-
stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceRequest(d.channelId).getMessage)
949+
log.info("rejecting splice request: feerate too low ({} < {})", msg.feerate, nodeParams.currentBitcoinCoreFeerates.minimum)
950+
stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceFeerate(d.channelId, msg.feerate, nodeParams.currentBitcoinCoreFeerates.minimum).getMessage)
951951
} else {
952952
val parentCommitment = d.commitments.latest.commitment
953953
val localFundingPubKey = nodeParams.channelKeyManager.fundingPublicKey(d.commitments.params.localParams.fundingKeyPath, parentCommitment.fundingTxIndex + 1).publicKey

eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,7 @@ private class InteractiveTxBuilder(replyTo: ActorRef[InteractiveTxBuilder.Respon
775775
val nextFeerate = Transactions.fee2rate(sharedTx.fees, tx.weight())
776776
if (nextFeerate <= previousFeerate) {
777777
log.warn("invalid interactive tx: next feerate isn't greater than previous feerate (previous={}, next={})", previousFeerate, nextFeerate)
778-
return Left(InvalidCompleteInteractiveTx(fundingParams.channelId))
778+
return Left(InvalidRbfFeerate(fundingParams.channelId, nextFeerate, previousFeerate))
779779
}
780780
case None =>
781781
val feeWithoutWitness = Transactions.weight2fee(fundingParams.targetFeerate, tx.weight())
@@ -791,7 +791,7 @@ private class InteractiveTxBuilder(replyTo: ActorRef[InteractiveTxBuilder.Respon
791791
}
792792
if (sharedTx.fees < minimumFee) {
793793
log.warn("invalid interactive tx: below the target feerate (target={}, actual={})", fundingParams.targetFeerate, Transactions.fee2rate(sharedTx.fees, tx.weight()))
794-
return Left(InvalidCompleteInteractiveTx(fundingParams.channelId))
794+
return Left(InvalidSpliceFeerate(fundingParams.channelId, Transactions.fee2rate(sharedTx.fees, tx.weight()), fundingParams.targetFeerate))
795795
}
796796
}
797797

eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2667,7 +2667,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
26672667
probe.expectMsgType[SendMessage]
26682668
// Alice --- tx_complete --> Bob
26692669
bob ! ReceiveMessage(TxComplete(params.channelId))
2670-
assert(probe.expectMsgType[RemoteFailure].cause == InvalidCompleteInteractiveTx(params.channelId))
2670+
assert(probe.expectMsgType[RemoteFailure].cause.isInstanceOf[InvalidSpliceFeerate])
26712671
}
26722672

26732673
test("previous attempts not double-spent") {

0 commit comments

Comments
 (0)