serviceability-instruction: user domain builders (RFC-26 R3) - #4052
Merged
Conversation
This was referenced Jul 13, 2026
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 14, 2026
…RFC-26 R0) (#4049) ## Summary RFC-26 **R0**: scaffold the pure, RPC-free instruction-builder crate `doublezero-serviceability-instruction` — SPL-style builders that return a single unsigned `Instruction` per serviceability instruction, no signing/sending. - `common::build` (no-permission trailing `[payer, system]`) + `common::build_with_permission` (the deferred, activate-in-one-place Permission append) + `compute_budget_prelude` (1.4M CU / 256 KiB). - Four exemplar builders establishing the pattern every later PR copies: `create_device`, `delete_device` (legacy/atomic), `create_link`, `create_subscribe_user`. - Deps limited to `doublezero-serviceability` + `solana-program` + `solana-system-interface` + `solana-compute-budget-interface` — no RPC tree. The `suspend_device` exemplar from the RFC was replaced with `delete_device` (`SuspendDevice` is a deprecated variant); the RFC and #4015 were updated, and the "length-detected family" classification was corrected (only `CreateUser` is length-detected). ## Why Instruction assembly is currently coupled to signing+sending inside `commands/*::execute()`; there is no reusable `build_xxx(args) -> Instruction`. See [rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md). ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for each exemplar, including the `delete_device` legacy vs atomic layouts and the `create_subscribe_user` optional-feed placement. Closes #4015. Part of RFC-26. --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars ← **this PR** 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
juan-malbeclabs
force-pushed
the
feat/rfc26-r2-link-builders
branch
from
July 21, 2026 17:01
19171d9 to
2d96fdb
Compare
juan-malbeclabs
force-pushed
the
feat/rfc26-r3-user-builders
branch
from
July 21, 2026 17:01
ab466cb to
fec27c8
Compare
juan-malbeclabs
force-pushed
the
feat/rfc26-r2-link-builders
branch
from
July 21, 2026 17:19
2d96fdb to
db742c9
Compare
juan-malbeclabs
force-pushed
the
feat/rfc26-r3-user-builders
branch
from
July 21, 2026 17:19
fec27c8 to
df0d689
Compare
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 22, 2026
## Summary RFC-26 **R1** (stacked on the previous phase's branch). Complete the device domain on top of the R0 exemplars: update_device (max(old,new) dz_prefix block), set_device_health, and interface create/delete/update (Vpnv4 topology PDAs, segment-routing reconcile). All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4016. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device ← **this PR** 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
Complete the link domain on top of the R0 create_link exemplar: accept_link, update_link (LinkUpdateAuthority preamble + conditional tunnel_net / tunnel resource / topology-union sections), delete_link (topology reference-count accounts), set_link_health. All route through authorize() -> build_with_permission. Refs #4017, RFC-26.
juan-malbeclabs
force-pushed
the
feat/rfc26-r2-link-builders
branch
from
July 22, 2026 12:59
db742c9 to
f75dc6b
Compare
Complete the user domain on top of the R0 create_subscribe_user exemplar: create_user (length-detected -> build, no permission), update_user, delete_user, request_ban_user, check_user_access_pass (-> build_with_permission), and set_user_bgp_status (metrics-publisher check, no authorize -> build). create_user and set_user_bgp_status are the first build (no-permission) callers. Refs #4018, RFC-26.
…ate/delete/ban builders update_user, delete_user, and request_ban_user always emit the multicast_publisher_block account but never set the matching multicast_publisher_count arg. The processor reads that account only when multicast_publisher_count > 0, so a caller passing 0 (e.g. default args) would desync the declared count from the account list, shifting every following account and corrupting parsing. Pin the count to 1 (same write-back pattern as dz_prefix_count) and assert count/account consistency in the unit tests.
juan-malbeclabs
force-pushed
the
feat/rfc26-r3-user-builders
branch
from
July 22, 2026 15:21
df0d689 to
9c50e51
Compare
…elete builders (RFC-26 R3 review)
…create builders (RFC-26 R3 review)
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 22, 2026
## Summary RFC-26 **R2** (stacked on the previous phase's branch). accept_link, update_link (LinkUpdateAuthority preamble + conditional tunnel_net / tunnel-resource / topology-union sections), delete_link (topology reference-count accounts), set_link_health. All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4017. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link ← **this PR** 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
ben-dz
approved these changes
Jul 22, 2026
ben-dz
left a comment
Contributor
There was a problem hiding this comment.
Re-reviewed at head f5170e0. One non-blocking consistency nit: debug_assert!(dz_prefix_count > 0) was added to create_user/create_subscribe_user but not to update_user/delete_user/request_ban_user, whose processors reject dz_prefix_count == 0 identically — apply it to all five for a uniform build-time guardrail. Everything else raised in the first pass is either addressed by the new commits (tenant-branch tests) or triaged as pre-existing/intentional SDK-parity behavior.
…o user update/delete/ban builders (RFC-26 R3 review)
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 22, 2026
…FC-26 R4) (#4053) ## Summary RFC-26 **R4** (stacked on the previous phase's branch). Three account_index-seeded CRUD domains (create/update/suspend/resume/delete). Exchange create/update carry globalconfig; set_device_exchange carries the device; create_contributor carries the owner. All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4019. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor ← **this PR** 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 23, 2026
…26 R5) (#4054) ## Summary RFC-26 **R5** (stacked on the previous phase's branch). create/update (conditional multicast_group_block)/suspend/reactivate/delete, update_multicast_group_roles, and the four pub/sub allowlist add/remove builders. All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4020. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists ← **this PR** 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 23, 2026
…4055) ## Summary RFC-26 **R6** (stacked on the previous phase's branch). Tenant CRUD + add/remove administrator + update_payment_status (globalstate writable on create, read-only elsewhere), and permission create/update/suspend/resume/delete (target PDA derived from args.user_payer). All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4021. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission ← **this PR** 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 23, 2026
## Summary RFC-26 **R7** (stacked on the previous phase's branch). Topology create/delete plus batched clear_topology / assign_topology_node_segments (single-chunk + *_batched; CLEAR_BATCH_SIZE=16 / BACKFILL_BATCH_SIZE=4 moved into the crate). Feed create/update/delete. All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4022. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed ← **this PR** 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 24, 2026
#4057) ## Summary RFC-26 **R8** (stacked on the previous phase's branch). Access-pass set (conditional tenant pair)/close/check-status/set-feeds, and resource-extension allocate/create/deallocate/close (resource PDA + associated account derived from the data-bearing args.resource_type). All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4023. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource ← **this PR** 10. #4058 — R9 globalstate/config/allowlist/index/migrate R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 24, 2026
…migrate builders (RFC-26 R9) (#4058) ## Summary RFC-26 **R9** (stacked on the previous phase's branch). init_global_state and migrate (no authorize -> build); setters, set_global_config (config PDA + all 8 resource pools), foundation/QA allowlist toggles, index create/delete. After this every buildable variant has a builder. All builders route through `authorize()` -> `build_with_permission` unless noted; each carries a verbatim account-layout doc-comment copied from its processor. ## Testing Verification - Unit tests assert the exact `AccountMeta` list (incl. trailing `[payer, system]`) and the borsh tag byte for every builder, covering the conditional/variable-account paths. Closes #4024. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each is based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate ← **this PR** R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.
juan-malbeclabs
added a commit
that referenced
this pull request
Jul 25, 2026
…4059) ## Summary RFC-26 **RF**: golden fixtures for the instruction builders + a CI drift guard. - Extend the serviceability fixture generator to depend on `doublezero-serviceability-instruction` and emit, per instruction, `ix_<name>.bin` (wire bytes = tag + borsh) and `ix_<name>.json` (`{ variant, data_hex, accounts: [{pubkey, is_signer, is_writable}] }`) from fixed, deterministic inputs. - Representative set covering the trickiest layouts: `create_device` (variable dz_prefix), `delete_device` (atomic close), `create_link`, `create_subscribe_user` (optional feed), `create_user` (length-detected), `clear_topology` / `assign_topology_node_segments` (batched), `set_global_config` (config PDA + all 8 pools). - `make generate-fixtures-check` (regenerate + fail on drift, scoped to the emitted `.bin`/`.json`) and a `fixtures-check` job in the `rust` workflow. These fixtures capture byte-for-byte the current SDK trailing convention (they will drive Go/Python/TS parity in a later phase). ## Testing Verification - `make generate-fixtures-check` passes (regenerated output is byte-identical to the committed fixtures); a hand-edited fixture makes it fail as expected. Closes #4026. Part of RFC-26 ([rfcs/rfc26-rust-instruction-builder-library.md](rfcs/rfc26-rust-instruction-builder-library.md)). --- ### PR stack (RFC-26 builder library) Stacked PRs, merge in order (each based on the previous one's branch): 1. #4049 — R0 scaffold + exemplars 2. #4050 — R1 device 3. #4051 — R2 link 4. #4052 — R3 user 5. #4053 — R4 location/exchange/contributor 6. #4054 — R5 multicastgroup + allowlists 7. #4055 — R6 tenant + permission 8. #4056 — R7 topology + feed 9. #4057 — R8 accesspass + resource 10. #4058 — R9 globalstate/config/allowlist/index/migrate 11. this PR — RF fixtures + CI guard R10 (commands/* migration + program-test) is the final PR and will carry the global changelog entry.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RFC-26 R3 (stacked on the previous phase's branch). create_user (length-detected -> build, no permission), update_user, delete_user, request_ban_user, check_user_access_pass, and set_user_bgp_status (metrics-publisher check, no authorize -> build).
All builders route through
authorize()->build_with_permissionunless noted; each carries a verbatim account-layout doc-comment copied from its processor.Testing Verification
AccountMetalist (incl. trailing[payer, system]) and the borsh tag byte for every builder, covering the conditional/variable-account paths.Closes #4018. Part of RFC-26 (rfcs/rfc26-rust-instruction-builder-library.md).
PR stack (RFC-26 builder library)
Stacked PRs, merge in order (each is based on the previous one's branch):
R10 (commands/* migration + program-test) and RF (fixtures) follow as separate PRs.