Section  QueryProtocol.
(* Arbitrary data type *)
Variable Data : Type.
Variable nodes : seq nat.
(* Serialize/decerialize functions *)
Variable serialize : Data -> seq nat.
Variable deserialize : seq nat -> Data.
Hypothesis ds_inverse : left_inverse serialize deserialize.
(* Protocol state *)
Definition st := ptr_nat 1.
(* Pending requests (client-side): node, request id *)
(* Pending responses (server-side): node, response id *)
Definition reqs := seq (nid * nat)%type.
Definition resp := seq (nid * nat)%type.
Definition qstate := (reqs * resp)%type.
(* All responses and requests are unique per-node *)
Definition localCoh (n : nid) : Pred heap :=
[Pred h | exists (s : qstate), h = st :-> s /\ (uniq s.1 && uniq s.2)].
(* Tags *)
Definition treq : nat := 0.
Definition tresp : nat := 1.
Definition tags := [:: treq; tresp].
Definition cohMsg (ms: msg TaggedMessage) : Prop :=
let body := content ms in
(* If a message is a request, it carries a request number *)
if tag body == treq then exists req_num, tms_cont body = [:: req_num]
(* Otherwise it's a response and serialized data *)
else exists resp_num sdata, tms_cont body = resp_num :: sdata.
Definition soupCoh : Pred soup :=
[Pred s | valid s /\ forall m ms, find m s = Some ms -> cohMsg ms].
Definition qcoh d : Prop :=
let: dl := dstate d in
let: ds := dsoup d in
[/\ soupCoh ds, valid dl, dom dl =i nodes &
forall n, n \in dom dl -> localCoh n (getLocal n d)].
(****************************************************)
(********* Getter lemmas for local state ************)
(****************************************************)
Definition getSt n d (C : QCoh d) : qstate :=
match find st (getLocal n d) as f return _ = f -> _ with
Some v => fun epf => icast (sym_eq (cohSt C epf)) (dyn_val v)
| _ => fun epf => ([::], [::])
end (erefl _).
(****************************************************)
Notation coh := QCoh.
(********************* Takes: - initial state q - a recipient node to - a transition tag tag - a request id to be spent (in the case of response)  Returns - a new local state **********************)
Definition send_step_fun (q : qstate) (to : nid) (tag : nat) (rid: nat) : qstate :=
let: (xs, ys) := q in
if tag == treq then ((to, fresh_id xs) :: xs, ys)
else if (tag == tresp) && ((to, rid) \in ys)
then (xs, seq.rem (to, rid) ys)
else q.
(********************* Takes: - initial state q - a sender node from - a transition tag tag - a request id to be processed (added or removed)  Returns - a new local state **********************)
Definition receive_step_fun (q : qstate) (from : nid) (tag : nat) (rid : nat) :=
let: (xs, ys) := q in
if (tag == treq) && ((from, rid) \notin ys)
then (xs, (from, rid) :: ys)
else if (tag == tresp) && ((from, rid) \in xs)
then (seq.rem (from, rid) xs, ys)
else q.

Lemma receive_step_uniq q from tag rid:
uniq q.1 -> uniq q.2 ->
uniq (receive_step_fun q from tag rid).1  /\
uniq (receive_step_fun q from tag rid).2.