Proof using.
induction l using rev_ind; intros; simpl in *; intuition; repeat break_let; repeat find_inversion; auto.
find_apply_lem_hyp applyEntries_app. break_exists. intuition.
simpl in *. break_let. find_inversion.
unfold cacheApplyEntry in *.
repeat break_match.
- subst. find_inversion.
copy_eapply_prop_hyp applyEntries applyEntries;
[| match goal with
| H : context [id] |- _ => apply H
end]. intuition.
right.
break_exists_name e; exists e.
break_exists_name xs.
exists xs.
break_exists_name ys.
break_exists.
intuition. subst.
match goal with
| _ : deduplicate_log' ?l ?ks = _ |- _ =>
pose proof deduplicate_log'_app l [x] ks
end.
repeat find_rewrite.
repeat eexists; eauto.
rewrite app_ass.
rewrite <- app_comm_cons. eauto.
- do_bool. repeat find_inversion.
copy_eapply_prop_hyp applyEntries applyEntries;
[| match goal with
| H : context [id] |- _ => apply H
end]. intuition.
right.
break_exists_name e; exists e.
break_exists_name xs.
exists xs.
break_exists_name ys.
break_exists.
intuition. subst.
match goal with
| _ : deduplicate_log' ?l ?ks = _ |- _ =>
pose proof deduplicate_log'_app l [x] ks
end.
repeat find_rewrite.
repeat eexists; eauto.
rewrite app_ass.
rewrite <- app_comm_cons. eauto.
- do_bool. subst.
destruct (clientId_eq_dec (eClient x) client).
+ subst.
assert (id = eId x).
{
unfold applyEntry in *.
break_let. find_inversion. unfold getLastId in *.
simpl in *. rewrite get_set_same in *. find_inversion. auto.
}
subst.
right.
unfold applyEntry in *. break_let. find_inversion.
exists x, (deduplicate_log' l (clientCache_to_ks (clientCache st))), [].
intuition.
* rewrite deduplicate_log'_app. f_equal.
simpl in *.
repeat break_match; auto.
do_bool.
find_apply_lem_hyp applyEntries_log_to_ks'.
find_apply_lem_hyp a_equiv_sym.
find_erewrite_lem assoc_a_equiv; eauto.
find_apply_lem_hyp clientCache_to_ks_assoc_getLastId.
break_exists. repeat find_rewrite. find_inversion.
omega.
* rewrite execute_log'_app. break_let.
simpl in *. break_let. simpl.
rewrite rev_app_distr. simpl. unfold value. repeat f_equal.
find_apply_lem_hyp applyEntries_execute_log'.
repeat find_rewrite. simpl in *. repeat find_rewrite. find_inversion.
unfold getLastId in *.
simpl in *. rewrite get_set_same in *.
find_inversion. auto.
+ unfold applyEntry in *.
break_let. find_inversion.
unfold getLastId in *.
simpl in *.
rewrite get_set_diff in *; auto.
copy_eapply_prop_hyp applyEntries applyEntries;
[| match goal with
| H : context [id] |- _ => apply H
end]. intuition.
right.
break_exists_name e; exists e.
break_exists_name xs.
exists xs.
break_exists_name ys.
break_exists.
intuition. subst.
match goal with
| _ : deduplicate_log' ?l ?ks = _ |- _ =>
pose proof deduplicate_log'_app l [x] ks
end.
repeat find_rewrite.
repeat eexists; eauto.
rewrite app_ass.
rewrite <- app_comm_cons. eauto.
- do_bool. subst.
destruct (clientId_eq_dec (eClient x) client).
+ subst.
assert (id = eId x).
{
unfold applyEntry in *.
break_let. find_inversion. unfold getLastId in *.
simpl in *. rewrite get_set_same in *. find_inversion. auto.
}
subst.
right.
unfold applyEntry in *. break_let. find_inversion.
exists x, (deduplicate_log' l (clientCache_to_ks (clientCache st))), [].
intuition.
* rewrite deduplicate_log'_app. f_equal.
simpl in *.
repeat break_match; auto.
do_bool.
find_apply_lem_hyp applyEntries_log_to_ks'.
find_apply_lem_hyp a_equiv_sym.
find_erewrite_lem assoc_a_equiv; eauto.
find_apply_lem_hyp clientCache_to_ks_assoc_getLastId.
break_exists. repeat find_rewrite.
congruence.
* rewrite execute_log'_app. break_let.
simpl in *. break_let. simpl.
rewrite rev_app_distr. simpl. unfold value. repeat f_equal.
find_apply_lem_hyp applyEntries_execute_log'.
repeat find_rewrite. simpl in *. repeat find_rewrite. find_inversion.
unfold getLastId in *.
simpl in *. rewrite get_set_same in *.
find_inversion. auto.
+ unfold applyEntry in *.
break_let. find_inversion.
unfold getLastId in *.
simpl in *.
rewrite get_set_diff in *; auto.
copy_eapply_prop_hyp applyEntries applyEntries;
[| match goal with
| H : context [id] |- _ => apply H
end]. intuition.
right.
break_exists_name e; exists e.
break_exists_name xs.
exists xs.
break_exists_name ys.
break_exists.
intuition. subst.
match goal with
| _ : deduplicate_log' ?l ?ks = _ |- _ =>
pose proof deduplicate_log'_app l [x] ks
end.
repeat find_rewrite.
repeat eexists; eauto.
rewrite app_ass.
rewrite <- app_comm_cons. eauto.
Qed.

Lemma doGenericServer_spec :
forall (orig_base_params : BaseParams)
(one_node_params : OneNodeParams orig_base_params)
(raft_params : RaftParams orig_base_params) (h : name)
(st : raft_data) (os : list raft_output) (st' : raft_data)
(ps : list (name * msg)),
doGenericServer h st = (os, st', ps) ->
st' = st \/
log st' = log st /\
lastApplied st < lastApplied st' /\
lastApplied st' = commitIndex st /\
exists os' st'',
applyEntries h st
(rev
(filter
(fun x : entry =>
(lastApplied st <? eIndex x) && (eIndex x <=? commitIndex st))
(findGtIndex (log st) (lastApplied st)))) = (os', st'')  /\
clientCache st' = clientCache st'' /\
forall c, getLastId st' c = getLastId st'' c.