Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "simbolik-komet",
"name": "stellar-debugger",
"build": {
"dockerfile": "Dockerfile"
},
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ jobs:
- name: Build
run: npm run build

# Guards the allowlist-shaped .vscodeignore. `vsce` packages from the disk,
# not from git, so a denylist regression quietly ships the committed wasm
# fixtures here — and gigabytes of Rust `target/` output on a dev machine.
- name: Package, and check the .vsix stays small
run: |
npm run package
size=$(stat -c%s stellar-debugger.vsix)
echo "stellar-debugger.vsix: $size bytes"
if [ "$size" -gt 2000000 ]; then
echo "::error::the .vsix is $size bytes (> 2 MB) — check .vscodeignore with 'npx vsce ls'"
exit 1
fi

# The end-to-end tests (test/integration.node.test.ts) run the REAL
# komet-node — the only way to catch a breaking change in its RPC or trace
# format. Install it the same way the devcontainer does: Nix + RV's binary
Expand Down
87 changes: 87 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Release

# Publishing is driven by a tag: `git tag v0.1.0 && git push origin v0.1.0`.
# The tagged commit must already be green on CI (which is what runs the real
# komet-node end-to-end suite); this workflow builds, packages, and publishes.
on:
push:
tags: ['v*']
# Allow a dry run that packages and uploads the .vsix without publishing.
workflow_dispatch:

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

# A tag that disagrees with package.json would publish the wrong version
# to the marketplace under a name nobody can correct later.
- name: Check the tag matches package.json
if: startsWith(github.ref, 'refs/tags/v')
run: |
manifest="$(node -p "require('./package.json').version")"
tag="${GITHUB_REF_NAME#v}"
if [ "$manifest" != "$tag" ]; then
echo "::error::tag $GITHUB_REF_NAME does not match package.json version $manifest"
exit 1
fi

- name: Type-check
run: npm run check-types

- name: Lint
run: npm run lint

# The real-komet-node e2e suite already ran on this commit in CI; opt out
# of it here (its own documented escape hatch) rather than spending ten
# minutes reinstalling Nix and the K semantics to re-prove the same thing.
- name: Test (without the real-node e2e suite)
run: npm test
env:
KOMET_NODE_E2E: '0'

- name: Package
run: npm run package

- name: Upload the .vsix as a build artifact
uses: actions/upload-artifact@v4
with:
name: stellar-debugger-vsix
path: stellar-debugger.vsix

- name: Publish to the VS Code Marketplace
if: startsWith(github.ref, 'refs/tags/v')
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
run: npx vsce publish --packagePath stellar-debugger.vsix

# Cursor, Windsurf and VSCodium install from Open VSX, not from the
# Microsoft marketplace, so a release that skips this is invisible to them.
- name: Publish to Open VSX
if: startsWith(github.ref, 'refs/tags/v')
env:
OVSX_PAT: ${{ secrets.OVSX_PAT }}
run: npx ovsx publish stellar-debugger.vsix

