Querying stuff from relays is not trivial. I am currently using 8 separate layers of abstraction to build feeds:
1. A websocket wrapper
2. A message buffer to avoid locking up the ui, sending too many concurrent reqs, and handle pausing messages while negotiating auth
3. A target interface which allows for different relay implementations like multiplextr or a local relay
4. An executor that works with a target to actually do stuff
5. A subscription object which queries multiple relays, aggregates results, and tracks which relay an event was seen on
6. A cursor object to perform windowing for a given relay
7. A load function which throttles and merges concurrent filters with a timeout
8. Feed/context loaders that take a filter, listen with a subscription, load using cursors, and fetch context with loaders
If relays always returned results in order it would simplify and optimize some of this away. But it really is irreducably complex.
Login to reply
Replies (11)
Olá ! Surely it will get better, what is the best strategy for a client to defend themselves against a malicious relay spam attack ?
Olá ! Surely it will get better, what is the best strategy for a client to defend themselves against a malicious relay spam attack ?
Probably not a problem for clients, since they only get what they ask for. Relays can use auth, PoW, rate limiting, payments, etc. Users need clients to build better tools
Wow that stack gives a lot of power. I've opted for a simpler architecture and haven't run into a situation where the power of that stack you describe has become necssary.
In gossip: Various things trigger the need for subscriptions to be created or updated, and each relay is handled by a different thread. So these subscriptions get passed to the thread to handle, possibly spinning up new threads for relays that aren't currently connected. Events returned from the relays are not coorelated to the subscription they came in on, they all just go down the same processing pipeline with no very little state about why it was requested. That pipeline stores them in the database, creates indexes as needed, and acts on them in other ways where appropriate. Feeds are then built periodically (every few seconds) by pulling matching events out of the local database, divorced from the relay fetching activity.
I'm not doing any windowing yet, but that shouldn't be hard to add. I very well may be sending messages while an AUTH is happening, but again that shouldn't be hard to fix.
That's a good way to do it if you have the resources. I try to keep my stores under 10k records which gets filled up surprisingly fast. The complexity in my stack also comes from me doing all kinds of weird experimental things
I think he means relays who don't play by the rules.
A malicious relay coud:
- send the same message(s) multiple times
- send extra messages that don't match the filters
- do this both for stored events (pre EOSE) and for streamed events (post EOSE)
IMO its a viable attack vector, because clients have less resources so by doing the above, a relay could DoS a client.
Even if unexpected events are "filtered out" by the client before showing them to the user, the client still presumably verifies they're valid events, and signature verification is quite intense. So unexpected large events are also an attack vector, they can hit the client CPU hard.
Nostr SDKs used in clients could defend against most of this by
- only returning events that match the subscription filters
- only validating if an event is valid (signature) if the above is true
- not processing and returning events that have already been seen before (much harder to do)
cc @Yuki Kishimoto
Probably not a concern now, because Nostr is small.
(Another defence for clients is to use a semi-trusted relay aggregator like Wine or caching service like Primal)
Clients can also simply disconnect from.misbehaving relays
True. But they need extra logic that checks if a relay is misbehaving in the first place.
I agree. However if you embrace local first, you will have an easier time.
Thanks for the insights. Helps me learn more about the ins and outs of nostr.