Section StateMachineCorrect.
Context {orig_base_params : BaseParams}.
Context {one_node_params : OneNodeParams orig_base_params}.
Context {raft_params : RaftParams orig_base_params}.
Context {si : sorted_interface}.
Context {misi : max_index_sanity_interface}.
Context {smsi : state_machine_safety_interface}.
Context {lmi : log_matching_interface}.
Ltac get_invariant_pre inv :=
match goal with
| H : raft_intermediate_reachable _ |- _=>
match (type of H) with
| context [mkNetwork] =>
fail 2
end || copy_apply inv H
end.
Ltac get_invariant_post inv :=
match goal with
| H : raft_intermediate_reachable _ |- _=>
match (type of H) with
| context [mkNetwork] =>
copy_apply inv H
end
end.
Definition clientCache_to_ks (c : list (clientId * (nat * output))) :=
map (fun e => (fst e, fst (snd e))) c.
Proof using.
induction l; intros; simpl in *; intuition;
break_let; eauto.
Qed.
Proof using.
eauto using snd_execute_log'.
Qed.
Proof using.
induction c; intros; simpl in *; try congruence.
break_if; eauto.
- subst. find_inversion.
break_let. subst. simpl in *. break_if; try congruence.
destruct p. simpl in *. eauto.
- break_let; subst; simpl in *. break_if; try congruence. eauto.
Qed.
Proof using.
eauto using clientCache_to_ks_assoc.
Qed.
Proof using.
induction c; intros; simpl in *; try congruence.
break_if; eauto; try congruence.
- break_let; subst; simpl in *. break_if; try congruence. eauto.
Qed.
Proof using.
eauto using clientCache_to_ks_assoc_none.
Qed.
Proof using.
intros.
unfold cacheApplyEntry, applyEntry in *.
repeat break_match; subst; repeat find_inversion; do_bool; try lia;
simpl in *; auto.
Qed.
Proof using.
intros.
unfold cacheApplyEntry, applyEntry in *.
repeat break_match; subst; repeat find_inversion; do_bool;
simpl in *; auto; lia.
Qed.
Proof using.
intros.
unfold cacheApplyEntry, applyEntry in *.
repeat break_match; subst; repeat find_inversion; do_bool; try lia;
simpl in *; auto; congruence.
Qed.
Proof using.
intros.
unfold cacheApplyEntry, applyEntry in *.
repeat break_match; subst; repeat find_inversion; do_bool;
simpl in *; auto; congruence.
Qed.
Proof using.
intros.
unfold cacheApplyEntry, applyEntry in *.
repeat break_match; subst; repeat find_inversion; do_bool;
simpl in *; auto; try lia; congruence.
Qed.
Proof using.
intros.
unfold cacheApplyEntry, applyEntry in *.
repeat break_match; subst; repeat find_inversion; do_bool;
simpl in *; auto; try lia; congruence.
Qed.
Proof using.
induction c; intros; simpl in *; intuition.
simpl.
break_if; simpl in *; eauto.
f_equal. eauto.
Qed.
Proof using.
induction l; intros; simpl in *; intuition.
- find_inversion. auto.
- repeat break_let. find_inversion.
repeat break_match; simpl in *.
+ break_let.
rewrite snd_execute_log'_nil.
find_apply_hyp_hyp. do_bool.
find_apply_lem_hyp clientCache_to_ks_assoc_getLastId.
break_exists.
find_copy_eapply_lem_hyp cacheApplyEntry_stateMachine_apply;
[|eauto|idtac|]; eauto. subst.
find_eapply_lem_hyp cacheApplyEntry_cache_apply; eauto.
erewrite clientCache_to_ks_assoc_set.
rewrite Heqp1. eauto.
+ do_bool.
find_apply_hyp_hyp.
find_apply_lem_hyp clientCache_to_ks_assoc_getLastId.
break_exists.
break_exists.
find_copy_eapply_lem_hyp cacheApplyEntry_stateMachine_no_apply; eauto.
find_eapply_lem_hyp cacheApplyEntry_cache_no_apply; eauto.
repeat find_rewrite. auto.
+ break_let.
rewrite snd_execute_log'_nil.
find_apply_hyp_hyp. do_bool.
find_apply_lem_hyp clientCache_to_ks_assoc_getLastId_none.
break_exists.
find_copy_eapply_lem_hyp cacheApplyEntry_stateMachine_apply_none; eauto.
subst.
find_eapply_lem_hyp cacheApplyEntry_cache_apply_none; eauto.
erewrite clientCache_to_ks_assoc_set.
rewrite Heqp1. eauto.
Qed.
Proof using.
induction l; simpl in *; intros.
- find_inversion. auto.
- repeat break_match; find_inversion; simpl in *;
unfold cacheApplyEntry, applyEntry in *;
repeat break_match; find_inversion; simpl in *; eauto;
copy_eapply_prop_hyp applyEntries applyEntries; intuition; simpl in *; auto.
Qed.
Proof using.
intros. induction l; simpl in *; auto.
Qed.
Proof using.
intros. induction l; simpl in *; auto.
repeat break_if; do_bool; simpl in *; auto.
- f_equal; eauto.
- intuition. congruence.
- intuition; try congruence.
assert (f a = true) by eauto.
congruence.
Qed.
Proof using.
intros. induction l; simpl in *; auto.
repeat (break_match; simpl in *); do_bool; intuition; try lia; try congruence.
f_equal. repeat find_reverse_rewrite.
rewrite removeAfterIndex_eq; auto.
intros. find_apply_hyp_hyp. lia.
Qed.
Fixpoint log_to_ks' (l : list entry) (ks : list (clientId * nat)) : list (clientId * nat) :=
match l with
| e :: l' =>
if (assoc_default clientId_eq_dec ks (eClient e) 0) <=? eId e then
log_to_ks' l' (assoc_set clientId_eq_dec ks (eClient e) (eId e))
else
log_to_ks' l' ks
| [] => ks
end.
Definition log_to_ks l := log_to_ks' l [].
Definition client_cache_keys_correct net :=
forall h,
a_equiv clientId_eq_dec
(clientCache_to_ks (clientCache (nwState net h)))
(log_to_ks'
(rev
(removeAfterIndex (log (nwState net h))
(lastApplied (nwState net h)))) []).
Proof using.
induction l1; intros; simpl in *; auto.
break_if; simpl in *; eauto.
Qed.
Proof using.
induction l; intros; simpl.
- auto.
- erewrite assoc_default_a_equiv by eauto.
break_if; auto using assoc_set_a_equiv.
Qed.
Fixpoint max_id_for_client_default (default : nat) (c : clientId) (l : list entry) : nat :=
match l with
| [] => default
| e :: l' => if clientId_eq_dec c (eClient e)
then max_id_for_client_default (max default (eId e)) c l'
else max_id_for_client_default default c l'
end.
Proof using.
induction l; simpl; intros.
- auto.
- repeat break_match; do_bool; rewrite IHl; subst; auto.
+ rewrite get_set_same_default.
now rewrite max_r by auto.
+ now rewrite get_set_diff_default by auto.
+ now rewrite max_l by lia.
Qed.
Proof using.
induction l; simpl; intros.
- auto.
- break_if.
+ rewrite IHl.
* subst. now rewrite max_l by eauto.
* intros. subst. eapply le_trans; [| apply Max.le_max_l]. eauto.
+ auto.
Qed.
Proof using.
induction l; simpl; intros.
- auto.
- break_if; repeat rewrite IHl. 2: reflexivity.
zify. lia.
Qed.
Proof using.
induction l; simpl; intuition.
break_if.
- specialize (IHl (max x (eId a))).
intuition.
+ destruct (le_lt_dec x (eId a)).
* rewrite max_r in * by auto.
right. eauto.
* rewrite max_l in * by lia. auto.
+ right.
break_exists. break_and.
rewrite max_id_for_client_default_on_max in *.
exists x0. intuition.
- specialize (IHl x). intuition. right. break_exists_exists. intuition.
Qed.
Proof using.
induction l; simpl; intuition; subst.
- break_if; try congruence.
rewrite Max.max_comm.
rewrite max_id_for_client_default_on_max.
apply Max.le_max_l.
- break_if; auto.
Qed.
Proof using.
induction l; simpl; intuition.
break_if; intuition.
rewrite max_id_for_client_default_on_max.
apply Max.le_max_l.
Qed.
Proof using.
intros.
pose proof max_id_for_client_default_or_entry c l x.
pose proof max_id_for_client_default_or_entry c l' x.
intuition; break_exists; intuition; repeat find_rewrite.
- eapply le_trans; [|eapply Nat.eq_le_incl].
apply max_id_for_client_default_ge_default.
eauto.
- find_apply_hyp_hyp.
eapply le_trans.
+ apply max_id_for_client_default_is_max; eauto.
+ eauto using Nat.eq_le_incl.
- find_apply_hyp_hyp.
eapply le_trans.
+ apply max_id_for_client_default_is_max; eauto.
+ eauto using Nat.eq_le_incl.
Qed.
Proof using.
intros.
apply le_antisym; auto using max_id_for_client_default_subset.
Qed.
Proof using.
induction l; intros; simpl.
- rewrite assoc_default_assoc_set. auto.
- break_if; simpl in *; eauto.
do_bool.
destruct (clientId_eq_dec (eClient a) c); simpl in *; auto.
+ subst.
find_rewrite_lem assoc_default_assoc_set.
rewrite assoc_set_assoc_set_same.
eauto using le_trans.
+ erewrite assoc_default_a_equiv;
[|eapply log_to_ks'_a_equiv;
eapply assoc_set_assoc_set_diff; auto].
eauto.
Qed.
Proof using.
induction l; intros; simpl in *; auto.
break_if; simpl in *; eauto.
do_bool.
destruct (clientId_eq_dec (eClient a) c); simpl in *; subst; auto.
- eapply le_trans; eauto.
eauto using log_to_ks'_assoc_default_ks.
- match goal with
| [ |- context [ assoc_set ?e ?ks ?c' ?i ] ] =>
assert (assoc_default e ks c 0 = assoc_default e (assoc_set e ks c' i) c 0)
end; repeat find_rewrite; eauto.
rewrite assoc_default_assoc_set_diff; auto.
Qed.
Proof using.
induction l; intros; simpl in *; auto.
repeat break_if; do_bool; simpl in *; eauto.
- destruct (clientId_eq_dec (eClient a) c); simpl in *; auto.
+ subst.
match goal with
| [ |- context [ assoc_set ?e ?ks ?c ?i ] ] =>
assert (assoc_default e ks c 0 = assoc_default e (assoc_set e ks c i) c 0)
end; repeat find_rewrite; eauto.
rewrite assoc_default_assoc_set.
eapply le_antisym; eauto.
eapply le_trans; [|eauto];
eauto using log_to_ks'_assoc_default_ks.
+ match goal with
| [ |- context [ assoc_set ?e ?ks ?c' ?i ] ] =>
assert (assoc_default e ks c 0 = assoc_default e (assoc_set e ks c' i) c 0)
end; repeat find_rewrite; eauto.
rewrite assoc_default_assoc_set_diff; auto.
- destruct (clientId_eq_dec (eClient a) c); simpl in *; auto.
+ subst.
match goal with
| [ |- context [ assoc_set ?e ?ks ?c ?i ] ] =>
assert (assoc_default e ks c 0 = assoc_default e (assoc_set e ks c i) c 0)
end; repeat find_rewrite; eauto.
rewrite assoc_default_assoc_set.
eapply le_antisym; eauto.
eapply le_trans; [|eauto];
eauto using log_to_ks'_assoc_default_ks.
eapply le_trans; [|eauto using log_to_ks'_assoc_default_assoc_default_le].
lia.
+ match goal with
| [ |- context [ assoc_set ?e ?ks ?c' ?i ] ] =>
assert (assoc_default e ks c 0 = assoc_default e (assoc_set e ks c' i) c 0)
end; repeat find_rewrite; eauto.
rewrite assoc_default_assoc_set_diff; auto.
Qed.
Proof using.
induction l; intros; simpl in *.
- rewrite get_set_diff by auto. auto.
- repeat break_match; simpl in *; eauto.
+ do_bool. destruct (clientId_eq_dec (eClient a) k); subst; simpl in *.
* rewrite assoc_set_assoc_set_same. auto.
* erewrite assoc_a_equiv; [|apply log_to_ks'_a_equiv;
apply assoc_set_assoc_set_diff]; eauto.
+ do_bool. destruct (clientId_eq_dec (eClient a) k); subst; simpl in *.
* rewrite assoc_set_assoc_set_same. auto.
* rewrite assoc_default_assoc_set_diff in *; auto; lia.
+ do_bool. destruct (clientId_eq_dec (eClient a) k); subst; simpl in *.
* erewrite <- assoc_set_assoc_set_same; eauto.
* rewrite assoc_default_assoc_set_diff in *; auto; lia.
Qed.
Proof using.
induction l; intros; simpl in *; auto using assoc_default_assoc_set_diff.
repeat break_match; simpl in *; eauto.
- do_bool. destruct (clientId_eq_dec (eClient a) k); subst; simpl in *.
+ rewrite assoc_set_assoc_set_same. auto.
+ erewrite assoc_default_a_equiv; [|apply log_to_ks'_a_equiv;
apply assoc_set_assoc_set_diff]; eauto.
- do_bool. destruct (clientId_eq_dec (eClient a) k); subst; simpl in *.
+ rewrite assoc_set_assoc_set_same. auto.
+ rewrite assoc_default_assoc_set_diff in *; auto; lia.
- do_bool. destruct (clientId_eq_dec (eClient a) k); subst; simpl in *.
+ erewrite <- assoc_set_assoc_set_same; eauto.
+ rewrite assoc_default_assoc_set_diff in *; auto; lia.
Qed.
Proof using.
induction l; intros; simpl in *; eauto using a_equiv_refl.
repeat break_if; simpl in *; eauto.
- do_bool.
destruct (clientId_eq_dec (eClient a) c); subst.
+ repeat rewrite assoc_set_assoc_set_same.
find_rewrite_lem assoc_default_assoc_set.
assert (i = eId a) by (eapply le_antisym; auto;
eapply le_trans; [|eauto];
eauto using log_to_ks'_assoc_default_ks).
subst. find_apply_hyp_hyp.
find_rewrite_lem assoc_set_assoc_set_same.
auto.
+ eapply a_equiv_sym.
eapply a_equiv_trans;
[eapply log_to_ks'_a_equiv;
eapply assoc_set_assoc_set_diff; auto|].
eapply a_equiv_sym. eauto.
- do_bool.
destruct (clientId_eq_dec (eClient a) c); subst.
+ find_rewrite_lem assoc_default_assoc_set.
find_apply_hyp_hyp.
find_rewrite_lem assoc_set_assoc_set_same.
auto.
+ rewrite assoc_default_assoc_set_diff in *; auto.
lia.
- do_bool.
destruct (clientId_eq_dec (eClient a) c); subst.
+ find_rewrite_lem assoc_default_assoc_set.
rewrite assoc_set_assoc_set_same.
assert (i = eId a); subst; eauto.
eapply le_antisym; eauto.
eapply le_trans; [|eauto].
eapply le_trans; [|eapply log_to_ks'_assoc_default_assoc_default_le].
lia.
+ rewrite assoc_default_assoc_set_diff in *; auto. lia.
Qed.
Proof using.
induction l; simpl; intuition.
- eauto.
- break_if; do_bool.
+ destruct (clientId_eq_dec (eClient e) (eClient a)).
* repeat find_rewrite. unfold assoc_default in *. find_rewrite.
specialize (IHl (assoc_set clientId_eq_dec ks (eClient a) (eId a)) (eId a)).
conclude_using ltac:(now rewrite get_set_same).
break_exists_exists. intuition.
* rewrite log_to_ks'_assoc_set_diff by auto.
auto.
+ auto.
Qed.
Proof using.
induction l; simpl; intuition.
- subst. break_if; do_bool.
+ apply in_ks_log_to_ks'_le.  rewrite get_set_same. auto.
+ unfold assoc_default in *.
break_match; try lia.
find_eapply_lem_hyp in_ks_log_to_ks'_le.
break_exists_exists. intuition eauto. lia.
- break_if; do_bool; auto.
Qed.
Proof using lmi smsi misi.
(* establish maxIndex guarantee in post state *)
intros.
get_invariant_post max_index_sanity_invariant.
unfold maxIndex_sanity in *; intuition.
unfold maxIndex_lastApplied in *; intuition.
match goal with
| H : forall _, lastApplied _ <= maxIndex _ |- _ =>
specialize (H (pDst p))
end. simpl in *. repeat find_higher_order_rewrite.
rewrite_update. repeat find_rewrite.
(* SMS *)
get_invariant_pre state_machine_safety_invariant.
unfold state_machine_safety in *. intuition.
match goal with
| H : state_machine_safety_nw _ |- _ =>
specialize (H (pDst p))
end.
find_copy_apply_lem_hyp handleAppendEntries_log.
intuition; repeat find_rewrite; eauto.
- match goal with
| _ : eIndex ?e <= lastApplied (nwState ?net ?h) |- _ =>
assert (commit_recorded net h e) by (unfold commit_recorded; eauto)
end.
get_invariant_pre log_matching_invariant.
unfold log_matching, log_matching_hosts in *. intuition.
copy_eapply_prop_hyp In In.
copy_eapply_prop_hyp pBody pBody; eauto.
intuition; try lia.
subst.
find_copy_apply_lem_hyp handleAppendEntries_same_lastApplied.
repeat find_rewrite. lia.
- match goal with
| _ : eIndex ?e <= lastApplied (nwState ?net ?h) |- _ =>
assert (commit_recorded net h e) by (unfold commit_recorded; eauto)
end.
get_invariant_pre log_matching_invariant.
unfold log_matching, log_matching_hosts in *. intuition.
copy_eapply_prop_hyp In In.
copy_eapply_prop_hyp pBody pBody; eauto.
intuition.
+ apply in_app_iff. right.
apply removeAfterIndex_le_In; eauto; lia.
+ apply in_app_iff. right.
apply removeAfterIndex_le_In; eauto; lia.
+ match goal with
| _ : context [maxIndex (?a ++ ?b)] |- _ =>
pose proof maxIndex_app a b
end. intuition.
repeat find_rewrite.
find_copy_apply_lem_hyp handleAppendEntries_same_lastApplied.
repeat find_rewrite. lia.
Qed.
Proof using lmi smsi misi si.
intros.
find_copy_apply_lem_hyp handleAppendEntries_same_lastApplied.
repeat find_rewrite.
get_invariant_pre logs_sorted_invariant.
get_invariant_post logs_sorted_invariant.
unfold logs_sorted in *. intuition.
apply removeAfterIndex_same_sufficient; auto.
- unfold logs_sorted_host in *. simpl in *.
match goal with
| H : forall h, sorted (log (st' h)) |- _ =>
specialize (H (pDst p))
end.
repeat find_higher_order_rewrite.
rewrite_update. auto.
- intros. eauto using handleAppendEntries_preserves_lastApplied_entries'.
- intros.
get_invariant_pre max_index_sanity_invariant.
unfold maxIndex_sanity, maxIndex_lastApplied in *. intuition.
enough (exists e', eIndex e' = eIndex e /\ In e' (log (nwState net (pDst p)))).
+ break_exists. intuition.
find_copy_eapply_lem_hyp handleAppendEntries_preserves_lastApplied_entries';
repeat find_rewrite; eauto.
enough (x = e) by now subst.
eapply uniqueIndices_elim_eq; eauto.
apply sorted_uniqueIndices.
unfold logs_sorted_host in *. simpl in *.
match goal with
| H : forall h, sorted (log (st' h)) |- _ =>
specialize (H (pDst p))
end.
repeat find_higher_order_rewrite.
rewrite_update. auto.
+ apply log_matching_invariant; auto.
intuition; eauto using le_trans.
enough (eIndex e > 0) by auto.
get_invariant_post log_matching_invariant.
unfold log_matching, log_matching_hosts in *. intuition.
match goal with
| H : context [eIndex _ > _] |- _ =>
eapply H with (h := (pDst p))
end.
simpl. repeat find_higher_order_rewrite.
rewrite_update. auto.
Qed.
Proof using.
intros.
simpl in *; break_if; do_bool; auto; lia.
Qed.
Proof using misi.
intros.
erewrite handleClientRequest_lastApplied; eauto.
find_apply_lem_hyp handleClientRequest_log.
intuition; repeat find_rewrite; eauto.
break_exists; intuition; repeat find_rewrite.
erewrite removeAfterIndex_cons; eauto.
get_invariant_pre max_index_sanity_invariant.
unfold maxIndex_sanity, maxIndex_lastApplied in *. intuition.
match goal with
| H : forall _, lastApplied _ <= maxIndex _ |- _ =>
specialize (H h)
end. lia.
Qed.
Proof using.
unfold client_cache_keys_correct, client_cache_complete.
intros.
unfold getLastId.
enough (exists id, assoc clientId_eq_dec (clientCache_to_ks (clientCache (nwState net h))) (eClient e) = Some id /\
eId e <= id).
- break_exists_exists.
intuition.
find_apply_lem_hyp clientCache_to_ks_assoc.
break_exists_exists. intuition.
- erewrite assoc_a_equiv by eauto.
find_apply_lem_hyp in_rev.
auto using in_l_log_to_ks'_le.
Qed.
Proof using.
induction l1; intros; simpl in *; auto.
repeat break_match; simpl in *; eauto; try solve [f_equal; eauto].
- exfalso. do_bool.
find_erewrite_lem assoc_assoc_default. lia.
- do_bool.
find_erewrite_lem assoc_assoc_default.
rewrite assoc_set_same; eauto.
find_eapply_lem_hyp le_antisym; eauto. subst. auto.
- exfalso. do_bool.
find_erewrite_lem assoc_assoc_default_missing. lia.
Qed.
Proof using.
induction l; intros; simpl in *; auto.
repeat break_match; simpl in *; auto; do_bool;
try solve [f_equal; eauto using assoc_set_a_equiv];
match goal with
| _ : assoc ?dec ?ks ?c = _, _ : assoc ?dec ?ks' ?c = _ |- _ =>
assert (assoc dec ks c = assoc dec ks' c) by (eauto using assoc_a_equiv)
end; repeat find_rewrite; try find_inversion; try congruence; lia.
Qed.
Proof using.
intros. unfold cacheApplyEntry in *.
repeat break_match; try find_inversion; subst; auto; do_bool.
- unfold applyEntry in *.
break_let. find_inversion.
simpl in *.
match goal with
| H : context [assoc_set] |- _ =>
unfold getLastId in H; simpl in H
end.
destruct (clientId_eq_dec client (eClient e));
try now rewrite get_set_diff in *; auto.
subst. rewrite get_set_same in *.
find_inversion. repeat find_rewrite.
right. intuition. find_inversion.
lia.
- unfold applyEntry in *.
break_let. find_inversion.
simpl in *.
match goal with
| H : context [assoc_set] |- _ =>
unfold getLastId in H; simpl in H
end.
destruct (clientId_eq_dec client (eClient e));
try now rewrite get_set_diff in *; auto.
subst. rewrite get_set_same in *.
find_inversion. repeat find_rewrite.
right. intuition. congruence.
Qed.
Proof using.
induction l; intros; simpl in *; try now repeat eexists; eauto.
repeat break_let. find_inversion.
find_apply_hyp_hyp.
break_exists. intuition.
repeat find_rewrite. find_inversion.
repeat eexists; eauto using app_ass.
Qed.
Proof using.
intros. unfold getLastId in *. induction (clientCache st).
- simpl in *. congruence.
- simpl in *. break_let. subst. simpl in *.
break_if; repeat find_inversion; auto.
Qed.
Proof using.
intros.
unfold assoc_default in *.
break_match; intuition; eauto; lia.
Qed.
Proof using.
induction l; intros; simpl in *; intuition.
- find_inversion.
apply a_equiv_refl.
- repeat break_let. find_inversion.
break_if.
+ do_bool.
unfold cacheApplyEntry in *.
repeat break_match; repeat find_inversion; do_bool.
* find_apply_lem_hyp getLastId_clientCache_to_ks_assoc.
find_erewrite_lem assoc_assoc_default. lia.
* find_apply_hyp_hyp.
subst.
rewrite assoc_set_same; eauto using a_equiv_refl.
eauto using getLastId_clientCache_to_ks_assoc.
* subst.
unfold applyEntry in *.
break_let. find_inversion.
find_apply_hyp_hyp.
eapply a_equiv_trans; eauto.
simpl.
erewrite clientCache_to_ks_assoc_set; eauto using a_equiv_refl.
* subst.
unfold applyEntry in *.
break_let. find_inversion.
find_apply_hyp_hyp.
eapply a_equiv_trans; eauto.
simpl.
erewrite clientCache_to_ks_assoc_set; eauto using a_equiv_refl.
+ do_bool. find_apply_lem_hyp i_lt_assoc_default_0.
break_exists. intuition.
find_apply_lem_hyp clientCache_to_ks_assoc_getLastId.
break_exists.
unfold cacheApplyEntry in *.
repeat find_rewrite. break_if; do_bool; try lia.
find_inversion. eauto.
Qed.
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.
lia.
* 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.
Proof using.
intros.
unfold doGenericServer in *.
break_let. break_if.
- right. do_bool. find_inversion.
simpl in *.
intuition; eauto;
use_applyEntries_spec; subst; simpl in *; auto.
- left. do_bool.  find_inversion.
match goal with
| _ : applyEntries _ _ (rev ?l) = _ |- _ =>
enough (l = []) by
(repeat find_rewrite; simpl in *; find_inversion;
destruct r; simpl in *; auto)
end.
erewrite filter_fun_ext_eq; eauto using filter_false.
intros. simpl in *.
apply Bool.not_true_is_false.
intuition.
do_bool. intuition. do_bool.
use_applyEntries_spec. subst. simpl in *. lia.
Qed.
Proof using.
eauto using deduplicate_log'_app.
Qed.
Proof using.
unfold output_correct.
intros.
break_exists.
intuition.
pose proof (deduplicate_log_app xs ys). break_exists.
repeat find_rewrite.
rewrite app_ass in *. simpl in *.
eexists. eexists. eexists. eexists. eexists.
intuition eauto.
Qed.
Proof using.
induction l; intros; simpl in *.
- find_inversion. auto.
- repeat break_let.
rewrite app_ass.
eauto.
Qed.
Proof using.
intros.
find_eapply_lem_hyp execute_log'_trace;
rewrite app_nil_r in *; eauto.
Qed.

(* FIXME: move to StructTact *)
Lemma hd_error_Some_app :
forall A l l' (x : A),
hd_error l = Some x ->
hd_error (l ++ l') = Some x.