Skip to content

feat: replace task scheduler with hydra#1369

Draft
Dodecahedr0x wants to merge 15 commits into
masterfrom
dode/crank-refactor
Draft

feat: replace task scheduler with hydra#1369
Dodecahedr0x wants to merge 15 commits into
masterfrom
dode/crank-refactor

Conversation

@Dodecahedr0x

@Dodecahedr0x Dodecahedr0x commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Closes #1375

Summary

First step toward moving toward an external crank service based on Hydra. This PR preserves backward compatibility by forward legacy crank requests to the Hydra program, with the validator being the sponsor of those cranks. Any cranks currently in the SQLite DB will be migrated, so completely removing the DB needs to be done in a subsequent PR

Breaking Changes

  • Yes

The task scheduler config is now removed, so validators that were specifying values need to remove them

Summary by CodeRabbit

  • New Features

    • Task scheduling now uses a dedicated funded keypair, improving setup for scheduled operations.
    • Added support for evicting accounts from the ephemeral validator.
    • Legacy scheduled tasks can now be migrated into the new scheduling flow on startup.
  • Bug Fixes

    • Simplified task cancellation and rescheduling behavior for more reliable lifecycle handling.
    • Improved startup checks so required funding and delegation are verified before scheduling begins.
    • Removed outdated scheduling settings from the sample configuration.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Dodecahedr0x, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1f933852-3c15-493c-8bd7-c8af0094a24f

📥 Commits

Reviewing files that changed from the base of the PR and between 7850f16 and 12bcb81.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • .agents/context/crates/magicblock-task-scheduler.md
  • magicblock-api/Cargo.toml
  • magicblock-api/src/crank_faucet.rs
  • magicblock-api/src/errors.rs
  • magicblock-api/src/lib.rs
  • magicblock-api/src/magic_validator.rs
  • magicblock-config/src/config/scheduler.rs
  • magicblock-task-scheduler/src/db.rs
  • magicblock-task-scheduler/src/service.rs
  • programs/magicblock/src/schedule_task/mod.rs
  • test-integration/test-task-scheduler/src/lib.rs
  • test-integration/test-task-scheduler/tests/test_cancel_ongoing_task.rs
  • test-integration/test-task-scheduler/tests/test_independent_authority.rs
  • test-integration/test-task-scheduler/tests/test_migration.rs
  • test-integration/test-task-scheduler/tests/test_reschedule_task.rs
  • test-integration/test-task-scheduler/tests/test_schedule_task.rs
  • test-integration/test-task-scheduler/tests/test_schedule_task_signed.rs
  • test-integration/test-task-scheduler/tests/test_scheduled_commits.rs
  • test-integration/test-task-scheduler/tests/test_undrained_faucet.rs
📝 Walkthrough

Walkthrough

This PR migrates task-scheduler crank execution out of the validator program to an external Hydra ephemeral service. It removes the internal ExecuteCrank instruction, crank PDA helpers, and crank builtin, reduces TaskSchedulerConfig to a single faucet keypair, trims the scheduler database to a migration-only store, and rewrites TaskSchedulerService to create/cancel Hydra crank accounts via RPC. It adds on-chain faucet delegation during validator startup, updates workspace dependencies (hydra-api, solana-svm revisions), and rewrites integration tests to assert on Hydra crank lifecycle instead of database/counter state.

Assessment against linked issues

