Per-fleet cost settings (SF-130)
Each customer fleet chooses the cadences that drive its network cost. The settings live on chain, bounded by the contract, and devices apply them within one check. The defaults are those of the 2026-10-23 business-plan proposal: the base price includes them, and faster options are priced add-ons. The settings page that shows the cost and collects the prepaid deposit is SF-131 (#266).
Settings, defaults and bounds
| Field | Default | Bounds (inclusive) | Applied by |
|---|---|---|---|
check_interval_ms |
30 minutes | 5 minutes to 6 hours | every device's chain check |
rollout_check_interval_ms |
60 seconds | 30 seconds to 10 minutes, at most check_interval_ms; 0 turns fast checks off |
the fast checks of the check cadence |
health_interval_ms |
daily | 1 minute to 1 day (as fleet_data) |
on-chain health reports (fleet_data) |
archive_interval_ms |
weekly | 1 hour to 1 week (as fleet_data) |
routine encrypted log archives (fleet_data) |
archive_retention_epochs |
3 (six weeks of two-week Mainnet epochs) | 1 to 53 Walrus epochs | the owner's archive storage purchases |
The values are shared through interfaces/fleet-v1.json (fleet_settings):
the generated FLEET_SETTINGS (TypeScript) and fleet_settings_values (Rust)
constants, and a generated Move test that checks the contract's defaults and
accepts every bound.
The bounds keep one device within Mysten's documented public full node guidance
of 100 requests per 30 seconds: routine checks at most every 5 minutes and fast
checks at most every 30 seconds. Health and archive bounds equal those
fleet_data already enforces.
Contract: sui_edge::fleet_settings
Introduced by a compatible upgrade of the core package. One Settings value
per fleet is stored in a dynamic field (key SettingsKey) of the fleet's
FleetBudget (FLEET_BUDGET.md), so:
- devices find it from the budget ID they already use, with one object read;
- a fleet has one record, never two that disagree;
- budgets created before the upgrade gain a record without migration.
| Function | Who | Effect |
|---|---|---|
set(budget, cap, check, rollout, health, archive, retention, clock) |
holder of the budget's BudgetOwnerCap |
creates or replaces the record; aborts EOutOfBounds outside the bounds |
defaults(), new(...) |
anyone | a bounds-checked value |
settings(budget) and getters |
anyone | the record, or none |
Every write emits FleetSettingsChanged { budget_id, changed_by, at_ms, previous, settings }; previous is none on the first write. set checks the
budget's package version through fleet_budget::assert_owner, and refuses to
overwrite a record written by a newer package version (ENewerVersion), so an
older package version cannot undo a later migration. There is no device-side
write.
Daemon
The daemon follows the settings of the budget named by [budget].budget_id,
or else [fleet_data].budget_id; configuration validation requires both to
name the same budget when both are set. A deployment manifest without the
fleet_settings type origins, or a fleet without a record, leaves the local
configuration in force.
- Checks. After every check the daemon reads the record and applies it
to the check cadence
as floors: the routine interval becomes
max(runtime.poll_seconds, check_interval_ms)and the fast interval (used while a deployment waits for rollout eligibility or admission, or a maintenance window is open) becomesmax(runtime.rollout_poll_seconds, rollout_check_interval_ms). With fast checks off (0) the fast interval is the routine interval. The cadence's single wakeups at a known admission time or window start, and its failure backoff, are unchanged. Intervals that are not whole seconds round up. - Health and archives. The
fleet_dataloop reads the record each round and reports health or archives logs at the slower of thefleet_datacadence (the contract-enforced minimum) and the fleet's setting. With a record, that loop also runs at the fleet's check interval instead of every minute, so diagnostics requests and archive cleanup follow within one check. - Retention is applied by the owner's storage purchases (pool epochs and renewal targets), not by devices; the daemon reads but does not use it.
Local configuration can only make a device slower and cheaper, never faster than the fleet allows. A change applies at the next check after it is written: within one interval. A record the daemon cannot use (unreadable, outside the bounds, or a newer version) keeps the settings already in force and is logged once. Older daemons ignore the record and keep their local configuration.
dApp
dapp/src/lib/fleet-settings.ts provides DEFAULT_SETTINGS,
SETTINGS_BOUNDS, settingsErrors (the contract's rules, checked before
signing), buildSetFleetSettingsTx and fetchFleetSettings (one dynamic-field
read). The /settings page (SF-131) prices each setting, sizes the prepaid
deposit from them and saves them with buildSetFleetSettingsTx; see
FLEET_BUDGET.md.
Verification
| Command | Covers |
|---|---|
sui move test --path contracts fleet_settings (in make test-contracts) |
defaults, inclusive bounds, owner-only writes, events with previous values, version gates, additive record on an existing budget |
cargo test fleet_settings (in make edge-test) |
parsing and bounds, local-only-slower floors on the check cadence, fast checks off, keeping settings in force on unusable reads |
python3 scripts/test_fleet_settings_ota.py (in make test-ota) |
the real daemon against the simulator: local cadence without a record, refused records, the fast interval during a notice in an open maintenance window, a change picked up within one interval, no checks before the routine interval |
scripts/test_fleet_data_ota.py (in make test-ota) |
health and routine archives slowed beyond the fleet_data minimum |
node scripts/test_fleet_settings.cjs (in make test-manifest) |
the dApp's defaults, bounds, transaction and read |
make test-settings-localnet (disposable network-none localnet) |
base-to-head upgrade over an existing budget, type origins, owner changes and events, on-chain refusals, base-package budget operations, real daemon and dApp reads |
Public-testnet upgrade acceptance runs in the normal automatic testnet CI. Physical-device and Mainnet acceptance remain in #32 and #159.
Source: Edit this page