feat(context): add ClockContext for opt-in timestamp/block_id access#227
Draft
vpavlin wants to merge 4 commits into
Draft
feat(context): add ClockContext for opt-in timestamp/block_id access#227vpavlin wants to merge 4 commits into
vpavlin wants to merge 4 commits into
Conversation
Adds `ClockContext` as a new injected parameter type for `#[instruction]` handlers, giving programs access to the current block number and timestamp without adding them to the instruction ABI or IDL. The dispatcher reads the LEZ clock account (`/LEZ/ClockProgramAccount/0000001`) from `pre_states[0]`, borsh-decodes it into `ClockContext`, and injects it into the handler call — exactly like `ProgramContext`. Transaction builders (ffi_codegen, codegen, logos_module_codegen) automatically prepend the clock account ID when `has_clock_context` is set in the IDL. Closes #226 (option 1 of the design discussion). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The setup-logos-blockchain-circuits.sh script was removed from the logos-blockchain/logos-blockchain repo on 2026-05-30 (commit 89259924) in "chore: Purge old circuits (#2829)". The curl call now fetches a 404 page and bash interprets "404: Not Found" as a command, causing all E2E jobs to fail immediately with exit code 127. The step was never needed for CI: the sequencer is built with `--features standalone`, which activates `sequencer_core/mock` and replaces actual ZK proof generation with mock implementations. Circuits are only required for production proving. Also removes two duplicate occurrences of the step in the privacy-smoke-test and ffi-call-test jobs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in ClockContext execution parameter to instruction handlers so programs can access the current LEZ block timestamp and block ID without adding new ABI/IDL arguments, and wires that opt-in through IDL + client generators so callers automatically prepend the LEZ clock account.
Changes:
- Introduces
ClockContext { block_id, timestamp }(borsh-decodable) inspel-framework-coreand re-exports it via the prelude. - Updates the proc-macro dispatcher and IDL generation to detect
ClockContext, inject it frompre_states[0], and emithas_clock_contextin the IDL. - Updates Rust client codegen and FFI codegen to prepend
/LEZ/ClockProgramAccount/0000001whenhas_clock_contextis set; adds unit tests forClockContext.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
spel-framework-macros/src/lib.rs |
Detects ClockContext, injects it from pre_states[0], reinserts unchanged post-state, and emits has_clock_context in IDL outputs. |
spel-framework-core/src/context.rs |
Adds the ClockContext struct and constructor. |
spel-framework-core/src/lib.rs |
Re-exports ClockContext through prelude. |
spel-framework-core/src/idl.rs |
Adds has_clock_context: bool to IdlInstruction (serde default/skip when false). |
spel-framework-core/src/idl_gen.rs |
Parses ClockContext and propagates has_clock_context into IDL generation. |
spel-framework-core/tests/context_parameter.rs |
Adds unit tests for ClockContext construction/traits/borsh decode behavior. |
spel-client-gen/src/codegen.rs |
Prepends the LEZ clock account ID when ix.has_clock_context is true. |
spel-client-gen/src/ffi_codegen.rs |
Prepends the LEZ clock account ID when ix.has_clock_context is true. |
spel-client-gen/src/tests.rs |
Updates IDL test fixtures to include has_clock_context. |
.github/workflows/ci.yml |
Removes Install logos-blockchain-circuits step(s) from CI jobs. |
.github/workflows/weekly-rc.yml |
Removes Install logos-blockchain-circuits step. |
.github/workflows/release.yml |
Removes Install logos-blockchain-circuits step. |
.github/workflows/lez-compat.yml |
Removes Install logos-blockchain-circuits step. |
.github/workflows/lez-compat-improved.yml |
Removes Install logos-blockchain-circuits step. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+869
to
+876
| let mut __ps = pre_states; | ||
| if __ps.is_empty() { | ||
| panic!("SPEL ClockContext: expected clock account as first pre_state, found none"); | ||
| } | ||
| let __c = __ps.remove(0); | ||
| let __ctx = borsh::from_slice::<spel_framework::context::ClockContext>(&__c.account.data) | ||
| .expect("SPEL ClockContext: failed to decode clock account data"); | ||
| (__c, __ctx, __ps) |
Comment on lines
605
to
+609
| } else if is_context_type(ty) { | ||
| // ProgramContext is injected by the dispatcher and never part of the IDL/ABI. | ||
| } else if is_clock_context_type(ty) { | ||
| // ClockContext is injected by the dispatcher and never part of the IDL/ABI. | ||
| has_clock_context = true; |
Comment on lines
31
to
36
| - uses: dtolnay/rust-toolchain@stable | ||
| - uses: Swatinem/rust-cache@v2 | ||
| with: | ||
| prefix-key: "e2e" | ||
| - name: Install logos-blockchain-circuits | ||
| run: | | ||
| curl -sSL https://raw.githubusercontent.com/logos-blockchain/logos-blockchain/main/scripts/setup-logos-blockchain-circuits.sh | bash | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Build (all packages including spel) | ||
| run: cargo build -p spel-framework -p spel-framework-core -p spel-framework-macros -p spel-client-gen -p spel |
54419c0 to
d817125
Compare
- Apply rustfmt: expand single-line writeln! calls and struct literal in ClockContext::new to conform to the project's 100-char line limit - Restore the logos-blockchain-circuits install step in ci.yml with the pinned commit hash; removing it was wrong — cargo build -p spel triggers the circuits build.rs check even in tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Validate clock account ID before decoding ClockContext: compare pre_states[0].account_id against the well-known LEZ clock account address (*b"/LEZ/ClockProgramAccount/0000001"). Without this, a caller could supply an attacker-controlled account at position 0 to forge timestamp/block_id values seen by the handler. - Mirror proc-macro constraints in idl_gen: reject duplicate ClockContext parameters and ClockContext appearing after account/arg params. The proc-macro already enforces these; idl_gen now matches so that it cannot produce an IDL that claims ClockContext injection for a signature the macro would refuse to compile. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Option 1 from the design discussion in #226: a
ClockContextparameter that gives instruction handlers opt-in access to the current block number and timestamp without polluting the ABI or IDL.ClockContext { block_id: BlockId, timestamp: Timestamp }struct inspel-framework-core(borsh-decodable, matches LEZClockAccountDatalayout)ClockContextby type name (same asProgramContext) and injects it frompre_states[0]has_clock_context: booladded toIdlInstruction— transaction builders (FFI, Rust client codegen) automatically prepend the LEZ clock account (/LEZ/ClockProgramAccount/0000001) when the flag is setidl_gen.rsupdated to parse and propagate the new context typeClockContextconstruction, copy/clone, equality, debug, borsh roundtrip, and borsh error pathUsage
Instructions that do not declare
ClockContextare completely unaffected — no breaking changes.Implementation notes
pre_states_clone.zip(post_states)loop in the generatedmain()stays aligned.ClockContextmust come before any account or arg parameters (enforced at macro parse time). It may followProgramContextor appear first if there is noProgramContext.CLOCK_01(updated every block,*b"/LEZ/ClockProgramAccount/0000001"). Cadence selection can be added as a follow-up.Test plan
cargo test --workspace --exclude spel-ffi-compile-test)test_clock_context_*tests inspel-framework-core/tests/context_parameter.rsall passClockContextand verify the generated IDL contains"has_clock_context":truehas_clock_contextis setCloses #226 (Option 1)
🤖 Generated with Claude Code