Added: Tier 1 audit Peer-sync flow Deterministic vectors Regenerator Verifier Corrected §5.8 regarding: Directional peering-key identity ordering. Public versus control destination handlers. Permissive announce parser behavior. Autopeer rules. Peer Resource framing and admission. PN_STAMP_THROTTLE = 180 seconds. Two documented LXMF 0.9.7 hazards. Verification: deterministic regeneration passed; full pinned suite passed 20/20; git diff --check passed. No commit created.
3.4 KiB
Flow: propagation-node discovery and peer synchronization
How two LXMF propagation nodes discover each other, authenticate a sync offer,
and transfer stored messages. Pinned against RNS 1.2.4 / LXMF 0.9.7;
cross-references ../SPEC.md §5.8, §10, and §11.
Sequence
1. Node announces lxmf.propagation
The producer emits the seven-element §5.8.5 app_data array containing its timebase, enabled state, transfer/sync limits, stamp costs, peering cost, and metadata.
2. Receiving node evaluates autopeering
LXMFPropagationAnnounceHandler validates app_data. A direct announce creates
or updates an autopeer only when the node is enabled, autopeering is enabled,
and the path is within autopeer_maxdepth (default 4). Ordinary path responses
do not create autopeers. An enabled=false direct announce removes an autopeer.
3. Initiator prepares a directional peering key
The offering node computes a proof-of-work key over:
receiving_identity_hash || offering_identity_hash
using the receiving node's announced peering cost. The key is cached and can be reused until the peer raises its cost.
4. Initiator selects messages and opens a Link
The peer state machine sorts unhandled entries by ascending weight:
priority_weight * age_weight * stored_size. It applies the peer's per-message
and per-sync limits, opens a Link to lxmf.propagation, and identifies with
its propagation-node identity.
LXMF 0.9.7 has a sender-side low-stamp prefilter defect: it uses
min(0, required_cost - flexibility). Receivers use the correct max(0, ...)
threshold, so low-value messages can be offered and then rejected.
5. Initiator sends /offer
The generic §11 request data is:
[peering_key, [transient_id_1, transient_id_2, ...]]
Each transient ID is the full 32-byte hash from §5.8. The receiver validates the directional key and marks the Link as validated.
6. Receiver selects wanted IDs
The /offer response value is:
False: receiver already has all offered messages.True: receiver wants all offered messages.[wanted_id, ...]: receiver wants only that subset.
7. Initiator transfers requested entries
Requested entries are read from the message store with their 32-byte propagation stamps and sent as a Resource:
msgpack.packb([time.time(), [stamped_entry_1, stamped_entry_2, ...]])
8. Receiver admits and stores the Resource
Multiple messages are accepted only when the Resource Link was validated by a
successful /offer. An unvalidated Link may submit one message, which supports
ordinary client submission. The receiver validates each propagation stamp,
stores valid opaque bodies, and tears down/throttles on invalid stamps.
9. Initiator marks sync state
After a successful Resource transfer, the initiator moves transferred IDs from unhandled to handled state, updates counters, tears down the Link, and may continue immediately under the persistent strategy.
Source map
| Step | File | Function / line |
|---|---|---|
| 1 | LXMF/LXMRouter.py |
get_propagation_node_app_data, line 306+ |
| 2 | LXMF/Handlers.py |
LXMFPropagationAnnounceHandler, line 35+ |
| 3-5 | LXMF/LXMPeer.py |
generate_peering_key / sync, line 242+ |
| 5-6 | LXMF/LXMRouter.py |
offer_request, line 2145+ |
| 7, 9 | LXMF/LXMPeer.py |
offer_response / resource_concluded, line 395+ |
| 8 | LXMF/LXMRouter.py |
propagation_resource_concluded, line 2200+ |