From 50b5fcbf89331c95a739638f5593661de9efff73 Mon Sep 17 00:00:00 2001 From: Sarfaraz Nawaz Date: Wed, 8 Jul 2026 01:09:16 +0530 Subject: [PATCH] refactor: move commit-and-undelegate scheduling service from magicblock-accounts to magicblock-services --- .agents/context/architecture.md | 13 +- .agents/context/crate-map.md | 19 +- .../crates/magicblock-account-cloner.md | 8 +- .agents/context/crates/magicblock-accounts.md | 388 ++---------------- .agents/context/crates/magicblock-api.md | 28 +- .../context/crates/magicblock-chainlink.md | 12 +- .../crates/magicblock-committor-program.md | 4 +- .../crates/magicblock-committor-service.md | 21 +- .agents/context/crates/magicblock-config.md | 2 +- .agents/context/crates/magicblock-core.md | 8 +- .../crates/magicblock-magic-program-api.md | 2 +- .agents/context/crates/magicblock-metrics.md | 2 +- .agents/context/crates/magicblock-services.md | 89 +++- .agents/specs/validator-specification.md | 4 +- Cargo.lock | 35 +- Cargo.toml | 2 - docs/architecture.md | 17 +- magicblock-accounts/Cargo.toml | 31 -- magicblock-accounts/README.md | 41 -- magicblock-accounts/src/config.rs | 18 - magicblock-accounts/src/errors.rs | 69 ---- magicblock-accounts/src/lib.rs | 7 - magicblock-accounts/src/traits.rs | 18 - magicblock-api/Cargo.toml | 1 - magicblock-api/src/errors.rs | 9 - magicblock-api/src/magic_validator.rs | 26 +- magicblock-committor-service/README.md | 2 +- magicblock-services/Cargo.toml | 8 + magicblock-services/src/lib.rs | 1 + .../src/undelegation_request_service.rs | 32 +- test-manual/Makefile | 2 +- .../helius-laser/sh/04_start-validator.sh | 2 +- 32 files changed, 227 insertions(+), 694 deletions(-) delete mode 100644 magicblock-accounts/Cargo.toml delete mode 100644 magicblock-accounts/README.md delete mode 100644 magicblock-accounts/src/config.rs delete mode 100644 magicblock-accounts/src/errors.rs delete mode 100644 magicblock-accounts/src/lib.rs delete mode 100644 magicblock-accounts/src/traits.rs rename magicblock-accounts/src/scheduled_commits_processor.rs => magicblock-services/src/undelegation_request_service.rs (93%) diff --git a/.agents/context/architecture.md b/.agents/context/architecture.md index 2efaf0cf6..53d17166f 100644 --- a/.agents/context/architecture.md +++ b/.agents/context/architecture.md @@ -60,7 +60,7 @@ Architecture rule: the RPC layer should route work to account sync and execution ### 3. Account synchronization -Owned primarily by `magicblock-chainlink`, `magicblock-account-cloner`, and `magicblock-accounts`. +Owned primarily by `magicblock-chainlink` and `magicblock-account-cloner`. Responsibilities: @@ -69,7 +69,7 @@ Responsibilities: - subscribe to remote changes where needed, - materialize local account/program state, - provide account availability to RPC and transaction execution, -- hand scheduled commit work toward settlement. +- expose DLP request observations to background services that schedule settlement work. Architecture rule: this layer prepares local state for execution. It should not decide post-execution account access rules; those belong to the execution/SVM path. Avoid fetch amplification, duplicate clone work, subscription churn, and unnecessary serialization in account availability paths. @@ -106,11 +106,11 @@ Architecture rule: maintenance operations that can race execution must be coordi ### 6. Base-layer settlement -Owned primarily by `magicblock-program`, `magicblock-magic-program-api`, `magicblock-committor-service`, `magicblock-committor-program`, `magicblock-table-mania`, and `magicblock-rpc-client`. +Owned primarily by `magicblock-program`, `magicblock-magic-program-api`, `magicblock-services`, `magicblock-committor-service`, `magicblock-committor-program`, `magicblock-table-mania`, and `magicblock-rpc-client`. Responsibilities: -- let programs schedule commits, commit-and-undelegate operations, intent bundles, and Magic Actions, +- let programs and validator background services schedule commits, commit-and-undelegate operations, intent bundles, and Magic Actions, - persist and recover pending settlement work, - build valid base-layer transactions, - handle address lookup tables and large changesets, @@ -128,7 +128,8 @@ Responsibilities: - execute scheduled program tasks, - replicate primary output to replicas, - expose metrics/admin/operator hooks, -- provide reusable service infrastructure. +- provide reusable service infrastructure, +- ingest DLP undelegation requests and submit local scheduling transactions. Architecture rule: background services should integrate through shared channels/service APIs rather than reaching through unrelated crate internals. @@ -160,7 +161,7 @@ base-layer delegation exists ```text program invokes Magic Program in ER -> MagicContext records scheduled intent - -> validator-side processing picks up intent + -> validator-side services pick up or create the intent -> committor builds/sends base-layer transaction(s) -> commit keeps delegation active OR undelegation returns ownership after settlement ``` diff --git a/.agents/context/crate-map.md b/.agents/context/crate-map.md index 1904ca0cd..617d1def4 100644 --- a/.agents/context/crate-map.md +++ b/.agents/context/crate-map.md @@ -9,7 +9,7 @@ The validator is performance-sensitive. When changing any crate on RPC, account | Crate | Purpose | Depends on | Used by | Notes | |---|---|---|---|---| | `magicblock-validator` | Main validator binary and process entrypoint. | `magicblock-api`, `magicblock-config`, `magicblock-core`, `magicblock-tui-client`, `magicblock-version` | End users/operators | Parses config, builds runtime, starts headless/TUI validator; see `.agents/context/crates/magicblock-validator.md` before changing this crate. | -| `magicblock-api` | Top-level service orchestration and `MagicValidator` implementation. | accounts, aperture, chainlink, committor, config, core, ledger, processor, replicator, task scheduler, admin/services | `magicblock-validator` | Owns startup/shutdown wiring for most services; see `.agents/context/crates/magicblock-api.md` before changing this crate. | +| `magicblock-api` | Top-level service orchestration and `MagicValidator` implementation. | accounts-db, aperture, chainlink, committor, config, core, ledger, processor, replicator, task scheduler, admin/services | `magicblock-validator` | Owns startup/shutdown wiring for most services; see `.agents/context/crates/magicblock-api.md` before changing this crate. | | `magicblock-config` | Validator configuration model and layered config loading. | none | Most service crates | CLI/env/TOML/default config source; see `.agents/context/crates/magicblock-config.md` before changing configurable behavior. | | `magicblock-core` | Shared channels, traits, account locks/helpers, intent/core types. | `magicblock-magic-program-api` | Most runtime crates | Central wiring layer; changes can affect scheduler, RPC, ledger, services, replication. See `.agents/context/crates/magicblock-core.md` before changing this crate. | | `magicblock-version` | Build/version metadata. | none | `magicblock-validator`, `magicblock-aperture` | Keep version reporting stable for RPC/operator tooling; see `.agents/context/crates/magicblock-version.md` before changing this crate. | @@ -28,7 +28,7 @@ The validator is performance-sensitive. When changing any crate on RPC, account | Crate | Purpose | Depends on | Used by | Notes | |---|---|---|---|---| | `magicblock-processor` | Transaction scheduler, executor pool, SVM execution, commit-to-local-state path. | `magicblock-accounts-db`, `magicblock-core`, `magicblock-ledger`, `magicblock-magic-program-api`, `magicblock-metrics`, `magicblock-program` | `magicblock-api`, tests | Core execution path; preserve account locking and writable-account access invariants. | -| `magicblock-accounts-db` | Custom local account database. | `magicblock-config`, `magicblock-magic-program-api` | account cloner, accounts, aperture, API, chainlink, processor, replicator, tests/tools | Append-only mmap storage plus indexes/snapshots; maintenance requires scheduler pause. See `.agents/context/crates/magicblock-accounts-db.md` before changing this crate. | +| `magicblock-accounts-db` | Custom local account database. | `magicblock-config`, `magicblock-magic-program-api` | account cloner, aperture, API, chainlink, processor, replicator, tests/tools | Append-only mmap storage plus indexes/snapshots; maintenance requires scheduler pause. See `.agents/context/crates/magicblock-accounts-db.md` before changing this crate. | | `magicblock-ledger` | Local ledger/history and latest block state. | `magicblock-core`, `magicblock-metrics`, `solana-storage-proto`, `test-kit` | aperture, API, processor, replicator, task scheduler, tools/tests | Stores tx/status/block history and latest blockhash/slot; see `.agents/context/crates/magicblock-ledger.md` before changing this crate. | | `solana-storage-proto` | Generated/protobuf storage support. | none | `magicblock-ledger` | Low-level ledger serialization support; see `.agents/context/crates/storage-proto.md` before changing this crate. | @@ -36,16 +36,15 @@ The validator is performance-sensitive. When changing any crate on RPC, account | Crate | Purpose | Depends on | Used by | Notes | |---|---|---|---|---| -| `magicblock-chainlink` | Base-chain account/delegation coordination. | accounts-db, AML, config, core, magic-program API, metrics | account-cloner, accounts, aperture, API, magic program | Checks/clones remote accounts, tracks delegation state, coordinates base-layer reads. See `.agents/context/crates/magicblock-chainlink.md` before changing this crate. | -| `magicblock-account-cloner` | Fetches and injects base-layer accounts/programs into local validator state. | accounts-db, chainlink, committor-service, config, core, ledger, magic-program API, magic program, rpc-client | accounts, aperture, API | Distinguishes fee payer, delegated, and undelegated accounts; handles large/program clone paths. See `.agents/context/crates/magicblock-account-cloner.md` before changing this crate. | -| `magicblock-accounts` | Account manager and scheduled commit processing glue. | account-cloner, accounts-db, chainlink, committor-service, core, metrics, magic program | `magicblock-api` | Current active role is scheduled commit processing and pending intent recovery; see `.agents/context/crates/magicblock-accounts.md` before changing this crate. | +| `magicblock-chainlink` | Base-chain account/delegation coordination. | accounts-db, AML, config, core, magic-program API, metrics | account-cloner, aperture, API, magic program, services | Checks/clones remote accounts, tracks delegation state, coordinates base-layer reads and DLP request observations. See `.agents/context/crates/magicblock-chainlink.md` before changing this crate. | +| `magicblock-account-cloner` | Fetches and injects base-layer accounts/programs into local validator state. | accounts-db, chainlink, committor-service, config, core, ledger, magic-program API, magic program, rpc-client | aperture, API, services | Distinguishes fee payer, delegated, and undelegated accounts; handles large/program clone paths. See `.agents/context/crates/magicblock-account-cloner.md` before changing this crate. | | `magicblock-aml` | External/cached risk-scoring integration. | `magicblock-config` (dev: `magicblock-core`) | `magicblock-chainlink` | Optional Range risk checks for post-delegation action signers; see `.agents/context/crates/magicblock-aml.md` before changing this crate. | ## Commit and base-layer settlement crates | Crate | Purpose | Depends on | Used by | Notes | |---|---|---|---|---| -| `magicblock-committor-service` | Executes scheduled base-layer intents: commit, undelegate, finalize, action. | committor program, core, metrics, magic program, rpc-client, table-mania | account-cloner, accounts, API | Durable commit pipeline; handles scheduling, transaction prep, buffers, ALTs, confirmations. See `.agents/context/crates/magicblock-committor-service.md` before changing this crate. | +| `magicblock-committor-service` | Accepts and executes scheduled base-layer intents: commit, undelegate, finalize, action. | accounts-db, account-cloner, chainlink, committor program, core, metrics, magic program, rpc-client, table-mania | account-cloner, API | Durable intent pipeline; accepts ER MagicContext intents, handles scheduling, transaction prep, buffers, ALTs, confirmations. See `.agents/context/crates/magicblock-committor-service.md` before changing this crate. | | `magicblock-committor-program` | On-chain committor program. | none | `magicblock-committor-service` | Base-layer program side for changeset buffers/commit application; see `.agents/context/crates/magicblock-committor-program.md` before changing this crate. | | `magicblock-table-mania` | Address lookup table management. | metrics, rpc-client | `magicblock-committor-service` | Creates/extends/deactivates/closes ALTs needed by commit transactions. See `.agents/context/crates/magicblock-table-mania.md` before changing this crate. | @@ -53,7 +52,7 @@ The validator is performance-sensitive. When changing any crate on RPC, account | Crate | Purpose | Depends on | Used by | Notes | |---|---|---|---|---| -| `magicblock-program` | Magic Program implementation (`programs/magicblock`). | chainlink, core, magic-program API, test-kit | account-cloner, accounts, API, committor, processor, task scheduler, admin | Implements scheduling, cloning, ephemeral accounts, validator-only operations. | +| `magicblock-program` | Magic Program implementation (`programs/magicblock`). | chainlink, core, magic-program API, test-kit | account-cloner, API, committor, processor, services, task scheduler, admin | Implements scheduling, cloning, ephemeral accounts, validator-only operations. | | `magicblock-magic-program-api` | Shared Magic Program instruction, PDA, args, and compatibility types. | none | core, accounts-db, chainlink, processor, magic program, services, cloner, API, test programs | Use this instead of duplicating Magic Program wire types; see `.agents/context/crates/magicblock-magic-program-api.md` before changing this crate. | | `guinea` | Test-only program for validator behavior. | `magicblock-magic-program-api` | processor tests, test-kit | Used to exercise ephemeral/delegated behavior in tests. | @@ -63,7 +62,7 @@ The validator is performance-sensitive. When changing any crate on RPC, account |---|---|---|---|---| | `magicblock-task-scheduler` | Program-scheduled task/crank service. | config, core, ledger, magic program | `magicblock-api` | SQLite-backed delay queue, retries/backoff, scheduled transaction submission. See `.agents/context/crates/magicblock-task-scheduler.md` before changing this crate. | | `magicblock-replicator` | Primary/replica event replication over NATS JetStream. | accounts-db, config, core, ledger | `magicblock-api` | Preserves HA/replica replay behavior; primary and replica modes differ intentionally. | -| `magicblock-services` | Shared service utilities/adapters. | core, magic-program API | `magicblock-api` | Common service abstractions; keep generic. See `.agents/context/crates/magicblock-services.md` before changing this crate. | +| `magicblock-services` | Shared validator service adapters, including action callbacks and DLP undelegation request processing. | account-cloner, chainlink, core, magic-program API, metrics, magic program | `magicblock-api`, committor | Background adapters may bridge existing service contracts; keep orchestration in API and base-layer execution in committor. See `.agents/context/crates/magicblock-services.md` before changing this crate. | | `magicblock-metrics` | Metrics helpers and instrumentation. | none | RPC, ledger, processor, chainlink, committor, table-mania, API | Prefer adding observability here rather than ad-hoc metrics code. See `.agents/context/crates/magicblock-metrics.md` before changing this crate. | ## Tools and test support @@ -78,8 +77,8 @@ The validator is performance-sensitive. When changing any crate on RPC, account ## How to use this map - For transaction correctness, start with `magicblock-processor`, then inspect `magicblock-accounts-db`, `magicblock-ledger`, and `magicblock-program` interactions. -- For delegation or account cloning bugs, start with `magicblock-chainlink`, `magicblock-account-cloner`, and `magicblock-accounts`. -- For commit or undelegation bugs, start with `magicblock-program`, `magicblock-accounts`, and `magicblock-committor-service`. +- For delegation or account cloning bugs, start with `magicblock-chainlink` and `magicblock-account-cloner`; for DLP undelegation request ingestion, also inspect `magicblock-services`. +- For commit or undelegation bugs, start with `magicblock-program`, `magicblock-services`, and `magicblock-committor-service`. - For RPC behavior, start with `magicblock-aperture`; check `magicblock-chainlink` if reads trigger cloning. - For validator lifecycle/startup/shutdown, start with `magicblock-api` and `magicblock-validator`. - When adding, removing, renaming, or repurposing a crate, update this file and `AGENTS.md` in the same change. diff --git a/.agents/context/crates/magicblock-account-cloner.md b/.agents/context/crates/magicblock-account-cloner.md index b87f00faa..39ec385f2 100644 --- a/.agents/context/crates/magicblock-account-cloner.md +++ b/.agents/context/crates/magicblock-account-cloner.md @@ -54,9 +54,9 @@ Main consumers: - `magicblock-api` creates `ChainlinkCloner::new(transaction_scheduler, latest_block)` during validator startup unless Chainlink is disabled for replica mode. - `magicblock-chainlink` owns clone decisions and invokes this crate through `Arc`-style generic wiring. -- `magicblock-accounts` aliases `ProdChainlink` for scheduled commit / undelegation integration. +- `magicblock-services` aliases `ProdChainlink` for DLP undelegation request integration. - `magicblock-aperture` stores the same production Chainlink alias in shared RPC state; it reaches the cloner indirectly through Chainlink. -- `magicblock-api` and `magicblock-accounts` convert `AccountClonerError` where committor diagnostic helpers are used. +- `magicblock-api` converts `AccountClonerError` where committor diagnostic helpers are used. Important upstream/downstream relationships: @@ -299,7 +299,7 @@ Risks: Inspect first: - `magicblock-api/src/magic_validator.rs::init_chainlink`; -- type aliases `InnerChainlinkImpl` / `ChainlinkImpl` in `magicblock-api` and `magicblock-accounts`; +- type aliases `InnerChainlinkImpl` / `ChainlinkImpl` in `magicblock-api`, `magicblock-chainlink`, and `magicblock-services`; - `magicblock-chainlink` production aliases and disabled replication mode behavior. Risks: @@ -316,7 +316,7 @@ Inspect first: - `magicblock-account-cloner/src/util.rs::get_tx_diagnostics`; - `magicblock-committor-service` error types; - `magicblock-rpc-client` transaction log/CU helpers; -- `magicblock-api/src/errors.rs` and `magicblock-accounts/src/errors.rs` conversions. +- `magicblock-api/src/errors.rs` conversions. Risks: diff --git a/.agents/context/crates/magicblock-accounts.md b/.agents/context/crates/magicblock-accounts.md index a38cf9b72..b08fd6d0b 100644 --- a/.agents/context/crates/magicblock-accounts.md +++ b/.agents/context/crates/magicblock-accounts.md @@ -1,360 +1,28 @@ -# `magicblock-accounts` - -## Purpose - -`magicblock-accounts` is the validator-side glue between Magic Program scheduled intents, Chainlink account lifecycle tracking, and the committor service. In the current implementation it does **not** own the account-cloning manager described by its historical README; account fetching/cloning is owned by `magicblock-chainlink` and `magicblock-account-cloner`. This crate's active runtime responsibility is scheduled commit processing. - -At a high level it: - -- exposes the `ScheduledCommitsProcessor` trait used by `magicblock-api`'s slot ticker; -- implements `ScheduledCommitsProcessorImpl`, which drains accepted `ScheduledIntentBundle`s from the Magic Program global transaction scheduler; -- forwards scheduled and recovered intent bundles to `magicblock-committor-service`; -- tracks per-intent metadata needed to signal `ScheduledCommitSent` back into local validator execution after base-layer intent execution finishes; -- notifies Chainlink when accounts are about to be undelegated so base-layer undelegation completion can be watched; -- starts a one-shot recovery pass for persisted pending intent bundles after ledger replay and account-bank reset. - -This crate sits on the commit/undelegation settlement path and interacts with the transaction scheduler. It is not part of ordinary SVM transaction execution, but its ticker-triggered work can affect slot progression, local commit lifecycle state, Chainlink subscription state, and committor throughput. Avoid adding blocking work, unbounded locks, duplicate intent scheduling, or heavy per-intent processing without an explicit performance tradeoff. - -## Update requirement - -Update this document in the same change whenever behavior in `magicblock-accounts` changes, or when another crate changes the flows/contracts consumed here. Update it for changes to: - -- `ScheduledCommitsProcessor` trait methods or `ScheduledCommitsProcessorImpl::new` wiring; -- scheduled intent draining, metadata tracking, result processing, or `SentCommit` construction; -- pending intent recovery timing, delegation checks, or recovered scheduling behavior; -- Chainlink undelegation notification behavior; -- Magic Program scheduled intent types, `TransactionScheduler` global state, `ScheduledCommitSent`, or `SentCommit` fields; -- committor result subscription, broadcast error handling, patched-error/callback-report handling, or execution-output variants; -- startup/shutdown ordering in `magicblock-api` that affects this processor; -- validation commands or integration suites relevant to schedule intents, commits, or undelegation; -- performance characteristics of scheduled commit processing, result handling, or recovery. - -For the general documentation-update rule, see `.agents/memory/agent-memory-and-docs.md`. - -## Where it sits in the repository - -Primary files and nearby contracts: - -| Path | Role | -|---|---| -| `magicblock-accounts/Cargo.toml` | Crate dependencies. Pulls in Chainlink/cloner aliases, committor service, core scheduler types, metrics, and Magic Program scheduled intent types. | -| `magicblock-accounts/README.md` | Historical notes about an `AccountsManager`/`ensure_accounts` design. Treat source and this guide as canonical for current behavior. | -| `magicblock-accounts/src/lib.rs` | Public exports: `config::*`, `traits::*`, `errors`, and `scheduled_commits_processor`. | -| `magicblock-accounts/src/config.rs` | Defines a local `LifecycleMode` enum and `requires_ephemeral_validation`; currently no tracked consumer uses this type. Do not confuse it with `magicblock-config::config::LifecycleMode`, which is the validator config type in use. | -| `magicblock-accounts/src/traits.rs` | Defines the `ScheduledCommitsProcessor` async trait consumed by the API slot ticker. | -| `magicblock-accounts/src/scheduled_commits_processor.rs` | Main implementation: scheduled intent draining, committor scheduling, pending recovery, Chainlink undelegation notifications, result subscription loop, and `SentCommit` signaling. | -| `magicblock-accounts/src/errors.rs` | Error enums and result aliases for scheduled commit processing plus older account/committor error variants. | -| `magicblock-api/src/magic_validator.rs` | Production wiring. Constructs `ScheduledCommitsProcessorImpl`, starts recovery after replay/reset, passes it to the slot ticker, and stops it before stopping the committor service. | -| `magicblock-api/src/tickers.rs` | Slot ticker checks `MagicContext::has_scheduled_commits`, executes `AcceptScheduleCommits`, then calls `ScheduledCommitsProcessor::process`. | -| `programs/magicblock/src/magic_context.rs` | `MagicContext` storage and `has_scheduled_commits` fast check used by the slot ticker. | -| `programs/magicblock/src/schedule_transactions/process_accept_scheduled_commits.rs` | Magic Program instruction that moves scheduled intents from `MagicContext` into global `TransactionScheduler` state. | -| `programs/magicblock/src/magic_scheduled_base_intent.rs` | Defines `ScheduledIntentBundle`, `MagicIntentBundle`, and helpers such as `get_all_committed_pubkeys` / `has_undelegate_intent`. | -| `magicblock-committor-service/src/service.rs` | `BaseIntentCommittor` trait and `CommittorService` oneshot APIs used by this crate. | -| `magicblock-committor-service/src/committor_processor.rs` | Persists and schedules normal intents; loads pending intent bundles for recovery; schedules recovered bundles without re-persisting. | -| `test-integration/test-schedule-intent/` and `test-integration/schedulecommit/` | Integration coverage for schedule intent, commit, and commit-and-undelegate behavior. | - -Main consumers: - -- `magicblock-api` is the only production consumer of `ScheduledCommitsProcessorImpl`. -- `magicblock-api::tickers` depends on the `ScheduledCommitsProcessor` trait rather than the concrete implementation. -- The committor service is the downstream executor for base-layer intents. -- Chainlink is notified when accounts are entering undelegation so it can watch/update base-layer state. -- The Magic Program is both upstream (schedules/accepts intents) and downstream (receives local `ScheduledCommitSent` signals). - -Important boundaries: - -- This crate does not fetch or clone transaction accounts for ordinary execution; use `magicblock-chainlink` / `magicblock-account-cloner` for account availability changes. -- This crate does not build base-layer commit transactions; that belongs to `magicblock-committor-service`. -- This crate does not enforce final SVM writable-account access rules; that belongs to the processor/SVM path. - -## Public API shape / Main public types and APIs - -`magicblock-accounts/src/lib.rs` exports: - -```rust -mod config; -pub mod errors; -pub mod scheduled_commits_processor; -mod traits; - -pub use config::*; -pub use traits::*; -``` - -### `ScheduledCommitsProcessor` trait - -Defined in `src/traits.rs`: - -- `async fn process(&self) -> ScheduledCommitsProcessorResult<()>` drains accepted scheduled intents and hands them to the committor; -- `fn scheduled_commits_len(&self) -> usize` returns the count of accepted intents in Magic Program global scheduler state; -- `fn clear_scheduled_commits(&self)` clears that global scheduler state; -- `fn stop(&self)` cancels processor background work. - -The trait is `Send + Sync + 'static` and is used by `magicblock-api/src/tickers.rs` to keep slot ticker code generic. - -### `ScheduledCommitsProcessorImpl` - -Defined in `src/scheduled_commits_processor.rs` and constructed with: - -```rust -pub fn new( - committor: Arc, - chainlink: Arc, - internal_transaction_scheduler: TransactionSchedulerHandle, - latest_block: impl LatestBlockProvider, -) -> Self -``` - -Stored state: - -- `committor: Arc` schedules intent bundles and provides result broadcasts / pending persisted intents; -- `chainlink: Arc` receives `undelegation_requested(pubkey)` calls before commit-and-undelegate execution; -- `cancellation_token: CancellationToken` stops the result-processing loop; -- `intents_meta_map: Arc>>` maps intent IDs to local metadata needed when committor results return; -- `transaction_scheduler: magicblock_program::TransactionScheduler` accesses the Magic Program's global scheduled action store. - -Important public method outside the trait: - -- `spawn_pending_intents_recovery(self: &Arc)` starts a one-shot task that loads persisted pending intent bundles from committor storage, filters them through Chainlink delegation checks, and schedules recoverable bundles. It must run only after ledger replay and account-bank reset. - -### Type aliases - -- `InnerChainlinkImpl = ProdInnerChainlink` -- `ChainlinkImpl = ProdChainlink` - -These encode the current production Chainlink/cloner stack. If Chainlink generic wiring changes, update these aliases and this guide together. - -### Errors - -`ScheduledCommitsProcessorError` wraps: - -- `tokio::sync::oneshot::error::RecvError` when committor oneshot requests fail; -- boxed `CommittorServiceError` from scheduling, recovery, or result-subscription operations. - -`AccountsError` still contains broader account/committor/cloner variants from older APIs. Check whether a variant is actually consumed before relying on it for new behavior. - -## Runtime flows - -### Normal scheduled commit flow - -```text -program invokes Magic Program schedule instruction - -> MagicContext stores ScheduledIntentBundle(s) - -> slot ticker sees MagicContext::has_scheduled_commits - -> validator-signed AcceptScheduleCommits transaction runs locally - -> Magic Program moves bundles into global TransactionScheduler state - -> ScheduledCommitsProcessorImpl::process drains them - -> committor service persists/schedules base-layer intent execution - -> committor broadcasts result - -> processor registers SentCommit and schedules local ScheduledCommitSent transaction -``` - -Ordered details: - -1. User/program code schedules commit, commit-and-undelegate, commit-finalize, and/or action intent bundles through the Magic Program. -2. `magicblock-api::init_slot_ticker` periodically reads `MAGIC_CONTEXT_PUBKEY` from `AccountsDb` and calls `MagicContext::has_scheduled_commits`. -3. If there are pending scheduled commits, `handle_scheduled_commits` builds `InstructionUtils::accept_scheduled_commits(latest_block.blockhash)` and submits it through the internal `TransactionSchedulerHandle`. -4. `process_accept_scheduled_commits` validates the validator authority signer, drains `MagicContext::scheduled_base_intents`, and calls `TransactionScheduler::default().accept_scheduled_base_intent(...)`. -5. `ScheduledCommitsProcessorImpl::process` calls `take_scheduled_intent_bundles()` on its `magicblock_program::TransactionScheduler` handle. Empty drains are no-ops. -6. For non-empty drains it increments `magicblock_metrics::metrics::inc_committor_intents_count_by` and calls `process_intent_bundles`. -7. `prepare_intent_bundles_for_scheduling` stores `ScheduledBaseIntentMeta` for every intent ID and gathers pubkeys from undelegation intents. -8. `process_undelegation_requests` concurrently calls `chainlink.undelegation_requested(pubkey)` for gathered pubkeys; failures are logged but do not abort the commit. -9. The committor receives the bundles via `CommittorService::schedule_intent_bundles` and returns through a oneshot when scheduling is accepted. -10. The background `result_processor` receives `BroadcastedIntentExecutionResult`s from the committor broadcast channel. -11. `process_intent_result` removes the intent metadata, builds/registers a `SentCommit`, creates or reuses the `ScheduledCommitSent` transaction, encodes it with `with_encoded`, and submits it to the internal scheduler. - -Caveats: - -- The slot ticker has a TODO about possible delay between accepting and processing scheduled commits. Do not add extra sleeps or slow work to this path. -- `process_undelegation_requests` logs subscription failures and continues. That can leave undelegating accounts in a problematic local state; changing this policy is a lifecycle decision, not a local cleanup. -- `intents_meta_map` is keyed by intent ID. Duplicate IDs or unexpected duplicate results can cause missing metadata and are logged as errors. - -### Pending intent recovery flow - -```text -validator start/restart - -> ledger replay - -> account-bank reset/cleanup - -> spawn_pending_intents_recovery - -> committor loads persisted pending bundles - -> Chainlink verifies accounts delegated on base and ER - -> recoverable bundles schedule through committor without re-persisting -``` - -Ordered details: - -1. `magicblock-api::MagicValidator::start` processes ledger replay and clears Magic Program global scheduled actions before starting the normal slot ticker. -2. After account-bank reset, and only in the branch where replay/reset is performed, the API calls `processor.spawn_pending_intents_recovery()`. -3. `recover_pending_intents` asks the committor for `get_pending_intent_bundles().await??`. -4. `recoverable_intent_bundles` checks every bundle's committed pubkeys with `chainlink.accounts_delegated_on_base_and_er(&pubkeys, AccountFetchOrigin::GetAccount)`. -5. Bundles with any non-delegated account, or bundles whose checks error, are skipped and logged. -6. Recoverable bundles go through `process_intent_bundles` with `CommittorService::schedule_recovered_intent_bundles`, which schedules without re-persisting rows. -7. If scheduling recovered bundles fails, metadata for those intent IDs is removed to avoid stale entries. - -Caveats: - -- Recovery must happen after replay/reset because Chainlink delegation checks read local bank state. -- Recovery currently only runs when `MagicValidator::start` enters the replay/reset path. Changing startup branches can affect pending intent durability. -- Filtering requires all committed accounts in a bundle to be delegated on both base and ER; this protects against re-sending stale or already-undelegated work. - -### Result-to-local-signal flow - -When the committor completes an intent: - -1. `BroadcastedIntentExecutionResult` includes the intent ID, success/error output, patched errors, and callback scheduling report. -2. `ScheduledBaseIntentMeta` supplies the original slot, blockhash, payer, committed pubkeys, optional prebuilt `sent_transaction`, and undelegation flag. -3. `build_sent_commit` converts execution output into chain signatures: - - `ExecutionOutput::SingleStage(signature)` becomes one signature; - - `ExecutionOutput::TwoStage { commit_signature, finalize_signature }` becomes two signatures; - - errors try to expose any available commit/finalize signatures through `err.signatures()`. -4. Patched errors and callback scheduling results are stringified into `SentCommit` fields. -5. `register_scheduled_commit_sent(sent_commit)` stores the result for the Magic Program's local `ScheduledCommitSent` processor. -6. The internal transaction scheduler executes the validator-signed `ScheduledCommitSent` transaction so local execution can observe the sent-commit result. - -If the original intent did not carry a signed `sent_transaction`, the processor builds a new one with the current latest blockhash. This fallback is important for recovered intents reconstructed from persistence. - -### Shutdown flow - -`MagicValidator::stop` cancels the validator token, then calls `scheduled_commits_processor.stop()` before `committor_service.stop()`. Preserve this ordering: the result processor must be told to stop while the committor is still available enough to shut down cleanly, and the committor is intentionally stopped last among these services. - -## Important internals and caveats - -### Magic Program global scheduler state - -`magicblock_program::TransactionScheduler::default()` is used as a handle to global scheduled action state. The `AcceptScheduleCommits` instruction writes into that state, and `ScheduledCommitsProcessorImpl::process` drains it. During ledger replay, `magicblock-api` clears this state to avoid re-committing accepted intents replayed from the ledger. - -Do not replace this with an ordinary per-instance queue unless the Magic Program and replay semantics are updated together. - -### Metadata map and locking - -`intents_meta_map` is protected by a standard `Mutex`. Current critical sections are intentionally small: insert metadata and remove metadata by intent ID. Avoid holding this lock across `.await`, committor calls, Chainlink calls, scheduler execution, or expensive logging/formatting. - -### Owner-program undelegation requests - -`magicblock-api` starts `ScheduledCommitsProcessorImpl::spawn_undelegation_request_processor` for non-replica validators. That method starts Chainlink's live observed Delegation Program `UndelegationRequest` subscription consumer and, unless disabled, a background polling backfill loop controlled by `chainlink.undelegation-request-poll-interval` (default `5m`). Both paths feed `ObservedUndelegationRequest` into the same retrying processor, which validates the request PDA, verifies the delegated account is still delegated on base and ER, starts Chainlink undelegation tracking, and submits validator-signed `ScheduleCommitAndUndelegate` through the internal transaction scheduler. - -The request account carries the delegated account and expiry slot only, so validator logic must verify the request PDA against the delegated account and must not depend on request-local owner, rent payer, or commit nonce fields. The backfill loop is intentionally stateless: every scanned request goes through the same base-and-ER delegation check before scheduling, and successful scheduling relies on the committor service retry path to finish settlement and close the request on base. Current DLP finalize instructions do not undelegate; the committor finalizes state and then sends standalone DLP `Undelegate`. When `DelegationMetadata.undelegation_requester = OwnerProgram`, the committor includes the derived request PDA in `Undelegate`; DLP validates it and uses the delegation metadata rent payer to close both delegation and request accounts. - -### Undelegation notifications are best-effort - -Before scheduling an intent bundle, the processor calls `chainlink.undelegation_requested` for accounts from commit-and-undelegate intents. Errors are aggregated and logged but do not fail scheduling. This favors settlement progress over local watcher correctness; if you change it, document how accounts that are already locally immutable/undelegating recover from missed base-layer subscriptions. - -### Historical README/API drift - -The README describes `AccountsManager`, `ExternalAccountsManager`, `BankAccountProvider`, `RemoteAccountCloner`, `Transwise`, and `ensure_accounts`. These are not present in the current crate source. Do not implement new features against those names without first checking current Chainlink/cloner/API ownership and updating/removing stale docs. - -### Local `LifecycleMode` drift - -`magicblock-accounts/src/config.rs` defines a `LifecycleMode` separate from `magicblock-config::config::LifecycleMode`. Current repository usages of validator lifecycle mode use `magicblock-config`, not this local type. Avoid adding new configuration wiring through the local enum unless that duplication is intentional and documented. - -## Important invariants - -1. `process()` must drain only accepted scheduled intent bundles from Magic Program global scheduler state; it must not re-read `MagicContext` directly. -2. `AcceptScheduleCommits` must be executed before `process()` so MagicContext intents are moved and cleared atomically by the Magic Program. -3. Intent metadata must be inserted before committor scheduling so result processing can build a correct `SentCommit`. -4. Intent metadata must be removed on result handling and on failed recovered scheduling; stale entries can make later duplicate IDs or results misleading. -5. Recovery must run only after ledger replay and local account-bank reset, because delegation checks depend on current local account state. -6. Recovered bundles must be filtered so all committed accounts are delegated on base and ER before scheduling. -7. Recovered bundles must use the committor recovered scheduling path, not the normal persistence path, to avoid duplicating persisted rows. -8. Commit-and-undelegate intents must notify Chainlink before scheduling whenever possible so base-layer undelegation completion can be tracked. -9. The result processor must not block indefinitely on slow local scheduler work without observing cancellation between results. -10. Broadcast lag from committor results is unexpected and requires investigation; silently dropping lagged results would leave local sent-commit state incomplete. -11. `SentCommit` fields must stay aligned with Magic Program `ScheduledCommitSent` expectations, including chain signatures, patched errors, callback reports, included pubkeys, payer, slot, blockhash, and undelegation flag. -12. Documentation and code must not describe this crate as the active account ensure/cloning owner unless that behavior is restored in source. - -## Common change areas and what to inspect - -### Changing scheduled commit acceptance or slot ticker behavior - -Inspect first: - -- `magicblock-api/src/tickers.rs` (`init_slot_ticker`, `handle_scheduled_commits`); -- `programs/magicblock/src/magic_context.rs` (`has_scheduled_commits`, `take_scheduled_commits`); -- `programs/magicblock/src/schedule_transactions/process_accept_scheduled_commits.rs`; -- `magicblock-accounts/src/scheduled_commits_processor.rs::process`. - -Risks: - -- accepting without processing can leave intents stranded in global scheduler state; -- processing without accepting misses MagicContext-staged intents; -- replay can re-populate global scheduled actions unless startup clear semantics are preserved. - -### Changing committor scheduling or result handling - -Inspect first: - -- `ScheduledCommitsProcessorImpl::process_intent_bundles`; -- `prepare_intent_bundles_for_scheduling`; -- `result_processor`, `process_intent_result`, and `build_sent_commit`; -- `magicblock-committor-service/src/service.rs` `BaseIntentCommittor` methods; -- `magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs` result fields. - -Risks: - -- missing result subscriptions can prevent local `ScheduledCommitSent` signaling; -- new `ExecutionOutput` variants must be converted into `SentCommit.chain_signatures` deliberately; -- callback or patched-error fields are user/operator-visible through Magic Program result state. - -### Changing undelegation lifecycle behavior - -Inspect first: - -- `prepare_intent_bundles_for_scheduling` and `process_undelegation_requests`; -- `magicblock-api/src/magic_validator.rs` startup wiring, especially whether the observed `UndelegationRequest` processor is spawned; -- `ScheduledIntentBundle::get_undelegate_intent_pubkeys` / `has_undelegate_intent`; -- `magicblock-chainlink::undelegation_requested`; -- Magic Program code that marks accounts undelegating/immutable when scheduling commit-and-undelegate. - -Risks: - -- missing Chainlink notification can leave local state out of sync with base-layer undelegation; -- failing the whole commit on notification errors may affect settlement availability; -- ordinary ER execution must not continue mutating accounts after commit-and-undelegate has been scheduled. - -### Changing pending intent recovery - -Inspect first: - -- `spawn_pending_intents_recovery`, `recover_pending_intents`, `recoverable_intent_bundles`, and `process_recovered_intent_bundles`; -- `magicblock-api/src/magic_validator.rs` startup ordering around replay/reset; -- `magicblock-committor-service/src/committor_processor.rs::pending_intent_bundles`; -- Chainlink `accounts_delegated_on_base_and_er` behavior. - -Risks: - -- running recovery before local bank repair can schedule invalid or stale commits; -- skipping delegation checks can re-send intents for accounts no longer delegated to this ER; -- normal scheduling can duplicate persistence rows for recovered work. - -### Cleaning up stale account-manager remnants - -Inspect first: - -- `magicblock-accounts/README.md`; -- `src/config.rs` and `src/errors.rs` for unused historical APIs; -- `.agents/context/crate-map.md` and this guide; -- current owners in `magicblock-chainlink`, `magicblock-account-cloner`, and `magicblock-api`. - -Risks: - -- deleting exported symbols can be a public API break even if no current workspace consumer uses them; -- account availability behavior belongs outside this crate in the current architecture. - -## Tests and validation - -- Markdown-only guide changes: run `git diff --check` for this file; no Rust checks are needed. -- Rust changes in this crate: use `.agents/rules/testing-and-validation.md` or `mbv-check`; include focused package checks for `magicblock-accounts`. -- Related package checks by change area: `magicblock-api`, `magicblock-program`, and `magicblock-committor-service` for scheduled commits, pending recovery, or undelegation behavior. -- Relevant integration suites: `test-schedule-intents`, `test-committor`, and `test-task-scheduler`; use `.agents/rules/testing-and-validation.md` for exact setup/test commands. -- Performance validation intent: changes to slot-ticker commit processing, intent metadata handling, Chainlink undelegation notification, or result handling should report whether they add work to periodic slot processing, committor scheduling, or transaction-scheduler submission. - -## Adjacent implementation references - -- `.agents/context/crates/magicblock-account-cloner.md` — current account-cloner guide; useful because this crate aliases the production cloner stack through Chainlink. -- `.agents/context/crates/magicblock-chainlink.md` — Chainlink lifecycle/delegation guide, especially `undelegation_requested` and delegation checks. -- `magicblock-accounts/README.md` — historical summary; verify against source before using. -- `magicblock-api/src/tickers.rs` — slot ticker that invokes this crate. -- `magicblock-api/src/magic_validator.rs` — startup/shutdown and recovery wiring. -- `programs/magicblock/src/schedule_transactions/` — Magic Program scheduling and acceptance processors. -- `magicblock-committor-service/` — base-layer intent execution, persistence, and recovery source. -- `test-integration/test-schedule-intent/` and `test-integration/schedulecommit/` — integration coverage for schedule intent, commit, and commit-and-undelegate behavior. +# Removed `magicblock-accounts` + +`magicblock-accounts` has been removed from the workspace. + +This crate used to contain account-manager and scheduled-commit glue, but that +ownership is obsolete: + +- local account storage is owned by `magicblock-accounts-db`; +- account synchronization and base-layer account observation are owned by + `magicblock-chainlink` and `magicblock-account-cloner`; +- DLP `UndelegationRequest` processing is owned by + `magicblock-services::undelegation_request_service`; +- scheduled intent acceptance and base-layer execution are owned by + `magicblock-committor-service`. + +Do not add new code or dependencies to `magicblock-accounts`. If future work +appears to need this crate, first choose the current owner above and update this +note only if the crate is intentionally reintroduced. + +For routing: + +- DLP request subscription/polling/scheduling: see + `.agents/context/crates/magicblock-services.md`; +- account cloning and delegation state: see + `.agents/context/crates/magicblock-chainlink.md` and + `.agents/context/crates/magicblock-account-cloner.md`; +- commit/undelegate execution and recovery: see + `.agents/context/crates/magicblock-committor-service.md`. diff --git a/.agents/context/crates/magicblock-api.md b/.agents/context/crates/magicblock-api.md index bd21450f0..84d3e2440 100644 --- a/.agents/context/crates/magicblock-api.md +++ b/.agents/context/crates/magicblock-api.md @@ -9,7 +9,7 @@ High-level responsibilities: - initialize persistent ledger and AccountsDb state; - sync and verify the validator keypair stored beside the ledger; - build genesis/sys accounts required by the local runtime; -- create Chainlink/account-cloning, committor, scheduled-commit, replication, metrics, task-scheduler, and Aperture RPC services; +- create Chainlink/account-cloning, committor, DLP undelegation request, replication, metrics, task-scheduler, and Aperture RPC services; - spawn transaction execution, RPC runtime, slot/system tickers, ledger truncation, and optional replication service threads/tasks; - transition the scheduler out of `StartingUp` after replay/reset/recovery; - register/unregister the validator in the Magic Domain Program and manage validator fee-vault setup in standalone ephemeral mode; @@ -24,7 +24,7 @@ Update this document in the same change whenever `magicblock-api` behavior or co - `MagicValidator::try_from_config`, `start`, `stop`, `prepare_ledger_for_shutdown`, or validator registration/unregistration behavior; - startup/shutdown ordering, service ownership, cancellation semantics, or thread/runtime spawning; - ledger, AccountsDb, keypair, genesis, MagicContext, ephemeral vault, or native mint initialization; -- Chainlink, committor, scheduled commit recovery, replication, task scheduler, RPC/Aperture, metrics, or ledger truncator wiring; +- Chainlink, committor, DLP undelegation request processing, replication, task scheduler, RPC/Aperture, metrics, or ledger truncator wiring; - scheduler mode transitions for standalone, primary, or replica roles; - MagicSys/commit nonce lookup behavior; - domain registry, fee vault, claim-fees, or other base-layer operator flows; @@ -56,7 +56,7 @@ Main consumers: - `test-integration/test-magicblock-api` directly uses `DomainRegistryManager` and exercises runtime behavior through integration contexts. - Other crates are mostly downstream services wired by this crate rather than consumers of it. -Important downstream dependencies include `magicblock-accounts-db`, `magicblock-ledger`, `magicblock-processor`, `magicblock-aperture`, `magicblock-chainlink`, `magicblock-account-cloner`, `magicblock-accounts`, `magicblock-committor-service`, `magicblock-replicator`, `magicblock-task-scheduler`, `magicblock-metrics`, `magicblock-services`, `magicblock-program`, and `magicblock-validator-admin`. +Important downstream dependencies include `magicblock-accounts-db`, `magicblock-ledger`, `magicblock-processor`, `magicblock-aperture`, `magicblock-chainlink`, `magicblock-account-cloner`, `magicblock-committor-service`, `magicblock-replicator`, `magicblock-task-scheduler`, `magicblock-metrics`, `magicblock-services`, `magicblock-program`, and `magicblock-validator-admin`. ## Public API shape / Main public types and APIs @@ -82,7 +82,7 @@ The exported public API is intentionally small for production use: Private but important internal APIs: - `MagicSysAdapter` implements `magicblock_core::traits::MagicSys` so Magic Program execution can synchronously ask the committor service for current commit nonces. -- `init_slot_ticker` periodically accepts scheduled commits through the transaction scheduler and then asks `ScheduledCommitsProcessor` to process them. +- `init_intent_execution_service` wires the committor service to periodically accept scheduled intents from ER state and process results back through local validator transactions. - `init_system_metrics_ticker` periodically updates storage/account gauges. ## Runtime flows @@ -97,7 +97,7 @@ ValidatorParams -> chainlink/account cloner -> replication service (optional) -> metrics + system metrics ticker - -> scheduled commit processor + -> intent execution service + undelegation request service -> program loading + validator authority init -> transaction scheduler/execution thread -> Aperture RPC runtime thread @@ -116,7 +116,7 @@ Current order matters: 8. Create replication service if a broker was configured. 9. Insert missing genesis accounts, initialize validator identity, MagicContext, and ephemeral vault accounts. 10. Start metrics service and system metrics ticker. -11. Create the scheduled-commit processor if a committor service exists. +11. Create the DLP undelegation request service for non-replica validators. 12. Load configured upgradeable programs and initialize Magic Program validator authority/override. 13. Build the SVM environment, transaction scheduler state, and executor count; spawn the transaction execution thread. 14. Build Aperture shared state and start the RPC server on its own Tokio runtime thread. @@ -137,27 +137,27 @@ Caveats: 5. Standalone/primary nodes reset the bank and, for primaries, send a replication `Message::Reset`. 6. Pending commit intent recovery runs only after replay and reset. 7. Standalone nodes switch the scheduler to `SchedulerMode::Primary`; primary/replica modes spawn the replication service instead. -8. Non-replica validators start the owner-program undelegation request observer/backfill through `ScheduledCommitsProcessorImpl::spawn_undelegation_request_processor`; replicas keep Chainlink disabled and do not scan DLP requests. +8. Non-replica validators start DLP undelegation request subscription/backfill through `UndelegationRequestService::start`; replicas keep Chainlink disabled and do not scan DLP requests. 9. Standalone ephemeral nodes start background base-layer setup: funding check, magic fee vault init/delegation, optional startup fee claim, and optional domain registration. 10. Claim-fees periodic task, slot ticker, ledger truncator, and primary-only task scheduler are started. -### Scheduled commit tick flow +### Scheduled intent execution flow ```text -slot ticker sleep +intent execution service sleep -> read MagicContext from AccountsDb -> if scheduled commits exist, execute AcceptScheduleCommits tx through scheduler - -> ScheduledCommitsProcessor::process() -> committor service schedules base-layer work + -> result processor submits ScheduledCommitSent locally ``` -The ticker uses the same transaction scheduler path as normal execution for the validator-signed accept transaction. It currently has a known TODO about possible delay between accept and processing; do not hide or worsen that behavior without an explicit fix. +The service uses the same transaction scheduler path as normal execution for validator-signed local transactions such as `AcceptScheduleCommits` and `ScheduledCommitSent`. Keep this work outside RPC request handling and transaction-execution hot loops. ### Shutdown flow: `MagicValidator::stop` 1. Send unregister transaction in the background when standalone ephemeral on-chain coordination is enabled. 2. Set the local `exit` flag and cancel the shared cancellation token. -3. Stop scheduled commit processor, then committor service. The code comment says the committor service should be stopped last, but the current implementation stops it early after scheduled-commit processing; treat this ordering as compatibility-sensitive and inspect in-flight intent behavior before changing it. +3. Stop the DLP undelegation request service, then the intent execution service. Treat this ordering as compatibility-sensitive and inspect in-flight intent behavior before changing it. 4. Stop claim-fees task. 5. Join RPC thread, slot ticker, ledger truncator, replication thread, and transaction execution thread. 6. Flush AccountsDb. @@ -209,7 +209,7 @@ The ledger stores a validator keypair file beside the blockstore parent. With `v 5. Ephemeral vault initialization must preserve the ephemeral flag and Magic Program owner. 6. Validator identity must remain privileged in local AccountsDb. 7. Committor service wiring must stay available before Magic Program execution can fetch commit nonces or schedule settlement work. -8. Owner-program DLP undelegation request polling must stay in the background processor path, not the slot ticker or transaction-execution hot path. +8. DLP undelegation request polling must stay in the background service path, not the slot ticker or transaction-execution hot path. 9. Do not add blocking RPC, slow I/O, or expensive serialization to scheduler/executor hot paths from this crate; keep such work in startup/background services where possible. 10. Shutdown must cancel/stop services before flushing AccountsDb and ledger. 11. Operator-facing config keys and base-layer registration/fee-vault behavior are compatibility-sensitive. @@ -300,7 +300,7 @@ Risks: ## Adjacent implementation references - `.agents/context/crates/magicblock-aperture.md` — RPC/pubsub service details wired by this crate. -- `.agents/context/crates/magicblock-account-cloner.md`, `.agents/context/crates/magicblock-accounts.md`, and `.agents/context/crates/magicblock-chainlink.md` — account sync and scheduled-commit dependencies wired by this crate. +- `.agents/context/crates/magicblock-account-cloner.md`, `.agents/context/crates/magicblock-chainlink.md`, `.agents/context/crates/magicblock-services.md`, and `.agents/context/crates/magicblock-committor-service.md` — account sync, DLP request, and scheduled-intent dependencies wired by this crate. - `magicblock-api/README.md` — short usage example for `MagicValidator`. - `magicblock-validator/src/main.rs` — production binary lifecycle around `MagicValidator`. - `test-integration/test-magicblock-api/` — integration tests for API-owned flows. diff --git a/.agents/context/crates/magicblock-chainlink.md b/.agents/context/crates/magicblock-chainlink.md index 3595c482d..2c0baedec 100644 --- a/.agents/context/crates/magicblock-chainlink.md +++ b/.agents/context/crates/magicblock-chainlink.md @@ -28,7 +28,7 @@ Whenever behavior in `magicblock-chainlink` changes, or another crate changes Ch - ATA/eATA projection, - post-delegation action dependency handling, - lifecycle-mode behavior, -- public APIs used by `magicblock-api`, `magicblock-aperture`, `magicblock-accounts`, `magicblock-account-cloner`, or `programs/magicblock`, +- public APIs used by `magicblock-api`, `magicblock-aperture`, `magicblock-services`, `magicblock-account-cloner`, or `programs/magicblock`, - tests or validation commands relevant to this crate, - performance characteristics of fetch/clone, deduplication, subscription, LRU/eviction, or update-ordering paths. @@ -54,7 +54,7 @@ Main consumers: - `magicblock-api` constructs the production Chainlink stack during validator startup. - `magicblock-aperture` uses Chainlink for RPC read misses and transaction submission account availability. -- `magicblock-accounts` uses Chainlink/account cloning glue for account-manager flows and scheduled commit integration. +- `magicblock-services` consumes Chainlink DLP request subscription/scan APIs for undelegation request processing. - `magicblock-account-cloner` implements the `Cloner` trait and submits clone/program/evict transactions into the local validator. - `programs/magicblock` uses `dev-context` Chainlink helpers in tests and validator-only program flows. @@ -76,7 +76,7 @@ Important methods: - `fetch_accounts(pubkeys, fetch_origin)`: ensures accounts and then reads them from the local bank. - `accounts_delegated_on_base_and_er(pubkeys, fetch_origin)`: checks that each account is DLP-owned on base and represented as delegated/DLP-owned locally. - `undelegation_requested(pubkey)`: called by committor/account flows before an account is undelegated so Chainlink keeps watching for base-layer completion. -- `fetch_undelegation_requests()`: scans base-layer Delegation Program accounts for active `UndelegationRequest` PDAs using filtered `getProgramAccounts` and returns decoded `ObservedUndelegationRequest`s for `magicblock-accounts`. +- `fetch_undelegation_requests()`: scans base-layer Delegation Program accounts for active `UndelegationRequest` PDAs using filtered `getProgramAccounts` and returns decoded `ObservedUndelegationRequest`s for `magicblock-services`. - `fetch_count()` / `is_watching()`: mainly observability/testing helpers. Disabled replication mode is intentionally conservative: @@ -282,7 +282,7 @@ Owner-program undelegation requests are discovered in two ways: - Live updates: DLP-owned `UndelegationRequest` account subscription/program-subscription updates are decoded in `FetchCloner::process_subscription_update` and broadcast as `ObservedUndelegationRequest`. - Backfill scans: `FetchCloner::fetch_undelegation_requests` calls `getProgramAccounts` for `dlp_api::id()` with a `DataSize(UndelegationRequest::size_with_discriminator())` filter and a discriminator `memcmp` at offset `0`, then decodes each returned account with `UndelegationRequest::try_from_bytes_with_discriminator`. -The scan uses Base64Zstd account encoding and gets a nearby base-chain slot for `observed_slot`. Malformed matching accounts are logged and skipped; a bad account must not abort the whole scan. Polling cadence is controlled by `chainlink.undelegation-request-poll-interval` in `magicblock-config` and consumed by `magicblock-accounts`. +The scan uses Base64Zstd account encoding and gets a nearby base-chain slot for `observed_slot`. Malformed matching accounts are logged and skipped; a bad account must not abort the whole scan. Polling cadence is controlled by `chainlink.undelegation-request-poll-interval` in `magicblock-config` and consumed by `magicblock-services`. ### Greedy discovery @@ -378,7 +378,7 @@ Changing SubMux behavior can affect ordering, duplicate clone submissions, and p ## Lifecycle mode and configuration -`ChainlinkConfig` wraps `RemoteAccountProviderConfig` and includes settings such as `remove_confined_accounts`, allowed program filters, resubscription delay, Range risk checks, and `undelegation_request_poll_interval` for the DLP request backfill consumer in `magicblock-accounts`. +`ChainlinkConfig` wraps `RemoteAccountProviderConfig` and includes settings such as `remove_confined_accounts`, allowed program filters, resubscription delay, Range risk checks, and `undelegation_request_poll_interval` for the DLP request backfill consumer in `magicblock-services`. `RemoteAccountProviderConfig` includes: @@ -494,7 +494,7 @@ Start with: ## Adjacent implementation references - `.agents/context/crates/magicblock-account-cloner.md` — clone request materialization boundary implemented by the production cloner. -- `.agents/context/crates/magicblock-accounts.md` — scheduled commit integration and undelegation notification consumer. +- `.agents/context/crates/magicblock-services.md` — DLP undelegation request consumer. - `.agents/context/crates/magicblock-aperture.md` — RPC read and transaction submission account-ensure caller. - `.agents/context/crates/magicblock-aml.md` — signer risk-check integration for post-delegation actions. - `magicblock-chainlink/src/cloner/mod.rs` — `Cloner`, `AccountCloneRequest`, and `DelegationActions` boundary. diff --git a/.agents/context/crates/magicblock-committor-program.md b/.agents/context/crates/magicblock-committor-program.md index 8efedccf3..5295f2e20 100644 --- a/.agents/context/crates/magicblock-committor-program.md +++ b/.agents/context/crates/magicblock-committor-program.md @@ -54,7 +54,7 @@ For the general documentation-update rule, see .agents/memory/agent-memory-and-d Main consumers: - `magicblock-committor-service`, which re-exports `ChangedAccount`, `Changeset`, and `ChangesetMeta`, builds buffer tasks, and sends committor-program instructions; -- `magicblock-accounts`, which uses `ChangesetMeta` in scheduled-commit error paths; +- `magicblock-committor-service`, which uses changeset metadata in scheduled-commit persistence and error paths; - integration tests under `test-integration/test-committor-service` and config tests that allow/deny the committor program id; - the workspace root, which depends on this crate with `features = ["no-entrypoint"]` for client-side/library use. @@ -214,7 +214,7 @@ Inspect `src/pdas.rs`, the `verified_seeds_and_pda!` macro, all instruction buil ### Changing commit/change-set metadata -Inspect `src/state/changeset.rs`, `magicblock-committor-service/src/tasks/task_builder.rs`, `magicblock-accounts/src/errors.rs`, and any recovery/persistence code that stores commit metadata. Preserve owner, slot, undelegation, and bundle semantics. +Inspect `src/state/changeset.rs`, `magicblock-committor-service/src/tasks/task_builder.rs`, and recovery/persistence code that stores commit metadata. Preserve owner, slot, undelegation, and bundle semantics. ### Changing cleanup behavior diff --git a/.agents/context/crates/magicblock-committor-service.md b/.agents/context/crates/magicblock-committor-service.md index 70b4e7737..f874555fa 100644 --- a/.agents/context/crates/magicblock-committor-service.md +++ b/.agents/context/crates/magicblock-committor-service.md @@ -6,7 +6,8 @@ High-level responsibilities: -- expose `CommittorService` / `BaseIntentCommittor` as the async service boundary used by `magicblock-api`, `magicblock-accounts`, and account cloning; +- expose `CommittorService` / `BaseIntentCommittor` as the async service boundary used by `magicblock-api` and account cloning; +- expose `IntentExecutionService` as the validator-side worker that accepts ER scheduled intents and submits them into the committor processor; - schedule intent bundles without executing mutually conflicting committed accounts in parallel; - fetch Delegation Program metadata, including commit nonces and rent payer data, plus base accounts needed for task construction; - choose commit delivery strategies: state args, diff args, state buffers, diff buffers, and optional ALTs; @@ -55,7 +56,7 @@ For the general documentation-update rule, see .agents/memory/agent-memory-and-d | `src/persist/` | SQLite persistence for commit rows, bundle signatures, status/strategy enums, and conversion utilities. | | `src/stubs/` | Feature-gated dev/test stub committor behind `dev-context-only-utils`. | | `magicblock-api/src/magic_validator.rs` | Starts the service at validator initialization with `committor_service.sqlite`, validator keypair, RPC URL, websocket URL, compute-unit price, and action callback scheduler. | -| `magicblock-accounts/src/scheduled_commits_processor.rs` | Main runtime producer/consumer: takes scheduled intent bundles from the transaction scheduler, schedules them with the committor, consumes result broadcasts, and performs pending-intent recovery after ledger replay. | +| `src/service/intent_client.rs` | ER intent client used by `IntentExecutionService`: accepts scheduled intents from MagicContext through local validator transactions and reports `ScheduledCommitSent` results. | | `magicblock-account-cloner/src/account_cloner.rs` | Uses `BaseIntentCommittor` for lookup-table reservation around account cloning and diagnostic mapping of committor errors. | | `magicblock-api/src/magic_sys_adapter.rs` | Fetches current commit nonces through the committor service for Magic syscalls. | | `test-integration/test-committor-service/` | Integration coverage for delivery preparators, transaction preparators, intent executor flows, and local commit execution. | @@ -136,14 +137,14 @@ magicblock-api::MagicValidator::init_committor_service -> actor run loop spawned on Tokio ``` -The service is initialized before the account manager starts pending-intent recovery. Pending recovery must run after ledger replay so local accounts reflect delegated state before recovered intents are checked. +The service is initialized before `IntentExecutionService` starts pending-intent recovery. Pending recovery must run after ledger replay so local accounts reflect delegated state before recovered intents are checked. ### Fresh scheduled intent flow ```text Magic Program schedules intent in ER -> transaction scheduler exposes ScheduledIntentBundle(s) - -> magicblock-accounts::ScheduledCommitsProcessor::process + -> IntentExecutionService accepts scheduled intents -> CommittorService::schedule_intent_bundles -> CommittorProcessor::schedule_intent_bundle -> IntentPersisterImpl::start_base_intents @@ -152,19 +153,19 @@ Magic Program schedules intent in ER -> IntentScheduler blocks conflicts by committed pubkeys -> IntentExecutorImpl executes selected intent -> broadcast result - -> ScheduledCommitsProcessor consumes result and updates local/metadata state + -> IntentExecutionService consumes result and updates local/metadata state ``` `CommittorProcessor::schedule_intent_bundle` logs persistence failures but still tries to execute. This is intentionally loud because losing persistence weakens restart recovery; do not hide or downgrade that error path. ### Recovery flow for pending intents -1. `magicblock-accounts` calls `get_pending_intent_bundles()` after replay. +1. `IntentExecutionService` calls `get_pending_intent_bundles()` after replay. 2. `CommittorProcessor::pending_intent_bundles` loads SQLite rows with `CommitStatus::Pending` and `created_at` inside the 14-day recovery window. 3. It fetches the current base-layer slot and reconstructs `ScheduledIntentBundle`s grouped by `message_id`. 4. Rows for a message must agree on ER slot and ER blockhash; otherwise that message is skipped. 5. Data-account rows without stored data are skipped because they cannot reconstruct a `CommittedAccount` safely. -6. `magicblock-accounts` filters recovered bundles against current delegated state, then calls `schedule_recovered_intent_bundles` so rows are not inserted again. +6. `IntentExecutionService` filters recovered bundles against current delegated state, then calls `schedule_recovered_intent_bundles` so rows are not inserted again. Preserve the no-repersist path for recovered intents. Re-inserting rows can violate primary keys or duplicate status history. @@ -272,7 +273,7 @@ The public service API uses nonblocking `try_send`. If the service channel is fu ### Changing service API, startup, or shutdown -Start with `src/service.rs`, `src/committor_processor.rs`, and `magicblock-api/src/magic_validator.rs`. Then inspect `magicblock-accounts/src/scheduled_commits_processor.rs`, `magicblock-account-cloner/src/account_cloner.rs`, and `magicblock-api/src/magic_sys_adapter.rs`. Check oneshot behavior, channel capacity/backpressure, cancellation, and whether consumers need errors instead of logged-only failures. +Start with `src/service.rs`, `src/service/intent_client.rs`, `src/committor_processor.rs`, and `magicblock-api/src/magic_validator.rs`. Then inspect `magicblock-account-cloner/src/account_cloner.rs` and `magicblock-api/src/magic_sys_adapter.rs`. Check oneshot behavior, channel capacity/backpressure, cancellation, and whether consumers need errors instead of logged-only failures. ### Changing scheduling or concurrency @@ -292,7 +293,7 @@ Start with `src/transaction_preparator/mod.rs` and `delivery_preparator.rs`, the ### Changing persistence or recovery -Start with `src/persist/db.rs`, `src/persist/commit_persister.rs`, `src/persist/types/`, and `src/committor_processor.rs` recovery helpers. Then inspect `magicblock-accounts/src/scheduled_commits_processor.rs`. Preserve schema compatibility, enum string values, `u64`/`i64` conversions, row grouping by `message_id`, 14-day recovery window, and no-repersist recovery scheduling. +Start with `src/persist/db.rs`, `src/persist/commit_persister.rs`, `src/persist/types/`, `src/committor_processor.rs` recovery helpers, and `src/service.rs`. Preserve schema compatibility, enum string values, `u64`/`i64` conversions, row grouping by `message_id`, 14-day recovery window, and no-repersist recovery scheduling. ### Changing metrics or observability @@ -312,6 +313,6 @@ Start with metric calls in `intent_execution_engine.rs`, `delivery_preparator.rs - `.agents/context/crates/magicblock-committor-program.md` — buffer/chunks on-chain helper contracts. - `.agents/context/crates/magicblock-rpc-client.md` — base-layer send/confirm and RPC helper behavior. - `.agents/context/crates/magicblock-table-mania.md` — ALT lifecycle and finalized-read semantics. -- `.agents/context/crates/magicblock-accounts.md` — scheduled commit processing and pending-intent recovery call sites. +- `.agents/context/crates/magicblock-services.md` — DLP request ingestion that creates local schedule-commit-and-undelegate transactions. - `magicblock-committor-service/README.md` — high-level implementation notes. - `test-integration/test-committor-service/` — integration coverage of delivery and intent execution. diff --git a/.agents/context/crates/magicblock-config.md b/.agents/context/crates/magicblock-config.md index 3d59405c3..0d9b7e4d1 100644 --- a/.agents/context/crates/magicblock-config.md +++ b/.agents/context/crates/magicblock-config.md @@ -278,7 +278,7 @@ Inspect first: - `magicblock-config/src/config/chain.rs` and `grpc.rs`; - `magicblock-api/src/magic_validator.rs::init_chainlink`; - `magicblock-chainlink/src/remote_account_provider/`; -- `magicblock-accounts/src/scheduled_commits_processor.rs` for DLP undelegation-request polling; +- `magicblock-services/src/undelegation_request_service.rs` for DLP undelegation-request polling; - `magicblock-aml` Range risk usage; - allowed-program filtering tests in Chainlink. diff --git a/.agents/context/crates/magicblock-core.md b/.agents/context/crates/magicblock-core.md index 06f23deae..e6dba1f12 100644 --- a/.agents/context/crates/magicblock-core.md +++ b/.agents/context/crates/magicblock-core.md @@ -55,7 +55,7 @@ Main consumers include: - `magicblock-processor`, which consumes `ValidatorChannelEndpoints`, executes `SchedulerCommand`s, drains `ExecutionTlsStash`, and emits account/status/replication messages; - `magicblock-replicator`, which consumes and publishes `link::replication::Message` and uses `wait_for_idle()` during checksum/reset operations; - `magicblock-ledger`, which replays persisted transactions through `TransactionSchedulerHandle::replay`; -- `magicblock-accounts`, `magicblock-account-cloner`, and `magicblock-task-scheduler`, which submit validator-internal transactions or consume scheduled tasks; +- `magicblock-services`, `magicblock-account-cloner`, and `magicblock-task-scheduler`, which submit validator-internal transactions or consume scheduled tasks; - `programs/magicblock`, which uses `MagicSys`, `CommittedAccount`, `BaseActionCallback`, coordination mode, and `ExecutionTlsStash`; - `magicblock-committor-service`, which consumes committed-account/action types and callback scheduling traits; - `magicblock-chainlink`, which uses token/eATA helpers and consolidated logging helpers. @@ -346,7 +346,8 @@ Start with: - `magicblock-core/src/traits.rs` - `programs/magicblock/src/magic_sys.rs` - `programs/magicblock/src/magic_scheduled_base_intent.rs` -- `magicblock-accounts/src/scheduled_commits_processor.rs` +- `magicblock-services/src/undelegation_request_service.rs` +- `magicblock-committor-service/src/service/intent_client.rs` - `magicblock-committor-service/src/` Check serialization, persistence, commit nonce behavior, callback error mapping, and base-layer settlement compatibility. @@ -389,6 +390,7 @@ Avoid adding high-cardinality or noisy logs to hot loops. Keep test logging idem - `.agents/context/crates/magicblock-api.md` — service wiring consumer of core endpoints. - `.agents/context/crates/magicblock-aperture.md` — RPC/account/status event consumer. - `.agents/context/crates/magicblock-account-cloner.md` — internal transaction submission consumer. -- `.agents/context/crates/magicblock-accounts.md` — scheduled commit consumer of core payloads. +- `.agents/context/crates/magicblock-services.md` — DLP request service consumer of internal transaction scheduling. +- `.agents/context/crates/magicblock-committor-service.md` — scheduled intent consumer of core payloads. - `.agents/context/crates/magicblock-chainlink.md` — token/eATA helper and logging consumer. - `.agents/context/crates/magicblock-config.md` — config types that drive startup mode and service wiring. diff --git a/.agents/context/crates/magicblock-magic-program-api.md b/.agents/context/crates/magicblock-magic-program-api.md index cc4c7bd82..cf50403f2 100644 --- a/.agents/context/crates/magicblock-magic-program-api.md +++ b/.agents/context/crates/magicblock-magic-program-api.md @@ -17,7 +17,7 @@ High-level responsibilities: - define callback response types (`MagicResponse`, `MagicResponseV1`, `ActionReceipt`) delivered to base-layer callback programs; - provide a `compat` boundary so public API users can opt into Solana 2.x-compatible types through the `backward-compat` feature while the default uses workspace Solana 3.x types. -Do not put Magic Program execution logic, validation policy, persistence, RPC behavior, or committor delivery logic in this crate. Those belong in `programs/magicblock`, `magicblock-core`, `magicblock-accounts`, and the committor/service crates. +Do not put Magic Program execution logic, validation policy, persistence, RPC behavior, or committor delivery logic in this crate. Those belong in `programs/magicblock`, `magicblock-core`, and the committor/service crates. ## Update requirement diff --git a/.agents/context/crates/magicblock-metrics.md b/.agents/context/crates/magicblock-metrics.md index ed34b98fb..345c1c273 100644 --- a/.agents/context/crates/magicblock-metrics.md +++ b/.agents/context/crates/magicblock-metrics.md @@ -57,7 +57,7 @@ Main consumers: - `magicblock-processor` records slot, transaction count, failed transaction count, and maximum lock-contention queue size. - `magicblock-ledger` records ledger column counts, storage size, shutdown/compaction/truncation timers, and RPC API column-family metrics. - `magicblock-chainlink` records account fetch outcomes, chain slot, monitored/evicted accounts, pubsub/gRPC subscription state, undelegation lifecycle counts, and some investigation counters. -- `magicblock-accounts` records scheduled committor-intent count. +- `magicblock-committor-service` records scheduled committor-intent count. - `magicblock-committor-service` records intent backlog, failed intents, busy executors, execution times, CU usage, task/ALT preparation timing, task-info fetcher state, and commit nonce wait time via `magicblock-api`. - `magicblock-rpc-client` records signature-subscribe and signature-status confirmation counters. - `magicblock-table-mania` records lookup-table fetch/close investigation counters. diff --git a/.agents/context/crates/magicblock-services.md b/.agents/context/crates/magicblock-services.md index 97c33d568..b7e2495b3 100644 --- a/.agents/context/crates/magicblock-services.md +++ b/.agents/context/crates/magicblock-services.md @@ -2,28 +2,31 @@ ## Purpose -`magicblock-services` contains small reusable service adapters that run alongside the validator and communicate through existing validator/RPC contracts. Its current responsibility is the action-callback adapter used by the committor pipeline to notify user callback programs about Magic Action results. +`magicblock-services` contains small reusable service adapters that run alongside the validator and communicate through existing validator/RPC contracts. It owns background adapters that bridge existing services, but not the underlying protocol execution engines. High-level responsibilities: - implement `magicblock_core::traits::ActionsCallbackScheduler` for validator-runtime use; - turn `BaseActionCallback` payloads from committed Magic Actions into local callback transactions; - wrap callback results in the `magicblock-magic-program-api` `MagicResponse::V1` wire shape; -- submit callback transactions asynchronously through Solana's nonblocking `RpcClient`. +- submit callback transactions asynchronously through Solana's nonblocking `RpcClient`; +- observe DLP `UndelegationRequest` accounts through Chainlink subscription and polling APIs; +- submit validator-signed local `ScheduleCommitAndUndelegate` transactions for valid requests. -This crate is settlement-adjacent and can affect Magic Action user experience. It is not the committor itself, does not own intent execution or persistence, and must stay generic enough to be used as a service adapter rather than a protocol owner. +This crate is settlement-adjacent and can affect Magic Action user experience and undelegation liveness. It is not the committor itself, does not own base-layer intent execution or persistence, and must stay generic enough to be used as a service adapter rather than a protocol owner. -End-to-end commit/undelegation semantics live in .agents/specs/validator-specification.md; this crate owns fire-and-forget local Magic Action callback transaction construction and scheduling. +End-to-end commit/undelegation semantics live in .agents/specs/validator-specification.md; this crate owns fire-and-forget local Magic Action callback transaction construction and DLP undelegation request ingestion. ## Update requirement Update this guide in the same change whenever behavior or contracts in `magicblock-services` change. In particular, update it for changes to: -- exported modules or public constructors in `magicblock-services/src/lib.rs` or `actions_callback_service.rs`; +- exported modules or public constructors in `magicblock-services/src/lib.rs`, `actions_callback_service.rs`, or `undelegation_request_service.rs`; - the `ActionsCallbackService` transaction layout, signer handling, blockhash source, or callback response encoding; - how callback signatures, errors, receipts, discriminators, payloads, or account metas are propagated; - asynchronous send behavior, logging, retry/confirmation semantics, or Tokio runtime assumptions; - call-site wiring in `magicblock-api` or committor expectations around `ActionsCallbackScheduler`; +- DLP undelegation request subscription, polling, validation, retry, or internal transaction scheduling behavior; - validation commands or integration suites relevant to action callbacks. Because callbacks are a cross-crate contract between Magic Program scheduling, committor execution, and user callback programs, also update this file when another crate changes `BaseActionCallback`, `MagicResponse`, `CallbackInstruction`, or `ActionsCallbackScheduler` semantics. @@ -34,10 +37,11 @@ For the general documentation-update rule, see .agents/memory/agent-memory-and-d | Path | Role | |---|---| -| `magicblock-services/Cargo.toml` | Package metadata and dependencies. Depends on `magicblock-core`, `magicblock-magic-program-api`, Solana transaction/RPC crates, Tokio, and tracing. | -| `magicblock-services/src/lib.rs` | Public module surface. Currently exports only `actions_callback_service`. | +| `magicblock-services/Cargo.toml` | Package metadata and dependencies. Depends on Chainlink, account-cloner aliases, core, metrics, Magic Program/API, Solana transaction/RPC crates, Tokio, and tracing. | +| `magicblock-services/src/lib.rs` | Public module surface. Exports service adapters. | | `magicblock-services/src/actions_callback_service.rs` | Implements `ActionsCallbackService` and `ActionsCallbackScheduler`. Builds and sends callback transactions. | -| `magicblock-api/src/magic_validator.rs` | Runtime wiring. `init_committor_service` creates `ActionsCallbackService` with the validator keypair, local latest-block provider, and an RPC client pointed at the validator aperture HTTP endpoint. | +| `magicblock-services/src/undelegation_request_service.rs` | Implements `UndelegationRequestService`. Consumes Chainlink-observed DLP request accounts, validates them, and schedules local `ScheduleCommitAndUndelegate` transactions. | +| `magicblock-api/src/magic_validator.rs` | Runtime wiring. Creates `ActionsCallbackService` for the committor and starts/stops `UndelegationRequestService` for non-replica validators. | | `magicblock-core/src/traits.rs` | Defines `ActionsCallbackScheduler`, `ActionResult`, `ActionError`, and `CallbackScheduleError`. | | `magicblock-core/src/intent.rs` | Defines `BaseActionCallback`, the callback payload this crate consumes. | | `magicblock-committor-service/src/intent_executor/utils.rs` | Extracts callbacks from action tasks and invokes the scheduler after success, action failure, or timeout. | @@ -45,9 +49,10 @@ For the general documentation-update rule, see .agents/memory/agent-memory-and-d Main consumers: -- `magicblock-api`, which constructs the concrete callback service for the validator; +- `magicblock-api`, which constructs the concrete services for the validator; - `magicblock-committor-service`, which is generic over `ActionsCallbackScheduler` and calls it from intent execution; -- callback-capable Magic Action flows scheduled through `programs/magicblock`. +- callback-capable Magic Action flows scheduled through `programs/magicblock`; +- Chainlink DLP request observation APIs consumed by `UndelegationRequestService`. There are no crate-local tests or README files for `magicblock-services` at the time of writing. Use the committor integration tests when callback behavior changes. @@ -57,9 +62,10 @@ There are no crate-local tests or README files for `magicblock-services` at the `src/lib.rs` exposes: -- `pub mod actions_callback_service`. +- `pub mod actions_callback_service`; +- `pub mod undelegation_request_service`. -Keep this surface small. New shared services should be added only when they are truly generic validator service adapters and not better owned by API orchestration, committor, RPC-client, or Magic Program crates. +Keep this surface small. New shared services should be added only when they are truly validator service adapters and not better owned by API orchestration, committor, RPC-client, Chainlink, or Magic Program crates. ### `ActionsCallbackService` @@ -87,6 +93,35 @@ The service implements `Clone` when `L: Clone`. Cloning uses `authority.insecure The return value reports scheduling/build success, not confirmed on-chain callback execution. The spawned task logs send failures but does not retry or update the returned result after the fact. +### `UndelegationRequestService` + +`UndelegationRequestService` stores: + +- `Arc>` for DLP request subscription, polling, delegated-state checks, and undelegation tracking; +- `TransactionSchedulerHandle` for validator-signed local `ScheduleCommitAndUndelegate` submission; +- validator authority keypair used as transaction payer/signer; +- a `LatestBlockProvider`-backed blockhash reader; +- a cancellation token and configured polling interval. + +Public constructor: + +```rust +UndelegationRequestService::new( + chainlink, + internal_transaction_scheduler, + validator_authority, + latest_block, + poll_interval, +) +``` + +Runtime methods: + +- `start()` starts the Chainlink subscription consumer and, when configured, the polling backfill loop; +- `stop()` cancels both background loops. + +The service schedules local ER transactions only. The committor service remains responsible for accepting resulting Magic Program intents and executing base-layer settlement. + ## Runtime flows ### Validator startup wiring @@ -98,6 +133,19 @@ The return value reports scheduling/build success, not confirmed on-chain callba Preserve this separation. `magicblock-services` should not reach back into validator orchestration or committor internals. +### DLP undelegation request processing + +```text +Chainlink DLP request subscription or backfill scan + -> UndelegationRequestService validates request PDA + -> verify delegated account is delegated on base and ER + -> notify Chainlink that undelegation was requested + -> submit validator-signed ScheduleCommitAndUndelegate locally + -> committor service later accepts and executes the scheduled intent +``` + +Live subscription updates are the low-latency path. Polling is a backfill path controlled by `chainlink.undelegation-request-poll-interval`; a zero duration disables polling. Processing retries transient delegated-state checks and internal scheduling failures up to the configured in-code attempt count. + ### Callback scheduling and transaction construction ```text @@ -169,6 +217,9 @@ The callback instruction data combines a program-specific discriminator with a b 6. The `Noop(counter)` uniqueness instruction must keep otherwise duplicate callback transactions from producing identical signatures. 7. Do not add blocking RPC confirmation or retry loops to the committor hot path without an explicit architecture decision and performance review. 8. Keep the crate dependency-light. Generic service adapters should not pull in validator orchestration, persistence, or large protocol owners. +9. DLP request processing must verify the request PDA against the delegated account before scheduling. +10. DLP request processing must not bypass the Magic Program or committor pipeline; it should only submit local validator-signed scheduling transactions. +11. DLP request processing must stay off RPC, scheduler/executor, and account-sync hot paths except for the intentional background Chainlink calls. ## Common change areas and what to inspect @@ -208,13 +259,25 @@ Be explicit about whether callbacks should be sent to local aperture or base-lay Start with `magicblock-services/src/lib.rs` and ask whether the new adapter belongs here. Prefer this crate only for small generic services that implement shared traits. Put orchestration in `magicblock-api`, settlement logic in `magicblock-committor-service`, RPC policy in `magicblock-rpc-client`, and protocol wire types in `magicblock-magic-program-api`. +### Changing DLP undelegation request processing + +Start with: + +- `magicblock-services/src/undelegation_request_service.rs`; +- `magicblock-chainlink` DLP request subscription and scan APIs; +- Magic Program `ScheduleCommitAndUndelegate`; +- `magicblock-committor-service` intent acceptance/execution flow. + +Check request PDA validation, base-and-ER delegated-state checks, retry behavior, cancellation, and that the service still schedules through the local transaction scheduler rather than calling committor internals directly. + ## Tests and validation - Markdown-only guide changes: run `git diff --check` for this file; no Rust checks are needed. - Rust changes in this crate: use `.agents/rules/testing-and-validation.md` or `mbv-check`; include focused package checks for `magicblock-services`. - Consumer validation intent: because this crate has no crate-local tests, include relevant `magicblock-committor-service` checks for callback behavior changes. - Relevant integration suites: committor suites that exercise action callbacks and timeouts; use `.agents/rules/testing-and-validation.md` for exact setup/test commands. -- Performance-risk validation intent: report any added synchronous RPC work, retries, confirmation, persistence, extra serialization, or unbounded spawning/logging and its effect on committor throughput and callback latency. +- DLP request validation intent: include `cargo check -p magicblock-api` when validator wiring changes, and include Chainlink/committor focused tests when request observation or scheduled intent execution behavior changes. +- Performance-risk validation intent: report any added synchronous RPC work, retries, confirmation, persistence, extra serialization, or unbounded spawning/logging and its effect on committor throughput, callback latency, or DLP request processing. ## Adjacent implementation references diff --git a/.agents/specs/validator-specification.md b/.agents/specs/validator-specification.md index aabc1abbe..d504baf44 100644 --- a/.agents/specs/validator-specification.md +++ b/.agents/specs/validator-specification.md @@ -268,7 +268,7 @@ record/metadata. Validators must still verify that the request PDA matches the delegated account before scheduling. The validator observes owner-program `UndelegationRequest` PDAs through -Chainlink and `magicblock-accounts`. Live request-account subscription updates +Chainlink and `magicblock-services`. Live request-account subscription updates are the low-latency path. A background backfill loop also scans DLP-owned accounts with a filtered `getProgramAccounts` every configured interval (`chainlink.undelegation-request-poll-interval`, default `5m`) and feeds the @@ -309,7 +309,7 @@ The committor service realizes scheduled base-layer intents. Its inputs are sche The documented commit pipeline is: 1. Magic Program schedules intents in MagicContext. -2. `magicblock-accounts` / scheduled commit processing picks up intents each slot. +2. `magicblock-committor-service::IntentExecutionService` accepts scheduled intents from ER state and schedules execution. 3. `magicblock-committor-service` schedules and executes intents. 4. Task building creates atomic base-layer tasks such as commit, undelegate, finalize, and action. 5. Task strategy packs tasks into valid transactions. diff --git a/Cargo.lock b/Cargo.lock index 9f17f4eca..2378479b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3500,32 +3500,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "magicblock-accounts" -version = "0.13.3" -dependencies = [ - "async-trait", - "magicblock-account-cloner", - "magicblock-chainlink", - "magicblock-committor-service", - "magicblock-core", - "magicblock-delegation-program-api", - "magicblock-metrics", - "magicblock-program", - "solana-hash 4.2.0", - "solana-instruction 3.3.0", - "solana-keypair", - "solana-pubkey 4.1.0", - "solana-signer", - "solana-transaction", - "solana-transaction-error 3.1.0", - "thiserror 2.0.18", - "tokio", - "tokio-util", - "tracing", - "url", -] - [[package]] name = "magicblock-accounts-db" version = "0.13.3" @@ -3627,7 +3601,6 @@ dependencies = [ "fd-lock", "magic-domain-program", "magicblock-account-cloner", - "magicblock-accounts", "magicblock-accounts-db", "magicblock-aperture", "magicblock-chainlink", @@ -4105,8 +4078,14 @@ version = "0.13.3" dependencies = [ "bincode", "futures-util", + "magicblock-account-cloner", + "magicblock-chainlink", "magicblock-core", + "magicblock-delegation-program-api", "magicblock-magic-program-api", + "magicblock-metrics", + "magicblock-program", + "solana-hash 4.2.0", "solana-instruction 3.3.0", "solana-keypair", "solana-message 3.1.0", @@ -4115,8 +4094,10 @@ dependencies = [ "solana-signature 3.3.0", "solana-signer", "solana-transaction", + "solana-transaction-error 3.1.0", "thiserror 2.0.18", "tokio", + "tokio-util", "tracing", ] diff --git a/Cargo.toml b/Cargo.toml index 822000adb..28b3af926 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ split-debuginfo = "packed" [workspace] members = [ "magicblock-account-cloner", - "magicblock-accounts", "magicblock-accounts-db", "magicblock-aml", "magicblock-aperture", @@ -102,7 +101,6 @@ log = { version = "0.4.20" } lru = "0.16.0" magic-domain-program = { git = "https://github.com/magicblock-labs/magic-domain-program.git", rev = "6cb903d", default-features = false } magicblock-account-cloner = { path = "./magicblock-account-cloner" } -magicblock-accounts = { path = "./magicblock-accounts" } magicblock-accounts-db = { path = "./magicblock-accounts-db" } magicblock-aml = { path = "./magicblock-aml" } magicblock-aperture = { path = "./magicblock-aperture" } diff --git a/docs/architecture.md b/docs/architecture.md index 0e77bbd3d..19da75341 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -25,7 +25,7 @@ flowchart TB subgraph delegation["Base-chain delegation"] chainlink[magicblock-chainlink] cloner[magicblock-account-cloner] - accounts[magicblock-accounts] + services[magicblock-services] committor[magicblock-committor-service] tablemania[magicblock-table-mania] tasksched[magicblock-task-scheduler] @@ -63,7 +63,8 @@ snapshot) → init committor service → init chainlink → genesis accounts → load programs → spawn transaction scheduler (in `StartingUp` mode) → spawn RPC thread → init task scheduler. `start()` then optionally replays the ledger, defragments accountsdb, resets stale accounts, recovers pending commit intents, and -finally flips the scheduler to `Primary`/`Replica` mode. +finally flips the scheduler to `Primary`/`Replica` mode and starts background DLP +undelegation request processing for non-replica validators. **Shutdown ordering matters** (`stop()`): cancellation tokens first, committor service stopped *last* among services (in-flight intents), then threads joined, then @@ -179,9 +180,11 @@ loader-specific paths (V1→V3 conversion, V4 buffer + deploy). in the 5 MB `MagicContext` account. A second validator-signed instruction (`AcceptScheduleCommits`) moves staged intents to a global map — a deliberate two-stage flow across slot boundaries. -2. [`magicblock-accounts`](../magicblock-accounts) - (`ScheduledCommitsProcessorImpl`) picks intents up each slot (driven by the slot - ticker) and feeds [`magicblock-committor-service`](../magicblock-committor-service). +2. [`magicblock-committor-service`](../magicblock-committor-service) + (`IntentExecutionService`) accepts scheduled intents from ER state and executes + them. [`magicblock-services`](../magicblock-services) observes DLP + `UndelegationRequest` accounts and submits local `ScheduleCommitAndUndelegate` + transactions that feed the same scheduled-intent path. 3. The committor service builds base-chain transactions: [`tasks/task_strategist.rs`](../magicblock-committor-service/src/tasks/task_strategist.rs) packs commit tasks under CPI-depth limits (falling back to a two-stage @@ -250,8 +253,8 @@ flowchart TB events --> ep[EventProcessor → WS subs / geyser] svm --> tasks[tasks channel → task-scheduler] sched -->|"slot boundary: streaming blockhash"| repl[Replicator → NATS replicas] - magicprog["magic program ScheduleCommit"] --> scp[ScheduledCommitsProcessor] - scp --> commsvc["committor-service
TaskStrategist + TableMania"] + magicprog["magic program ScheduleCommit"] --> commsvc["committor-service
IntentExecutionService + TaskStrategist + TableMania"] + services2["services DLP request processor"] --> magicprog commsvc -->|commit txs| remote ``` diff --git a/magicblock-accounts/Cargo.toml b/magicblock-accounts/Cargo.toml deleted file mode 100644 index acd1da290..000000000 --- a/magicblock-accounts/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "magicblock-accounts" -version.workspace = true -authors.workspace = true -repository.workspace = true -homepage.workspace = true -license.workspace = true -edition.workspace = true - -[dependencies] -async-trait = { workspace = true } -tracing = { workspace = true } - -magicblock-account-cloner = { workspace = true } -magicblock-chainlink = { workspace = true } -magicblock-committor-service = { workspace = true } -magicblock-core = { workspace = true } -magicblock-delegation-program-api = { workspace = true } -magicblock-metrics = { workspace = true } -magicblock-program = { workspace = true } -solana-hash = { workspace = true } -solana-instruction = { workspace = true } -solana-keypair = { workspace = true } -solana-pubkey = { workspace = true } -solana-signer = { workspace = true } -solana-transaction = { workspace = true } -solana-transaction-error = { workspace = true } -tokio = { workspace = true } -tokio-util = { workspace = true } -thiserror = { workspace = true } -url = { workspace = true } diff --git a/magicblock-accounts/README.md b/magicblock-accounts/README.md deleted file mode 100644 index 18ce5d972..000000000 --- a/magicblock-accounts/README.md +++ /dev/null @@ -1,41 +0,0 @@ - -# Summary - -Implements a `AccountsManager`, which is reponsible for: - -- fetching chain accounts content -- commiting content back to chain - -# Details - -*Important symbols:* - -- `AccountsManager` type - - Implemented by a `ExternalAccountsManager` - - depends on an `InternalAccountProvider` (implemented by `BankAccountProvider`) - - depends on an `AccountCloner` (implemented by `RemoteAccountCloner`) - - depends on a `Transwise` - - denepds on a `CommittorServiceExt` that is used for Manual commits - - Implements `ensure_accounts` function - - Maintains a local cache of accounts already validated and cloned - -- `BankAccountProvider` - - depends on a `Bank` - -- `RemoteAccountCloner` - - depends on a `Bank` - -# Notes - -*How does `ensure_accounts` work:* - -- Collect readonly and writable accounts that we haven't already cloned in the validator -- Those accounts we haven't seen yet we "validate" using `Transwise.validate_accounts` -- We need all accounts to be cloned for the transaction to run, so we clone accounts after the validation -- We also set the correct owners on cloned delegated accounts so that the smart contracts can use them -- Also fund the payer lamports so that it can pay for transactions costs -- Also modify the delegated accounts to have the original owner inside the validator - -*Important dependencies:* - -- Provides `Transwise`: the conjuncto repository diff --git a/magicblock-accounts/src/config.rs b/magicblock-accounts/src/config.rs deleted file mode 100644 index 70e3995d2..000000000 --- a/magicblock-accounts/src/config.rs +++ /dev/null @@ -1,18 +0,0 @@ -#[derive(Debug, PartialEq, Eq)] -pub enum LifecycleMode { - Replica, - ProgramsReplica, - Ephemeral, - Offline, -} - -impl LifecycleMode { - pub fn requires_ephemeral_validation(&self) -> bool { - match self { - LifecycleMode::Replica => false, - LifecycleMode::ProgramsReplica => false, - LifecycleMode::Ephemeral => true, - LifecycleMode::Offline => false, - } - } -} diff --git a/magicblock-accounts/src/errors.rs b/magicblock-accounts/src/errors.rs deleted file mode 100644 index d4a7b5980..000000000 --- a/magicblock-accounts/src/errors.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::collections::HashSet; - -use magicblock_committor_service::{ - error::CommittorServiceError, ChangesetMeta, -}; -use solana_pubkey::Pubkey; -use solana_transaction_error::TransactionError; -use thiserror::Error; -use tokio::sync::oneshot::error::RecvError; - -pub type AccountsResult = std::result::Result; - -#[derive(Error, Debug)] -pub enum AccountsError { - #[error("UrlParseError: {0}")] - UrlParseError(#[from] Box), - - #[error("TransactionError: {0}")] - TransactionError(#[from] Box), - - #[error("CommittorSerivceError: {0}")] - CommittorSerivceError(#[from] CommittorServiceError), - - #[error("TokioOneshotRecvError")] - TokioOneshotRecvError(#[from] Box), - - #[error("InvalidRpcUrl '{0}'")] - InvalidRpcUrl(String), - - #[error("FailedToUpdateUrlScheme")] - FailedToUpdateUrlScheme, - - #[error("FailedToUpdateUrlPort")] - FailedToUpdateUrlPort, - - #[error("FailedToGetLatestBlockhash '{0}'")] - FailedToGetLatestBlockhash(String), - - #[error("FailedToGetReimbursementAddress '{0}'")] - FailedToGetReimbursementAddress(String), - - #[error("FailedToSendCommitTransaction '{0}'")] - FailedToSendCommitTransaction(String, HashSet, HashSet), - - #[error("Too many committees: {0}")] - TooManyCommittees(usize), - - #[error("FailedToObtainReqidForCommittedChangeset {0:?}")] - FailedToObtainReqidForCommittedChangeset(Box), -} - -#[derive(Error, Debug)] -pub enum ScheduledCommitsProcessorError { - #[error("RecvError: {0}")] - RecvError(#[from] RecvError), - #[error("CommittorSerivceError: {0}")] - CommittorSerivceError(Box), -} - -impl From for ScheduledCommitsProcessorError { - fn from(e: CommittorServiceError) -> Self { - Self::CommittorSerivceError(Box::new(e)) - } -} - -pub type ScheduledCommitsProcessorResult< - T, - E = ScheduledCommitsProcessorError, -> = Result; diff --git a/magicblock-accounts/src/lib.rs b/magicblock-accounts/src/lib.rs deleted file mode 100644 index d11a013b2..000000000 --- a/magicblock-accounts/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod config; -pub mod errors; -pub mod scheduled_commits_processor; -mod traits; - -pub use config::*; -pub use traits::*; diff --git a/magicblock-accounts/src/traits.rs b/magicblock-accounts/src/traits.rs deleted file mode 100644 index c039558be..000000000 --- a/magicblock-accounts/src/traits.rs +++ /dev/null @@ -1,18 +0,0 @@ -use async_trait::async_trait; - -use crate::errors::ScheduledCommitsProcessorResult; - -#[async_trait] -pub trait ScheduledCommitsProcessor: Send + Sync + 'static { - /// Processes all commits that were scheduled and accepted - async fn process(&self) -> ScheduledCommitsProcessorResult<()>; - - /// Returns the number of commits that were scheduled and accepted - fn scheduled_commits_len(&self) -> usize; - - /// Clears all scheduled commits - fn clear_scheduled_commits(&self); - - /// Stop processor - fn stop(&self); -} diff --git a/magicblock-api/Cargo.toml b/magicblock-api/Cargo.toml index 1ddbc66de..76828a769 100644 --- a/magicblock-api/Cargo.toml +++ b/magicblock-api/Cargo.toml @@ -16,7 +16,6 @@ tracing = { workspace = true } magicblock-delegation-program-api = { workspace = true } magic-domain-program = { workspace = true } magicblock-account-cloner = { workspace = true } -magicblock-accounts = { workspace = true } magicblock-accounts-db = { workspace = true } magicblock-aperture = { workspace = true } magicblock-chainlink = { workspace = true } diff --git a/magicblock-api/src/errors.rs b/magicblock-api/src/errors.rs index 4f80a6b72..f04f30d8c 100644 --- a/magicblock-api/src/errors.rs +++ b/magicblock-api/src/errors.rs @@ -13,9 +13,6 @@ pub enum ApiError { #[error("Aperture service error: {0}")] Aperture(#[from] magicblock_aperture::error::ApertureError), - #[error("Accounts error: {0}")] - AccountsError(Box), - #[error("Ledger error: {0}")] LedgerError(Box), @@ -113,12 +110,6 @@ pub enum ApiError { Replication(#[from] magicblock_replicator::Error), } -impl From for ApiError { - fn from(e: magicblock_accounts::errors::AccountsError) -> Self { - Self::AccountsError(Box::new(e)) - } -} - impl From for ApiError { fn from(e: magicblock_ledger::errors::LedgerError) -> Self { Self::LedgerError(Box::new(e)) diff --git a/magicblock-api/src/magic_validator.rs b/magicblock-api/src/magic_validator.rs index 4c87d0a2a..85fd3c865 100644 --- a/magicblock-api/src/magic_validator.rs +++ b/magicblock-api/src/magic_validator.rs @@ -9,7 +9,6 @@ use std::{ }; use magicblock_account_cloner::ChainlinkCloner; -use magicblock_accounts::scheduled_commits_processor::ScheduledCommitsProcessorImpl; use magicblock_accounts_db::{traits::AccountsBank, AccountsDb}; use magicblock_aperture::{ initialize_aperture, @@ -58,7 +57,10 @@ use magicblock_program::{ TransactionScheduler as ActionTransactionScheduler, }; use magicblock_replicator::{nats::Broker, BrokerSource, ReplicationService}; -use magicblock_services::actions_callback_service::ActionsCallbackService; +use magicblock_services::{ + actions_callback_service::ActionsCallbackService, + undelegation_request_service::UndelegationRequestService, +}; use magicblock_task_scheduler::{SchedulerDatabase, TaskSchedulerService}; use magicblock_validator_admin::claim_fees::{claim_fees, ClaimFeesTask}; use mdp::state::{ @@ -114,7 +116,7 @@ pub struct MagicValidator { ledger_truncator: LedgerTruncator, intent_execution_service: IntentExecutionServiceImpl, replication_service: Option, - scheduled_commits_processor: Option>, + undelegation_request_service: Option>, rpc_handle: thread::JoinHandle<()>, identity: Pubkey, transaction_scheduler: TransactionSchedulerHandle, @@ -325,12 +327,12 @@ impl MagicValidator { ); log_timing("startup", "system_metrics_ticker_start", step_start); - let scheduled_commits_processor = (!matches!( + let undelegation_request_service = (!matches!( config.validator.replication_mode, ReplicationMode::Replica { .. } )) .then(|| { - Arc::new(ScheduledCommitsProcessorImpl::new( + Arc::new(UndelegationRequestService::new( chainlink.clone(), dispatch.transaction_scheduler.clone(), identity_keypair.insecure_clone(), @@ -460,7 +462,7 @@ impl MagicValidator { _metrics: (metrics_service, system_metrics_ticker), intent_execution_service, replication_service, - scheduled_commits_processor, + undelegation_request_service, token, ledger, ledger_truncator, @@ -1058,8 +1060,8 @@ impl MagicValidator { self.config.validator.replication_mode, ReplicationMode::Replica { .. } ) { - if let Some(processor) = self.scheduled_commits_processor.as_ref() { - processor.spawn_undelegation_request_processor(); + if let Some(service) = self.undelegation_request_service.as_ref() { + service.start(); } } @@ -1151,14 +1153,14 @@ impl MagicValidator { // Ordering is important here // Commitor service shall be stopped last self.token.cancel(); - if let Some(ref scheduled_commits_processor) = - self.scheduled_commits_processor + if let Some(ref undelegation_request_service) = + self.undelegation_request_service { let step_start = Instant::now(); - scheduled_commits_processor.stop(); + undelegation_request_service.stop(); log_timing( "shutdown", - "scheduled_commits_processor_stop", + "undelegation_request_service_stop", step_start, ); } diff --git a/magicblock-committor-service/README.md b/magicblock-committor-service/README.md index 714dfcb0e..8e3b08f99 100644 --- a/magicblock-committor-service/README.md +++ b/magicblock-committor-service/README.md @@ -12,7 +12,7 @@ We can't directly spawn a bunch of **IntentExecutor**s. The reason is that one m Details: Once message make it to `CommittorProcessor::schedule_base_intents` it outsources intent to tokio task `IntentExecutionEngine` which figures out a scheduling. ## IntentExecutionEngine -Accepts new messages, schedules them, and spawns up to `MAX_EXECUTORS`(50) parallel **IntentExecutor**s for each Intent. Once a particular **IntentExecutor** finishes execution we broadcast result to subscribers, like: `RemoteScheduledCommitsProcessor` or `ExternalAccountsManager` +Accepts new messages, schedules them, and spawns up to `MAX_EXECUTORS`(50) parallel **IntentExecutor**s for each Intent. Once a particular **IntentExecutor** finishes execution we broadcast result to subscribers, such as `IntentExecutionService` result handling or test/external managers. Details: For scheduling logic see **IntentScheduler**. Number of parallel **IntentExecutor** is controller by Semaphore. diff --git a/magicblock-services/Cargo.toml b/magicblock-services/Cargo.toml index 2c4134370..da9fe6a0b 100644 --- a/magicblock-services/Cargo.toml +++ b/magicblock-services/Cargo.toml @@ -11,9 +11,15 @@ description = "Services that run on top of the MagicBlock validator and communic [dependencies] bincode = { workspace = true } futures-util = { workspace = true } +magicblock-account-cloner = { workspace = true } +magicblock-chainlink = { workspace = true } magicblock-core = { workspace = true } +magicblock-delegation-program-api = { workspace = true } magicblock-magic-program-api = { workspace = true } +magicblock-metrics = { workspace = true } +magicblock-program = { workspace = true } thiserror = { workspace = true } +solana-hash = { workspace = true } solana-instruction = { workspace = true } solana-keypair = { workspace = true } solana-message = { workspace = true } @@ -22,5 +28,7 @@ solana-rpc-client = { workspace = true } solana-signature = { workspace = true } solana-signer = { workspace = true } solana-transaction = { workspace = true } +solana-transaction-error = { workspace = true } tokio = { workspace = true } +tokio-util = { workspace = true } tracing = { workspace = true } diff --git a/magicblock-services/src/lib.rs b/magicblock-services/src/lib.rs index a3b1ee7f5..ae39af350 100644 --- a/magicblock-services/src/lib.rs +++ b/magicblock-services/src/lib.rs @@ -1 +1,2 @@ pub mod actions_callback_service; +pub mod undelegation_request_service; diff --git a/magicblock-accounts/src/scheduled_commits_processor.rs b/magicblock-services/src/undelegation_request_service.rs similarity index 93% rename from magicblock-accounts/src/scheduled_commits_processor.rs rename to magicblock-services/src/undelegation_request_service.rs index 4e15593be..9f100bb4a 100644 --- a/magicblock-accounts/src/scheduled_commits_processor.rs +++ b/magicblock-services/src/undelegation_request_service.rs @@ -50,13 +50,13 @@ impl fmt::Display for ObservedUndelegationRequestError { } } -pub struct ScheduledCommitsProcessorImpl { +pub struct UndelegationRequestService { chainlink: Arc, cancellation_token: CancellationToken, internal_transaction_scheduler: TransactionSchedulerHandle, validator_authority: Arc, latest_block_reader: Arc, - undelegation_request_poll_interval: Duration, + poll_interval: Duration, } trait LatestBlockReader: Send + Sync { @@ -72,13 +72,13 @@ where } } -impl ScheduledCommitsProcessorImpl { +impl UndelegationRequestService { pub fn new( chainlink: Arc, internal_transaction_scheduler: TransactionSchedulerHandle, validator_authority: Keypair, latest_block: impl LatestBlockProvider, - undelegation_request_poll_interval: Duration, + poll_interval: Duration, ) -> Self { Self { chainlink, @@ -86,11 +86,11 @@ impl ScheduledCommitsProcessorImpl { internal_transaction_scheduler, validator_authority: Arc::new(validator_authority), latest_block_reader: Arc::new(latest_block.clone()), - undelegation_request_poll_interval, + poll_interval, } } - async fn undelegation_request_processor( + async fn subscription_processor( mut requests: broadcast::Receiver, cancellation_token: CancellationToken, chainlink: Arc, @@ -135,7 +135,7 @@ impl ScheduledCommitsProcessorImpl { } } - async fn undelegation_request_poll_processor( + async fn poll_processor( poll_interval: Duration, cancellation_token: CancellationToken, chainlink: Arc, @@ -361,18 +361,18 @@ impl ScheduledCommitsProcessorImpl { ) } - pub fn spawn_undelegation_request_processor(self: &Arc) { + pub fn start(self: &Arc) { let Some(requests) = self.chainlink.subscribe_undelegation_requests() else { - if !self.undelegation_request_poll_interval.is_zero() { + if !self.poll_interval.is_zero() { warn!( "Cannot subscribe to DLP undelegation requests; falling back to polling only" ); } - self.spawn_undelegation_request_poll_processor(); + self.spawn_poll_processor(); return; }; - tokio::spawn(Self::undelegation_request_processor( + tokio::spawn(Self::subscription_processor( requests, self.cancellation_token.clone(), self.chainlink.clone(), @@ -380,16 +380,16 @@ impl ScheduledCommitsProcessorImpl { self.validator_authority.clone(), self.latest_block_reader.clone(), )); - self.spawn_undelegation_request_poll_processor(); + self.spawn_poll_processor(); } - fn spawn_undelegation_request_poll_processor(self: &Arc) { - if self.undelegation_request_poll_interval.is_zero() { + fn spawn_poll_processor(self: &Arc) { + if self.poll_interval.is_zero() { debug!("Skipping DLP undelegation request poll processor"); return; } - tokio::spawn(Self::undelegation_request_poll_processor( - self.undelegation_request_poll_interval, + tokio::spawn(Self::poll_processor( + self.poll_interval, self.cancellation_token.clone(), self.chainlink.clone(), self.internal_transaction_scheduler.clone(), diff --git a/test-manual/Makefile b/test-manual/Makefile index c6f1998e1..7ee28b2b0 100644 --- a/test-manual/Makefile +++ b/test-manual/Makefile @@ -19,7 +19,7 @@ test-laser: $(HELIUS_LASER_SH_DIR)/03_create-config.sh @echo @echo "## Starting validator in background..." - RUST_LOG=warn,magicblock=info,magicblock_chainlink=debug,magicblock_accounts=debug \ + RUST_LOG=warn,magicblock=info,magicblock_chainlink=debug,magicblock_services=debug \ cargo run --bin magicblock-validator --manifest-path=$(DIR)../Cargo.toml \ -- /tmp/mb-test-laser.toml \ > /tmp/validator.log 2>&1 & diff --git a/test-manual/helius-laser/sh/04_start-validator.sh b/test-manual/helius-laser/sh/04_start-validator.sh index 02810638a..0ae192757 100755 --- a/test-manual/helius-laser/sh/04_start-validator.sh +++ b/test-manual/helius-laser/sh/04_start-validator.sh @@ -2,6 +2,6 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -RUST_LOG=warn,magicblock=info,magicblock_chainlink=debug,magicblock_chainlink::chainlink::fetch_cloner=trace,magicblock_accounts=debug \ +RUST_LOG=warn,magicblock=info,magicblock_chainlink=debug,magicblock_chainlink::chainlink::fetch_cloner=trace,magicblock_services=debug \ cargo run --bin magicblock-validator --manifest-path=$DIR/../../../Cargo.toml \ -- /tmp/mb-test-laser.toml