Skip to content

Conversation

@Dodecahedr0x
Copy link
Contributor

@Dodecahedr0x Dodecahedr0x commented Nov 5, 2025

Fix #523

This PR is a draft based on #608, which is also currently a draft. It reduces overhead by receiving new tasks instead of periodically deserializing the task context. It also introduces new task scheduler tests using test-kit

Summary by CodeRabbit

  • New Features

    • Task scheduling now uses channel-based delivery with a thread-local task stash; scheduling/cancellation no longer require a separate on-chain task-context account.
    • Added native task request types and in-process task channels for richer scheduling semantics.
  • Bug Fixes / Behavior

    • Removed legacy "process tasks" pathway and on-chain task-context flows.
  • Tests

    • Added integration tests covering schedule and cancel scenarios.
  • Chores

    • Removed milliseconds-per-tick config option; added cargo features for custom-heap and custom-panic.

bmuddha and others added 5 commits November 2, 2025 18:39
This stash can be used for communication between magic program
and the rest of the validator, as a more performant and easier
to use alternative to Context accounts.
@github-actions
Copy link

github-actions bot commented Nov 5, 2025

Manual Deploy Available

You can trigger a manual deploy of this PR branch to testnet:

Deploy to Testnet 🚀

Alternative: Comment /deploy on this PR to trigger deployment directly.

⚠️ Note: Manual deploy requires authorization. Only authorized users can trigger deployments.

Comment updated automatically when the PR is synchronized.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Walkthrough

Refactors task scheduling from on-chain TaskContext and ticker polling to an event-driven design: removes TaskContext and ProcessTasks, adds TLS-based ExecutionTlsStash and TaskRequest types, wires ScheduledTasks channels through core/link into executor/validator, and replaces the tick-based TaskSchedulerService with a channel-driven service.

Changes

