Ltac prove_in :=
    match goal with
      | _ : nwPackets ?net = ?xs ++ ?p :: ?ys,
            p : packet |- _ =>
        assert (In p (nwPackets net)) by (repeat find_rewrite; in_crush)
    end.Ltac contradict_append_entries :=
    match goal with
      | H : is_append_entries _ -> False |- _ =>
        exfalso; apply H; repeat eexists; eauto; repeat find_rewrite; simpl in *; eauto
    end.Ltac ensure_pbody p :=
    try match goal with
          | _ : pBody p = AppendEntries _ _ _ _ _ _ |- _ =>
            fail 1
          | H : context [AppendEntries ?t ?lid ?pli ?plt ?e ?lc] |- _ =>
            assert (pBody p = AppendEntries t lid pli plt e lc) by eauto
        end.Ltac use_nw p :=
    ensure_pbody p;
    match goal with
      | [ Hinv : forall _ _ _ _ _ _ _, In _ _ -> Net.pBody _ = _ -> _,
            H: Net.pBody p = _, net : network |- _ ] =>
        let Hin := fresh "H" in
        cut (In p (nwPackets net)); [intros Hin; apply Hinv in H; clear Hinv; intuition|]; intuition
    end.Ltac use_log_matching_nw_nw' :=
    match goal with
      | [ H : forall _ _ _ _ _ _ _, In _ _ -> _,
            Hp' : Net.pBody ?p' = AppendEntries _ _ _ _ ?entries' _,
            Hp : Net.pBody ?p = _
            |- context [ In _ ?entries' ] ] =>
        apply H in Hp'; clear H; intuition
    end;
    try match goal with
          | [ H : forall _ _ _ _ _ _ _, In _ _ -> _,
              _ : eIndex ?e = eIndex ?e',
              Hp : Net.pBody ?p = _
              |- context [In _ ?entries' ] ] =>
              match (type of H) with
                | context [entries'] =>
                          try (eapply H with (e1:=e)(e2:=e') in Hp; eauto; [idtac]);
                    eapply H with (e1:=e')(e2:=e) in Hp; eauto
              end
        end; intuition.Ltac ensure_sorted :=
    match goal with
      | _ : pBody _ = AppendEntries _ _ _ _ ?es _ |- _ =>
        try match goal with
              | _ : sorted es |- _ =>
                fail 2
            end; assert (sorted es) by eauto
    end.Ltac prep_packets :=
    simpl in *; repeat find_higher_order_rewrite;
    prove_in;
    repeat (find_apply_hyp_hyp; intuition; [|contradict_append_entries];
            match goal with
              | _ : nwPackets ?net = (?xs ++ ?p1 :: ?ys), H : In ?p2 (?xs ++ ?ys) |- _ =>
                let Heq := fresh "H" in
                let p' := fresh "p" in
                remember p2 as p' eqn:Heq; clear Heq;
              assert (In p' (nwPackets net)) by (repeat find_rewrite; in_crush);
              clear H
            end);
    match goal with
      | _ : nwPackets ?net = (?xs ++ ?p1 :: ?ys) |- _ =>
        replace (xs ++ p1 :: ys) with (nwPackets net) in *; subst
    end;
    repeat ensure_sorted.

(* Specifications: *)
Lemma handleAppendEntries_log_matching : raft_net_invariant_append_entries log_matching.
Theorem log_matching_invariant: forall net, raft_intermediate_reachable net -> log_matching net.