Section QueryHooked.
(* Constructing the composite world *)
Variables (lq : Label) (pc : protocol).
Variable Data : Type.
Variable qnodes : seq nat.
Variable serialize : Data -> seq nat.
Variable deserialize : seq nat -> Data.
Hypothesis ds_inverse : left_inverse serialize deserialize.
Definition pq := QueryProtocol qnodes serialize lq.
Variable core_state_to_data : nid -> heap -> Data -> Prop.
Hypothesis core_state_to_data_inj :
forall n h d d', core_state_to_data n h d -> core_state_to_data n h d' -> d = d'.
(* The query hook extracts certain data from the the core protocol *)
(* local state if it's present there. *)
Definition query_hook : hook_type :=
fun hc hq ms to =>
forall n rid d, ms = rid :: serialize d -> core_state_to_data n hc d.
Definition query_hookz := (1, (plab pc), (plab pq, tresp)) \\-> query_hook.
Definition W : world := ((plab pc \\-> pc) \+ (plab pq \\-> pq), query_hookz).
Hypothesis Lab_neq: lq != (plab pc).
(* Hypothesis Nodes_eq: forall d, nodes pc d =i qnodes. *)
rewrite /getProtocol/W/= findUnL; last by case/andP: W_valid.
by rewrite domPt inE eqxx findPt.
Qed.
(* TODO: this is a good candidate for a general lemma in the framework. *)
(***************************************************)
(*  Query-specific intermediate predicate          *)
(***************************************************)
(* 1. We've just sent our stuff. *)
Definition msg_just_sent d (reqs resp : seq (nid * nat)) req_num to :=
[/\ getLocal this d = qst :-> (reqs, resp),
no_msg_from_to' to this response_msg (dsoup d),
(to, req_num) \in reqs,
msg_spec' this to treq ([:: req_num]) (dsoup d) &
holds_res_perms d to (fun _ => false)].
(* 2. Our request is received but not yet responded. *)
Definition msg_received d (reqs resp : seq (nid * nat)) req_num to :=
[/\ getLocal this d = qst :-> (reqs, resp),
(to, req_num) \in reqs,
no_msg_from_to' this to request_msg (dsoup d),
no_msg_from_to' to this response_msg (dsoup d) &
holds_res_perms d to (fun rn => rn == req_num)].
(* 3. Our request is responded. *)
Definition msg_responded d (reqs resp : seq (nid * nat)) req_num to data :=
[/\ getLocal this d = qst :-> (reqs, resp),
(to, req_num) \in reqs,
no_msg_from_to' this to request_msg (dsoup d),
msg_spec' to this tresp (req_num :: serialize data) (dsoup d) &
holds_res_perms d to (fun _ => false)].
(* 4. Stability of the local state of a core protocol, to be proved separately *)
(* A local assertion ensuring stability of the core_state_to_data *)
Variable local_indicator : Data -> Pred heap.
Hypothesis core_state_stable_step : forall z s data s' n,
this != z -> network_step (plab pc \\-> pc, Unit) z s s' ->
n \in qnodes ->
local_indicator data (getLc s) ->
core_state_to_data n (getLc' s n) data  ->
core_state_to_data n (getLc' s' n) data.
(************************************************************************)
(******       Auxiliary lemmas for establishing stability          ******)
(************************************************************************)

Lemma send_lq_all_cases req_num data reqs resp to s
(N : this != to) (Qn : to \in qnodes) (H : core_state_to_data to (getLc' s to) data)
(L : local_indicator data (getLc' s this))
(M : [\/ msg_just_sent (getSq s) reqs resp req_num to, msg_received (getSq s) reqs resp req_num to
| msg_responded (getSq s) reqs resp req_num to data])
to' msg (n : heap) (C : Coh W s) (st : send_trans (Protocols.coh (getProtocol W (plab pq))))
(H1 : st \In get_st W (plab pq))
(H2 : to \in nodes (getProtocol W (plab pq)) (getSq s))
(H4 : send_safe st to to' (getSq s) msg) :
all_hooks_fire query_hookz (plab pq) (t_snd st) s to msg to' -> Some n = send_step H4 ->
let: d := getStatelet (upd (plab pq)
(DStatelet (upd to n (dstate (getSq s)))
(dsoup (getSq s) \+ fresh (dsoup (getSq s)) \\->
Msg (TMsg (t_snd st) msg) to to' true)) s) lq in
[\/ msg_just_sent d reqs resp req_num to,
msg_received  d reqs resp req_num to
| msg_responded d reqs resp req_num to data].