refactor: Move ClarityRuntimeTxError into clarity and expose whether failed txs are included in block - #7486
Open
jbencin-stacks wants to merge 11 commits into
Conversation
jbencin-stacks
force-pushed
the
refactor/clarity-runtime-tx-error
branch
from
August 4, 2026 22:32
d3187e2 to
aa0fa92
Compare
Move `ClarityRuntimeTxError` and `handle_clarity_runtime_error` from `stackslib` to `clarity`, and add `ClarityRuntimeTxError::is_included_in_block` plus `analysis_failure_is_included_in_block`. This will allow Clarinet to tell if a failed transaction was included in a block, and whether to charge the sender a fee and increment its nonce. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jbencin-stacks
force-pushed
the
refactor/clarity-runtime-tx-error
branch
from
August 10, 2026 18:09
aa0fa92 to
94b2f43
Compare
jbencin-stacks
marked this pull request as ready for review
August 11, 2026 19:22
ClarityRuntimeTxError into clarity and expose whether failed txs are included in blockClarityRuntimeTxError into clarity and expose whether failed txs are included in block
dhaney-stacks
requested review from
aaronb-stacks,
brice-stacks and
hstove-stacks
and removed request for
aaronb-stacks
August 13, 2026 16:26
jbencin-stacks
added a commit
to jbencin-stacks/clarinet
that referenced
this pull request
Aug 17, 2026
Repoint the seven stacks-core git dependencies at jbencin-stacks/stacks-core rev 87f95946, the head of stacks-network/stacks-core#7486, which moves `ClarityRuntimeTxError` into `clarity` and exposes whether a failed transaction is included in a block. Clarinet needs that to decide nonce consumption without re-deriving the rule; the previous pin `b17d3a12` is 103 commits behind its base. Migration fallout from that jump, all mechanical: - `EvalHook` moved to `clarity::vm::hooks`. The trait itself is unchanged for our purposes — `will_begin_eval`, `did_finish_eval` and `did_complete` keep their signatures, and upstream documents `did_complete` as clarinet-driven — so this is an import change only. - `clarity::vm::time_tracker` is gone; `run_analysis` now takes a `ResourceLimiter`. - `CallableType`'s native/special variants moved under `CallableType::Builtin { kind: BuiltinKind::… }`. - Upstream added `StacksEpochId::Epoch41`, so the exhaustive matches in `clarity-static-cost` and `datastore.rs` gain an arm. Clarinet has no `EpochSpec` for 4.1, cannot name it in a manifest, and still defaults to 4.0, so `From<StacksEpochId> for EpochSpec` mirrors its existing `Epoch10` arm rather than growing user-facing 4.1 surface here. `set_epoch_command` asserted that `StacksEpochId::latest()` is settable, which stopped holding the moment 4.1 landed upstream. Re-aim it at the epoch clarinet actually supports, pin 4.1 as the known-pending one so the test fires again on the next upstream epoch, and assert that an unadopted epoch is reported as unusable instead of silently ignored. Verified: 996 Rust tests pass; the 15 failures are the pre-existing network-dependent `mxs` tests, which fail identically on `main`. `cargo fmt-stacks --check`, both clippy invocations, and `pnpm run build:sdk-wasm` are clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jbencin-stacks
added a commit
to jbencin-stacks/clarinet
that referenced
this pull request
Aug 17, 2026
Bump the sender's nonce for every simnet operation that is a transaction — contract deploys, STX transfers, public and private contract calls, and a deployment plan's emulated contract calls. The hard part is not *which* operations are transactions but *which failures still count as one*. Mainnet mines a transaction that reverts: the fee is charged and the nonce advances even though the call failed. Deciding that by hand means re-deriving a consensus rule that changes whenever a `ClarityError` variant is added upstream, so the decision is delegated to `clarity`'s `handle_clarity_runtime_error` / `handle_clarity_analysis_error` (stacks-network/stacks-core#7486), which the node itself calls on the block assembly path. `BlockInclusion` is the only place clarinet touches it. Getting the verdict to the bump sites required keeping the typed `ClarityError` alive: `interpreter.rs` used to flatten every failure into `format!("Runtime error while interpreting …")` before anyone could classify it. Failures now carry `ExecutionError { diagnostics, inclusion }` (or `ContractCallFailure` / `OperationFailure` at the call and wasm layers). Every `Display` output is unchanged, so the tracer hook, `interpreter.rs`'s runtime error test, and `simnet-usage.test.ts` need no edits. `Session::eval` keeps its diagnostics-only signature — it also backs bare REPL snippets and function-argument evaluation, which are not transactions — and `stx_transfer` uses a private `eval_with_inclusion` instead. Likewise `Session::call_contract_fn` stays nonce-neutral because `callReadOnlyFn` shares it; only callers that know an operation is a transaction bump. This closes three divergences the previous approach had, where clarinet keyed the bump off `result.is_ok()`: divide-by-zero and `unwrap-panic` (`Runtime` / `EarlyReturn` → `Acceptable`), and a deploy that fails analysis or parsing with a non-`rejectable_in_epoch` error. All three are reported as failures by clarinet but mined by mainnet. Tests were mutation-checked rather than assumed. Restoring the `is_ok()` rule fails exactly the three new divergence tests and no others. Separately, mapping every failure to `Included` passed the entire suite — the end-to-end tests can only reach *included* failures, since cost overruns and `rejectable_in_epoch` errors are impractical to provoke from contract source — so `block_inclusion_delegates_to_clarity` pins both directions directly; it fails under either an always-included or an always-rejected mutation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
brice-stacks
left a comment
Contributor
There was a problem hiding this comment.
I think this looks good, I just had a couple of naming comments, but feel free to push back.
1 task
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.
Description
This PR contains a couple more changes needed for Clarinet:
ClarityRuntimeTxErrorintoclarity, so it builds for WASMClarityRuntimeTxErrorto make it clear which failed transactions are included in blocksis_included_in_block()so Clarinet can tell if failed transaction was included in blockThis will expose information to Clarinet about why a transaction failed, which it needs to know if the transaction charges a fee and consumes a nonce
Applicable issues
Additional info (benefits, drawbacks, caveats)
Checklist
docs/property-testing.md)changelog.d/README.md)rpc/openapi.yamlfor RPC endpoints,event-dispatcher.mdfor new events)clarity-benchmarkingrepo