Section DecompositionWithPostState.
Context {orig_base_params : BaseParams}.
Context {one_node_params : OneNodeParams orig_base_params}.
Context {raft_params : RaftParams orig_base_params}.
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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
(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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
(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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
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 ->
raft_intermediate_reachable (mkNetwork ps' st') ->
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_reboot' (P : network -> Prop) :=
forall net net' d h d',
reboot d = d' ->
P net ->
raft_intermediate_reachable 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'.

Theorem raft_net_invariant' :
forall P net,
raft_net_invariant_init P ->
raft_net_invariant_client_request' P ->
raft_net_invariant_timeout' P ->
raft_net_invariant_append_entries' P ->
raft_net_invariant_append_entries_reply' P ->
raft_net_invariant_request_vote' P ->
raft_net_invariant_request_vote_reply' P ->
raft_net_invariant_do_leader' P ->
raft_net_invariant_do_generic_server' P ->
raft_net_invariant_state_same_packet_subset P ->
raft_net_invariant_reboot' P ->
raft_intermediate_reachable net ->
P net.