mirror of
https://github.com/lightningnetwork/lnd.git
synced 2026-08-13 12:32:48 +02:00
This commit plumbs the combined IngressLimiter (per-peer + global) through peer.Config and consults it from the readHandler's *lnwire.OnionMessage case. The decision is factored into a small allowOnionMessage helper so that the ingress policy is directly unit-testable without standing up a full Brontide harness. Per-peer is checked first inside the IngressLimiter: if we consulted the global limiter first, a peer whose own bucket was already empty would still get to burn a global token on each attempt, letting a single hostile peer drain the shared budget and starve legitimate peers. peer.Config carries a single OnionLimiter field of IngressLimiter type; the brontide readHandler calls a single AllowN per incoming onion message and dispatches on sentinel errors via errors.Is for the first-drop log path. Nil limiter values are treated as "disabled" throughout, which both preserves the pre-change behavior when onion messaging is entirely turned off and keeps the brontide test harness from needing to construct real limiters. Per-peer bucket state is retained across disconnect at the IngressLimiter layer so a peer cannot cycle the connection to reset its per-peer allowance. OnionMessage also gains a WireSize method that computes the on-the-wire size directly from the in-memory fields (no round-trip through Encode) so the hot ingress path can charge the right number of byte tokens without paying for a full serialization. The accompanying unit tests cover the nil/disabled path, the per-peer-rejects-first ordering invariant (asserting the global limiter is not consulted when the per-peer bucket is empty), the global rejection path, per-peer isolation across distinct pubkeys, and a small concurrent stress test that asserts every attempt is accounted for as either accepted or dropped and that the total accepted count equals the configured burst under -race. A property-based rapid test on WireSize guards against silent divergence from WriteMessage if the OnionMessage wire format ever gains a TLV extension.
39 lines
1.2 KiB
Go
39 lines
1.2 KiB
Go
package lnwire
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"pgregory.net/rapid"
|
|
)
|
|
|
|
// TestOnionMessageWireSizeMatchesEncode verifies that the value produced by
|
|
// OnionMessage.WireSize — the value fed to the onion message rate limiter on
|
|
// every incoming packet — matches the number of bytes WriteMessage actually
|
|
// emits for that same message. WireSize computes its result directly from the
|
|
// in-memory fields without round-tripping through Encode, which is fast but
|
|
// creates a risk of silent divergence if the OnionMessage wire format ever
|
|
// gains an optional TLV extension or extra field. This test is the
|
|
// compile-time-cheap regression guard that divergence does not go undetected.
|
|
func TestOnionMessageWireSizeMatchesEncode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rapid.Check(t, func(rt *rapid.T) {
|
|
msg, ok := (*OnionMessage)(nil).RandTestMessage(
|
|
rt,
|
|
).(*OnionMessage)
|
|
require.True(
|
|
rt, ok, "RandTestMessage did "+
|
|
"not return an OnionMessage",
|
|
)
|
|
|
|
var buf bytes.Buffer
|
|
written, err := WriteMessage(&buf, msg, 0)
|
|
require.NoError(rt, err, "WriteMessage error")
|
|
require.Equal(rt, written, msg.WireSize(),
|
|
"WireSize=%d, WriteMessage wrote=%d bytes",
|
|
msg.WireSize(), written,
|
|
)
|
|
})
|
|
}
|