(* Batch size *)
Definition batch_recv_loop_spec := forall (nsa : nat * Sstate * reqs),
DHT [sv, W]
(fun i => let: (n, s, acc) := nsa in
[/\ loc i = st :-> acc,
size acc + n = bsize,
(forall e, e \in acc ->
[/\ e.1.1 \in cls, e.1.2 = sv & prec e.2]) &
state_wf s],
fun (r : (reqs * Sstate)) m =>
[/\ loc m = st :-> r.1,
size r.1 = bsize,
(forall e, e \in r.1 ->
[/\ e.1.1 \in cls, e.1.2 = sv & prec e.2]) &
state_wf r.2]).
Program Definition receive_req_loop s :
DHT [sv, W]
(fun i => loc i = st :-> ([::]:reqs) /\ state_wf s,
fun (r : (reqs * Sstate)) m =>
[/\ loc m = st :-> r.1,
size r.1 = bsize,
(forall e, e \in r.1 -> [/\ e.1.1 \in cls, e.1.2 = sv & prec e.2]) &
state_wf r.2]) :=
Do (ffix (fun (rec : batch_recv_loop_spec) nsa =>
Do _ (let: (n, s, acc) := nsa in
if n is n'.+1
then r <-- blocking_receive_req l f prec cs cls _ Hs;
let: (from, args) := r in
let: acc' := (from, sv, args) :: acc in
rec (n', s, acc')
else ret _ _ (acc, s))) (bsize, tt, [::])).
Next Obligation.
move=>i1/=[L1]S P _; case: n S=>//[|n]S.
- by apply: ret_rule=>i2 R1/=; rewrite (rely_loc' _ R1) addn0.
apply: step; apply: (gh_ex (g:=r)).
apply: call_rule=>//[[from args]]i2/=[L2]H1 H2 C2.
apply: call_rule=>// _; split=>//; first by rewrite addSnnS.
move=>e; rewrite inE=>/orP; case; last by apply: P.
by move/eqP=>Z; subst e.
Qed.
Next Obligation.
by move=>i1/=[L1]_; apply: call_rule.
Qed.
(* Send batch responses *)
Definition batch_send_loop_spec := forall (acc : reqs),
DHT [sv, W]
(fun i => [/\ loc i = st :-> acc &
(forall e, e \in acc -> [/\ e.1.1 \in cls, e.1.2 = sv & prec e.2])],
fun (r : Sstate) m =>
[/\ loc m = st :-> ([::]:reqs) & state_wf r]).
Program Definition send_ans_loop (acc : reqs) :
DHT [sv, W]
(fun i => loc i = st :-> acc /\
(forall e, e \in acc -> [/\ e.1.1 \in cls, e.1.2 = sv & prec e.2]),
fun (r : Sstate) m =>
[/\ loc m = st :-> ([::]:reqs) & state_wf r]) :=
ffix (fun (rec : batch_send_loop_spec) acc =>
Do _ (if acc is (from, _, args) :: acc'
then let r := if f args is Some v then v else 0 in
send_answer l f prec cs cls _ Hs from args r;;
rec acc'
else ret _ _ tt)) acc.
Next Obligation.
move=>i1/=[L1]P1; case: acc L1 P1=>[|[[from b]]args acc] L1 P1.
- by apply: ret_rule=>i2 R1[H1]_; rewrite (rely_loc' _ R1).
apply: step.
move: (P1 (from, b, args)).
rewrite inE eqxx/==>/(_ is_true_true)[X1]Z /prec_valid [v]F; subst b.
move: (erefl (f args))=>e.
have X: (match f args as anonymous' return (anonymous' = f args -> nat) with
| Some v => fun _ : Some v = f args => v
| None => fun _ : None = f args => 0
end e) = v by move: e; rewrite F.
rewrite X=>{X e}.
apply: (gh_ex (g:=((from, sv, args) :: acc))).
apply: call_rule; first by move=>_; split=>//; rewrite inE eqxx.
move=>x i2/= [L2 H2] C2; apply: call_rule=>//_.
rewrite eqxx in L2; split=>//e A; apply: P1.
by rewrite inE A orbC.
Qed.
(* Main batching server *)
Program Definition batched_body : forall _ : unit,
server_loop_body_spec l f prec cs cls sv _ state_wf state0 :=
fun _ => Do _ (
sr <-- receive_req_loop tt;
send_ans_loop sr.1).
Next Obligation.
move=>i1/=[L1]_; apply: step.
apply: call_rule=>//[[acc _]]/= i2[L2 H2]P2 _ C2.
by apply: call_rule.
Qed.
Definition batched_server :=
server_loop _ _ _ _ _ _ _ _ _ state0_wf batched_body.
End BatchingServer.
End BatchingServer.
(***** Memoizing Server *****)
Module MemoizingServer.
Section MemoizingServer.
Variable l : Label.
Variable f : input -> option nat.
Variable prec : input -> bool.
Hypothesis prec_valid :
forall i, prec i -> exists v, f i = Some v.
Variables (cs cls : seq nid).
Notation nodes := (cs ++ cls).
Hypothesis Huniq : uniq nodes.
Notation cal := (CalculatorProtocol f prec cs cls l).
Notation sts := (snd_trans cal).
Notation rts := (rcv_trans cal).
Notation W := (mkWorld cal).
Variable sv : nid.
Hypothesis  Hs : sv \in cs.
Notation loc i := (getLocal sv (getStatelet i l)).
(* Server-specific infrastructure *)
Notation Sstate := (seq ((seq nat) * nat)).
Definition state_wf (s : Sstate) :=
forall e, e \in s -> f e.1 = Some e.2.
Definition state0 : Sstate := [::].

Lemma state0_wf : state_wf state0. Proof. by []. Qed.
Definition update_mem_table (s : Sstate) args v :=
(args, v) :: s.