- name: Create the GitHub release
if: startsWith(github.ref, 'refs/tags/v')
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$GITHUB_REF_NAME" \
--title "$GITHUB_REF_NAME" \
--notes "See [CHANGELOG.md](https://github.com/runtimeverification/stellar-debugger/blob/$GITHUB_REF_NAME/CHANGELOG.md)." \
stellar-debugger.vsix
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ reports/
*.vsix
.DS_Store
*.log
.env
.env.*
# Local checkouts of komet / komet-node / wasm-semantics for dev iteration.
.deps/
state.kore
.claude/
test/fixtures/sample-contract/target/
test/fixtures/*/target/
examples/*/target/
# Fixture crates are built by hand only, to regenerate the committed .wasm.
test/fixtures/*/Cargo.lock
.notes/
31 changes: 17 additions & 14 deletions .vscodeignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
.vscode/**
.devcontainer/**
src/**
test/**
out/**
node_modules/**
.gitignore
.mocharc.json
esbuild.js
tsconfig*.json
.eslintrc.json
**/*.map
**/*.ts
!dist/**
# Allowlist-shaped: ignore everything, then add back exactly what the installed
# extension needs. A denylist is a trap here — `examples/*/target` and
# `test/fixtures/*/target` are gitignored but still on disk, and `vsce` packages
# from the disk, not from git.
**

!dist/extension.js
!dist/dap-server.js
!dist/trace.js
!images/icon.png
!package.json
!README.md
!CHANGELOG.md
!LICENSE

# Source maps are dev-only (`vscode:prepublish` builds minified, without them).
dist/**/*.map
102 changes: 19 additions & 83 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,28 @@
# Changelog

All notable changes to this extension are documented in this file. The format is
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
All notable changes to this extension are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [0.1.0] — 2026-08-21

### Added

- **Multi-transaction debug configurations.** A launch config now states an
ordered `transactions` sequence of `deploy` / `invoke` steps, run against one
accumulating local ledger, with `trace` selecting which of them feeds the
session (`"last"` by default, or an index, or a step `id`). Constructors,
seeded state and multi-step flows are debuggable, not just a single bare call.
Each transaction's status is reported in the debug console, and a step that
fails or traps no longer aborts the run — its trace is still fetched and
replayed.
- **Spec-driven arguments.** An invoke's `args` is an object keyed by the
function's own parameter names, encoded against the contract's
`contractspecv0` spec, so structs, enums, tuples, vecs and maps work without
hand-written ScVal type tags. The tokens `${sourceAddress}` and
`${contract:<id>}` expand inside string values, wiring a deployed contract's
address into a later call.
- **Just-my-code stepping** (`justMyCode`, default true): source stepping rests
only in workspace files, skipping Rust `std`/`core` and crates.io dependency
sources. `--no-just-my-code` opts out in the CLI.
- **Stellar ledger inspection.** A new **Ledger** scope shows the chain state at
every step: contract storage across all three durabilities with their TTLs,
account balances, the ledger sequence and close time, the executing contract's
wasm hash and instance TTL, the host object table, and the open contract-call
stack. Values render as Soroban types with `C…`/`G…` addresses, and composites
expand. Storage is reconstructed from the trace's own call baselines and write
events — including undoing the writes of a sub-call that trapped — so it
matches what the contract would read.
- **WebAssembly globals.** A new **Globals** scope lists the executing module's
globals by module-relative index, for traces that carry them.
- The `soroban-trace` CLI reports the same state per stop as `globals` and
`ledger`, with a `changed` flag marking the storage entries that moved since
the previous stop, and `hasGlobals`/`hasLedger` announced in `meta`.
- New contributor spec: [`docs/state-inspection.md`](docs/state-inspection.md),
whose numbered rules (G1–G4, L1–L15) the test suite pins.

### Changed
This is the first public release. The extension debugs Stellar smart contracts written in Rust, in VSCode or from the command line, and it steps backward as readily as forward.

- **The single-invoke launch config is gone.** `contract`, `function`, `args`,
`buildCommand` and `debugInfo` no longer sit at the top level: wrap them in a
`transactions` array (see [`docs/debug-config.md`](docs/debug-config.md)). A
config still using the old shape is rejected with a message pointing at the
new one, rather than silently ignored.
- **Invoke arguments are spec-driven only.** The positional
`[{ "type", "value" }]` form is removed, along with the hand-written ScVal
encoder behind it; the contract's own spec now decides how each argument
encodes. `soroban-trace --args-json` takes the same named object.
- **Requires komet v0.1.87 or newer.** That release reorganised the trace: every
record now names itself with a `kind` field, and the operands that used to ride
inside `instr` are named fields of the record. The parser reads that shape and
rejects a record without a `kind`, so a trace recorded against an older komet
no longer replays — re-record it. Failing loudly is deliberate: a trace this
parser cannot classify would otherwise open a session with every state view
mysteriously empty.
- The cross-contract gate no longer relies on komet-node tagging each trace
record with the contract executing at it. The adapter folds that out of the
`callContract`/`endWasm` boundaries the trace already carries, so nothing needs
to be sent per record for it.

### Fixed

- Debug sessions start ~8 seconds faster: rendering Stellar addresses no longer
pulls `@stellar/stellar-sdk` into the debug adapter's module graph (a local
strkey encoder replaces it), which had been delaying every session past the
DAP handshake timeout.
- The invocation's return value is reported again in the debug console (and in
the CLI's `result` line), read from the trace's own call-exit record; a call
that trapped says so.
- Byte-identical transactions in one run are no longer deduplicated by
komet-node into a single execution: every envelope carries its own account
sequence, so calling the same function twice with the same arguments really
runs twice.
- DWARF type resolution no longer hangs on malformed debug info containing a
cyclic `typedef`/qualifier chain; `stripTypedefs` now terminates on cycles.
### Added

