Skip to content

Commit 7f95807

Browse files
Merge pull request #26 from runtimeverification/devex/cli-tracing-io-dir
feat: streamline CLI devex (tracing, traceTransaction, logging, io-dir)
2 parents 760d8d4 + c8eff9a commit 7f95807

14 files changed

Lines changed: 418 additions & 339 deletions

File tree

README.md

Lines changed: 40 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
It is built for developing, testing, and debugging Soroban contracts locally, and adds two capabilities a public Stellar network does not offer:
2222

23-
- **Instruction-level traces.** The `traceTransaction` method runs a transaction and returns a step-by-step record of every WebAssembly instruction the contract executed, so you can see exactly what happened — and where it went wrong.
23+
- **Instruction-level traces.** Every transaction is traced as it runs, and the `traceTransaction` method returns that step-by-step record of every WebAssembly instruction the contract executed, so you can see exactly what happened — and where it went wrong.
2424
- **Reproducible, replayable state.** The ledger state is persisted to disk, so you can stop and restart the node, save a state, and replay transactions against it to reproduce a result.
2525

2626
## 🚀 Quick Start
@@ -66,63 +66,41 @@ docker run --rm -p 8000:8000 \
6666

6767
#### Start the server
6868

69-
```bash
70-
komet-node # serve on localhost:8000, state in ./state.kore
71-
komet-node --help # print general usage information
72-
komet-node --port 9000 # custom port
73-
komet-node --trace # enable instruction-level execution tracing
69+
Run `komet-node` to start the server; `komet-node --help` prints the full usage:
70+
71+
```
72+
usage: komet-node [-h] [--host HOST] [--port PORT] [--io-dir IO_DIR]
73+
74+
Komet Node — a local Stellar testnet backed by the K semantics of Soroban.
75+
76+
options:
77+
-h, --help show this help message and exit
78+
--host HOST bind address (default: localhost)
79+
--port PORT port to listen on (default: 8000)
80+
--io-dir IO_DIR directory for all input/output artifacts (default: a fresh
81+
temporary directory)
82+
83+
examples:
84+
komet-node serve on localhost:8000 in a fresh temp dir
85+
komet-node --port 9000 use a custom port
86+
komet-node --io-dir ./chain keep all artifacts under ./chain (persistent)
87+
komet-node --host 0.0.0.0 accept connections from outside localhost
7488
```
7589

76-
| Flag | Default | Description |
77-
|---|---|---|
78-
| `--host` | `localhost` | Bind address |
79-
| `--port` | `8000` | Port to listen on |
80-
| `--state-file` | `state.kore` | Path to the persistent state file |
81-
| `--trace` | off | Enable instruction-level execution tracing |
90+
#### Trace a transaction
8291

83-
On first start the server creates `state.kore` in the state file's directory — along with two small bookkeeping files, `metadata.json` and `transactions.json` — and begins from an empty chain. The state persists across restarts, so stopping and restarting the node resumes the same chain. To start over from an empty chain, delete `state.kore`; to resume from a chain you saved earlier, point `--state-file` at it.
92+
Every submitted transaction is traced as it executes, and the instruction-level trace is stored on its receipt. `traceTransaction` retrieves that stored trace, looked up by transaction hash — the same hash `getTransaction` takes. So tracing a contract invocation is two calls: `sendTransaction` to run it, then `traceTransaction` with the returned hash. Tracing is always on; there is no flag to enable.
8493

85-
#### Verify the server with `curl`
94+
Submitting transactions uses the standard two-step Stellar pattern — `sendTransaction` with a base64 XDR envelope, then poll `getTransaction` by hash. Because there is no mempool, `komet-node` executes the transaction synchronously inside `sendTransaction`, so the result is already available by the time you poll. See [docs/server.md](docs/server.md) for the full RPC reference.
8695

87-
The server is operated via the Stellar RPC protocol. The read-only methods below take no transaction payload and can be used as a quick health check:
96+
A trace requires a deployed contract. The four envelopes below are pre-built and signed (a tiny contract whose `foo()` returns void, deployed from a fixed key) so you can paste them straight in — the local node does not check signatures, sequence numbers, or timebounds, so they work as-is on a fresh chain. After a quick health check, run them in order against the server started above.
8897

8998
```bash
9099
# Is the server alive?
91-
curl -s http://localhost:8000 \
92-
-H 'Content-Type: application/json' \
100+
curl -s http://localhost:8000 -H 'Content-Type: application/json' \
93101
-d '{"jsonrpc":"2.0","id":1,"method":"getHealth","params":{}}'
94102
# => {"jsonrpc":"2.0","id":1,"result":{"status":"healthy"}}
95-
```
96-
97-
```bash
98-
# Which network am I connected to?
99-
curl -s http://localhost:8000 \
100-
-H 'Content-Type: application/json' \
101-
-d '{"jsonrpc":"2.0","id":1,"method":"getNetwork","params":{}}'
102-
# => {"jsonrpc":"2.0","id":1,"result":{"passphrase":"Test SDF Network ; September 2015","protocolVersion":"22","friendbotUrl":null}}
103-
```
104-
105-
```bash
106-
# What is the current ledger sequence? (increments per committed transaction)
107-
curl -s http://localhost:8000 \
108-
-H 'Content-Type: application/json' \
109-
-d '{"jsonrpc":"2.0","id":1,"method":"getLatestLedger","params":{}}'
110-
# => {"jsonrpc":"2.0","id":1,"result":{"id":"00...00","protocolVersion":"22","sequence":0}}
111-
```
112103

113-
Submitting transactions uses the standard two-step Stellar pattern — `sendTransaction` with a base64 XDR envelope, then poll `getTransaction` by hash. Because there is no mempool, `komet-node` executes the transaction synchronously inside `sendTransaction`, so the result is already available by the time you poll. The trace example below shows this flow end-to-end with ready-to-run envelopes; see [docs/server.md](docs/server.md) for the full RPC reference.
114-
115-
#### Trace a transaction
116-
117-
`traceTransaction` executes a transaction and returns an instruction-level execution trace inline, in a single call. Tracing only applies to contract invocations, so the server must be started with `--trace`:
118-
119-
```bash
120-
komet-node --trace
121-
```
122-
123-
A trace requires a deployed contract. The four envelopes below are pre-built and signed (a tiny contract whose `foo()` returns void, deployed from a fixed key) so you can paste them straight in — the local node does not check signatures, sequence numbers, or timebounds, so they work as-is on a fresh chain. Run them in order against the server above.
124-
125-
```bash
126104
# 1. Create the deployer account
127105
curl -s http://localhost:8000 -H 'Content-Type: application/json' \
128106
-d '{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":{"transaction":"AAAAAgAAAAADoQe/884Qvh1w3RjnS8CZZ+TWMJulDV8d3IZkElUxuAAAAGQAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAADoQe/884Qvh1w3RjnS8CZZ+TWMJulDV8d3IZkElUxuAAAAAJUC+QAAAAAAAAAAAESVTG4AAAAQMOMXdUuK9E9tF0pgpqX+z+nXFlE6Mn5e7rqOFL8jIolInsXc7XHPgvYs4VWDqlCGI/fom9SpYiHOQYUqKTvDAc="}}'
@@ -135,31 +113,29 @@ curl -s http://localhost:8000 -H 'Content-Type: application/json' \
135113
curl -s http://localhost:8000 -H 'Content-Type: application/json' \
136114
-d '{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":{"transaction":"AAAAAgAAAAADoQe/884Qvh1w3RjnS8CZZ+TWMJulDV8d3IZkElUxuAAAAGQAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAMAAAAAAAAAAAAAAAADoQe/884Qvh1w3RjnS8CZZ+TWMJulDV8d3IZkElUxuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFdPOLtg6vmmrgodRyN6P3wk1UfHrQxVekpbnsYYOcpvAAAAAAAAAAAAAAAAAAAAARJVMbgAAABAnLtNirBI7XdD2xwH3ws3rTDEhCxJ8mCRNU66d7b4MR2Ih9WtZzqb6akBqK6yA1GIavzVa7ahq2FNBflk+JpOBg=="}}'
137115

