test_alice_and_bob fails: relay leaks internal size field on outgoing events #5

Open
opened 2026-05-03 15:17:27 +00:00 by padreug · 0 comments
Owner

Symptom

tests/test_clients.py::test_alice_and_bob fails with:

AssertionError: Bob: Wrong response for Alice's meta (updated version)
assert '["EVENT", "p..."size": 397}]' == '["EVENT", "p...c54a0dc89c"}]'

- 54a0dc89c"}]
+ 54a0dc89c", "size": 397}]

The relay is appending "size": <bytes> to every outgoing event payload. Test fixtures (tests/fixture/...) don't carry that field, so dict comparisons via dumps(...) blow up.

Pre-existing — confirmed via git log -S '"size"' -- '*.py': the field was introduced in commit 73054fd feat: update to v1.0.0 (#30), well before the recent 4811fcf feat(nip17): support gift-wrapped private direct messages. NIP-17 is not the cause; just the time when the failure was noticed during a full test run.

Root cause

relay/event.py:26 adds size: int = 0 to the relay's event model:

class Event(...):
    size: int = 0
    ...

It's populated in relay/client_connection.py:126:

event.size = event.size_bytes

This field is internal accounting used by event_validator._validate_storage (per-pubkey storage quotas, prune_old_events, etc.) — it has no place in the wire format defined by NIP-01. When the model is serialized to JSON for delivery to clients, size gets included.

This means:

  • All connected clients receive an extra non-spec field on every event
  • Wire-format-strict clients may reject the events
  • Test fixtures across the project will keep being out of sync with reality

Suggested fix (preferred)

Strip size (and any other internal-only fields) from the dict that gets shipped to clients. Either:

  1. Add a Config.fields = {"size": {"exclude": True}} on the pydantic model, or
  2. Have a to_wire_dict() method that returns only NIP-01 fields, used in the broadcast path.

Option 2 is more explicit — easier to evolve without surprising other call sites that legitimately want size (DB writes, validators).

Alternative

Update tests/fixture/*.json to include "size" everywhere. Cheap but brittle: every test fixture has to track a relay-internal accounting detail that has nothing to do with what the relay actually exposes per spec.

Verification

After the fix, make test should pass cleanly:

docker exec regtest-lnbits-1 sh -c "cd /shared/extensions/nostrrelay && \
  LNBITS_DATA_FOLDER=./tests/data /app/.venv/bin/pytest"

Currently 14/15 pass; this is the one remaining failure.

## Symptom `tests/test_clients.py::test_alice_and_bob` fails with: ``` AssertionError: Bob: Wrong response for Alice's meta (updated version) assert '["EVENT", "p..."size": 397}]' == '["EVENT", "p...c54a0dc89c"}]' - 54a0dc89c"}] + 54a0dc89c", "size": 397}] ``` The relay is appending `"size": <bytes>` to every outgoing event payload. Test fixtures (`tests/fixture/...`) don't carry that field, so dict comparisons via `dumps(...)` blow up. Pre-existing — confirmed via `git log -S '"size"' -- '*.py'`: the field was introduced in commit `73054fd feat: update to v1.0.0 (#30)`, well before the recent `4811fcf feat(nip17): support gift-wrapped private direct messages`. NIP-17 is **not** the cause; just the time when the failure was noticed during a full test run. ## Root cause `relay/event.py:26` adds `size: int = 0` to the relay's event model: ```python class Event(...): size: int = 0 ... ``` It's populated in `relay/client_connection.py:126`: ```python event.size = event.size_bytes ``` This field is **internal accounting** used by `event_validator._validate_storage` (per-pubkey storage quotas, prune_old_events, etc.) — it has no place in the wire format defined by [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md). When the model is serialized to JSON for delivery to clients, `size` gets included. This means: - All connected clients receive an extra non-spec field on every event - Wire-format-strict clients may reject the events - Test fixtures across the project will keep being out of sync with reality ## Suggested fix (preferred) Strip `size` (and any other internal-only fields) from the dict that gets shipped to clients. Either: 1. Add a `Config.fields = {"size": {"exclude": True}}` on the pydantic model, or 2. Have a `to_wire_dict()` method that returns only NIP-01 fields, used in the broadcast path. Option 2 is more explicit — easier to evolve without surprising other call sites that legitimately want `size` (DB writes, validators). ## Alternative Update `tests/fixture/*.json` to include `"size"` everywhere. Cheap but brittle: every test fixture has to track a relay-internal accounting detail that has nothing to do with what the relay actually exposes per spec. ## Verification After the fix, `make test` should pass cleanly: ``` docker exec regtest-lnbits-1 sh -c "cd /shared/extensions/nostrrelay && \ LNBITS_DATA_FOLDER=./tests/data /app/.venv/bin/pytest" ``` Currently 14/15 pass; this is the one remaining failure.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/nostrrelay#5
No description provided.