Cohort / File(s) Summary
Core task model removed
programs/magicblock/src/task_context.rs, programs/magicblock/src/lib.rs
Deleted TaskContext module, related types (TaskRequest, ScheduleTaskRequest, CancelTaskRequest, CrankTask), constants and re-exports.
TLS-based task stash & API
magicblock-magic-program-api/src/tls.rs, magicblock-magic-program-api/src/lib.rs
Added ExecutionTlsStash (register_task/next_task/clear); removed TASK_CONTEXT_* constants and added tls module.
Task request types & instruction change
magicblock-magic-program-api/src/args.rs, magicblock-magic-program-api/src/instruction.rs
Added TaskRequest enum, ScheduleTaskRequest, CancelTaskRequest; removed ProcessTasks instruction variant.
TaskSchedulerService rewrite
magicblock-task-scheduler/src/service.rs, magicblock-task-scheduler/tests/service.rs, magicblock-task-scheduler/Cargo.toml
Replaced generic bank-coupled, tick-driven service with non-generic, channel-driven TaskSchedulerService using ScheduledTasksRx + CancellationToken; adjusted API and added integration tests.
Channel types & link wiring
magicblock-core/src/link.rs, magicblock-core/src/link/transactions.rs
Added ScheduledTasksRx/ScheduledTasksTx type aliases and wired a tasks_service channel into DispatchEndpoints and ValidatorChannelEndpoints.
Executor / processor plumbing
magicblock-processor/src/executor/mod.rs, magicblock-processor/src/executor/processing.rs, magicblock-processor/src/scheduler/state.rs
Propagated tasks_tx into TransactionExecutor and TransactionSchedulerState; drain ExecutionTlsStash after commit and clear on simulate; send TLS-collected TaskRequest via channel.
Validator & service lifecycle
magicblock-api/src/magic_validator.rs, magicblock-api/src/fund_account.rs
MagicValidator now holds an Option (not JoinHandle); removed fund_task_context and TASK_CONTEXT setup; wire tasks_service into validator/dispatch.
On-chain instruction handlers updated
programs/magicblock/src/schedule_task/process_schedule_task.rs, programs/magicblock/src/schedule_task/process_cancel_task.rs, programs/magicblock/src/schedule_task/mod.rs
Schedule/Cancel handlers register requests into ExecutionTlsStash instead of mutating on-chain TaskContext; removed process_process_tasks and utils; added minimal interval validation.
ProcessTasks instruction & helpers removed
programs/magicblock/src/magicblock_processor.rs, programs/magicblock/src/utils/instruction_utils.rs, programs/magicblock/src/schedule_task/process_process_tasks.rs
Removed ProcessTasks handling, builders, and related utilities and tests.
Client & integration updates
test-integration/programs/flexi-counter/src/*, test-integration/test-task-scheduler/tests/*, test-integration/programs/schedulecommit/Cargo.toml, test-integration/configs/schedule-task.ephem.toml, test-integration/test-ledger-restore/src/lib.rs
Removed task_context parameter from schedule/cancel instruction builders and call sites; updated TaskSchedulerConfig init and fixtures/tests to omit millis-per-tick; added crate feature flags in some Cargo.toml.
Guinea & NOOP test wiring
programs/guinea/src/lib.rs, programs/guinea/Cargo.toml, test-kit/src/lib.rs, programs/magicblock/src/validator.rs
Guinea: added Increment/ScheduleTask/CancelTask instruction variants and handlers invoking magicblock. Test-kit preloads NOOP program and wires tasks_tx into TransactionSchedulerState. Added init_validator_authority_if_needed helper.
Blacklist & miscellaneous
magicblock-chainlink/src/chainlink/blacklisted_accounts.rs, magicblock-config/src/*, magicblock-core tests/fixtures
Removed TASK_CONTEXT_PUBKEY from blacklist and many callsites; removed millis_per_tick field and Default impl from TaskSchedulerConfig and updated tests/fixtures accordingly.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Proc as Transaction Processor
    participant TLS as ExecutionTlsStash
    participant Chan as ScheduledTasksTx (tasks_tx)
    participant Sched as TaskSchedulerService

    rect rgb(200,220,240)
    note over Proc,Sched: Old flow (removed)
    Proc->>OnChain: write TaskContext account
    Sched->>OnChain: periodic ticker reads TaskContext
    Sched->>Sched: deserialize/process requests
    end

    rect rgb(220,240,200)
    note over Proc,Sched: New flow (event-driven)
    Proc->>TLS: register_task (during instruction)
    Proc->>TLS: after commit drain -> for each TaskRequest
    TLS->>Chan: send(TaskRequest)
    Chan->>Sched: receive(TaskRequest)
    Sched->>Sched: process immediately (schedule/cancel)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Areas requiring extra attention:

  • magicblock-task-scheduler/src/service.rs — verify new non-generic lifecycle, channel receive loop, cancellation handling, persistence/error paths.
  • magicblock-processor/src/executor/processing.rs — ensure TLS drain/clear behavior is correct across simulate vs real commit paths.
  • programs/magicblock/src/schedule_task/{process_schedule_task.rs,process_cancel_task.rs} — account indexing, signer checks, MIN_EXECUTION_INTERVAL validation.
  • magicblock-api/src/magic_validator.rs — TaskSchedulerService startup/stop semantics and error handling integration.
  • Widespread test updates — ensure integration tests reflect removed on-chain context and new wiring.

Possibly related PRs

Suggested reviewers

  • thlorenz
  • bmuddha
  • GabrielePicco

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the primary change: replacing task context (on-chain) with thread-local storage (TLS) for task scheduling.
Linked Issues check ✅ Passed The PR addresses issue #523 by eliminating ticker-based polling of task context and implementing direct channel-based task delivery via ExecutionTlsStash and ScheduledTasksRx.
Out of Scope Changes check ✅ Passed All changes are scoped to eliminating ticker-based task polling and implementing TLS-based task scheduling. Minor additions like Cargo features and test infrastructure are supporting changes aligned with the main objective.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dode/crank-tls-task-queue

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 and usage tips.

@Dodecahedr0x Dodecahedr0x marked this pull request as ready for review November 5, 2025 17:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (2)
programs/magicblock/src/schedule_task/process_schedule_task.rs (1)

42-49: Update the out-of-date error text.
This log still references the old task-context account even though the instruction no longer requires it, which will mislead operators debugging failures.

Apply this diff to keep the message accurate:

-            "ScheduleTask ERR: not enough accounts to schedule task ({}), need payer, signing program and task context",
+            "ScheduleTask ERR: not enough accounts to schedule task ({}), need payer and signing program accounts",
magicblock-task-scheduler/src/service.rs (1)

234-237: Cancellation currently ignored for freshly scheduled tasks

Newly scheduled tasks never record their DelayQueue key, so remove_task_from_queue cannot pull them out if a cancel request arrives before the first execution—cancellations silently fail and the task still runs. Please stash the key when inserting (and clear any existing entry) so we can honor cancel requests.

         self.db.insert_task(&db_task)?;
-        self.task_queue
-            .insert(db_task.clone(), Duration::from_millis(0));
+        self.remove_task_from_queue(task.id);
+        let key = self
+            .task_queue
+            .insert(db_task.clone(), Duration::from_millis(0));
+        self.task_queue_keys.insert(task.id, key);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7955c3 and 7a9aced.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • programs/elfs/guinea.so is excluded by !**/*.so
  • test-integration/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (46)
  • magicblock-api/src/fund_account.rs (1 hunks)
  • magicblock-api/src/magic_validator.rs (8 hunks)
  • magicblock-chainlink/src/chainlink/blacklisted_accounts.rs (0 hunks)
  • magicblock-committor-program/Cargo.toml (1 hunks)
  • magicblock-config/src/lib.rs (4 hunks)
  • magicblock-config/src/task_scheduler.rs (1 hunks)
  • magicblock-config/tests/fixtures/11_everything-defined.toml (0 hunks)
  • magicblock-config/tests/parse_config.rs (1 hunks)
  • magicblock-config/tests/read_config.rs (1 hunks)
  • magicblock-core/src/link.rs (6 hunks)
  • magicblock-core/src/link/transactions.rs (3 hunks)
  • magicblock-magic-program-api/src/args.rs (1 hunks)
  • magicblock-magic-program-api/src/instruction.rs (0 hunks)
  • magicblock-magic-program-api/src/lib.rs (1 hunks)
  • magicblock-magic-program-api/src/tls.rs (1 hunks)
  • magicblock-processor/Cargo.toml (1 hunks)
  • magicblock-processor/src/executor/mod.rs (3 hunks)
  • magicblock-processor/src/executor/processing.rs (4 hunks)
  • magicblock-processor/src/scheduler/state.rs (2 hunks)
  • magicblock-task-scheduler/Cargo.toml (1 hunks)
  • magicblock-task-scheduler/src/service.rs (6 hunks)
  • magicblock-task-scheduler/tests/service.rs (1 hunks)
  • programs/guinea/Cargo.toml (1 hunks)
  • programs/guinea/src/lib.rs (5 hunks)
  • programs/magicblock/src/lib.rs (0 hunks)
  • programs/magicblock/src/magicblock_processor.rs (1 hunks)
  • programs/magicblock/src/schedule_task/mod.rs (1 hunks)
  • programs/magicblock/src/schedule_task/process_cancel_task.rs (5 hunks)
  • programs/magicblock/src/schedule_task/process_process_tasks.rs (0 hunks)
  • programs/magicblock/src/schedule_task/process_schedule_task.rs (6 hunks)
  • programs/magicblock/src/schedule_task/utils.rs (0 hunks)
  • programs/magicblock/src/task_context.rs (0 hunks)
  • programs/magicblock/src/utils/instruction_utils.rs (2 hunks)
  • test-integration/configs/schedule-task.ephem.toml (0 hunks)
  • test-integration/programs/flexi-counter/src/instruction.rs (0 hunks)
  • test-integration/programs/flexi-counter/src/processor.rs (2 hunks)
  • test-integration/programs/schedulecommit/Cargo.toml (1 hunks)
  • test-integration/test-ledger-restore/src/lib.rs (1 hunks)
  • test-integration/test-task-scheduler/src/lib.rs (1 hunks)
  • test-integration/test-task-scheduler/tests/test_cancel_ongoing_task.rs (1 hunks)
  • test-integration/test-task-scheduler/tests/test_reschedule_task.rs (1 hunks)
  • test-integration/test-task-scheduler/tests/test_schedule_error.rs (1 hunks)
  • test-integration/test-task-scheduler/tests/test_schedule_task.rs (1 hunks)
  • test-integration/test-task-scheduler/tests/test_schedule_task_signed.rs (1 hunks)
  • test-integration/test-task-scheduler/tests/test_unauthorized_reschedule.rs (1 hunks)
  • test-kit/src/lib.rs (3 hunks)
💤 Files with no reviewable changes (9)
  • programs/magicblock/src/lib.rs
  • programs/magicblock/src/schedule_task/utils.rs
  • programs/magicblock/src/schedule_task/process_process_tasks.rs
  • magicblock-magic-program-api/src/instruction.rs
  • magicblock-config/tests/fixtures/11_everything-defined.toml
  • test-integration/programs/flexi-counter/src/instruction.rs
  • programs/magicblock/src/task_context.rs
  • magicblock-chainlink/src/chainlink/blacklisted_accounts.rs
  • test-integration/configs/schedule-task.ephem.toml
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Applied to files:

  • magicblock-magic-program-api/src/lib.rs
  • programs/guinea/src/lib.rs
  • magicblock-api/src/fund_account.rs
  • programs/magicblock/src/schedule_task/process_schedule_task.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • programs/magicblock/src/schedule_task/process_cancel_task.rs
