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.

Lemma cacheApplyEntry_getLastId :
forall st e l st' client id out,
cacheApplyEntry st e = (l, st') ->
getLastId st' client = Some (id, out) ->
getLastId st client = Some (id, out) \/
eClient e = client /\
l = [out] /\
eId e = id /\
out = fst (handler (eInput e) (stateMachine st)) /\
(forall id' out', getLastId st client = Some (id', out') ->
id' < id).