22
33** Authors:** [ Igor Konnov] [ ] and [ Thomas Pani] [ ]
44
5- A simple JSON-RPC server module for Apalache. This is work in progress:
5+ A simple JSON-RPC server module for Apalache. ** This is work in progress. **
66
77This server is not meant to be a replacement for the current gRPC server (SHAI).
88Rather, it is a lightweight alternative that can be used for symbolic
@@ -41,7 +41,7 @@ exploration of TLA+ specifications.
4141 - [ Jetty Server] [ ] . Yes, it is about 30 years old.
4242 It works. It is fast, simple, reliable, maintained, and is well-documented.
4343 - [ Jackson] [ ] . It is fast, simple, reliable, maintained, and is well-documented.
44- It uses plain-old Java objects, and it supports basic Scala types. No super- advanced
44+ It uses plain-old Java objects, and it supports basic Scala types. No advanced
4545 FP here.
4646
4747## 2. JSON-RPC methods
@@ -53,6 +53,15 @@ See the [JSON-RPC specification][] for more details. It is real short.
5353
5454This is work in progress. More methods to be added in the future.
5555
56+ In the JSON format below, we write ` "${placeholders}" ` to indicate values that
57+ should be replaced with actual values. They have to be of proper types, e.g.,
58+ strings, numbers, booleans, arrays, or objects. We write them in quotes to
59+ produce valid JSON snippets.
60+
61+ Some of the methods accept and return traces and expressions in the
62+ [ ITF Format] [ ] . You can use the [ itf-py] [ ] library to produce and parse
63+ such traces and expressions in Python.
64+
5665** Running the server.** To try the examples below, you need to start the server
5766first:
5867
@@ -83,21 +92,21 @@ be used in subsequent calls to refer to this session.
8392 "method" : " loadSpec" ,
8493 "params" : {
8594 "sources" : [
86- <rootModuleInBase64> ,
87- <importedModule1InBase64> ,
88- ...
95+ " ${root-module-in-base64} " ,
96+ " ${imported-module1-in-base64} " ,
97+ " ..."
8998 ],
90- "init" : " optional-initializer-predicate" ,
91- "next" : " optional-transition-predicate" ,
99+ "init" : " ${ optional-initializer-predicate} " ,
100+ "next" : " ${ optional-transition-predicate} " ,
92101 "invariants" : [
93- " invariant 1 " ,
94- ...,
95- " invariant N "
102+ " ${ invariant-1} " ,
103+ " ..." ,
104+ " ${ invariant-N} "
96105 ],
97106 "exports" : [
98- " exported-operator-1" ,
99- ...,
100- " exported-operator-M"
107+ " ${ exported-operator-1} " ,
108+ " ..." ,
109+ " ${ exported-operator-M} "
101110 ]
102111 }
103112}
@@ -113,13 +122,13 @@ operators such as `Init`, `Next`, and the invariants.
113122``` json
114123{
115124 "result" : {
116- "sessionId" : " unique-session-identifier" ,
117- "snapshotId" : snapshot-identifier-after-loading-the-spec,
125+ "sessionId" : " ${ unique-session-identifier} " ,
126+ "snapshotId" : " ${ snapshot-identifier-after-loading-the-spec} " ,
118127 "specParameters" : {
119- "initTransitions" : init-metadata,
120- "nextTransitions" : next-metadata,
121- "stateInvariants" : state-invariants-metadata,
122- "actionInvariants" : action-invariants-metadata,
128+ "initTransitions" : " ${ init-metadata} " ,
129+ "nextTransitions" : " ${ next-metadata} " ,
130+ "stateInvariants" : " ${ state-invariants-metadata} " ,
131+ "actionInvariants" : " ${ action-invariants-metadata} "
123132 }
124133 }
125134}
@@ -129,8 +138,8 @@ The metadata entries look like:
129138
130139``` json
131140{
132- "index" : i ,
133- "labels" : [" label1" , " label2" , ... ]
141+ "index" : " ${integer-index} " ,
142+ "labels" : [" label1" , " label2" , " ..." ]
134143}
135144```
136145
@@ -206,7 +215,7 @@ session identifier. No further calls should be made with this session identifier
206215{
207216 " method" : " disposeSpec" ,
208217 " params" : {
209- " sessionId" : " session-identifier"
218+ " sessionId" : " ${ session-identifier} "
210219 }
211220}
212221` ` `
@@ -219,7 +228,7 @@ This identifier cannot be used in the future calls.
219228` ` ` json
220229{
221230 " result" : {
222- " sessionId" : " session-identifier"
231+ " sessionId" : " ${ session-identifier} "
223232 }
224233}
225234` ` `
@@ -262,8 +271,8 @@ roll back to it again later.
262271{
263272 " method" : " rollback" ,
264273 " params" : {
265- " sessionId" : " session-id" ,
266- " snapshotId" : snapshot-id
274+ " sessionId" : " ${ session-id} " ,
275+ " snapshotId" : " ${ snapshot-id} "
267276 }
268277}
269278` ` `
@@ -276,8 +285,8 @@ that was rolled back to:
276285` ` ` json
277286{
278287 " result" : {
279- " sessionId" : " session-id" ,
280- " snapshotId" : snapshot-id
288+ " sessionId" : " ${ session-id} " ,
289+ " snapshotId" : " ${ snapshot-id} "
281290 }
282291}
283292` ` `
@@ -323,10 +332,10 @@ snapshot.
323332{
324333 " method" : " assumeTransition" ,
325334 " params" : {
326- " sessionId" : " session-identifier" ,
327- " transitionId" : transition-identifier,
328- " checkEnabled" : check-if-transition-is-enabled ,
329- " timeoutSec" : timeout-in-seconds-or-0,
335+ " sessionId" : " ${ session-identifier} " ,
336+ " transitionId" : " ${integer- transition-identifier} " ,
337+ " checkEnabled" : " ${boolean-flag} " ,
338+ " timeoutSec" : " ${ timeout-in-seconds-or-0} "
330339 }
331340}
332341` ` `
@@ -336,9 +345,9 @@ snapshot.
336345` ` ` json
337346{
338347 " result" : {
339- " sessionId" : " session-identifier" ,
340- " snapshotId" : new-snapshot-id,
341- " transitionId" : transition-identifier,
348+ " sessionId" : " ${ session-identifier} " ,
349+ " snapshotId" : " ${ new-snapshot-id} " ,
350+ " transitionId" : " ${integer- transition-identifier} " ,
342351 " status" : " ENABLED|DISABLED|UNKNOWN"
343352 }
344353}
@@ -381,7 +390,7 @@ new constraints, `nextStep` takes a new snapshot.
381390{
382391 "method": "nextState",
383392 "params": {
384- "sessionId": "session-identifier"
393+ "sessionId": "${ session-identifier} "
385394 }
386395}
387396```
@@ -391,9 +400,9 @@ new constraints, `nextStep` takes a new snapshot.
391400```json
392401{
393402 "result": {
394- "sessionId": "session-identifier",
395- "snapshotId": new-snapshot-id,
396- "newStepNo": new-step-number
403+ "sessionId": "${ session-identifier} ",
404+ "snapshotId": "${ new-snapshot-id}" ,
405+ "newStepNo": "${ new-step-number}"
397406 }
398407}
399408```
@@ -446,10 +455,10 @@ checking the invariant, the context is rolled back to the state before the call.
446455{
447456 "method": "checkInvariant",
448457 "params": {
449- "sessionId": "session-identifier",
450- "invariantId": invariant-identifier,
458+ "sessionId": "${ session-identifier} ",
459+ "invariantId": "${integer- invariant-identifier}" ,
451460 "kind": "STATE|ACTION",
452- "timeoutSec": timeout-in-seconds-or-0
461+ "timeoutSec": "${ timeout-in-seconds-or-0}"
453462 }
454463}
455464```
@@ -459,9 +468,9 @@ checking the invariant, the context is rolled back to the state before the call.
459468```json
460469{
461470 "result": {
462- "sessionId": "session-identifier",
471+ "sessionId": "${ session-identifier} ",
463472 "invariantStatus": "SATISFIED|VIOLATED|UNKNOWN",
464- "trace": trace-in-itf-or-null,
473+ "trace": "${ trace-in-itf-or-null}"
465474 }
466475}
467476```
@@ -520,10 +529,10 @@ set, or it is set to `0`, then the timeout is infinite.
520529{
521530 "method": "query",
522531 "params": {
523- "sessionId": "session-identifier",
524- "kinds": [ kind1, kind2, ... ],
525- "operator": optional-operator-name,
526- "timeoutSec": timeout-in-seconds-or-0
532+ "sessionId": "${ session-identifier} ",
533+ "kinds": [ "${ kind1}", "${ kind2}", " ..." ],
534+ "operator": "${ optional-operator-name}" ,
535+ "timeoutSec": "${ timeout-in-seconds-or-0}"
527536 }
528537}
529538```
@@ -537,9 +546,9 @@ and `expr` are in the [ITF Format][].
537546```json
538547{
539548 "result": {
540- "sessionId": "session-identifier",
541- "trace": trace-in-itf-or-null,
542- "operatorValue": expr-in-itf-or-null
549+ "sessionId": "${ session-identifier} ",
550+ "trace": "${ trace-in-itf-or-null}" ,
551+ "operatorValue": "${ expr-in-itf-or-null}"
543552 }
544553}
545554```
@@ -592,9 +601,9 @@ returned by `nextState`).
592601{
593602 "method": "nextModel",
594603 "params": {
595- "sessionId": "session-identifier",
596- "operator": < operator-name> ,
597- "timeoutSec": timeout-in-seconds-or-0
604+ "sessionId": "${ session-identifier} ",
605+ "operator": "${ operator-name}" ,
606+ "timeoutSec": "${ timeout-in-seconds-or-0}"
598607 }
599608}
600609```
@@ -619,10 +628,10 @@ The output contains the following fields:
619628```json
620629{
621630 "result": {
622- "sessionId": "session-identifier",
623- "oldValue": expr-in-itf-or-null,
624- "hasOld": ( TRUE|FALSE|UNKNOWN) ,
625- "hasNext": ( TRUE|FALSE|UNKNOWN)
631+ "sessionId": "${ session-identifier} ",
632+ "oldValue": "${ expr-in-itf-or-null}" ,
633+ "hasOld": " TRUE|FALSE|UNKNOWN" ,
634+ "hasNext": " TRUE|FALSE|UNKNOWN"
626635 }
627636}
628637```
@@ -658,6 +667,73 @@ The output is as follows:
658667}
659668```
660669
670+ ### 2.9. Method assumeState
671+
672+ Given a session identifier and concrete equalities `x = e` over a subset of the state
673+ variables, add the equality constraints to the SMT context. The expressions in the
674+ right-hand sides are given as expressions in the [ITF Format][].
675+
676+ Additionally, if `checkEnabled` is set to `true`, the server checks, whether there is a
677+ state that is reachable via the current transition prefix, including the added
678+ constraints. The parameter `timeoutSec` sets the timeout for this check in seconds.
679+ If `timeout` is not set, or it is set to `0`, then the timeout is infinite.
680+
681+ **Precondition.** The call to `assumeState` can be made only after at least single
682+ call to `assumeTransition` and `nextStep`.
683+
684+ **Effect.** The concrete equalities are translated as SMT equality constraints in
685+ the current context against the current symbolic state (sometimes, called a frame).
686+ These constraints do not override the existing assignments in the context. Rather,
687+ they pose additional constraints on top of the existing ones.
688+
689+ **Input:**
690+
691+ ```json
692+ {
693+ "method": "assumeState",
694+ "params": {
695+ "sessionId": "${session-identifier}",
696+ "checkEnabled": "${boolean-flag}",
697+ "timeoutSec": "${timeout-in-seconds-or-0}",
698+ "equalities": {
699+ "${var-1}": "${expr-in-itf}",
700+ "...": "...",
701+ "${var-k}": "${expr-in-itf}"
702+ }
703+ }
704+ }
705+ ```
706+
707+ **Output:**
708+
709+ ```json
710+ {
711+ "result": {
712+ "sessionId": "${session-identifier}",
713+ "snapshotId": "${new-snapshot-id}",
714+ "status": "ENABLED|DISABLED|UNKNOWN"
715+ }
716+ }
717+ ```
718+
719+ **Example**:
720+
721+ Execute the following command:
722+
723+ ```sh
724+ $ curl -X POST http://localhost:8822/rpc \
725+ -H "Content-Type: application/json" \
726+ -d ' {" jsonrpc" :" 2.0" ," method" :" assumeState" ,
727+ " params" :{" sessionId" :" 1" ," checkEnabled" :true," equalities" : {" x" :{" #bigint" :" 1" }}}," id" :4}'
728+ ```
729+
730+ It produces the following output:
731+
732+ ```json
733+ {"jsonrpc":"2.0","id":2,"result":{"sessionId":"1","snapshotId":3,"status":"ENABLED"}}
734+ ```
735+
736+
661737[Jetty Server]: https://jetty.org/
662738
663739[Jackson]: https://github.com/FasterXML/jackson
@@ -672,4 +748,6 @@ The output is as follows:
672748
673749[Apalache IR]: https://apalache-mc.org/docs/adr/005adr-json.html
674750
675- [SMT randomization]: https://apalache-mc.org/docs/apalache/tuning.html#randomization
751+ [SMT randomization]: https://apalache-mc.org/docs/apalache/tuning.html#randomization
752+
753+ [itf-py]: https://github.com/konnov/itf-py/
0 commit comments