📚 Learning: 2025-11-04T10:53:50.922Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-processor/src/scheduler/locks.rs:110-122
Timestamp: 2025-11-04T10:53:50.922Z
Learning: In magicblock-processor, the TransactionScheduler runs in a single, dedicated thread and will always remain single-threaded. The `next_transaction_id()` function in scheduler/locks.rs uses `unsafe static mut` which is safe given this architectural guarantee.

Applied to files:

  • magicblock-core/src/link/transactions.rs
  • magicblock-processor/src/executor/mod.rs
  • magicblock-core/src/link.rs
  • magicblock-processor/src/scheduler/state.rs
  • programs/magicblock/src/schedule_task/process_schedule_task.rs
  • magicblock-task-scheduler/src/service.rs
  • test-kit/src/lib.rs
  • magicblock-api/src/magic_validator.rs
📚 Learning: 2025-10-14T09:56:14.047Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 564
File: test-integration/programs/flexi-counter/src/processor/call_handler.rs:122-125
Timestamp: 2025-10-14T09:56:14.047Z
Learning: The file test-integration/programs/flexi-counter/src/processor/call_handler.rs contains a test smart contract used for integration testing, not production code.

Applied to files:

  • test-integration/test-task-scheduler/tests/test_unauthorized_reschedule.rs
  • magicblock-processor/src/executor/processing.rs
  • magicblock-task-scheduler/tests/service.rs
  • test-integration/test-ledger-restore/src/lib.rs
  • programs/magicblock/src/schedule_task/process_schedule_task.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-task-scheduler/tests/test_schedule_task_signed.rs
  • test-integration/test-task-scheduler/tests/test_schedule_error.rs
  • test-kit/src/lib.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_cancel_ongoing_task.rs
  • programs/magicblock/src/schedule_task/process_cancel_task.rs
📚 Learning: 2025-10-21T10:34:59.140Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-accounts-db/src/lib.rs:63-72
Timestamp: 2025-10-21T10:34:59.140Z
Learning: In magicblock-validator, the AccountsDb "stop-the-world" synchronizer is managed at the processor/executor level, not at the AccountsDb API level. Transaction executors in magicblock-processor hold a read lock (sync.read()) for the duration of each slot and release it only at slot boundaries, ensuring all account writes happen under the read lock. Snapshot operations acquire a write lock, blocking until all executors release their read locks. This pattern ensures mutual exclusion between writes and snapshots without requiring read guards in AccountsDb write APIs.

Applied to files:

  • magicblock-api/src/fund_account.rs
  • magicblock-processor/src/scheduler/state.rs
📚 Learning: 2025-11-04T10:48:00.070Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-processor/src/scheduler/mod.rs:217-219
Timestamp: 2025-11-04T10:48:00.070Z
Learning: In magicblock-validator, the codebase uses a pattern where types containing non-Send/non-Sync fields (like Rc<RefCell<...>>) are marked with unsafe impl Send when they are guaranteed to be confined to a single thread through careful API design and thread spawning patterns.

Applied to files:

  • magicblock-task-scheduler/src/service.rs
🧬 Code graph analysis (7)
magicblock-processor/src/executor/processing.rs (1)
magicblock-magic-program-api/src/tls.rs (2)
  • next_task (22-24)
  • clear (26-31)
programs/magicblock/src/magicblock_processor.rs (4)
programs/magicblock/src/utils/instruction_utils.rs (1)
  • schedule_task (200-209)
programs/magicblock/src/schedule_task/process_cancel_task.rs (1)
  • process_cancel_task (13-52)
test-integration/programs/flexi-counter/src/processor.rs (2)
  • process_cancel_task (458-485)
  • process_schedule_task (401-456)
programs/magicblock/src/schedule_task/process_schedule_task.rs (1)
  • process_schedule_task (18-123)
magicblock-task-scheduler/tests/service.rs (1)
test-kit/src/lib.rs (3)
  • new (83-85)
  • default (67-69)
  • get_account (281-291)
programs/magicblock/src/schedule_task/process_schedule_task.rs (2)
programs/magicblock/src/utils/accounts.rs (1)
  • get_instruction_pubkey_with_idx (94-102)
magicblock-magic-program-api/src/tls.rs (1)
  • register_task (17-20)
magicblock-task-scheduler/src/service.rs (4)
magicblock-core/src/link.rs (1)
  • link (60-89)
magicblock-task-scheduler/src/db.rs (2)
  • new (50-89)
  • path (46-48)
magicblock-api/src/magic_validator.rs (1)
  • start (635-711)
magicblock-magic-program-api/src/args.rs (1)
  • id (142-147)
programs/magicblock/src/schedule_task/process_cancel_task.rs (2)
programs/magicblock/src/utils/accounts.rs (1)
  • get_instruction_pubkey_with_idx (94-102)
magicblock-magic-program-api/src/tls.rs (1)
  • register_task (17-20)
magicblock-api/src/magic_validator.rs (4)
magicblock-core/src/link.rs (1)
  • link (60-89)
magicblock-task-scheduler/src/db.rs (1)
  • path (46-48)
magicblock-task-scheduler/src/service.rs (1)
  • new (58-91)
magicblock-processor/src/executor/mod.rs (1)
  • new (68-110)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_lint
  • GitHub Check: Build Project
🔇 Additional comments (43)
programs/guinea/Cargo.toml (1)

19-19: Dependency is properly used and necessary.

The verification confirms that magicblock-magic-program-api is actively imported and used in the guinea crate (programs/guinea/src/lib.rs:4 with usages at lines 109 and 130). The dependency addition is justified and follows the existing workspace dependency pattern used throughout the Cargo.toml file.

magicblock-task-scheduler/Cargo.toml (1)

32-38: All dev-dependencies are valid and properly used in tests.

Verification confirms:

  • All 6 crates are defined in the workspace root Cargo.toml
  • Test file magicblock-task-scheduler/tests/service.rs uses guinea, test-kit, magicblock-magic-program-api, and solana-account directly; solana-pubkey and solana-signature are transitively integrated through test-kit
  • Two integration tests exercise task scheduling functionality (schedule and cancel operations)
magicblock-committor-program/Cargo.toml (1)

32-33: Clarify the purpose and necessity of these feature flags for the PR objective.

The addition of custom-heap and custom-panic features across multiple crates appears unrelated to the stated PR objective of replacing ticker-based task scheduling with thread-local storage. These features should either be:

  1. Documented with a clear explanation of their necessity, or
  2. Moved to a separate PR if they're orthogonal to this refactoring.

Provide clarification on:

  • Why are custom-heap and custom-panic features required for the TLS task scheduling refactoring?
  • Are these features documented in an RFC or design document?
  • Are they gated by conditional compilation logic that ties to the scheduler changes?

If these features are preparatory/future work, consider extracting them to a separate infrastructure improvement PR to keep this PR focused on the task scheduling objective.

