Skip to main content

Crate svmscope

Crate svmscope 

Source
Expand description

Decode, reconstruct, replay, and mutate Solana transactions.

Point svmscope at a mainnet signature and it (1) decodes the transaction — the full cross-program invocation tree with every instruction named from its on-chain Anchor IDL or known native layout, balance and token changes, and compute units per program; (2) replays it locally in an embedded SVM (LiteSVM), re-executing the real program binaries against the transaction’s reconstructed state; and (3) mutates — change an account’s lamports or data, warp the clock, flip feature gates, then replay again to ask “what if this had been different?”.

§Installation

svmscope is a testing tool, so add it as a dev-dependency:

cargo add --dev svmscope

or in Cargo.toml:

[dev-dependencies]
svmscope = "0.4"

§Quickstart

Two nouns: a Scope fetches and caches, a Replay is one transaction’s reconstructed world. All RPC happens in Scope::replay; every run after that is local and free.

use svmscope::{Mutation, Scope};

let scope = Scope::new("https://api.mainnet-beta.solana.com");
let sig = "your transaction signature";

// 1. Decode: CPI tree, named instructions, balance/token diffs, CU per program.
let analysis = scope.analyze(sig)?;
println!("fee: {} lamports, {} top-level instructions",
         analysis.overview.fee, analysis.cpi_tree.len());

// 2. Replay the real programs locally in LiteSVM.
let mut replay = scope.replay(sig)?;
println!("replay success: {}", replay.run()?.result.success);

// 3. What-if: zero out an account, jump 30 days ahead, and replay again —
//    zero further RPC.
replay.advance_seconds(30 * 86_400);
let what_if = replay.simulate(&[Mutation::lamports("SomeAccount111...", 0)])?;
println!("mutated replay success: {}", what_if.result.success);

§Building and submitting transactions

You don’t have to start from an existing signature. Against a local validator, Scope::program_with_idl gives an IDL-driven builder: pick a method, supply accounts and JSON arguments, and MethodBuilder::send_and_capture signs, submits, waits for the transaction to land, and returns a CapturedTransaction whose replay holds the exact pre-transaction world — ready for mutation and time travel with no further RPC.

let captured = scope
    .program_with_idl(program_id, idl)
    .method("setValue")?
    .payer(&payer)
    .account("state", state)
    .args(json!({ "value": 42 }))?
    .send_and_capture()?;
println!("landed: {}", captured.signature);

§Hermetic testing

Replays against live RPC state drift as the chain moves on. To pin a transaction’s world forever, Scope::capture snapshots the transaction, every account it touched, and every program ELF into a Fixture; Replay::from_fixture then rebuilds the world and runs what-if scenario suites (mutations + expectations + named-field assertions) against that frozen state — offline, deterministic, CI-friendly.

§Public API

Consumer-facing types are re-exported from the crate root. Prefer imports such as svmscope::{Scope, Replay, Mutation, Check, Fixture}; implementation modules are private. The idl, report, and spec modules expose the specialized IDL, HTML-report, and JSON-suite APIs.

§Errors

A reverting replay is not an error — it comes back as a successful observation with result.success == false. Error always means svmscope itself couldn’t do what was asked (RPC failure, unknown transaction, a mutation targeting an account that isn’t loaded, an unknown field name…).

§Feature flags

None — the crate is a plain library. The HTTP API server lives in a separate (unpublished) workspace crate, so library consumers never compile axum/tokio.

This same library powers the svmscope CLI, the HTTP API, and the hosted UI at https://svmscope.vercel.app — identical results in all four.

Re-exports§

pub use scan::scan_breaking_points;
pub use scan::BreakingPoint;
pub use scan::ScanOptions;

Modules§

idl
On-chain Anchor IDL fetching, parsing, and account/instruction decoding.
profile
Compute profiler: where every BPF instruction of a transaction went.
reconstruct
Historical state reconstruction — rebuild an account’s state at a past slot by replaying its own write history forward, instead of buying it from a paid archive. This is the free, self-owned path to “replay at any slot”.
report
Render a scenario-suite run as a self-contained HTML report — the human-facing artifact an auditor attaches to a finding (“here’s what happens under each edge case”). No external assets, opens offline.
scan
Auto breaking-point scan — the deterministic “beast” that finds every single-change way a transaction can break, driven by each account’s schema.
spec
The JSON suite-file format — the on-disk spec for svmscope test, and the wire types the web server and browser share.

Structs§

