Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ __pycache__/
*.py[cod]

# Node
node_modules/
node_modules
examples/react-native-app/node_modules/
*.log
npm-debug.log*
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,28 @@ archived by series under [docs/changelog/](docs/changelog/); see the
reference server. Nothing ships in this entry but the contract; the
reference server follows it.

- **Custody v1.** A device can now hold a neighbour's replication frames for
hours instead of the five seconds a forwarder gives them
(`docs/spec/custody.md`), off by default. `ProtocolConfig::custody`
(`custody` in every binding) switches it on and sets the hold and the
quotas; the hold is validated strictly shorter than the outbox lifetime. The
depositor's engine writes the one-hop request on its own sealed `delta`,
`snap`, `vv` and `blob_gone` frames when it offers them to neighbours, from
the plaintext it retains for re-sealing and never after a restart; every
forwarder strips the request from a third-party frame it transmits. A
custodian judges a frame at the drop point, after the forwarding identifier
is released, so it never blanks its own route; answers a depositor that
advertises `data_versions` entry 7 with the signed `__CUSTODY_RECEIPT__`
once, over the arrival link; redelivers on neighbour discovery through a
dedicated governor intake, at most once per neighbour per hold and straight
to the recipient when it appears; expires records in wall time against the
hold in force; and keeps them sealed under the new `custody_entries` storage
category, restored at launch. A receipt settles nothing. `custody_stats()`
(`get_custody_stats()` over the FFI) reports the counters, every refusal
reason included, and `erase_custody()` drops every record; the data-layer
wipe calls it. The receipt body has frozen vectors at
`crates/offline-protocol/tests/data/custody-receipt-v1.vectors.json`.

- **The custody chapter.** `docs/spec/custody.md` specifies how a device
holds a neighbour's replication frame for hours instead of the five
seconds a forwarder gives it today: an explicit deposit in which the
Expand Down Expand Up @@ -241,6 +263,13 @@ archived by series under [docs/changelog/](docs/changelog/); see the

### Fixed

- **The iOS config readers read `0` and `1` as numbers.** The Foundation-only
readers behind `meshRelay` and `custody` excluded JSON booleans with an
`is Bool` test that Swift also answers true for the numbers 0 and 1, so a
`fanout: 1`, an `activityIdleWindows: 1` or a `jitterMinMs: 0` written from
React Native reached the core as unset and the dial silently stayed at its
default. Both readers now exclude booleans by their CoreFoundation type.

- **The storage conformance suite no longer deletes a merging backend's
records.** `runStorageConformance` cleaned up its probe records by listing
a probe key type and deleting what it listed, before any check had run.
Expand Down
3 changes: 3 additions & 0 deletions bindings/python/offline_protocol_sdk/local_api/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
"get_retry_queue_size",
"get_mesh_relay_stats",
"get_mesh_relay_tunables",
"get_custody_stats",
# instance-wide tuning
"set_relay_priority",
"update_relay_config",
Expand Down Expand Up @@ -282,6 +283,8 @@
"data.with_storage",
# the operator's logout
"data.wipe_all",
# erases what every client's traffic deposited
"erase_custody",
# takes a callback interface
"run_storage_conformance",
}
Expand Down
36 changes: 35 additions & 1 deletion bindings/python/offline_protocol_sdk/local_api/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from __future__ import annotations

UDL_SHA256 = "6e46f0053aa0b08d7b1b5e31cb2e3802fc126351fed72a97dee28558f70ee424"
UDL_SHA256 = "d2b3a4e23be560b35388bfe45c5164ce4b7c002f5e11022700618c7e102823cb"

TABLE = {'callbacks': ('MlsStorageProvider',
'ProtocolStateStorageProvider',
Expand Down Expand Up @@ -219,6 +219,7 @@
('app_state', 'AppState')),
'void'),
'end_telemetry_session': ((), 'void'),
'erase_custody': ((), 'void'),
'establish_secure_session': ((('peer_id', 'string'),),
'MlsWelcomeMessage?'),
'finalize_file': ((('file_id', 'string'),), 'void'),
Expand All @@ -239,6 +240,7 @@
'get_active_transports': ((), 'sequence<string>'),
'get_battery_level': ((), 'u8?'),
'get_blocked_users': ((), 'sequence<string>'),
'get_custody_stats': ((), 'CustodyStats'),
'get_dedup_stats': ((), 'DedupStats'),
'get_delivery_success_rate': ((), 'f32'),
'get_dors_config': ((), 'DorsConfig'),
Expand Down Expand Up @@ -522,6 +524,37 @@
'records': {'AckConfig': (('default_timeout_ms', 'u64', False),
('max_pending_acks', 'u64', False)),
'BleFragment': (('recipient_id', 'string', False), ('data', 'sequence<u8>', False)),
'CustodyConfig': (('enabled', 'boolean?', True),
('hold_ms', 'u64?', True),
('max_entries_per_depositor', 'u64?', True),
('max_bytes_per_depositor', 'u64?', True),
('max_entries', 'u64?', True),
('max_bytes', 'u64?', True),
('stranger_max_entries', 'u64?', True),
('stranger_max_bytes', 'u64?', True),
('overflow_policy', 'OverflowPolicy?', True)),
'CustodyStats': (('held', 'u64', False),
('held_bytes', 'u64', False),
('accepted', 'u64', False),
('delivered', 'u64', False),
('re_originated', 'u64', False),
('expired', 'u64', False),
('duplicates', 'u64', False),
('evicted', 'u64', False),
('receipts_sent', 'u64', False),
('receipts_dropped', 'u64', False),
('receipts_received', 'u64', False),
('receipts_ignored', 'u64', False),
('refused_disabled', 'u64', False),
('refused_no_request', 'u64', False),
('refused_unknown_class', 'u64', False),
('refused_not_sealed', 'u64', False),
('refused_unproven_peer', 'u64', False),
('refused_not_depositor', 'u64', False),
('refused_stranger', 'u64', False),
('refused_depositor_full', 'u64', False),
('refused_store_full', 'u64', False),
('refused_battery', 'u64', False)),
'DedupConfig': (('max_tracked_messages', 'u64', False),
('retention_time_secs', 'u64', False)),
'DedupStats': (('total_tracked', 'u64', False),
Expand Down Expand Up @@ -728,6 +761,7 @@
('rich_payload_enabled', 'boolean', True),
('crypto_recovery_enabled', 'boolean', True),
('mesh_relay', 'MeshRelayConfig?', True),
('custody', 'CustodyConfig?', True),
('data_enabled', 'boolean', True),
('control_freshness_enforced', 'boolean', True)),
'ProtocolLockDiagnostics': (('held', 'boolean', False),
Expand Down
Loading
Loading