magicblock-processor/Cargo.toml (1)

21-21: Remove unused dependency or add integration code.

The workspace dependency is properly configured; however, magicblock-magic-program-api is not imported or used anywhere in the magicblock-processor codebase. Either remove this dependency from magicblock-processor/Cargo.toml line 21, or add the code that integrates it (if this PR is incomplete).

⛔ Skipped due to learnings
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 564
File: test-integration/programs/flexi-counter/src/processor/call_handler.rs:122-125
Timestamp: 2025-10-14T09:56:14.047Z
Learning: The file test-integration/programs/flexi-counter/src/processor/call_handler.rs contains a test smart contract used for integration testing, not production code.
programs/magicblock/src/utils/instruction_utils.rs (2)

240-251: Verification confirmed: No issues found.

The CancelTask instruction change has been properly implemented end-to-end:

  • The processor (process_cancel_task.rs) expects only one account (the authority at index 0), with no references to TASK_CONTEXT_PUBKEY.
  • The instruction builder (cancel_task_instruction) creates a single-account instruction matching the processor's expectation.
  • All callsites—including internal tests and external programs (guinea, flexi-counter)—pass only the authority account.
  • Tests verify the correct behavior: authority must be a signer, unsigned attempts fail appropriately.

The breaking change has been consistently applied throughout the codebase.


211-226: No verification required—changes are properly coordinated.

The removal of TASK_CONTEXT_PUBKEY is correctly implemented across the codebase:

  • process_schedule_task() expects accounts: [payer (idx 0), ...instruction_accounts (idx 1+)]
  • process_cancel_task() expects accounts: [authority (idx 0)]
  • All instruction builders match these expectations ✓
  • All callsites are compatible ✓

Minor note: The error message in process_schedule_task still mentions "task context," which is outdated documentation but doesn't affect functionality. Consider updating to reflect the current channel-based architecture.

programs/guinea/src/lib.rs (4)

4-6: LGTM!

The imports are properly organized and all are necessary for the cross-program invocation functionality.

Also applies to: 12-12, 14-14


27-31: LGTM!

The new instruction variants are well-defined and appropriately typed for the task scheduling functionality.


67-75: LGTM!

The increment function follows the existing patterns in the file and includes proper error handling.


160-168: LGTM!

The instruction handling in the match statement is properly implemented and follows the existing patterns.

test-integration/test-task-scheduler/tests/test_schedule_error.rs (2)

3-3: LGTM!

The import change from TASK_CONTEXT_PUBKEY to MAGIC_PROGRAM_ID aligns with the PR's refactoring objective to remove TaskContext-based scheduling.


43-51: LGTM!

The instruction constructor calls are properly updated to use MAGIC_PROGRAM_ID, maintaining consistency with the API refactoring.

Also applies to: 128-132

test-kit/src/lib.rs (3)

40-41: LGTM!

The NOOP_PROGRAM_ID constant is properly defined with compile-time validation.


127-127: LGTM!

The tasks_tx channel integration is essential for the new event-driven task scheduling architecture.


138-143: NOOP program binary verified — code is ready.

The NOOP program binary exists at the specified path. The code follows the established test program initialization pattern.

test-integration/test-task-scheduler/tests/test_reschedule_task.rs (2)

3-3: LGTM!

The import change is consistent with the broader refactoring to remove TaskContext-based scheduling.


42-50: LGTM!

All instruction constructor calls are consistently updated to use MAGIC_PROGRAM_ID.

Also applies to: 77-85, 168-172

test-integration/test-task-scheduler/src/lib.rs (1)

46-46: LGTM!

The TaskSchedulerConfig simplification is consistent with the shift to event-driven task scheduling.

test-integration/test-ledger-restore/src/lib.rs (1)

155-155: LGTM!

The formatting change improves code conciseness without affecting functionality.

programs/magicblock/src/magicblock_processor.rs (2)

8-8: LGTM!

The removal of process_process_tasks import is consistent with the elimination of the ProcessTasks instruction path.


68-73: ProcessTasks removal verified complete.

The MagicBlockInstruction enum and match statement in magicblock_processor.rs have been properly updated. ProcessTasks has been completely removed from the codebase with no remaining references, and the ScheduleTask and CancelTask instruction variants are correctly handled. The event-driven scheduling refactoring is complete.

magicblock-config/tests/parse_config.rs (1)

285-285: Verified: TaskSchedulerConfig correctly refactored for event-driven scheduling.

The struct definition confirms that millis_per_tick has been removed and only the reset field remains, exactly as shown in the test at line 285. The initialization TaskSchedulerConfig { reset: true } is correct.

magicblock-config/src/lib.rs (1)

271-271: LGTM! Tests updated consistently with the new TaskSchedulerConfig API.

All test cases correctly reflect the removal of millis_per_tick from the public TaskSchedulerConfig struct, using only the reset field.

Also applies to: 356-356, 438-438, 513-513

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

3-3: LGTM! Instruction builder correctly updated to remove TaskContext dependency.

The removal of TASK_CONTEXT_PUBKEY from both the import and the create_schedule_task_ix calls aligns with the PR's objective to replace task context with thread-local storage.

Also applies to: 47-55, 82-90

magicblock-magic-program-api/src/lib.rs (1)

3-3: LGTM! TLS module addition aligns with the event-driven architecture.

The new tls module introduces thread-local storage for task scheduling, replacing the previous TaskContext-based polling approach.

magicblock-config/src/task_scheduler.rs (1)

7-24: LGTM! Simplified configuration aligns with the new event-driven architecture.

Removing millis_per_tick is consistent with eliminating ticker-based polling in favor of direct channel-based task notification. The derived Default implementation simplifies the code.

magicblock-config/tests/read_config.rs (1)

204-204: LGTM! Test correctly updated for the new TaskSchedulerConfig API.

The test configuration construction is consistent with the removal of millis_per_tick.

test-integration/programs/flexi-counter/src/processor.rs (2)

451-451: LGTM! Correctly removed task_context_info from schedule task invocation.

The invoke_signed call now correctly omits the task_context_info account, aligning with the shift to TLS-based task scheduling.


479-482: LGTM! Correctly removed task_context_info from cancel task flow.

Both the AccountMeta vector and the invoke call have been updated to exclude task_context_info, consistent with the removal of TaskContext-based task management.

programs/magicblock/src/schedule_task/mod.rs (1)

1-5: LGTM! Module structure simplified by removing ProcessTasks pathway.

The removal of process_process_tasks and utils modules aligns with eliminating ticker-based task polling. Only the essential schedule and cancel operations remain, consistent with the new event-driven architecture.

magicblock-processor/src/scheduler/state.rs (1)

6-8: LGTM! New task channel properly initialized across all construction sites.

