Status: model and CLI boundary implemented. The sans-IO parser models committed real
simulateTransactioncaptures and the offline tests exercise it.sgp simulateaccepts a fully assembled transaction envelope; no page in the dashboard or indexer renders an impact today.
Dry-run (simulateTransaction) modeling
Sans-IO parser side of the dry-run feature. Code: crates/core/src/simulate.rs;
offline tests: crates/core/tests/simulate.rs (committed real captures).
Charter rule 5
Every dry-run output is an estimate. ExecutionImpact.estimate is always
true, and simulated_at_ledger is mandatory — a response without
latestLedger is an error, never a default. Simulation runs against the current
ledger, not the future execution ledger; timelocks and state changes between now
and execution can change the real result.
Modeled fields
Modeled against the committed raw captures under
tests/fixtures/seed-v2/rpc/*-simulateTransaction-*.json. The RPC
response.result object carries exactly:
| RPC field | ExecutionImpact field | notes |
|---|---|---|
latestLedger | simulated_at_ledger | always present; required |
minResourceFee | min_resource_fee_stroops | string; absent ⇒ null |
stateChanges | state_changes | present only when the call writes; else null |
results | (presence only) | presence ⇒ success; XDR not decoded here ⇒ decode_status: unverified |
cost.cpuInsns | cpu_instructions | not present in any capture ⇒ always null |
cost.memBytes | memory_bytes | not present in any capture ⇒ always null |
Absent means null; nothing is defaulted to zero or to “success”.
Rent
Not modeled. The captured responses contain no rent figure, and the Soroban
rent model depends on entry TTLs and ledger timing the simulation response does
not expose directly. Rather than derive a number from an assumption, the field is
omitted and this limitation recorded. A future capture that includes a rent
figure (or a documented derivation from stateChanges durability + TTL) can add
it.
IO split
build_simulate_request(transaction_xdr_base64, request_id) returns the JSON-RPC
2.0 request body and validates the envelope (fail-closed). Assembling the
transaction from a decoded action, and sending it, is IO and lives in the CLI’s
RpcClient; the core crate stays sans-IO.
The CLI exposes the same boundary without guessing how to assemble a proposal:
sgp simulate <transaction-envelope-base64> --capture raw-simulate-response.json
cat transaction-envelope-base64.txt | sgp simulate -
The command validates the envelope before making the RPC call, prints only the
parsed ExecutionImpact, and writes the raw response only when --capture is
provided. The output remains an estimate and is not a guarantee of future
execution.
Not yet done
- The CLI accepts a fully assembled transaction envelope; it does not assemble proposal actions it cannot verify.
decode_statusisunverified: the impact parser does not decode the result XDR against a contract spec.