Section Raft.
Context {orig_base_params : BaseParams}.
Context {one_node_params : OneNodeParams orig_base_params}.
Context {raft_params : RaftParams orig_base_params}.
Definition term := nat.
Definition logIndex := nat.
Definition name := fin N.
Definition nodes : list name := all_fin _.
Definition name_eq_dec : forall x y : name, {x = y} + {x <> y} := fin_eq_dec _.
Notation "a >? b" := (b <? a) (at level 70).
Notation "a >=? b" := (b <=? a) (at level 70).
Notation "a == b" := (beq_nat a b) (at level 70).
Notation "a != b" := (negb (beq_nat a b)) (at level 70).
Notation "a === b" := (if fin_eq_dec _ a b then true else false) (at level 42).
Record entry := mkEntry {
eAt : name;
eClient : clientId;
eId : nat;
eIndex : logIndex;
eTerm : term;
eInput : input
}.
Inductive msg : Type :=
| RequestVote : term -> name -> logIndex -> term -> msg
| RequestVoteReply : term -> bool -> msg
| AppendEntries : term -> (name) -> logIndex -> term -> (list entry) -> logIndex -> msg
| AppendEntriesReply : term -> (list entry) -> bool -> msg.
Inductive raft_input : Type :=
| Timeout : raft_input
| ClientRequest : clientId -> nat -> input -> raft_input.
Inductive raft_output : Type :=
| NotLeader : clientId -> nat -> raft_output
| ClientResponse : clientId -> nat -> output -> raft_output.
Inductive serverType : Set :=
| Follower
| Candidate
| Leader.
Definition serverType_eq_dec : forall x y : serverType, {x = y} + {x <> y}.
Proof using.
intros.
replace net with (snd (failed, net)); [|simpl; auto].
eapply step_failure_star_raft_intermediate_reachable'; eauto.
Qed.
Proof using.
intros.
prep_induction H.
induction H using refl_trans_1n_trace_n1_ind; intros; subst.
- find_inversion. auto.
- destruct x'. simpl in *.
eapply RIR_step_failure; [|eauto].
eauto.
Qed.
Definition raft_net_invariant_client_request (P : network -> Prop) :=
forall h net st' ps' out d l client id c,
handleClientRequest h (nwState net h) client id c = (out, d, l) ->
P net ->
raft_intermediate_reachable net ->
(forall h', st' h' = update name_eq_dec (nwState net) h d h') ->
(forall p', In p' ps' -> In p' (nwPackets net) \/
In p' (send_packets h l)) ->
P (mkNetwork ps' st').
Definition raft_net_invariant_timeout (P : network -> Prop) :=
forall net h st' ps' out d l,
handleTimeout h (nwState net h) = (out, d, l) ->
P net ->
raft_intermediate_reachable net ->
(forall h', st' h' = update name_eq_dec (nwState net) h d h') ->
(forall p', In p' ps' -> In p' (nwPackets net) \/
In p' (send_packets h l)) ->
P (mkNetwork ps' st').
Definition raft_net_invariant_append_entries (P : network -> Prop) :=
forall xs p ys net st' ps' d m t n pli plt es ci,
handleAppendEntries (pDst p) (nwState net (pDst p)) t n pli plt es ci = (d, m) ->
pBody p = AppendEntries t n pli plt es ci ->
P net ->
raft_intermediate_reachable net ->
nwPackets net = xs ++ p :: ys ->
(forall h, st' h = update name_eq_dec (nwState net) (pDst p) d h) ->
(forall p', In p' ps' -> In p' (xs ++ ys) \/
p' = mkPacket (pDst p) (pSrc p) m) ->
P (mkNetwork ps' st').
Definition raft_net_invariant_append_entries_reply (P : network -> Prop) :=
forall xs p ys net st' ps' d m t es res,
handleAppendEntriesReply (pDst p) (nwState net (pDst p)) (pSrc p) t es res = (d, m) ->
pBody p = AppendEntriesReply t es res ->
P net ->
raft_intermediate_reachable net ->
nwPackets net = xs ++ p :: ys ->
(forall h, st' h = update name_eq_dec (nwState net) (pDst p) d h) ->
(forall p', In p' ps' -> In p' (xs ++ ys) \/
In p' (send_packets (pDst p) m)) ->
P (mkNetwork ps' st').
Definition raft_net_invariant_request_vote (P : network -> Prop) :=
forall xs p ys net st' ps' d m t cid lli llt,
handleRequestVote (pDst p) (nwState net (pDst p)) t (pSrc p) lli llt  = (d, m) ->
pBody p = RequestVote t cid lli llt ->
P net ->
raft_intermediate_reachable net ->
nwPackets net = xs ++ p :: ys ->
(forall h, st' h = update name_eq_dec (nwState net) (pDst p) d h) ->
(forall p', In p' ps' -> In p' (xs ++ ys) \/
p' = mkPacket (pDst p) (pSrc p) m) ->
P (mkNetwork ps' st').
Definition raft_net_invariant_request_vote_reply (P : network -> Prop) :=
forall xs p ys net st' ps' d t v,
handleRequestVoteReply (pDst p) (nwState net (pDst p)) (pSrc p) t v = d ->
pBody p = RequestVoteReply t v ->
P net ->
raft_intermediate_reachable net ->
nwPackets net = xs ++ p :: ys ->
(forall h, st' h = update name_eq_dec (nwState net) (pDst p) d h) ->
(forall p', In p' ps' -> In p' (xs ++ ys)) ->
P (mkNetwork ps' st').
Definition raft_net_invariant_do_leader (P : network -> Prop) :=
forall net st' ps' d h os d' ms,
doLeader d h = (os, d', ms) ->
P net ->
raft_intermediate_reachable net ->
nwState net h = d ->
(forall h', st' h' = update name_eq_dec (nwState net) h d' h') ->
(forall p, In p ps' -> In p (nwPackets net) \/
In p (send_packets h ms)) ->
P (mkNetwork ps' st').
Definition raft_net_invariant_do_generic_server (P : network -> Prop) :=
forall net st' ps' d os d' ms h,
doGenericServer h d = (os, d', ms) ->
P net ->
raft_intermediate_reachable net ->
nwState net h = d ->
(forall h', st' h' = update name_eq_dec (nwState net) h d' h') ->
(forall p, In p ps' -> In p (nwPackets net) \/
In p (send_packets h ms)) ->
P (mkNetwork ps' st').
Proof using.
intros.
unfold handleMessage in *.
break_match; repeat break_let; repeat find_inversion;
[eapply_prop raft_net_invariant_request_vote|
eapply_prop raft_net_invariant_request_vote_reply|
eapply_prop raft_net_invariant_append_entries|
eapply_prop raft_net_invariant_append_entries_reply]; eauto;
unfold send_packets in *; simpl in *; intros; find_apply_hyp_hyp; intuition.
Qed.
Proof using.
intros.
unfold handleInput in *.
break_match; repeat break_let; repeat find_inversion;
[eapply_prop raft_net_invariant_timeout|
eapply_prop raft_net_invariant_client_request]; eauto;
unfold send_packets in *; simpl in *; intros; find_apply_hyp_hyp; intuition.
Qed.
Definition raft_net_invariant_state_same_packet_subset (P : network -> Prop) :=
forall net net',
(forall h, nwState net h = nwState net' h) ->
(forall p, In p (nwPackets net') -> In p (nwPackets net)) ->
P net ->
raft_intermediate_reachable net ->
P net'.
Definition raft_net_invariant_reboot (P : network -> Prop) :=
forall net net' d h d',
reboot d = d' ->
P net ->
raft_intermediate_reachable net ->
nwState net h = d ->
(forall h', nwState net' h' = update name_eq_dec (nwState net) h d' h') ->
nwPackets net = nwPackets net' ->
P net'.
Definition raft_net_invariant_init (P : network -> Prop) :=
P step_async_init.
Proof using.
intros.
induction H10.
- intuition.
-  match goal with [H : step_failure _ _ _ |- _ ] => invcs H end.
+ unfold RaftNetHandler in *. repeat break_let.
repeat find_inversion.
assert
(raft_intermediate_reachable
{|
nwPackets := (xs ++ ys) ++ (send_packets (pDst p) l0);
nwState := update name_eq_dec (nwState net) (pDst p) r
|}) by (eapply RIR_handleMessage; eauto; in_crush).
assert
(raft_intermediate_reachable
{|
nwPackets := ((xs ++ ys) ++ (send_packets (pDst p) l0)) ++
(send_packets (pDst p) l1) ;
nwState := (update name_eq_dec (update name_eq_dec (nwState net) (pDst p) r) (pDst p) r0)
|}) by (eapply RIR_doLeader; eauto;
[simpl in *; break_if; try congruence; eauto| in_crush]).
eapply_prop raft_net_invariant_do_generic_server. eauto.
eapply_prop raft_net_invariant_do_leader. eauto.
eapply raft_invariant_handle_message with (P := P); eauto using in_app_or.
auto.
simpl. break_if; intuition eauto.
eauto.
simpl. eapply in_app_or. auto.
simpl. break_if; congruence.
simpl. intros.
break_if; subst;
repeat rewrite update_same by auto;
repeat rewrite update_neq by auto; auto.
simpl. in_crush.
+ unfold RaftInputHandler in *. repeat break_let.
repeat find_inversion.
assert
(raft_intermediate_reachable
{|
nwPackets := nwPackets net ++ send_packets h l0;
nwState := update name_eq_dec (nwState net) h r |})
by (eapply RIR_handleInput; eauto; in_crush).
assert
(raft_intermediate_reachable
{|
nwPackets := ((nwPackets net ++ send_packets h l0) ++ send_packets h l2) ;
nwState := update name_eq_dec (update name_eq_dec (nwState net) h r) h r0
|})  by (eapply RIR_doLeader; eauto;
[simpl in *; break_if; try congruence; eauto| in_crush]).
eapply_prop raft_net_invariant_do_generic_server. eauto.
eapply_prop raft_net_invariant_do_leader. eauto.
eapply raft_invariant_handle_input with (P := P); eauto using in_app_or.
auto.
simpl. break_if; intuition eauto.
eauto.
simpl. eapply in_app_or.
auto.
simpl. break_if; congruence.
simpl. intros.
break_if; subst;
repeat rewrite update_same by auto;
repeat rewrite update_neq by auto; auto.
simpl. unfold send_packets.  intros. in_crush.
+ match goal with
| [ H : nwPackets ?net = _ |- _ {| nwPackets := ?ps ; nwState := ?st |} ] =>
assert (forall p, In p (nwPackets {| nwPackets := ps ; nwState := st |}) ->
In p (nwPackets net)) by (intros; simpl in *; find_rewrite; in_crush)
end.
eapply_prop raft_net_invariant_state_same_packet_subset; [|eauto|idtac|];
eauto.
+ match goal with
| [ H : nwPackets ?net = _ |- _ {| nwPackets := ?ps ; nwState := ?st |} ] =>
assert (forall p, In p (nwPackets {| nwPackets := ps ; nwState := st |}) ->
In p (nwPackets net)) by (intros; simpl in *; find_rewrite; in_crush)
end.
eapply_prop raft_net_invariant_state_same_packet_subset; [|eauto|idtac|];
eauto.
+ auto.
+ eapply_prop raft_net_invariant_reboot; eauto;
intros; simpl in *; repeat break_if; intuition; subst; intuition eauto.
- eapply raft_invariant_handle_input; eauto.
- eapply raft_invariant_handle_message; eauto.
- eapply_prop raft_net_invariant_do_leader; eauto.
- eapply_prop raft_net_invariant_do_generic_server; eauto.
Qed.
Proof using.
reflexivity.
Qed.

Lemma reboot_idem :
forall d, reboot (reboot d) = reboot d.