Skip to content

Commit

Permalink
Avoid herd effect watching external channels
Browse files Browse the repository at this point in the history
When we restart, we put watches on every public channel in the network.
That creates a lot of RPC calls to bitcoind, which aren't time-sensitive.
It's ok if we don't see immediately that an external channel was closed,
the spec even recommends waiting for 12 blocks to distinguish a channel
close from a splice.

By default, we now smooth that over a 1 hour period. This means we should
also allow our peers to be late at discovering that a channel was closed.
We thus stop sending a `warning` in that case and increase our tolerance
to that kind of behavior.
  • Loading branch information
t-bast committed Aug 29, 2023
1 parent 3174b43 commit ce7be93
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 11 deletions.
2 changes: 1 addition & 1 deletion eclair-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ eclair {
autoprobe-count = 0 // number of parallel tasks that send test payments to detect invalid channels

router {
watch-spent-window = 1 minute // at startup watches will be put back within that window to reduce herd effect; must be > 0s
watch-spent-window = 60 minutes // at startup watches on public channels will be put back within that window to reduce herd effect; must be > 0s

channel-exclude-duration = 60 seconds // when a temporary channel failure is returned, we exclude the channel from our payment routes for this duration
broadcast-interval = 60 seconds // see BOLT #7
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,11 @@ class PeerConnection(keyPair: KeyPair, conf: PeerConnection.Conf, switchboard: A
} else if (d.behavior.fundingTxAlreadySpentCount < MAX_FUNDING_TX_ALREADY_SPENT) {
d.behavior.copy(fundingTxAlreadySpentCount = d.behavior.fundingTxAlreadySpentCount + 1)
} else {
// Our peer isn't necessarily malicious: their bitcoind node may be late, or they restarted and have not
// yet received notifications for the recently closed channels. There may also be splicing attempts that
// are being confirmed and look like closed channels, but actually aren't.
// But we still need to protect ourselves against potentially malicious peers and ignore them.
log.warning(s"peer sent us too many channel announcements with funding tx already spent (count=${d.behavior.fundingTxAlreadySpentCount + 1}), ignoring network announcements for $IGNORE_NETWORK_ANNOUNCEMENTS_PERIOD")
d.transport ! Warning("too many channel announcements with funding tx already spent, please check your bitcoin node")
startSingleTimer(ResumeAnnouncements.toString, ResumeAnnouncements, IGNORE_NETWORK_ANNOUNCEMENTS_PERIOD)
d.behavior.copy(fundingTxAlreadySpentCount = d.behavior.fundingTxAlreadySpentCount + 1, ignoreNetworkAnnouncement = true)
}
Expand Down Expand Up @@ -529,10 +532,7 @@ object PeerConnection {
// @formatter:on

val IGNORE_NETWORK_ANNOUNCEMENTS_PERIOD: FiniteDuration = 5 minutes

// @formatter:off
val MAX_FUNDING_TX_ALREADY_SPENT = 10
// @formatter:on
val MAX_FUNDING_TX_ALREADY_SPENT = 250

def props(keyPair: KeyPair, conf: PeerConnection.Conf, switchboard: ActorRef, router: ActorRef): Props =
Props(new PeerConnection(keyPair, conf, switchboard, router))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ class PeerConnectionSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wi
val probe = TestProbe()
connect(nodeParams, remoteNodeId, switchboard, router, connection, transport, peerConnection, peer)

val fakeRoutingInfo = RoutingSyncSpec.shortChannelIds.take(PeerConnection.MAX_FUNDING_TX_ALREADY_SPENT + 1).toSeq.map(RoutingSyncSpec.makeFakeRoutingInfo(pub2priv))
val channels = fakeRoutingInfo.map(_._1.ann)
val updates = fakeRoutingInfo.flatMap(_._1.update_1_opt) ++ fakeRoutingInfo.flatMap(_._1.update_2_opt)

val query = QueryShortChannelIds(
Alice.nodeParams.chainHash,
EncodedShortChannelIds(EncodingType.UNCOMPRESSED, List(RealShortChannelId(42000))),
Expand All @@ -355,13 +359,8 @@ class PeerConnectionSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wi
router.send(peerConnection, GossipDecision.ChannelClosed(c))
}
// peer will temporary ignore announcements coming from bob
var warningSent = false
for (ann <- channels ++ updates) {
transport.send(peerConnection, ann)
if (!warningSent) {
transport.expectMsgType[Warning]
warningSent = true
}
transport.expectMsg(TransportHandler.ReadAck(ann))
}
router.expectNoMessage(1 second)
Expand Down

0 comments on commit ce7be93

Please sign in to comment.