138-
# 4. Invoke foo() via traceTransaction — the trace comes back inline
116+
# 4. Invoke foo() — sendTransaction runs it and returns its hash
117+
curl -s http://localhost:8000 -H 'Content-Type: application/json' \
118+
-d '{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":{"transaction":"AAAAAgAAAAADoQe/884Qvh1w3RjnS8CZZ+TWMJulDV8d3IZkElUxuAAAAGQAAAAAAAAABAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABaiD+wakIF3Ol8jzjcPkl8jY0blEEON3W1A9rJxHBNOAAAAADZm9vAAAAAAAAAAAAAAAAAAAAAAESVTG4AAAAQKB9w/QmdK59UzXVbxXJp+5qfNpFSa495yajOyPM5KmYblE3/AbWqnnZMxTiBea0ShGZehgvo12AIyw48Lb1Xw0="}}'
119+
# => {"jsonrpc":"2.0","id":1,"result":{"hash":"c7099cbe10a9bfa1cdf9c9d368e1e1c932f535a70e4403b7aa409ce19fc36805","status":"PENDING", ...}}
120+
121+
# 5. Retrieve the trace for that hash
139122
curl -s http://localhost:8000 -H 'Content-Type: application/json' \
140-
-d '{"jsonrpc":"2.0","id":1,"method":"traceTransaction","params":{"transaction":"AAAAAgAAAAADoQe/884Qvh1w3RjnS8CZZ+TWMJulDV8d3IZkElUxuAAAAGQAAAAAAAAABAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABaiD+wakIF3Ol8jzjcPkl8jY0blEEON3W1A9rJxHBNOAAAAADZm9vAAAAAAAAAAAAAAAAAAAAAAESVTG4AAAAQKB9w/QmdK59UzXVbxXJp+5qfNpFSa495yajOyPM5KmYblE3/AbWqnnZMxTiBea0ShGZehgvo12AIyw48Lb1Xw0="}}'
123+
-d '{"jsonrpc":"2.0","id":1,"method":"traceTransaction","params":{"hash":"c7099cbe10a9bfa1cdf9c9d368e1e1c932f535a70e4403b7aa409ce19fc36805"}}'
141124
```
142125

143-
The final call returns the result inline. The `trace` field is itself a JSONL string (one JSON record per executed WebAssembly instruction); it is shown decoded here for readability:
126+
`traceTransaction` returns the stored trace as its result. The trace is a JSONL string (one JSON record per executed WebAssembly instruction); it is shown decoded here for readability:
144127

145128
```jsonc
146129
{
147130
"jsonrpc": "2.0",
148131
"id": 1,
149-
"result": {
150-
"hash": "c7099cbe10a9bfa1cdf9c9d368e1e1c932f535a70e4403b7aa409ce19fc36805",
151-
"status": "SUCCESS",
152-
"ledger": "4",
153-
"latestLedger": "4",
154-
"latestLedgerCloseTime": "1716000000",
155-
"trace": [
156-
{"pos": 3, "instr": ["const", "i32", 1048576], "stack": [], "locals": {}},
157-
{"pos": 11, "instr": ["const", "i32", 1048576], "stack": [], "locals": {}},
158-
{"pos": 19, "instr": ["const", "i32", 1048576], "stack": [], "locals": {}},
159-
{"pos": null, "instr": ["block"], "stack": [], "locals": {}},
160-
{"pos": 3, "instr": ["const", "i64", 2], "stack": [], "locals": {}}
161-
]
162-
}
132+
"result": [
133+
{"pos": 3, "instr": ["const", "i32", 1048576], "stack": [], "locals": {}},
134+
{"pos": 11, "instr": ["const", "i32", 1048576], "stack": [], "locals": {}},
135+
{"pos": 19, "instr": ["const", "i32", 1048576], "stack": [], "locals": {}},
136+
{"pos": null, "instr": ["block"], "stack": [], "locals": {}},
137+
{"pos": 3, "instr": ["const", "i64", 2], "stack": [], "locals": {}}
138+
]
163139
}
164140
```
165141

0 commit comments

Comments
 (0)