reticiulum-specification/flows/propagation-peer-sync.md
John Poole 5aa3920b76 Completed the propagation-node announce and peer-sync three-tier unit.
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.
2026-06-08 17:32:55 -07:00

94 lines
3.4 KiB
Markdown

# 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`](../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:
```text
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:
```python
[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:
```python
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+ |