Section RaftLinearizableProofs.
Context {orig_base_params : BaseParams}.
Context {one_node_params : OneNodeParams orig_base_params}.
Context {raft_params : RaftParams orig_base_params}.
Context {oiai : output_implies_applied_interface}.
Context {aiii : applied_implies_input_interface}.
Context {copi : causal_order_preserved_interface}.
Context {iboi : input_before_output_interface}.
Context {oci : output_correct_interface}.
Context {ogii : output_greatest_id_interface}.
Definition op_eq_dec : forall x y : op key, {x = y} + {x <> y}.
Proof using.
decide equality; auto using key_eq_dec.
Qed.
Fixpoint import (tr : list (name * (raft_input + list raft_output)))
: list (op key) :=
match tr with
| [] => []
| (_, (inl (ClientRequest c id cmd))) :: xs =>
I (c, id) :: remove op_eq_dec (I (c, id)) (import xs)
| (_, (inr l)) :: xs =>
let os := dedup op_eq_dec
(filterMap (fun x =>
match x with
| ClientResponse c id cmd => Some (O (c, id))
| _ => None
end) l)
in os ++ remove_all op_eq_dec os (import xs)
| _ :: xs => import xs
end.
Inductive exported (env_i : key -> option input) (env_o : key -> option output) :
list (IR key) -> list (input * output) -> Prop :=
| exported_nil : exported env_i env_o nil nil
| exported_IO : forall k i o l tr,
env_i k = Some i ->
env_o k = Some o ->
exported env_i env_o l tr ->
exported env_i env_o (IRI k :: IRO k :: l) ((i, o) :: tr)
| exported_IU : forall k i o l tr,
env_i k = Some i ->
exported env_i env_o l tr ->
exported env_i env_o (IRI k :: IRU k :: l) ((i, o) :: tr).
Fixpoint get_input (tr : list (name * (raft_input + list raft_output))) (k : key)
: option input :=
match tr with
| [] => None
| (_, (inl (ClientRequest c id cmd))) :: xs =>
if (sumbool_and _ _ _ _
(clientId_eq_dec c (fst k))
(eq_nat_dec id (snd k))) then
Some cmd
else
get_input xs k
| _ :: xs => get_input xs k
end.
Fixpoint get_output' (os : list raft_output) (k : key) : option output :=
match os with
| [] => None
| ClientResponse c id o :: xs =>
if (sumbool_and _ _ _ _
(clientId_eq_dec c (fst k))
(eq_nat_dec id (snd k))) then
Some o
else
get_output' xs k
| _ :: xs => get_output' xs k
end.
Fixpoint get_output (tr : list (name * (raft_input + list raft_output))) (k : key)
: option output :=
match tr with
| [] => None
| (_, (inr os)) :: xs => (match get_output' os k with
| Some o => Some o
| None => get_output xs k
end)
| _ :: xs => get_output xs k
end.
Proof using.
unfold has_key.
intros.
destruct e.
simpl.
break_if; repeat (do_bool; intuition).
Qed.
Proof using.
intros. subst. apply has_key_intro.
Qed.
Proof using.
unfold has_key.
intros.
destruct e'.
simpl in *.
do_bool. right. do_bool. auto.
Qed.
Proof using.
unfold has_key.
intros.
destruct e'.
simpl in *.
do_bool. left. break_if; congruence.
Qed.
Proof using.
induction l; simpl.
- intuition.
- intros. repeat break_match; intuition; subst; simpl in *; intuition eauto.
+ do_bool. destruct (clientId_eq_dec (eClient e) (eClient a)).
* assert (eId a <= eId e).
{ repeat find_rewrite. auto using has_key_intro.
}
{ find_apply_lem_hyp le_lt_or_eq. break_or_hyp.
- specialize (IHl _ ltac:(eauto)).
match goal with
| [ |- context [deduplicate_log' _ ?ks] ] =>
specialize (IHl ks)
end.
forward IHl.
{ intuition.
repeat find_rewrite. rewrite get_set_same in *. find_injection. auto.
}
concludes.
forward IHl.
{ intuition auto using has_key_different_id_false with *. }
concludes.
break_exists_exists. intuition.
- eauto.
}
* specialize (IHl _ ltac:(eauto)).
match goal with
| [ |- context [deduplicate_log' _ ?ks] ] =>
specialize (IHl ks)
end.
forward IHl.
{ intuition.
repeat find_rewrite. rewrite get_set_diff in * by auto. auto.
}
concludes.
forward IHl.
{ intuition auto using has_key_different_client_false with *. }
concludes.
break_exists_exists. intuition.
+ do_bool. assert (n < eId e) by auto. lia.
+ do_bool. apply IHl; auto.
intros.
destruct (clientId_eq_dec (eClient e) (eClient a)).
* assert (eId e <> eId a).
{ intro. repeat find_rewrite.
assert (n < eId a) by auto. lia.
}
intuition auto using has_key_different_id_false with *.
* intuition auto using has_key_different_client_false with *.
+ destruct (clientId_eq_dec (eClient e) (eClient a)).
* assert (eId a <= eId e).
{ repeat find_rewrite. auto using has_key_intro.
}
{ find_apply_lem_hyp le_lt_or_eq. break_or_hyp.
- specialize (IHl _ ltac:(eauto)).
match goal with
| [ |- context [deduplicate_log' _ ?ks] ] =>
specialize (IHl ks)
end.
forward IHl.
{ intuition.
repeat find_rewrite. rewrite get_set_same in *. find_injection. auto.
}
concludes.
forward IHl.
{ intuition auto using has_key_different_id_false with *. }
concludes.
break_exists_exists. intuition.
- eauto.
}
* specialize (IHl _ ltac:(eauto)).
match goal with
| [ |- context [deduplicate_log' _ ?ks] ] =>
specialize (IHl ks)
end.
forward IHl.
{ intuition.
repeat find_rewrite. rewrite get_set_diff in * by auto. auto.
}
concludes.
forward IHl.
{ intuition auto using has_key_different_client_false with *. }
concludes.
break_exists_exists. intuition.
Qed.
Proof using.
unfold deduplicate_log'.
intros.
eapply deduplicate_log'_In with (ks := []) in H; simpl; intuition; try discriminate.
Qed.
Proof using.
eauto using deduplicate_log'_In_if.
Qed.
Fixpoint log_to_IR (env_o : key -> option output) (log : list entry) {struct log} : list (IR key) :=
match log with
| [] => []
| mkEntry h client id index term input :: log' =>
(match env_o (client, id) with
| None => [IRI (client, id); IRU (client, id)]
| Some _ => [IRI (client, id); IRO (client, id)]
end) ++ log_to_IR env_o log'
end.
Proof using.
intros.
induction log; simpl in *; auto.
- repeat break_match; simpl in *; constructor; auto.
Qed.
Proof using.
induction tr; intros; simpl in *; intuition.
repeat break_match; subst; intuition.
- find_apply_hyp_hyp. break_exists_exists.
intuition.
- simpl in *. intuition; try congruence.
find_apply_lem_hyp in_remove.
find_apply_hyp_hyp. break_exists_exists.
intuition.
- do_in_app. intuition.
+ find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap.
break_exists. intuition.
break_match; try congruence.
find_inversion.
repeat eexists; intuition eauto.
+ find_apply_lem_hyp in_remove_all_was_in.
find_apply_hyp_hyp. break_exists_exists.
intuition.
Qed.
Proof using.
induction tr; intros; simpl in *; intuition.
repeat break_match; subst.
- find_apply_hyp_hyp. break_exists.
eauto 10.
- simpl in *. intuition.
+ find_inversion. simpl. eauto 10.
+ find_apply_lem_hyp in_remove.
find_apply_hyp_hyp. break_exists. eauto 10.
- do_in_app. intuition.
+ find_apply_lem_hyp in_dedup_was_in.
find_eapply_lem_hyp In_filterMap. break_exists. break_and.
break_match; discriminate.
+ find_eapply_lem_hyp in_remove_all_was_in.
find_apply_hyp_hyp. break_exists. eauto 10.
Qed.
Proof using.
intros.
induction log; simpl in *; intuition.
- subst. break_exists.
repeat break_match; intuition.
simpl in *.
subst. congruence.
- repeat break_match; in_crush.
Qed.
Proof using.
intros. induction l; simpl in *; intuition.
- subst. break_if; simpl in *; intuition eauto.
- break_match; simpl in *; intuition eauto.
break_if; simpl in *; intuition eauto.
Qed.
Proof using.
intros.
induction tr; simpl in *; intuition.
repeat break_match; intuition; subst; simpl in *; intuition; try congruence;
try do_in_app; intuition eauto.
- find_apply_lem_hyp in_remove; auto.
- find_apply_lem_hyp in_dedup_was_in; auto.
find_apply_lem_hyp In_filterMap.
break_exists; break_match; intuition; try congruence.
subst. find_inversion.
find_apply_lem_hyp In_get_output'. break_exists; congruence.
- find_apply_lem_hyp in_remove_all_was_in. auto.
Qed.
Proof using.
induction log; intros; simpl in *; intuition.
repeat break_match; subst; simpl in *; intuition; try congruence; try find_inversion; simpl.
- eexists. eexists. intuition; eauto.
- find_apply_hyp_hyp. break_exists_exists. intuition.
- find_apply_hyp_hyp. break_exists_exists. intuition.
Qed.
Proof using.
induction l; intros; simpl in *; intuition.
- discriminate.
- repeat break_match; subst; eauto.
find_inversion. break_and. subst. eauto.
Qed.
Proof using.
induction tr; intros; simpl in *.
- discriminate.
- repeat break_match; subst; simpl; intuition eauto.
+ right. apply remove_preserve; try discriminate. eauto.
+ find_inversion. apply in_or_app. left.
find_apply_lem_hyp get_output'_In.
apply dedup_In.
eapply filterMap_In; eauto.
simpl. now rewrite <- surjective_pairing.
+ apply in_or_app. right.
apply in_remove_all_preserve.
* intro. find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap.
break_exists. break_and.
break_match; try discriminate.
find_inversion.
find_apply_lem_hyp In_get_output'.
break_exists. congruence.
* eauto.
Qed.
Proof using.
induction log; intros; simpl in *; intuition.
repeat break_match; subst; simpl in *; intuition; try congruence; try find_inversion; simpl.
- find_apply_hyp_hyp. break_exists_exists. intuition.
- eexists. intuition; eauto.
- find_apply_hyp_hyp. break_exists_exists. intuition.
Qed.
Proof using.
induction tr; intros; simpl in *; intuition; subst.
- rewrite <- surjective_pairing. intuition.
- break_match; simpl; eauto.
subst.
destruct (key_eq_dec (c, n) k).
+ subst. auto.
+ right. apply remove_preserve.
* congruence.
* eauto.
- apply in_or_app.
right.
apply in_remove_all_preserve.
+ intro. find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap.
break_exists. break_and.
break_match; try discriminate.
+ eauto.
Qed.
Proof using.
induction log; simpl; intuition.
repeat break_match; subst; simpl in *;
rewrite get_IR_input_keys_defn; auto using f_equal.
Qed.
Proof using.
induction log; simpl; intuition.
repeat break_match; subst; simpl in *;
repeat rewrite get_IR_output_keys_defn; auto using f_equal.
Qed.
Proof using.
induction tr; intros.
- constructor.
- simpl. repeat break_match; subst.
+ auto.
+ rewrite get_op_input_keys_defn. constructor; auto.
* intro. find_apply_lem_hyp get_op_input_keys_sound.
eapply remove_In; eauto.
* eapply subseq_NoDup; eauto.
eapply subseq_get_op_input_keys.
auto using subseq_remove.
+ rewrite get_op_input_keys_app.
rewrite get_op_input_keys_on_Os_nil.
* simpl.
eapply subseq_NoDup; eauto.
eapply subseq_get_op_input_keys.
apply subseq_remove_all.
apply subseq_refl.
* intros.
find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap.
break_exists.  break_and.
break_match; try discriminate.
subst. find_inversion. eauto.
Qed.
Proof using.
induction tr; intros.
- constructor.
- simpl. repeat break_match; subst.
+ auto.
+ rewrite get_op_output_keys_defn.
eapply subseq_NoDup; eauto.
apply subseq_get_op_output_keys.
apply subseq_remove.
+ rewrite get_op_output_keys_app.
apply NoDup_disjoint_append.
* apply get_op_output_keys_preserves_NoDup.
apply NoDup_dedup.
* eapply subseq_NoDup; eauto.
eapply subseq_get_op_output_keys.
apply subseq_remove_all.
apply subseq_refl.
* intros. intro.
repeat find_apply_lem_hyp get_op_output_keys_sound.
eapply in_remove_all_not_in; eauto.
Qed.
Proof using.
induction tr; intros; simpl in *; intuition.
repeat break_match; subst; simpl in *; intuition eauto; try congruence;
unfold output_before_input; simpl in *; intuition.
- right. intuition.
+ do_bool.
destruct k'.  simpl in *.
match goal with
| _ : I (?x, ?y) = I (?x', ?y') -> False |- _ =>
destruct (clientId_eq_dec x x'); destruct (eq_nat_dec y y')
end; subst; intuition.
* right. do_bool. intuition.
* left. break_if; congruence.
* left. break_if; congruence.
+ apply IHtr. eauto using before_remove.
- break_if; intuition. right.
intuition. find_apply_lem_hyp before_app; [find_apply_lem_hyp before_remove_all|]; intuition eauto.
+ find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap.
break_exists. intuition. break_match; congruence.
+ find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap.
break_exists.
intuition. break_match; try congruence.
subst. find_inversion. simpl in *.
match goal with
| H : _ -> False |- False => apply H
end. eexists; eauto.
Qed.
Proof using.
intros. unfold has_key, key_of in *.
break_match. subst. simpl in *. break_if; try discriminate. repeat (do_bool; intuition).
subst; reflexivity.
Qed.
Proof using.
intros. unfold has_key, key_of in *.
break_match. subst. simpl in *. find_inversion. break_if; try congruence. repeat (do_bool; intuition).
Qed.
Proof using.
intros. unfold has_key, key_of in *.
break_match. subst. simpl in *. break_if; try congruence. repeat (do_bool; intuition); congruence.
Qed.
Proof using.
intros. unfold has_key, key_of in *.
break_match. subst. simpl in *. repeat (do_bool; intuition).
match goal with
| _ : (?x, ?y) = (?x', ?y') -> False |- _ =>
destruct (clientId_eq_dec x x'); destruct (eq_nat_dec y y')
end; subst; intuition.
- right. do_bool. congruence.
- left. break_if; congruence.
- left. break_if; congruence.
Qed.
Proof using.
unfold has_key.
intros. destruct e.
simpl. do_bool. break_and. do_bool. break_if; congruence.
Qed.
Proof using.
unfold has_key.
intros. destruct e.
simpl. do_bool. intuition. do_bool. auto.
Qed.
Proof using.
intuition eauto using has_key_true_same_client, has_key_true_same_id.
Qed.
Proof using.
unfold has_key.
intros. destruct e. simpl. do_bool. intuition (do_bool; auto).
break_if; try congruence. auto.
Qed.
Proof using.
induction l; simpl; intros.
- intuition.
- intuition.
+ repeat break_match; simpl; auto.
do_bool.
find_apply_lem_hyp has_key_true_elim. break_and. repeat find_rewrite.
assert (n < snd k) by auto. lia.
+ repeat break_match; simpl.
* { destruct (has_key (fst k) (snd k) a) eqn:?; auto.
right. intuition. apply IHl; auto.
do_bool.
intros. destruct (clientId_eq_dec (eClient a) (fst k)).
- repeat find_rewrite. rewrite get_set_same in *. find_inversion.
repeat match goal with
| H : context [ has_key (fst k')] |- _ => clear H
end.
find_apply_lem_hyp has_key_false_elim.
intuition; try congruence.
assert (has_key (fst k) (eId a) a = true) by eauto using has_key_intro'.
assert (eId a <= snd k) by auto.
lia.
- rewrite get_set_diff in * by auto. auto.
}
* do_bool. apply IHl; auto. intros.
{ destruct (has_key (fst k) (snd k) a) eqn:?; auto.
find_apply_lem_hyp has_key_true_elim. break_and.
repeat find_rewrite. assert (n < snd k) by auto. lia.
}
* { destruct (has_key (fst k) (snd k) a) eqn:?; auto.
right. intuition. apply IHl; auto.
do_bool.
intros. destruct (clientId_eq_dec (eClient a) (fst k)).
- repeat find_rewrite. rewrite get_set_same in *. find_inversion.
repeat match goal with
| H : context [ has_key (fst k')] |- _ => clear H
end.
find_apply_lem_hyp has_key_false_elim.
intuition; try congruence.
assert (has_key (fst k) (eId a) a = true) by eauto using has_key_intro'.
assert (eId a <= snd k) by auto.
lia.
- rewrite get_set_diff in * by auto. auto.
}
Qed.
Proof using.
intros.
apply before_func_deduplicate'; auto.
simpl. intros. discriminate.
Qed.
Proof using ogii.
intros. unfold entries_ordered in *.
remember (applied_entries (nwState net)) as l.
find_apply_lem_hyp before_func_deduplicate.
{
remember (deduplicate_log l) as l'; clear Heql'. clear Heql. clear l. rename l' into l.
induction l; simpl in *; intuition.
- repeat break_match; subst; simpl in *; break_if; try discriminate; repeat (do_bool; intuition).
+ destruct k; simpl in *; subst. right. intuition.
find_inversion. simpl in *. intuition.
+ exfalso. destruct k; subst; simpl in *.
find_apply_lem_hyp import_get_output. break_exists. congruence.
- repeat break_match; subst; simpl in *; repeat (do_bool; intuition); try break_if; try congruence.
+ right. destruct k'. simpl in *. intuition; try congruence.
destruct (key_eq_dec k (eClient, eId)); subst; intuition.
right. intuition; congruence.
+ right. destruct k'. simpl in *. intuition; try congruence.
destruct (key_eq_dec k (eClient, eId)); subst; intuition.
right. intuition; congruence.
+ right. intuition; [find_inversion; simpl in *; intuition|].
right. intuition. congruence.
+ right. intuition; [find_inversion; simpl in *; intuition|].
right. intuition. congruence.
}
{
intros. subst.
eapply output_greatest_id with (client := fst k) (id := snd k) in H.
- intros. unfold greatest_id_for_client in *.
destruct (le_lt_dec id' (snd k)); auto.
find_copy_apply_hyp_hyp.
exfalso. eapply before_func_antisymmetric; try eassumption.
unfold has_key.
intros. destruct x.
do_bool. intuition. do_bool. subst. lia.
- red. find_apply_lem_hyp in_import_in_trace_O.
break_exists_exists. intuition.
}
Qed.
Proof using.
intros; induction tr; simpl in *; intuition.
- repeat break_match; subst; simpl in *; intuition; try congruence.
break_if; repeat (do_bool; intuition); try congruence.
destruct k; subst; simpl in *; intuition.
- repeat break_match; subst; simpl in *; intuition; try congruence.
+ destruct k.
match goal with
| |- context [ I (?x, ?y) = I (?x', ?y') ] =>
destruct (op_eq_dec (I (x, y)) (I (x', y')))
end; subst; intuition.
right.
intuition; try congruence.
apply before_remove_if; intuition.
+ break_if; try congruence.
apply before_app_if; [apply before_remove_all_if|]; auto.
* intuition. find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap. break_exists.
break_match; intuition; congruence.
* intuition.
match goal with
| H : _ -> False |- False => apply H
end.
find_apply_lem_hyp in_dedup_was_in.
find_apply_lem_hyp In_filterMap.
break_exists. intuition. break_match; try congruence.
find_inversion.
unfold key_in_output_list. simpl.
eexists; eauto.
Qed.
Proof using iboi.
intros.
find_apply_lem_hyp in_import_in_trace_O.
find_eapply_lem_hyp output_implies_input_before_output; eauto.
eauto using input_before_output_import.
Qed.
Proof using.
intros. induction l; simpl in *; intuition.
repeat break_match; subst; compute; simpl; f_equal; auto.
Qed.
Proof using.
intros. induction l; simpl in *; intuition.
repeat break_match; subst; compute; simpl; f_equal; auto.
Qed.
Proof using.
induction l; intros; simpl in *; intuition.
repeat break_match; simpl in *; do_bool; intuition; subst; eauto;
repeat find_rewrite; repeat find_inversion; intuition.
- destruct (clientId_eq_dec (eClient e) (eClient a)); repeat find_rewrite.
* find_injection.
eapply IHl with (id := eId a) in H1; try lia.
repeat find_rewrite. eauto using get_set_same.
* eapply IHl with (id := id) in H1; try lia.
rewrite get_set_diff; auto.
- congruence.
- destruct (clientId_eq_dec (eClient e) (eClient a)); repeat find_rewrite.
* congruence.
* eapply IHl with (id := id) in H1; try lia.
rewrite get_set_diff; auto.
Qed.
Proof using.
induction l; intros.
- simpl in *. constructor.
- simpl in *. repeat break_match; eauto.
+ simpl in *. constructor; eauto.
intuition. do_in_map. find_inversion.
eapply deduplicate_log'_ks with (id := eId a) in H0; try lia.
repeat find_rewrite.
rewrite get_set_same. auto.
+ simpl in *. constructor; eauto.
intuition. do_in_map. find_inversion.
eapply deduplicate_log'_ks with (id := eId a) in H0; try lia.
repeat find_rewrite.
rewrite get_set_same. auto.
Qed.
Proof using.
eauto using NoDup_deduplicate_log'.
Qed.
Proof using.
intros.
rewrite get_IR_input_keys_log_to_IR.
eauto using NoDup_deduplicate_log.
Qed.
Proof using.
intros.
rewrite get_IR_output_keys_log_to_IR.
eauto using NoDup_deduplicate_log.
Qed.
Hint Constructors exported : core.
Proof using.
induction 1; intros; simpl; auto.
Qed.
Proof using.
induction 1; intros; simpl; auto.
Qed.
Proof using.
induction xs; intros; simpl; intuition.
repeat break_match; subst; simpl; auto using f_equal.
Qed.
Proof using.
induction l using rev_ind; intros; simpl in *.
- rewrite app_nil_r.  auto.
- rewrite execute_log'_app. simpl. repeat break_let.
simpl.
eapply_prop_hyp execute_log execute_log; auto.
+ find_rewrite. simpl in *.
rewrite <- app_ass.
rewrite log_to_IR_app.
simpl.
specialize (H x). conclude_using eauto.
specialize (H0 l [] x l0 d).
break_match; subst; simpl in *.
rewrite app_nil_r.
break_match.
* specialize (H0 o o0 d0). repeat concludes.
apply exported_snoc_IO; congruence.
* apply exported_snoc_IU; auto.
+ intros. apply H. intuition.
+ intros. subst. eapply (H0 _ (ys ++ [x])).
rewrite app_ass. simpl. eauto.
eauto.
eauto.
eauto.
Qed.
Proof using.
intros.
unfold execute_log.
change (log_to_IR env_o l) with (log_to_IR env_o ([] ++ l)).
eapply exported_execute_log'; eauto.
Qed.
Definition input_correct (tr : list (name * (raft_input + list raft_output))) : Prop :=
(forall client id i i' h h',
In (h, inl (ClientRequest client id i)) tr ->
In (h', inl (ClientRequest client id i')) tr ->
i = i').
Proof using.
unfold in_input_trace, input_correct.
induction tr; intros; break_exists; simpl in *; intuition; subst;
repeat break_match; intuition; subst; eauto 10 using f_equal.
Qed.

Lemma get_output_in_output_trace :
forall tr client id o,
get_output tr (client, id) = Some o ->
in_output_trace client id o tr.