[Unreleased]: https://github.com/runtimeverification/stellar-debugger/compare/v0.0.1...HEAD
- You can set breakpoints in your Rust source and step through it line by line, inspecting your own variables at every stop.
- You can step backward. Stepping back, stepping back out of a call, and running backward to the previous breakpoint are all as fast as going forward, so overshooting the bug costs you nothing.
- The call stack shows every function that led to the current line, including the ones the compiler inlined away. Selecting a frame shows that frame's variables and jumps to its line.
- Stepping stays in the code you wrote. The debugger steps over Rust standard-library and dependency sources rather than into them, unless you set `justMyCode` to `false`.
- A launch configuration runs an ordered sequence of deployments and calls against one fresh local network, and names the call you want to debug. You can therefore set up state — run a constructor, deploy a second contract, seed storage — before the call under test.
- Call arguments are written as JSON, keyed by the parameter names in your contract's own signature. Structs, enums, tuples, vectors and maps all work without encoding anything by hand.
- The Ledger view shows the chain as your contract sees it at the current step: contract storage with its expiry, account balances, the ledger sequence number and close time, and the contracts currently on the call stack. It travels with you as you step.
- When you need to go below your source, the debugger also shows WebAssembly locals, the operand stack, globals and linear memory, and VSCode's Disassembly View steps through the instructions themselves in either direction.
- Debugging a contract takes one keypress. The extension builds it, starts a local network, deploys it, makes the call, and opens the session.
- A recorded run can be replayed later with no network and no toolchain installed. That makes a saved recording a reproducible bug report you can hand to someone else.
- Outside the editor, `stellar-trace` prints the execution of a call as JSON lines for use in scripts and CI, and `stellar-dap` serves the debugger over TCP so that editors such as Neovim, IntelliJ and Emacs can drive it.

## [0.0.1]
### Requirements

Initial release: time-travel debugging for Stellar/Soroban smart contracts, with
Rust source-level and WebAssembly stepping (forward and backward), state
inspection, a one-click build-deploy-debug pipeline, and offline replay of
recorded runs.
- Debugging a contract requires [komet-node](https://github.com/runtimeverification/komet-node), the local Stellar network that runs it. It must be built with komet v0.1.87 or newer; an older build produces recordings this version cannot open, and says so rather than opening an empty session.
- Building and deploying a contract also requires a Rust toolchain with a WebAssembly target and the Stellar CLI. Replaying a recording requires neither.

[0.0.1]: https://github.com/runtimeverification/stellar-debugger/releases/tag/v0.0.1
[0.1.0]: https://github.com/runtimeverification/stellar-debugger/releases/tag/v0.1.0
21 changes: 21 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Code of conduct

## Our pledge

We want participating in this project to be a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our standards

Behaviour that makes this community work: showing empathy and kindness, respecting differing opinions and experiences, giving and gracefully accepting constructive feedback, taking responsibility for our mistakes, and focusing on what is best for the project as a whole.

Behaviour that does not: sexualised language or imagery and unwelcome sexual attention, trolling, insulting or derogatory comments, personal or political attacks, public or private harassment, publishing others' private information without permission, and anything else a reasonable person would consider inappropriate in a professional setting.

## Enforcement

Maintainers are responsible for clarifying and enforcing these standards, and will take fair corrective action — from removing a comment to a temporary or permanent ban — in response to behaviour they judge inappropriate. They will respect the privacy and security of anyone who reports an incident.

Report abusive, harassing, or otherwise unacceptable behaviour privately to the maintainers, through [GitHub's private reporting](https://github.com/runtimeverification/stellar-debugger/security/advisories/new) or by contacting a maintainer directly. All complaints will be reviewed and investigated promptly and fairly.

## Attribution

Adapted from the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html), version 2.1.
Loading