Objective Addressed Explanation
Migrate crank execution out of the validator to an external service using Hydra (#1375)
Remove internal crank executor/program and related instruction handling (#1375)
Ensure faucet funding/delegation works with external Hydra service (#1375)

Out-of-scope changes

Code Change Explanation
Cargo.toml git revision bumps for solana-account, solana-program-runtime, solana-svm, solana-transaction-context (Cargo.toml, test-integration/Cargo.toml) Unrelated dependency upgrades not tied to the Hydra crank migration objective; appears to be a separate upstream sync.
Addition of EvictAccount instruction variant (magicblock-magic-program-api/src/instruction.rs) Not described by the linked issue's scope of moving cranks to an external service; appears to be an unrelated new capability.

Suggested reviewers

  • bmuddha
  • GabrielePicco
  • taco-paco
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dode/crank-refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
magicblock-task-scheduler/src/db.rs (1)

117-143: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Don’t let one malformed row abort all migration.

A single bad instructions blob or authority string makes get_tasks() return Err, so valid tasks are not migrated and the DB is not drained. Parse rows independently and remove/quarantine only the malformed task id.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-task-scheduler/src/db.rs` around lines 117 - 143, In the
task-loading path around the `stmt.query_map`/`rows.collect` logic in
`get_tasks`, a single malformed `instructions` blob or `authority` value
currently turns the whole read into `Err` and blocks draining valid tasks.
Change the row handling so each record is parsed independently, and on
deserialization/parse failure, skip or quarantine only that task’s `id` instead
of propagating the error. Keep the successful `DbTask` construction path
unchanged, but ensure bad rows are removed or marked separately so migration can
continue for the rest.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@magicblock-task-scheduler/src/db.rs`:
- Around line 19-28: Preserve the legacy scheduling timing when migrating tasks:
DbTask and get_tasks currently drop the previous last_execution_millis/timestamp
data, so recreated Hydra cranks can drift from their original cadence. Update
DbTask to retain enough legacy timing metadata and have get_tasks use it to
compute the correct Hydra start_slot, or otherwise make the migration explicitly
reset timing with documented behavior. Use the existing DbTask and get_tasks
flow as the place to carry this state through the migration path.

In `@magicblock-task-scheduler/src/hydra.rs`:
- Around line 67-94: The Hydra create serialization path in
CreateArgs::serialize and build_create_ix currently assumes scheduled is
non-empty and blindly casts meta/data lengths with as, which can generate
invalid wire data. Update the builder/serializer to return a Result and validate
the Hydra invariants up front: reject empty scheduled slices, and use checked
conversions for metas.len() and data.len() so oversized values fail
deterministically instead of truncating.

In `@magicblock-task-scheduler/src/service.rs`:
- Around line 143-158: Keep valid tasks in SQLite until Hydra creation succeeds;
the migration path in the task scheduler currently removes tasks even when
`wait_for_block_ready()` times out or `schedule_crank()` fails. Update the
migration logic around `schedule_crank`, `wait_for_block_ready`, and
`db.remove_task` so each task is only deleted after a successful Hydra creation,
and leave the SQLite row intact on any error so it can be retried later.
- Around line 201-213: Reject non-positive iteration counts before calling
schedule_crank so we never create a Hydra crank with remaining = 0; update the
task scheduling path in service.rs to validate task.iterations up front and
return early for zero or negative values, mirroring the migration behavior that
skips exhausted tasks. Apply the same guard in the other task creation/update
paths that feed schedule_crank, using the existing schedule_crank and
task.iterations symbols to locate the affected flows.

In `@programs/magicblock/src/schedule_task/mod.rs`:
- Around line 22-28: The signer rejection in the schedule_task logic is now
broader than the current log message implies, so update the stale error text in
the `if account.is_signer` branch to match the new rule. Keep the change
localized to the `ic_msg!` call in `schedule_task` so it clearly states that no
signer is allowed, rather than saying the crank signer PDA is permitted.

---

Outside diff comments:
In `@magicblock-task-scheduler/src/db.rs`:
- Around line 117-143: In the task-loading path around the
`stmt.query_map`/`rows.collect` logic in `get_tasks`, a single malformed
`instructions` blob or `authority` value currently turns the whole read into
`Err` and blocks draining valid tasks. Change the row handling so each record is
parsed independently, and on deserialization/parse failure, skip or quarantine
only that task’s `id` instead of propagating the error. Keep the successful
`DbTask` construction path unchanged, but ensure bad rows are removed or marked
separately so migration can continue for the rest.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 70d07510-06dd-49d4-a882-8e1ad7b04ea5

📥 Commits

Reviewing files that changed from the base of the PR and between 5e8a24a and 5fe3626.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
  • test-integration/programs/hydra/hydra.so is excluded by !**/*.so
📒 Files selected for processing (32)
  • config.example.toml
  • magicblock-api/src/magic_validator.rs
  • magicblock-config/src/config/mod.rs
  • magicblock-config/src/config/scheduler.rs
  • magicblock-config/src/consts.rs
  • magicblock-config/src/lib.rs
  • magicblock-config/src/tests.rs
  • magicblock-magic-program-api/src/instruction.rs
  • magicblock-magic-program-api/src/pda.rs
  • magicblock-processor/src/builtins.rs
  • magicblock-task-scheduler/Cargo.toml
  • magicblock-task-scheduler/src/db.rs
  • magicblock-task-scheduler/src/hydra.rs
  • magicblock-task-scheduler/src/lib.rs
  • magicblock-task-scheduler/src/service.rs
  • programs/magicblock/src/magicblock_processor.rs
  • programs/magicblock/src/schedule_task/mod.rs
  • programs/magicblock/src/schedule_task/process_execute_task.rs
  • programs/magicblock/src/schedule_task/process_schedule_task.rs
  • programs/magicblock/src/utils/instruction_utils.rs
  • test-integration/configs/schedule-task.devnet.toml
  • test-integration/test-ledger-restore/src/lib.rs
  • test-integration/test-task-scheduler/src/lib.rs
  • test-integration/test-task-scheduler/tests/test_cancel_ongoing_task.rs
  • test-integration/test-task-scheduler/tests/test_independent_authority.rs
  • test-integration/test-task-scheduler/tests/test_migration.rs
  • test-integration/test-task-scheduler/tests/test_reschedule_task.rs
  • test-integration/test-task-scheduler/tests/test_schedule_error.rs
  • test-integration/test-task-scheduler/tests/test_schedule_magic_cpi_crank.rs
  • test-integration/test-task-scheduler/tests/test_schedule_task.rs
  • test-integration/test-task-scheduler/tests/test_unauthorized_reschedule.rs
  • test-integration/test-task-scheduler/tests/test_use_crank_signer.rs
💤 Files with no reviewable changes (14)
  • test-integration/test-task-scheduler/tests/test_use_crank_signer.rs
  • test-integration/test-task-scheduler/tests/test_schedule_magic_cpi_crank.rs
  • test-integration/test-task-scheduler/tests/test_schedule_error.rs
  • magicblock-config/src/config/scheduler.rs
  • magicblock-magic-program-api/src/pda.rs
  • magicblock-processor/src/builtins.rs
  • magicblock-config/src/consts.rs
  • magicblock-magic-program-api/src/instruction.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/test-task-scheduler/tests/test_unauthorized_reschedule.rs
  • config.example.toml
  • magicblock-config/src/config/mod.rs
  • programs/magicblock/src/schedule_task/process_execute_task.rs
  • magicblock-config/src/tests.rs

Comment thread magicblock-task-scheduler/src/db.rs
Comment thread magicblock-task-scheduler/src/hydra.rs Outdated
Comment thread magicblock-task-scheduler/src/service.rs Outdated
Comment thread magicblock-task-scheduler/src/service.rs
Comment thread programs/magicblock/src/schedule_task/mod.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
magicblock-task-scheduler/src/service.rs (1)

110-125: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Wait for a usable blockhash before serving runtime requests.

send_create() and send_cancel() pull self.block.load().blockhash directly, but the main loop only gates on faucet readiness. In magicblock-api/src/magic_validator.rs, the scheduler is spawned before init_slot_ticker(...), so the first schedule/cancel requests can still hit the default blockhash and get logged+dropped instead of retried. Gate the runtime loop on block readiness too, or retry requests until a real blockhash exists.

Also applies to: 217-230, 333-335, 391-399

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-task-scheduler/src/service.rs` around lines 110 - 125, The
scheduler loop currently waits only for faucet readiness, but runtime requests
in send_create and send_cancel can still see the default blockhash and get
dropped. Update TaskSchedulerService::run (or the request processing path used
by process_request) to also wait until self.block.load().blockhash is usable
before receiving scheduled_tasks, or add retry/requeue handling when the
blockhash is not yet initialized. Make sure the same readiness guard covers the
initial spawn path from magic_validator so requests are not processed until both
faucet and block readiness are satisfied.
magicblock-api/src/magic_validator.rs (1)

439-442: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Replace this expect with proper error propagation.

A missing tasks_service channel now panics during startup instead of returning a structured ApiError. Handle it like the replication-channel branch above and fail initialization cleanly.

Suggested change
         let task_scheduler = TaskSchedulerService::new(
             &task_scheduler_db_path,
             config.aperture.listen.http(),
             faucet_keypair.insecure_clone(),
             dispatch
                 .tasks_service
                 .take()
-                .expect("tasks_service should be initialized"),
+                .ok_or_else(|| {
+                    ApiError::FailedToSendModeSwitch(
+                        "tasks_service channel missing after init".to_owned(),
+                    )
+                })?,
             ledger.latest_block().clone(),
             Duration::from_millis(config.ledger.block_time_ms()),
             token.clone(),

As per path instructions, {magicblock-*,programs,storage-proto}/**: Treat any usage of .unwrap() or .expect() in production Rust code as a MAJOR issue. These should not be categorized as trivial or nit-level concerns. Request proper error handling or explicit justification with invariants.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-api/src/magic_validator.rs` around lines 439 - 442, The
`tasks_service` initialization in `magic_validator.rs` still uses `expect`,
which can panic during startup instead of returning a structured `ApiError`.
Update the `tasks_service` branch in the same way as the replication-channel
handling above by checking the `Option`, converting the missing-channel case
into an error, and propagating it through the existing initialization flow. Use
the surrounding `dispatch.tasks_service.take()` logic and related startup error
path to keep failure handling consistent and non-panicking.

Source: Path instructions

test-integration/test-task-scheduler/tests/test_cancel_ongoing_task.rs (1)

72-81: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Fetch a fresh blockhash before the cancel transaction.

wait_for_hydra_crank() can spend up to 10s here, but the cancel send below still reuses the blockhash fetched before scheduling. With the 50ms test block time, that can age out of the recent-blockhash window and make this test intermittently fail.

Proposed fix
     wait_for_hydra_crank(
         &ctx,
         &crank_pda,
         Duration::from_secs(10),
         &mut validator,
     );
 
+    let ephem_blockhash =
+        expect!(ctx.try_get_latest_blockhash_ephem(), validator);
+
     // Cancel the task while it is still ongoing.
     let sig = expect!(
         ctx.send_transaction_ephem_with_preflight(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-integration/test-task-scheduler/tests/test_cancel_ongoing_task.rs`
around lines 72 - 81, The cancel flow in test_cancel_ongoing_task is reusing an
old blockhash after wait_for_hydra_crank() can block for several seconds, which
may let the transaction fall out of the recent-blockhash window. Before
constructing and sending the cancel transaction, fetch a fresh blockhash in the
same place you build the cancel request (near the cancel task step) so the
transaction uses up-to-date cluster state. Refer to the cancel path around
wait_for_hydra_crank(), the cancel send logic, and the task cancellation
transaction setup in test_cancel_ongoing_task.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@magicblock-api/Cargo.toml`:
- Line 56: Enable the missing bincode feature for the solana-system-interface
dependency in the Cargo.toml entry used by magicblock-api. The fund_account path
relies on solana_system_interface::instruction::assign, so update the existing
workspace dependency declaration to include the bincode feature and keep the
dependency location intact. Refer to the solana-system-interface dependency line
and the fund_account.rs usage when making the change.

In `@magicblock-api/src/errors.rs`:
- Around line 39-40: The `FailedToDelegateFaucet` error text in `errors.rs` is
misleading because `ensure_faucet_delegated_on_chain` only checks/delegates a
pre-funded faucet and never funds it. Update the `#[error(...)]` message for
`FailedToDelegateFaucet(Pubkey, String)` to describe the correct remediation:
the faucet must already be funded before delegation, while keeping the faucet
pubkey and underlying error details in the message.

In `@magicblock-api/src/fund_account.rs`:
- Around line 94-97: The early delegation check in fund_account should not rely
only on account.owner == dlp_api::id(), because it can miss cases where the
faucet is delegated to a different validator. Update the already_delegated logic
to verify the delegation matches the target validator binding used by the later
delegation setup in this function, or return an error when the existing
delegation points elsewhere. Apply the same validator-specific validation in the
related delegation path around the later delegation checks so startup does not
skip re-delegation on a mismatched faucet.

In `@magicblock-config/src/config/scheduler.rs`:
- Around line 20-27: The default implementation of TaskSchedulerConfig should
not fall back to the repository-known faucet private key. Update
TaskSchedulerConfig::default and any config-loading path used by
MagicValidator::try_from_config so task-scheduler.faucet-keypair must be
explicitly provided for real deployments, or is only populated by an explicit
dev/test-only mode. Replace consts::DEFAULT_TASK_SCHEDULER_FAUCET_KEYPAIR with a
non-reusable placeholder/example value and ensure
SerdeKeypair/Keypair::from_base58_string are not used to silently enable the
published secret by default.

In `@test-integration/test-task-scheduler/src/lib.rs`:
- Around line 71-89: The test harness is pre-delegating the faucet in a way that
hides startup delegation behavior. Update airdrop_faucet to only fund the faucet
and remove the delegate_account_to_validator call there, so setup_validator*
starts with an undelegated faucet and exercises
ensure_faucet_delegated_on_chain. If needed, add a separate startup-focused test
that explicitly begins with an undelegated faucet and verifies the delegation
path.

In `@test-integration/test-task-scheduler/tests/test_undrained_validator.rs`:
- Around line 33-35: The test is using a hard-coded default validator keypair
literal instead of the validator identity from the harness, which can make the
balance check target the wrong account. Update the setup in
test_undrained_validator to source the validator pubkey from setup_validator()
or reuse the shared consts::DEFAULT_VALIDATOR_KEYPAIR, and then use that value
wherever validator_identity is checked.

---

Outside diff comments:
In `@magicblock-api/src/magic_validator.rs`:
- Around line 439-442: The `tasks_service` initialization in
`magic_validator.rs` still uses `expect`, which can panic during startup instead
of returning a structured `ApiError`. Update the `tasks_service` branch in the
same way as the replication-channel handling above by checking the `Option`,
converting the missing-channel case into an error, and propagating it through
the existing initialization flow. Use the surrounding
`dispatch.tasks_service.take()` logic and related startup error path to keep
failure handling consistent and non-panicking.

In `@magicblock-task-scheduler/src/service.rs`:
- Around line 110-125: The scheduler loop currently waits only for faucet
readiness, but runtime requests in send_create and send_cancel can still see the
default blockhash and get dropped. Update TaskSchedulerService::run (or the
request processing path used by process_request) to also wait until
self.block.load().blockhash is usable before receiving scheduled_tasks, or add
retry/requeue handling when the blockhash is not yet initialized. Make sure the
same readiness guard covers the initial spawn path from magic_validator so
requests are not processed until both faucet and block readiness are satisfied.

In `@test-integration/test-task-scheduler/tests/test_cancel_ongoing_task.rs`:
- Around line 72-81: The cancel flow in test_cancel_ongoing_task is reusing an
old blockhash after wait_for_hydra_crank() can block for several seconds, which
may let the transaction fall out of the recent-blockhash window. Before
constructing and sending the cancel transaction, fetch a fresh blockhash in the
same place you build the cancel request (near the cancel task step) so the
transaction uses up-to-date cluster state. Refer to the cancel path around
wait_for_hydra_crank(), the cancel send logic, and the task cancellation
transaction setup in test_cancel_ongoing_task.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c6831594-1813-492f-998c-c519f321926d

📥 Commits

Reviewing files that changed from the base of the PR and between 5fe3626 and 7850f16.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
  • test-integration/programs/hydra/hydra.so is excluded by !**/*.so
📒 Files selected for processing (23)
  • Cargo.toml
  • config.example.toml
  • magicblock-api/Cargo.toml
  • magicblock-api/src/errors.rs
  • magicblock-api/src/fund_account.rs
  • magicblock-api/src/magic_validator.rs
  • magicblock-config/src/config/scheduler.rs
  • magicblock-config/src/consts.rs
  • magicblock-config/src/lib.rs
  • magicblock-config/src/types/crypto.rs
  • magicblock-task-scheduler/Cargo.toml
  • magicblock-task-scheduler/src/errors.rs
  • magicblock-task-scheduler/src/lib.rs
  • magicblock-task-scheduler/src/service.rs
  • test-integration/Cargo.toml
  • test-integration/test-task-scheduler/Cargo.toml
  • test-integration/test-task-scheduler/src/lib.rs
  • test-integration/test-task-scheduler/tests/test_cancel_ongoing_task.rs
  • test-integration/test-task-scheduler/tests/test_independent_authority.rs
  • test-integration/test-task-scheduler/tests/test_migration.rs
  • test-integration/test-task-scheduler/tests/test_reschedule_task.rs
  • test-integration/test-task-scheduler/tests/test_schedule_task.rs
  • test-integration/test-task-scheduler/tests/test_undrained_validator.rs
💤 Files with no reviewable changes (1)
  • magicblock-task-scheduler/src/lib.rs

Comment thread magicblock-api/Cargo.toml Outdated
Comment thread magicblock-api/src/errors.rs Outdated
Comment on lines +39 to +40
#[error("Failed to fund and delegate task scheduler faucet '{0}': {1}")]
FailedToDelegateFaucet(Pubkey, String),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the faucet error text.

ensure_faucet_delegated_on_chain requires the faucet to be pre-funded; it never funds it. This message points operators at the wrong remediation when startup fails.

Suggested change
-    #[error("Failed to fund and delegate task scheduler faucet '{0}': {1}")]
+    #[error("Failed to delegate task scheduler faucet '{0}': {1}")]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[error("Failed to fund and delegate task scheduler faucet '{0}': {1}")]
FailedToDelegateFaucet(Pubkey, String),
#[error("Failed to delegate task scheduler faucet '{0}': {1}")]
FailedToDelegateFaucet(Pubkey, String),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-api/src/errors.rs` around lines 39 - 40, The
`FailedToDelegateFaucet` error text in `errors.rs` is misleading because
`ensure_faucet_delegated_on_chain` only checks/delegates a pre-funded faucet and
never funds it. Update the `#[error(...)]` message for
`FailedToDelegateFaucet(Pubkey, String)` to describe the correct remediation:
the faucet must already be funded before delegation, while keeping the faucet
pubkey and underlying error details in the message.

Comment thread magicblock-api/src/fund_account.rs Outdated
Comment on lines +94 to +97
let already_delegated = matches!(
rpc.get_account(&faucet_pubkey).await,
Ok(account) if account.owner == dlp_api::id()
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Verify delegation against the target validator, not just the account owner.

The early return only checks account.owner == dlp_api::id(), but the delegation you build below is explicitly validator-specific. If this faucet was previously delegated to another validator, startup will skip re-delegation and leave the local scheduler with a faucet it cannot use. Please validate the validator-binding delegation state here, or fail fast on mismatch.

Also applies to: 113-121

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-api/src/fund_account.rs` around lines 94 - 97, The early
delegation check in fund_account should not rely only on account.owner ==
dlp_api::id(), because it can miss cases where the faucet is delegated to a
different validator. Update the already_delegated logic to verify the delegation
matches the target validator binding used by the later delegation setup in this
function, or return an error when the existing delegation points elsewhere.
Apply the same validator-specific validation in the related delegation path
around the later delegation checks so startup does not skip re-delegation on a
mismatched faucet.

Comment thread magicblock-config/src/config/scheduler.rs
Comment thread test-integration/test-task-scheduler/src/lib.rs
Comment on lines +33 to +35
// The default validator identity keypair (see consts::DEFAULT_VALIDATOR_KEYPAIR).
let validator_keypair = Keypair::from_base58_string("9Vo7TbA5YfC5a33JhAi9Fb41usA6JwecHNRw3f9MzzHAM8hFnXTzL5DcEHwsAFjuUZ8vNQcJ4XziRFpMc3gTgBQ");
let validator_identity = validator_keypair.pubkey();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Read the validator identity from the harness instead of a copied keypair literal.

This test is supposed to prove the running validator is not paying for cranks, but it currently measures a hard-coded default identity. If that default changes, the balance check can read the wrong account and still pass. Reuse the shared default constant or return the validator pubkey from setup_validator().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-integration/test-task-scheduler/tests/test_undrained_validator.rs`
around lines 33 - 35, The test is using a hard-coded default validator keypair
literal instead of the validator identity from the harness, which can make the
balance check target the wrong account. Update the setup in
test_undrained_validator to source the validator pubkey from setup_validator()
or reuse the shared consts::DEFAULT_VALIDATOR_KEYPAIR, and then use that value
wherever validator_identity is checked.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: migrate cranks to an external service

1 participant