The tasks_tx field successfully introduces event-driven task scheduling by replacing ticker-based polling. Verification confirms the channel is properly initialized in both known construction sites (test-kit and magicblock-api), consistently sourced from validator_channels.tasks_service.

magicblock-processor/src/executor/processing.rs (1)

98-99: LGTM: Proper stash cleanup.

The unconditional clearing of ExecutionTlsStash after transaction processing (lines 98-99) and in the simulate path (lines 145-147) correctly prevents task leakage between transactions and ensures simulations don't interfere with actual executions.

Also applies to: 145-147

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

3-3: LGTM: Test updated to match new instruction signatures.

The test correctly updates to use MAGIC_PROGRAM_ID instead of TASK_CONTEXT_PUBKEY, aligning with the removal of TaskContext-based scheduling. The test logic remains functionally equivalent.

Also applies to: 42-50, 133-137

magicblock-api/src/fund_account.rs (1)

6-6: LGTM: Simplified account funding aligns with TaskContext removal.

The removal of fund_task_context and related TaskContext handling is consistent with the architectural shift to TLS-based task scheduling. The code correctly retains only the MagicContext initialization.

Also applies to: 74-87

magicblock-processor/src/executor/mod.rs (1)

8-8: LGTM: Clean channel integration.

The addition of the tasks_tx channel to TransactionExecutor is properly wired through initialization and aligns with the new task scheduling architecture.

Also applies to: 53-54, 105-105

magicblock-core/src/link/transactions.rs (1)

34-37: Verify unbounded channel choice for scheduled tasks.

The use of UnboundedSender/UnboundedReceiver means tasks will accumulate in memory without backpressure if the task scheduler service falls behind or hangs. While the send-side error handling (in processing.rs line 89) logs warnings on failure, an unbounded channel can still lead to memory growth.

Consider whether a bounded channel with appropriate capacity would provide better resource management, or confirm that unbounded semantics are intentional for the "fire-and-forget" task scheduling model.

programs/magicblock/src/schedule_task/process_cancel_task.rs (2)

3-6: LGTM: Clean migration to TLS-based task cancellation.

The refactor from TaskContext manipulation to ExecutionTlsStash registration is clean and correct. Signer validation is properly maintained, and the cancel request is correctly queued for processing.

Also applies to: 36-43


76-79: LGTM: Test updates aligned with TaskContext removal.

The tests correctly simplify to only require the payer account, removing the now-unnecessary TaskContext account handling. Test expectations remain functionally equivalent.

Also applies to: 101-104

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

2-2: LGTM: Test updated consistently with instruction signature changes.

The test correctly updates to use MAGIC_PROGRAM_ID instead of TASK_CONTEXT_PUBKEY, maintaining consistency with other test updates in this PR.

Also applies to: 38-46

magicblock-magic-program-api/src/tls.rs (1)

1-32: LGTM: Well-designed thread-local task stash.

The implementation correctly uses thread-local storage with interior mutability for per-executor-thread task queuing. Key design points:

  • FIFO ordering (push_back/pop_front) is appropriate for task queue semantics
  • No size limits on the queues is acceptable because the caller (processing.rs) clears unconditionally after each transaction (line 99) and in simulate paths (line 147), preventing unbounded accumulation
  • Thread-local isolation ensures tasks don't leak between executor threads
magicblock-core/src/link.rs (1)

65-86: Task channel wiring LGTM.
Channel creation and hand-off mirror the existing pattern for other endpoints, and wrapping the dispatch receiver in Option lets downstream consumers take() ownership safely.

magicblock-magic-program-api/src/args.rs (1)

119-148: TaskRequest shape is clean.
The enum plus id() helper keep schedule/cancel aligned and make downstream code straightforward to match on identifiers.

magicblock-api/src/magic_validator.rs (1)

332-343: Task scheduler initialization looks solid.
Passing ownership of the dispatch tasks_service receiver into TaskSchedulerService::new here completes the new TLS-driven flow without leaving dangling consumers.

Comment on lines 89 to 91
let _ = self.tasks_tx.send(task).inspect_err(|_|
warn!("Scheduled tasks service has hung up and longer running")
);
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 5, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in warning message.

Line 90: "and longer running" should be "is no longer running" for grammatical correctness.

Apply this diff:

-                        let _ = self.tasks_tx.send(task).inspect_err(|_|
-                            warn!("Scheduled tasks service has hung up and longer running")
-                        );
+                        let _ = self.tasks_tx.send(task).inspect_err(|_|
+                            warn!("Scheduled tasks service has hung up and is no longer running")
+                        );
📝 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
let _ = self.tasks_tx.send(task).inspect_err(|_|
warn!("Scheduled tasks service has hung up and longer running")
);
let _ = self.tasks_tx.send(task).inspect_err(|_|
warn!("Scheduled tasks service has hung up and is no longer running")
);
🤖 Prompt for AI Agents
In magicblock-processor/src/executor/processing.rs around lines 89 to 91, the
warn! message contains a typo "and longer running"; change the log string to
read "is no longer running" for correct grammar. Update the closure passed to
inspect_err so the warn! call prints "Scheduled tasks service has hung up and is
no longer running" (preserving surrounding code and punctuation).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in b282868

Copy link
Contributor

Choose a reason for hiding this comment

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

@Dodecahedr0x, thank you for fixing the typo! 🎉


🧠 Learnings used
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-processor/src/scheduler/locks.rs:110-122
Timestamp: 2025-11-04T10:53:50.922Z
Learning: In magicblock-processor, the TransactionScheduler runs in a single, dedicated thread and will always remain single-threaded. The `next_transaction_id()` function in scheduler/locks.rs uses `unsafe static mut` which is safe given this architectural guarantee.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: test-kit/src/lib.rs:275-0
Timestamp: 2025-11-07T13:09:52.253Z
Learning: In test-kit, the transaction scheduler in ExecutionTestEnv is not expected to shut down during tests. Therefore, using `.unwrap()` in test helper methods like `schedule_transaction` is acceptable and will not cause issues in the test environment.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 596
File: magicblock-processor/src/scheduler.rs:1-1
Timestamp: 2025-10-28T13:15:42.706Z
Learning: In magicblock-processor, transaction indexes were always set to 0 even before the changes in PR #596. The proper transaction indexing within slots will be addressed during the planned ledger rewrite.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/http/get_program_accounts.rs:17-25
Timestamp: 2025-10-21T13:06:38.900Z
Learning: The magicblock validator does not support ledger forking, so commitment-based state queries (processed/confirmed/finalized) are not applicable. RPC methods can safely ignore commitment and minContextSlot parameters from Solana RPC config objects.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 587
File: test-manual/Cargo.toml:0-0
Timestamp: 2025-10-26T16:54:39.084Z
Learning: In the magicblock-validator repository, use git branch references (not commit hashes or tags) for the helius-laserstream dependency to allow automatic updates when the branch is pushed to.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-aperture/src/requests/http/get_fee_for_message.rs:25-31
Timestamp: 2025-11-04T13:22:38.811Z
Learning: In magicblock-aperture, request size validation (including limits on message size) is enforced at the request ingestion layer, before handlers like get_fee_for_message are invoked. Therefore, handlers do not need additional size guards on decoded data.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/encoder.rs:176-187
Timestamp: 2025-10-21T11:00:18.396Z
Learning: In the magicblock validator, the current slot is always the root slot. The SlotEncoder in magicblock-aperture/src/encoder.rs correctly sets `root: slot` because there is no lag between current and root slots in this architecture.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-processor/src/scheduler/mod.rs:217-219
Timestamp: 2025-11-04T10:48:00.070Z
Learning: In magicblock-validator, the codebase uses a pattern where types containing non-Send/non-Sync fields (like Rc<RefCell<...>>) are marked with unsafe impl Send when they are guaranteed to be confined to a single thread through careful API design and thread spawning patterns.

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (1)
magicblock-processor/src/executor/processing.rs (1)

