lnd/lnutils
Olaoluwa Osuntokun c0827e8e39 peer: gate onion message ingress on having an open channel
Onion message forwarding is an unpaid side channel. Without any peer
qualification the byte-bucket limiters added in the previous commits are
our only defense against a Sybil attacker: an attacker that can cheaply
spin up N identities and burn a full per-peer byte budget on each one
saturates the global bucket and converts the aggregate cap into a
service-denial primitive against legitimate channel peers. This was
raised on PR review — the per-peer cap is good, but the global cap on
its own is a Sybil multiplier if peer identity is free. The proper fix
is to make new identities cost real capital, which is what requiring a
funded channel does.

This commit adds a channel-presence gate as the first check in
allowOnionMessage, ahead of both the per-peer and the global rate
limiters. Messages from peers that do not have at least one fully
open channel with us are dropped with a new dropReasonNoChannel
sentinel and never allocate any rate limiter state — the gate runs
before either limiter is consulted, so no-channel peers cannot burn
tokens on any bucket. Pending channels are deliberately excluded from
the check: they are represented as nil values in the activeChannels
map, are cheap to open and prone to getting stuck, and so do not
provide the capital-cost guarantee the Sybil defense depends on.
Existing Brontide cleanup paths (StopOnionActorIfExists,
OnionPeerLimiter.Forget) already handle teardown on peer disconnect;
nothing new is needed there because the gate keeps no-channel peers
from ever allocating per-peer state in the first place.

For the hot path we cannot afford to iterate the activeChannels
registry on every incoming onion message, so Brontide now carries a
numActiveChans atomic.Int32 that shadows the count of non-pending
entries in activeChannels. hasActiveChannels is a single atomic Load
and is therefore O(1). The counter is maintained in lockstep with
activeChannels at every mutation site: loadActiveChannels increments
it as it populates the registry during Start(); addActiveChannel uses
a new lnutils.SyncMap.Swap method (a thin typed wrapper around
sync.Map.Swap) to atomically replace any prior entry so that both
brand-new channels and pending-to-active promotions bump the counter
by exactly one; WipeChannel and handleRemovePendingChannel both use
LoadAndDelete so they can inspect the prior value and only decrement
when the removed entry was non-nil. Under race, this keeps the
counter and the map consistent even when RPC WipeChannel races with
the channelManager goroutine.

The accompanying unit tests cover: the no-channel drop path at the
allowOnionMessage level, asserting that neither the global stub
counter nor the per-peer limiter's dropped counter move when the
gate fires; the subsequent channel-gained path on the same peer,
asserting the same message is accepted once hasChannel flips; and a
focused Brontide-level test that walks the counter through initial
emptiness, a pending-only state (counter must stay at zero), a
pending-to-active promotion via direct Store + Add, the pending
delete path through handleRemovePendingChannel (must not underflow),
and the active delete path through LoadAndDelete + Add(-1) that
WipeChannel uses internally. Running with -race confirms the
Swap/LoadAndDelete patterns keep the counter and the map in sync
under concurrent access.
2026-04-15 13:23:50 -07:00
..
chan.go multi: make linter happy 2023-03-11 23:29:41 -08:00
context.go lnutils: add ContextFromQuit to bridge quit channels to contexts 2026-04-10 19:16:49 -07:00
context_test.go multi/test: add unit tests for gossip result helpers and context bridge 2026-04-10 19:16:49 -07:00
errors.go lnwallet: check mempool acceptance before publishing 2024-01-25 07:54:39 +08:00
fs.go lnutils: add createdir util function 2025-02-20 17:08:21 +01:00
fs_test.go lnutils: add createdir util function 2025-02-20 17:08:21 +01:00
log.go lnutil: add LogPubKey helper function 2025-04-17 17:20:09 -07:00
memory.go input: create new ScriptDesciptor interface 2023-08-22 16:33:44 -07:00
README.md multi: add lnutils to host fundamental utility functions 2023-01-19 06:38:50 +08:00
stream.go multi: add lnutils to host fundamental utility functions 2023-01-19 06:38:50 +08:00
sync_map.go peer: gate onion message ingress on having an open channel 2026-04-15 13:23:50 -07:00
sync_map_bench_test.go lnutils+lntemp: move SyncMap to lnutils 2023-01-19 07:08:18 +08:00
sync_map_test.go peer: gate onion message ingress on having an open channel 2026-04-15 13:23:50 -07:00

lnutils

This package provides fundamental types and utility functions that can be used by all other packages.