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

Attributable errors #2519

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Default to legacy
thomash-acinq committed Nov 14, 2023
commit bfdb39e40e70270e407f0c21fb16941ef086a6c5
Original file line number Diff line number Diff line change
@@ -640,8 +640,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
case PostRevocationAction.RejectHtlc(add) =>
log.debug("rejecting incoming htlc {}", add)
// NB: we don't set commit = true, we will sign all updates at once afterwards.
// The HTLC is rejected without reading the onion, we default to using attributable errors if the feature is activated.
self ! CMD_FAIL_HTLC(add.id, Right(TemporaryChannelFailure(d.channelUpdate)), useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.now(), commit = true)
// The HTLC is rejected without reading the onion, we default to legacy errors.
self ! CMD_FAIL_HTLC(add.id, Right(TemporaryChannelFailure(d.channelUpdate)), useAttributableErrors = false, TimestampMilli.now(), commit = true)
case PostRevocationAction.RelayFailure(result) =>
log.debug("forwarding {} to relayer", result)
relayer ! result
@@ -1342,13 +1342,13 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
case PostRevocationAction.RelayHtlc(add) =>
// BOLT 2: A sending node SHOULD fail to route any HTLC added after it sent shutdown.
log.debug("closing in progress: failing {}", add)
// The HTLC is rejected without reading the onion, we default to using attributable errors if the feature is activated.
self ! CMD_FAIL_HTLC(add.id, Right(PermanentChannelFailure()), useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.now(), commit = true)
// The HTLC is rejected without reading the onion, we default to legacy errors.
self ! CMD_FAIL_HTLC(add.id, Right(PermanentChannelFailure()), useAttributableErrors = false, TimestampMilli.now(), commit = true)
case PostRevocationAction.RejectHtlc(add) =>
// BOLT 2: A sending node SHOULD fail to route any HTLC added after it sent shutdown.
log.debug("closing in progress: rejecting {}", add)
// The HTLC is rejected without reading the onion, we default to using attributable errors if the feature is activated.
self ! CMD_FAIL_HTLC(add.id, Right(PermanentChannelFailure()), useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.now(), commit = true)
// The HTLC is rejected without reading the onion, we default to legacy errors.
self ! CMD_FAIL_HTLC(add.id, Right(PermanentChannelFailure()), useAttributableErrors = false, TimestampMilli.now(), commit = true)
case PostRevocationAction.RelayFailure(result) =>
log.debug("forwarding {} to relayer", result)
relayer ! result
Original file line number Diff line number Diff line change
@@ -131,8 +131,8 @@ class PostRestartHtlcCleaner(nodeParams: NodeParams, register: ActorRef, initial
val failure = InvalidOnionBlinding(ByteVector32.Zeroes)
CMD_FAIL_MALFORMED_HTLC(htlc.id, failure.onionHash, failure.code, commit = true)
case None =>
// By default we use attributable errors if the feature is activated.
CMD_FAIL_HTLC(htlc.id, Right(TemporaryNodeFailure()), useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.min, commit = true)
// By default we use legacy errors.
CMD_FAIL_HTLC(htlc.id, Right(TemporaryNodeFailure()), useAttributableErrors = false, TimestampMilli.min, commit = true)
}
channel ! cmd
} else {
@@ -262,8 +262,8 @@ class PostRestartHtlcCleaner(nodeParams: NodeParams, register: ActorRef, initial
val failure = InvalidOnionBlinding(ByteVector32.Zeroes)
CMD_FAIL_MALFORMED_HTLC(originHtlcId, failure.onionHash, failure.code, commit = true)
case None =>
// By default we use attributable errors if the feature is activated.
ChannelRelay.translateRelayFailure(originHtlcId, fail, useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.min)
// By default we use legacy errors.
ChannelRelay.translateRelayFailure(originHtlcId, fail, useAttributableErrors = false, TimestampMilli.min)
}
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, originChannelId, cmd)
case Origin.TrampolineRelayedCold(origins) =>
@@ -272,8 +272,8 @@ class PostRestartHtlcCleaner(nodeParams: NodeParams, register: ActorRef, initial
Metrics.Resolved.withTag(Tags.Success, value = false).withTag(Metrics.Relayed, value = true).increment()
// We don't bother decrypting the downstream failure to forward a more meaningful error upstream, it's
// very likely that it won't be actionable anyway because of our node restart.
// By default we use attributable errors if the feature is activated.
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, channelId, CMD_FAIL_HTLC(htlcId, Right(TemporaryNodeFailure()), useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.min, commit = true))
// By default we use legacy errors.
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, channelId, CMD_FAIL_HTLC(htlcId, Right(TemporaryNodeFailure()), useAttributableErrors = false, TimestampMilli.min, commit = true))
}
}
}
Original file line number Diff line number Diff line change
@@ -84,17 +84,17 @@ class Relayer(nodeParams: NodeParams, router: ActorRef, register: ActorRef, paym
// We are the introduction point of a blinded path: we add a non-negligible delay to make it look like it
// could come from a downstream node.
val delay = Some(500.millis + Random.nextLong(1500).millis)
// By default we use attributable errors if the feature is activated.
CMD_FAIL_HTLC(add.id, Right(InvalidOnionBlinding(badOnion.onionHash)), useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.now(), delay, commit = true)
// By default we use legacy errors.
CMD_FAIL_HTLC(add.id, Right(InvalidOnionBlinding(badOnion.onionHash)), useAttributableErrors = false, TimestampMilli.now(), delay, commit = true)
case _ =>
CMD_FAIL_MALFORMED_HTLC(add.id, badOnion.onionHash, badOnion.code, commit = true)
}
log.warning(s"rejecting htlc #${add.id} from channelId=${add.channelId} reason=malformed onionHash=${badOnion.onionHash} failureCode=${badOnion.code}")
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, add.channelId, cmdFail)
case Left(failure) =>
log.warning(s"rejecting htlc #${add.id} from channelId=${add.channelId} reason=$failure")
// By default we use attributable errors if the feature is activated.
val cmdFail = CMD_FAIL_HTLC(add.id, Right(failure), useAttributableErrors = nodeParams.features.hasFeature(Features.AttributableError), TimestampMilli.now(), commit = true)
// By default we use legacy errors.
val cmdFail = CMD_FAIL_HTLC(add.id, Right(failure), useAttributableErrors = false, TimestampMilli.now(), commit = true)
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, add.channelId, cmdFail)
}

Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ import com.softwaremill.quicklens.ModifyPimp
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong}
import fr.acinq.eclair.FeatureSupport.Optional
import fr.acinq.eclair.Features.{AttributableError, KeySend, RouteBlinding}
import fr.acinq.eclair.Features.{KeySend, RouteBlinding}
import fr.acinq.eclair.channel.{DATA_NORMAL, RealScidStatus}
import fr.acinq.eclair.integration.basic.fixtures.MinimalNodeFixture
import fr.acinq.eclair.integration.basic.fixtures.MinimalNodeFixture.{connect, getChannelData, getPeerChannels, getRouterData, knownFundingTxs, nodeParamsFor, openChannel, watcherAutopilot}
@@ -61,19 +61,16 @@ class OfferPaymentSpec extends FixtureSpec with IntegrationPatience {
val aliceParams = nodeParamsFor("alice", ByteVector32(hex"b4acd47335b25ab7b84b8c020997b12018592bb4631b868762154d77fa8b93a3"))
.modify(_.onionMessageConfig.timeout).setTo(5 minutes)
.modify(_.features.activated).using(_ + (RouteBlinding -> Optional))
.modify(_.features.activated).using(_ - AttributableError)
.modify(_.channelConf.channelFlags.announceChannel).setTo(!testData.tags.contains(PrivateChannels))
val bobParams = nodeParamsFor("bob", ByteVector32(hex"7620226fec887b0b2ebe76492e5a3fd3eb0e47cd3773263f6a81b59a704dc492"))
.modify(_.onionMessageConfig.timeout).setTo(5 minutes)
.modify(_.features.activated).using(_ + (RouteBlinding -> Optional))
.modify(_.features.activated).using(_ - AttributableError)
.modify(_.features.activated).usingIf(testData.tags.contains(RouteBlindingDisabledBob))(_ - RouteBlinding)
.modify(_.channelConf.channelFlags.announceChannel).setTo(!testData.tags.contains(PrivateChannels))
val carolParams = nodeParamsFor("carol", ByteVector32(hex"ebd5a5d3abfb3ef73731eb3418d918f247445183180522674666db98a66411cc"))
.modify(_.onionMessageConfig.timeout).setTo(5 minutes)
.modify(_.features.activated).using(_ + (RouteBlinding -> Optional))
.modify(_.features.activated).using(_ + (KeySend -> Optional))
.modify(_.features.activated).using(_ - AttributableError)
.modify(_.features.activated).usingIf(testData.tags.contains(RouteBlindingDisabledCarol))(_ - RouteBlinding)
.modify(_.channelConf.channelFlags.announceChannel).setTo(!testData.tags.contains(PrivateChannels))