54-60: Critical: ExecutionTlsStash not cleared on early return.

When a transaction fails to load, the function returns early without clearing the ExecutionTlsStash. Any tasks added during the failed execution will leak into the next transaction, potentially causing incorrect task scheduling.

Apply this diff to clear the stash before the early return:

     if let Err(err) = result {
         let status = Err(err);
         self.commit_failed_transaction(txn, status.clone());
         FAILED_TRANSACTIONS_COUNT.inc();
+        ExecutionTlsStash::clear();
         tx.map(|tx| tx.send(status));
         return;
     }
♻️ Duplicate comments (2)
magicblock-task-scheduler/tests/service.rs (1)

74-87: Remove redundant sleep before polling loop.

The fixed 10ms sleep at line 75 is unnecessary because the polling loop (lines 78-84) immediately follows and will efficiently wait for the account mutation. The polling loop already handles the timing correctly with its 20ms interval and 1-second timeout.

Apply this diff to remove the redundant sleep:

-    // Wait the task scheduler to receive the task
-    tokio::time::sleep(Duration::from_millis(10)).await;
-
     // Wait until the task scheduler actually mutates the account (with an upper bound to avoid hangs)
     tokio::time::timeout(Duration::from_secs(1), async {
magicblock-processor/src/executor/processing.rs (1)

89-91: Already flagged: Typo in warning message + optional improvement.

The typo "and longer running" → "is no longer running" was already flagged in a previous review.

Additionally, the error is not captured in the closure, so the actual error details aren't logged. Consider capturing and logging it for better diagnostics.

Apply this diff to fix both issues:

-                        let _ = self.tasks_tx.send(task).inspect_err(|_|
-                            warn!("Scheduled tasks service has hung up and is longer running")
+                        let _ = self.tasks_tx.send(task).inspect_err(|e|
+                            warn!("Scheduled tasks service has hung up and is no longer running: {e}")
                         );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a9aced and b282868.

📒 Files selected for processing (4)
  • magicblock-processor/src/executor/processing.rs (4 hunks)
  • magicblock-task-scheduler/tests/service.rs (1 hunks)
  • programs/guinea/src/lib.rs (5 hunks)
  • programs/magicblock/src/validator.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-11-07T13:09:52.253Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: test-kit/src/lib.rs:275-0
Timestamp: 2025-11-07T13:09:52.253Z
Learning: In test-kit, the transaction scheduler in ExecutionTestEnv is not expected to shut down during tests. Therefore, using `.unwrap()` in test helper methods like `schedule_transaction` is acceptable and will not cause issues in the test environment.

Applied to files:

  • magicblock-processor/src/executor/processing.rs
  • magicblock-task-scheduler/tests/service.rs
📚 Learning: 2025-11-07T13:20:13.793Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-processor/src/scheduler/coordinator.rs:227-238
Timestamp: 2025-11-07T13:20:13.793Z
Learning: In magicblock-processor's ExecutionCoordinator (scheduler/coordinator.rs), the `account_contention` HashMap intentionally does not call `shrink_to_fit()`. Maintaining slack capacity is beneficial for performance by avoiding frequent reallocations during high transaction throughput. As long as empty entries are removed from the map (which `clear_account_contention` does), the capacity overhead is acceptable.

Applied to files:

  • magicblock-processor/src/executor/processing.rs
  • programs/guinea/src/lib.rs
  • magicblock-task-scheduler/tests/service.rs
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Applied to files:

  • programs/guinea/src/lib.rs
📚 Learning: 2025-11-07T14:20:31.425Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs:457-495
Timestamp: 2025-11-07T14:20:31.425Z
Learning: In magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs, the unsubscribe closure returned by PubSubConnection::account_subscribe(...) resolves to () (unit), not a Result. Downstream code should not attempt to inspect an unsubscribe result and can optionally wrap it in a timeout to guard against hangs.

Applied to files:

  • programs/guinea/src/lib.rs
  • magicblock-task-scheduler/tests/service.rs
📚 Learning: 2025-10-14T09:56:14.047Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 564
File: test-integration/programs/flexi-counter/src/processor/call_handler.rs:122-125
Timestamp: 2025-10-14T09:56:14.047Z
Learning: The file test-integration/programs/flexi-counter/src/processor/call_handler.rs contains a test smart contract used for integration testing, not production code.

Applied to files:

  • magicblock-task-scheduler/tests/service.rs
🧬 Code graph analysis (2)
magicblock-processor/src/executor/processing.rs (1)
magicblock-magic-program-api/src/tls.rs (2)
  • next_task (22-24)
  • clear (26-31)
magicblock-task-scheduler/tests/service.rs (2)
programs/magicblock/src/validator.rs (1)
  • init_validator_authority_if_needed (54-62)
test-kit/src/lib.rs (1)
  • new (83-85)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: Build Project
🔇 Additional comments (15)
magicblock-task-scheduler/tests/service.rs (9)

1-18: LGTM!

The imports are well-organized and all appear necessary for the integration tests.


19-45: LGTM! Test setup is thorough.

The test properly initializes the execution environment, validator authority, and task scheduler service. The use of expect on the ledger parent path and tasks service is acceptable in test code.


47-72: LGTM! Task scheduling logic is correct.

The test correctly constructs a ScheduleTask instruction with a single Increment instruction and properly asserts the transaction execution succeeds.


77-87: LGTM! Polling loop properly addresses past flakiness concerns.

The bounded retry with timeout and polling correctly replaces the previous fixed sleep, making the test resilient to scheduler timing variations. The 20ms poll interval and 1-second timeout are reasonable values.


89-92: LGTM! Cleanup is correct.

Canceling the token and awaiting the handle ensures proper shutdown of the task scheduler service.

Based on learnings


151-166: LGTM! Polling loop properly addresses past flakiness concerns.

The bounded retry correctly waits until at least 5 executions are observed before proceeding with cancellation. The 20ms poll interval and 2-second timeout are appropriate for this test.


168-183: LGTM! Task cancellation logic is correct.

The test properly constructs and executes the CancelTask instruction.


196-209: LGTM! Cancellation verification is thorough.

The test correctly waits for multiple intervals after cancellation and verifies that the account value remains unchanged, confirming that the scheduler stopped executing the task.


211-214: LGTM! Cleanup is correct.

Canceling the token and awaiting the handle ensures proper shutdown of the task scheduler service.

Based on learnings

magicblock-processor/src/executor/processing.rs (2)

98-99: LGTM: Unconditional stash clearing.

The stash is correctly cleared after transaction processing, ensuring no tasks leak between transactions (once the early-return issue at line 60 is fixed).


145-147: LGTM: Simulation stash clearing.

Correctly clears the stash after simulation without draining tasks, preventing simulations from scheduling actual tasks or interfering with real execution.

programs/guinea/src/lib.rs (4)

4-14: LGTM! Imports are appropriate for CPI.

All new imports (ScheduleTaskArgs, MagicBlockInstruction, AccountMeta, Instruction, invoke) are properly used in the new task scheduling functions.


23-32: LGTM! New instruction variants are well-defined.

The Increment, ScheduleTask, and CancelTask variants are properly typed and consistent with the existing enum style.


104-114: Good! Past review feedback has been addressed.

The previous review flagged that _magic_program_info was extracted but never validated. The current implementation correctly:

  • Removes the underscore prefix (line 104)
  • Validates the program ID matches magicblock_magic_program_api::ID (lines 108-110)
  • Validates the payer is a signer (lines 112-114)

176-184: LGTM! Instruction routing is correct.

The new instruction variants are properly routed to their respective handler functions with appropriate error propagation.

self.commit_accounts(feepayer, &processed, is_replay);

// And commit transaction to the ledger
// Commit transaction to the ledger and schedule tasks and intents (if any)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Comment mentions intents but code doesn't process them.

The comment references scheduling intents, but the code at lines 86-92 only drains and sends tasks. Intents are cleared at line 99 but never processed.

If intents are not yet implemented or handled elsewhere, consider updating the comment for clarity.

Apply this diff if intents are not handled here:

-            // Commit transaction to the ledger and schedule tasks and intents (if any)
+            // Commit transaction to the ledger and schedule tasks (if any)
📝 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
// Commit transaction to the ledger and schedule tasks and intents (if any)
// Commit transaction to the ledger and schedule tasks (if any)
🤖 Prompt for AI Agents
magicblock-processor/src/executor/processing.rs around line 80: the inline
comment mentions "schedule tasks and intents" but the surrounding code only
drains and schedules tasks and then clears intents without processing them;
either update the comment to remove or clarify the intents part if intent
handling is implemented elsewhere, or implement intent processing here (drain
intents like tasks, schedule/send them appropriately before clearing, and handle
errors/metrics similarly to tasks). Ensure the final comment accurately reflects
the implemented behavior.

Comment on lines +95 to +121
#[tokio::test]
pub async fn test_cancel_task() -> TaskSchedulerResult<()> {
let mut env = ExecutionTestEnv::new();
let account =
env.create_account_with_config(LAMPORTS_PER_SOL, 1, guinea::ID);

init_validator_authority_if_needed(env.payer.insecure_clone());

let token = CancellationToken::new();
let task_scheduler_db_path = SchedulerDatabase::path(
env.ledger
.ledger_path()
.parent()
.expect("ledger_path didn't have a parent, should never happen"),
);
let handle = TaskSchedulerService::new(
&task_scheduler_db_path,
&TaskSchedulerConfig::default(),
env.transaction_scheduler.clone(),
env.dispatch
.tasks_service
.take()
.expect("Tasks service should be initialized"),
env.ledger.latest_block().clone(),
token.clone(),
)?
.start()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider extracting common setup into a helper function.

The setup code (lines 97-121) is nearly identical to lines 21-45 in test_schedule_task. Extracting the common initialization logic into a helper function would reduce duplication and improve maintainability.

Example helper function:

async fn setup_test_env_with_scheduler(
) -> TaskSchedulerResult<(
    ExecutionTestEnv,
    Signer,
    tokio::task::JoinHandle<TaskSchedulerResult<()>>,
    CancellationToken,
)> {
    let mut env = ExecutionTestEnv::new();
    let account = env.create_account_with_config(LAMPORTS_PER_SOL, 1, guinea::ID);
    
    init_validator_authority_if_needed(env.payer.insecure_clone());
    
    let token = CancellationToken::new();
    let task_scheduler_db_path = SchedulerDatabase::path(
        env.ledger
            .ledger_path()
            .parent()
            .expect("ledger_path didn't have a parent, should never happen"),
    );
    let handle = TaskSchedulerService::new(
        &task_scheduler_db_path,
        &TaskSchedulerConfig::default(),
        env.transaction_scheduler.clone(),
        env.dispatch
            .tasks_service
            .take()
            .expect("Tasks service should be initialized"),
        env.ledger.latest_block().clone(),
        token.clone(),
    )?
    .start()?;
    
    Ok((env, account, handle, token))
}
🤖 Prompt for AI Agents
In magicblock-task-scheduler/tests/service.rs around lines 95 to 121, the test
setup (creating ExecutionTestEnv, account, initializing validator authority,
creating CancellationToken, resolving SchedulerDatabase.path, and starting
TaskSchedulerService) is duplicated from test_schedule_task; extract this
sequence into a single helper function (e.g., setup_test_env_with_scheduler)
that returns the env, account/signers, the started TaskSchedulerService handle,
and the token, replace the duplicated lines in both tests with a call to that
helper, and update imports and return types to use TaskSchedulerResult as
needed.

Comment on lines +185 to +194
let value_at_cancel = env
.get_account(account.pubkey())
.data()
.first()
.copied()
.unwrap_or_default();
assert!(
value_at_cancel >= executed_before_cancel,
"value regressed before cancellation"
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Clarify assertion message.

The assertion checks that the value at cancellation time is at least as large as the value observed when we detected 5 executions. However, the message "value regressed before cancellation" is slightly misleading—this assertion fires when the value at cancel time is LESS than expected, which would actually be impossible given that time has passed and the scheduler may have executed more iterations. Consider a more descriptive message.

Apply this diff to clarify the assertion:

     assert!(
         value_at_cancel >= executed_before_cancel,
-        "value regressed before cancellation"
+        "unexpected: value at cancellation ({}) < value when 5 executions were observed ({})",
+        value_at_cancel,
+        executed_before_cancel
     );
📝 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
let value_at_cancel = env
.get_account(account.pubkey())
.data()
.first()
.copied()
.unwrap_or_default();
assert!(
value_at_cancel >= executed_before_cancel,
"value regressed before cancellation"
);
let value_at_cancel = env
.get_account(account.pubkey())
.data()
.first()
.copied()
.unwrap_or_default();
assert!(
value_at_cancel >= executed_before_cancel,
"unexpected: value at cancellation ({}) < value when 5 executions were observed ({})",
value_at_cancel,
executed_before_cancel
);
🤖 Prompt for AI Agents
In magicblock-task-scheduler/tests/service.rs around lines 185 to 194, the
assertion message "value regressed before cancellation" is misleading; change it
to a clearer message that indicates the observed value at cancellation is
unexpectedly lower than the value recorded when we detected 5 executions (e.g.,
"value at cancellation is less than value observed at 5 executions" or "value
decreased between detection and cancellation"). Replace the assertion's message
string with one of these clearer, more descriptive messages so future failures
show the precise expectation.

Comment on lines +67 to +75
fn increment(accounts: slice::Iter<AccountInfo>) -> ProgramResult {
for a in accounts {
let mut data = a.try_borrow_mut_data()?;
let first =
data.first_mut().ok_or(ProgramError::AccountDataTooSmall)?;
*first += 1;
}
Ok(())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider overflow behavior in increment operation.

The increment operation on line 72 will wrap around when the byte value reaches 255 (wrapping to 0). If this wrapping behavior is unintended, consider adding an overflow check:

-        *first += 1;
+        *first = first.checked_add(1).ok_or(ProgramError::ArithmeticOverflow)?;

However, for a test program like guinea, the wrapping behavior may be acceptable or even intentional.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In programs/guinea/src/lib.rs around lines 67 to 75, the byte increment at line
72 will wrap from 255 to 0; if that is unintended, replace the direct addition
with a checked add and return an error when overflow would occur (e.g., use
u8::checked_add on *first and map None to an appropriate ProgramError or custom
error), or explicitly document the wrapping behavior if intentional. Ensure you
borrow_mut, perform the checked add, set the byte only on success, and return a
clear error when overflow is detected.

Comment on lines +116 to +128
let ix = Instruction::new_with_bincode(
magicblock_magic_program_api::ID,
&MagicBlockInstruction::ScheduleTask(args),
vec![
AccountMeta::new(*payer_info.key, true),
AccountMeta::new(*counter_pda_info.key, false),
],
);

invoke(&ix, &[payer_info.clone(), counter_pda_info.clone()])?;

Ok(())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Include the magic program account in the CPI invoke call.

While the magic_program_info is correctly validated (lines 108-110), it should also be included in the invoke call on line 125. In Solana CPI, passing the program account to invoke is a standard practice that allows the runtime to verify the program is executable and matches the expected program ID.

Apply this diff:

-    invoke(&ix, &[payer_info.clone(), counter_pda_info.clone()])?;
+    invoke(
+        &ix,
+        &[
+            magic_program_info.clone(),
+            payer_info.clone(),
+            counter_pda_info.clone(),
+        ],
+    )?;
🤖 Prompt for AI Agents
In programs/guinea/src/lib.rs around lines 116 to 128, the CPI invoke call omits
the validated magic_program_info account; add magic_program_info.clone() to the
slice of account infos passed to invoke so the runtime can verify the program
account (e.g. invoke(&ix, &[payer_info.clone(), counter_pda_info.clone(),
magic_program_info.clone()])?), keeping the Instruction as-is since the program
ID was already set to magicblock_magic_program_api::ID and ensuring the added
account is the same magic_program_info validated on lines ~108-110.

Comment on lines +137 to +154
if magic_program_info.key != &magicblock_magic_program_api::ID {
return Err(ProgramError::InvalidAccountData);
}

if !payer_info.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}

let ix = Instruction::new_with_bincode(
magicblock_magic_program_api::ID,
&MagicBlockInstruction::CancelTask { task_id },
vec![AccountMeta::new(*payer_info.key, true)],
);

invoke(&ix, &[payer_info.clone()])?;

Ok(())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Include the magic program account in the CPI invoke call.

Similar to schedule_task, the magic_program_info should be included in the invoke call on line 151 for proper CPI execution.

Apply this diff:

-    invoke(&ix, &[payer_info.clone()])?;
+    invoke(&ix, &[magic_program_info.clone(), payer_info.clone()])?;
🤖 Prompt for AI Agents
In programs/guinea/src/lib.rs around lines 137 to 154, the CPI invoke call only
passes payer_info but must include the magic program account as well; update the
invoke call to pass both payer_info.clone() and magic_program_info.clone() (in
the same order expected by the callee) so the CPI has the program account
available during execution.

Comment on lines +54 to +62
pub fn init_validator_authority_if_needed(keypair: Keypair) {
let mut validator_authority_lock = VALIDATOR_AUTHORITY
.write()
.expect("RwLock VALIDATOR_AUTHORITY poisoned");
if validator_authority_lock.as_ref().is_some() {
return;
}
validator_authority_lock.replace(keypair);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM! Idempotent initialization pattern is correct and aligns with PR objectives.

The function correctly implements idempotent initialization by acquiring a write lock, checking if the authority is already set, and returning early if so. This enables stable initialization without panics, supporting the task scheduler refactor.

Optional: Consider reducing code duplication.

Lines 55-57 and 58-60 are duplicated across three initialization functions (init_validator_authority, init_validator_authority_if_needed, and generate_validator_authority_if_needed). Consider extracting a helper function to reduce duplication:

fn with_validator_authority_lock<F>(f: F) 
where
    F: FnOnce(&mut Option<Keypair>),
{
    let mut lock = VALIDATOR_AUTHORITY
        .write()
        .expect("RwLock VALIDATOR_AUTHORITY poisoned");
    f(&mut lock);
}

Optional: Add logging or return value to indicate initialization state.

The function silently does nothing if the authority is already set. While the _if_needed naming makes this clear, consider logging when initialization is skipped or returning a bool to indicate whether initialization occurred. This can help with debugging and prevent subtle bugs where a caller expects to set a specific keypair but a different one was already set.

🤖 Prompt for AI Agents
programs/magicblock/src/validator.rs around lines 54 to 62, duplicate
lock-and-init logic appears in init_validator_authority,
init_validator_authority_if_needed, and generate_validator_authority_if_needed;
extract a small helper that acquires the VALIDATOR_AUTHORITY write lock and
invokes a closure with &mut Option<Keypair> to centralize the lock handling and
mutation, then refactor the three functions to call that helper instead of
repeating the lock/replace pattern; additionally consider changing the
_if_needed variant to return a bool indicating whether it performed
initialization (or emit a debug log when initialization is skipped or performed)
so callers can observe the outcome.

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.

Do not use a ticker for task scheduling

3 participants