AccountCheck
Builder for state checks against one account, finished with AccountCheck::build. All checks read post-replay state; *_delta variants compare against the pre-transaction value.
AccountDiff
One account’s before → after, with named field changes where the layout is known.
AccountInfo
One account’s summary plus (if recognized) its decoded fields.
AccountOverview
An account/program’s on-chain overview — what an explorer’s address page shows.
AccountProvenance
One account’s provenance within a replay.
AccountRole
An account’s role in the transaction — the signer/writable classification Solana Explorer’s inspector shows, derived from the message header + key ordering (static writable-signers, readonly-signers, writable-unsigned, readonly-unsigned, then ALT writable, then ALT readonly).
AccountState
A reconstructed account’s raw state — its data bytes, lamports, and owner.
Analysis
The full analysis of a transaction — the payload the CLI prints and the API serves.
AssertOutcome
The result of one post-replay assertion.
BalanceChange
A change in an account’s SOL (lamport) balance.
CapturedTransaction
A submitted transaction together with the pre-transaction world captured for deterministic local replay, mutation, and time travel.
Check
One declarative check on a replay’s outcome or resulting state. Construct via the associated functions; combine on a Scenario.
Cmp
A comparison against a numeric value: Cmp::eq(5), Cmp::ge(-100).
CpiEntry
One instruction in the transaction’s cross-program invocation tree.
CuUsage
Compute units one program consumed within a transaction.
DecodedAccount
A recognized account, broken into named fields.
DecodedEvent
One Anchor event, decoded.
Diagnosis
A plain-English diagnosis of a transaction’s outcome.
Explanation
A program failure translated into plain language.
FeatureToggle
A Solana runtime feature gate to flip for a replay: activate one that isn’t live on mainnet yet (“will my tx still work when this ships?”), or deactivate an active one. Most execution-affecting SIMDs land on-chain as one of these.
FidelityCertificate
An honest report of how faithful a replay’s starting state is: the verdict, where every account’s bytes came from, which accounts may have drifted from the transaction’s true slot, and whether there is a recorded on-chain outcome to check the replay against. Trust is a product feature — svmscope should never silently hand back a convincing but historically inaccurate replay.
Field
One field within a decoded account.
FieldDiff
One named field’s before → after inside an AccountDiff.
Fixture
A portable, self-contained snapshot of a transaction and its world.
Invariant
A named security property over a replay’s resulting state. Every constructor returns a Check; drop it into a Scenario or Replay::verify alongside your mutations.
IxAccount
One account an instruction touches, with its IDL role name where known.
IxArg
One decoded instruction argument.
MethodBuilder
A fluent request to invoke one IDL method.
OnchainRecord
The transaction’s actual on-chain outcome, kept alongside the replay so local results can be compared against what really happened.
Overview
Headline facts about the transaction as it actually ran on-chain.
PatchComparison
The result of replaying a transaction against an original program and a patched one — the pre-deployment “does this patch change what happened?” gate.
PreflightIx
One decoded top-level instruction of a pre-flight transaction.
PreflightOverview
The pre-sign overview block of a crate::SimulationReport.
ProgramClient
An IDL-backed client for one deployed Solana program.
ProgramInfo
Deployment details for an executable program account.
Replay
A transaction’s reconstructed world — fetched once via Scope::replay, then replayed locally any number of times. Every run builds a pristine SVM, so runs are independent, repeatable, and free.
ReplayResult
The outcome of one local replay run.
Replayed
The outcome of one local replay: the result itself, what changed, and — on failure — a plain-language explanation.
ReturnData
Return data a program set during a step.
Scenario
One named test case: what-if mutations plus the checks that must hold. A scenario with no outcome check implicitly asserts Check::success.
ScenarioOutcome
The result of running one scenario.
Scope
An RPC-backed client with caches. Everything svmscope fetches — transaction JSON, program IDLs — is fetched once per Scope and reused, so analyze(sig) followed by replay(sig) costs one transaction fetch, and repeated simulations cost zero.
SigInfo
One entry in an address’s recent transaction history.
SimulationReport
A simulation result enriched with what a developer actually needs: a human-readable failure reason and the field-level account diff.
Step
One instruction or CPI.
StepAccountState
One account as it stands after a step.
StepDiff
One step’s before/after across two traces. None on a side means the step did not execute in that trace (an earlier step failed).
StepError
A failure attributed to a step.
StepSummary
One step’s outcome, compact enough to compare across two traces.
Threshold
The result of a counterfactual threshold search: the value at which the transaction’s outcome flips, and the outcomes at the search bounds.
TimeTravel
Move the SVM’s clock forward (or to an absolute point) so time-gated program logic can be tested without waiting: unstake after an epoch, claim after a vesting cliff, withdraw after a cooldown, settle after an auction ends.
TokenChange
A change in an SPL token account’s balance, in raw base units (client divides by 10^decimals for display).
Trace
The whole transaction, unrolled.
TraceDiff
What changed between two traces of the same transaction (typically before and after a mutation).

Enums§

Error
Everything that can go wrong short of the transaction itself reverting.
Fidelity
How faithful a replay’s starting state is to the transaction’s real slot — the honest label on every replay, so a convincing-but-drifted run is never mistaken for an exact one.
FixtureEntry
One captured account: either a data account (loaded verbatim) or a program (its resolved ELF bytecode, ready for LiteSVM’s loader).
Mutation
A change to apply to an account before replaying.
Provenance
Where an account’s loaded bytes came from — the honest per-account source.

Constants§

FIXTURE_VERSION
The highest fixture schema version this build reads and writes.

Functions§

compute_breakdown
Per-program compute breakdown for a preflight simulation — fills PreflightOverview::compute once the simulation has produced logs and a total. Same attribution as the analyze view’s Compute Units panel.
resolve_rpc_url
Resolve a cluster name or explicit RPC URL to an endpoint. Precedence: explicit rpc URL > cluster name > default.

Type Aliases§

Result
Convenience alias used across the crate.