Skip to content

Comments

serviceability: add reservation account for connection pre-reservation#3086

Open
martinsander00 wants to merge 5 commits intomainfrom
ms/reserve-connections
Open

serviceability: add reservation account for connection pre-reservation#3086
martinsander00 wants to merge 5 commits intomainfrom
ms/reserve-connections

Conversation

@martinsander00
Copy link
Contributor

@martinsander00 martinsander00 commented Feb 24, 2026

Summary

  • Add Reservation onchain account that allows an offchain reservation authority to pre-reserve connection seats on devices before the Activator creates User accounts
  • Introduce ReserveConnection and CloseReservation instructions — account existence represents a reserved seat, closing the account releases it
  • Add reserved_seats to Device, factored into capacity checks (users_count + reserved_seats >= max_users)
  • Add reservation_authority_pk to GlobalState for access control

Key files

  • state/reservation.rs — new Reservation account struct and serialization
  • state/device.rsreserved_seats field, capacity check update
  • processors/reservation/reserve.rs — ReserveConnection processor
  • processors/reservation/close.rs — CloseReservation processor (closes account, decrements seats)
  • processors/globalstate/setauthority.rs — support for setting reservation_authority_pk

Details

The Reservation account is a lightweight PDA ([prefix, reservation, device_pk, client_ip]) that tracks which device and client IP a seat is held for. There is no status enum — the account existing means "reserved", and closing it means "done". CloseReservation closes the account, returns rent to the payer, and decrements reserved_seats on the device.

Authority is checked against reservation_authority_pk in GlobalState, with a fallback to the foundation allowlist.

Testing Verification

  • 6 integration tests covering: happy-path reserve, close reservation, capacity limit (reserved_seats only), capacity limit (users_count + reserved_seats), unauthorized rejection with separate keypair, duplicate reservation for same (device, client_ip)
  • All 174 existing unit tests continue to pass
  • make rust-lint clean

Add Reservation onchain account to hold connection seats on devices
before the Activator creates the actual User account. This enables
the reserve-connections-for-settlement workflow where an offchain
oracle can pre-reserve capacity.

New state:
- Reservation struct (account_type, owner, device_pk, client_ip, status)
- ReservationStatus enum (Reserved, Settled, Pruned)
- PDA: [prefix, reservation, device_pk, client_ip]

New instructions:
- ReserveConnection (95): creates reservation, increments device.reserved_seats
- PruneReservation (96): marks pruned, decrements device.reserved_seats
- SettleReservation (97): marks settled, seat stays committed

GlobalState changes:
- reservation_authority_pk field for access control

Device changes:
- reserved_seats field, factored into capacity checks
…uction

Remove ReservationStatus enum and status field — account existence is
sufficient. Collapse PruneReservation + SettleReservation into a single
CloseReservation that closes the account and decrements reserved_seats.
Add integration tests for reserve, close, capacity, and double-reserve.
Add test_reserve_connection_at_capacity_with_users_count that sets
users_count=1 via UpdateDevice and verifies the combined capacity
formula (users_count + reserved_seats >= max_users) rejects correctly.
Replace the foundation_allowlist fallback test with a proper test that
creates a second keypair not in the allowlist and not the reservation
authority, then verifies ReserveConnection fails with NotAllowed.
Add Device.reserved_seats (u16) and GlobalState.reservation_authority_pk
(pubkey) to Go, TypeScript, and Python SDKs. Regenerate binary fixtures.
pub activator_authority_pk: Option<Pubkey>,
pub sentinel_authority_pk: Option<Pubkey>,
pub health_oracle_pk: Option<Pubkey>,
#[incremental(default = None)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can exclude this and it'll just use None as the default.

let mut device = Device::try_from(device_account)?;

// Check device capacity: users_count + reserved_seats < max_users
if device.max_users > 0 && device.users_count + device.reserved_seats >= device.max_users {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If max_users == 0 I think we want this to error with MaxUsersExceeded

let mut device = Device::try_from(device_account)?;

// Check device capacity: users_count + reserved_seats < max_users
if device.max_users > 0 && device.users_count + device.reserved_seats >= device.max_users {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants