Theory Stellar_Quorums
text 
‹This theory formalizes some of the results appearing in the paper "Stellar Consensus By Reduction"\<^cite>‹"disc_paper"›.
We prove static properties of personal Byzantine quorum systems and Stellar quorum systems.›
theory Stellar_Quorums
  imports Main 
begin
section "Personal Byzantine quorum systems"
locale personal_quorums =
  fixes quorum_of :: "'node ⇒ 'node set ⇒ bool" 
  assumes quorum_assm:"⋀ p p' . ⟦quorum_of p Q; p' ∈ Q⟧ ⟹ quorum_of p' Q"
    
begin
definition blocks where
  
  "blocks R p ≡ ∀ Q . quorum_of p Q ⟶ Q ∩ R ≠ {}"
abbreviation blocked_by where "blocked_by R ≡ {p . blocks R p}"
lemma blocked_blocked_subset_blocked:
  "blocked_by (blocked_by R) ⊆ blocked_by R"
proof -
  have False if "p ∈ blocked_by (blocked_by R)" and "p ∉ blocked_by R" for p
  proof -
    have "Q ∩ blocked_by R ≠ {}" if "quorum_of p Q" for Q
      using ‹p ∈ blocked_by (blocked_by R)› that unfolding blocks_def by auto
    have "Q ∩ R ≠ {}" if " quorum_of p Q" for Q
    proof -
      obtain p' where "p' ∈ blocked_by R" and "p' ∈ Q"
        by (meson Int_emptyI ‹⋀Q. quorum_of p Q ⟹ Q ∩ blocked_by R ≠ {}› ‹quorum_of p Q›)
      hence "quorum_of p' Q"
        using quorum_assm that by blast
      with ‹p' ∈ blocked_by R› show "Q ∩ R ≠ {}"
        using blocks_def by auto
    qed
    hence "p ∈ blocked_by R" by (simp add: blocks_def)
    thus False using that(2) by auto
  qed
  thus "blocked_by (blocked_by R) ⊆ blocked_by R"
    by blast
qed
end
text ‹We now add the set of correct participants to the model.›
locale with_w = personal_quorums quorum_of for quorum_of  :: "'node ⇒ 'node set ⇒ bool" +
  fixes W::"'node set" 
begin
abbreviation B where "B ≡ -W"
  
definition quorum_of_set where "quorum_of_set S Q ≡ ∃ p ∈ S . quorum_of p Q"
subsection "The set of participants not blocked by malicious participants"
definition L where "L ≡ W - (blocked_by B)"
lemma l2: "p ∈ L ⟹ ∃ Q  ⊆ W. quorum_of p Q" 
  unfolding L_def blocks_def using DiffD2 by auto
 
lemma l3: 
  assumes "p ∈ L" shows "∃ Q ⊆ L . quorum_of p Q"
proof -
  have False if "⋀ Q . quorum_of p Q ⟹ Q ∩ (-L) ≠ {}"
  proof -
    obtain Q where "quorum_of p Q" and "Q ⊆ W" 
      using l2 ‹p ∈ L› by auto 
    have "Q ∩ (-L) ≠ {}"  using that ‹quorum_of p Q› by simp
    obtain p' where "p' ∈ Q ∩ (-L)" and "quorum_of p' Q"
      using ‹Q ∩ - L ≠ {}› ‹quorum_of p Q› inf.left_idem quorum_assm by fastforce 
    hence "Q ∩ B ≠ {}" unfolding L_def
      using CollectD Compl_Diff_eq Int_iff inf_le1 personal_quorums.blocks_def personal_quorums_axioms subset_empty by fastforce
    thus False using ‹Q ⊆ W› by auto  
  qed 
  thus ?thesis by (metis disjoint_eq_subset_Compl double_complement)
qed
subsection "Consensus clusters and intact sets"
definition is_intertwined where
  
  "is_intertwined S ≡ S ⊆ W 
    ∧ (∀ Q Q' . quorum_of_set S Q ∧ quorum_of_set S Q' ⟶ W ∩ Q ∩ Q' ≠ {})"
definition is_cons_cluster where
  
  "is_cons_cluster C ≡ C ⊆ W ∧ (∀ p ∈ C . ∃ Q ⊆ C . quorum_of p Q)
      ∧ (∀ Q Q' . quorum_of_set C Q ∧ quorum_of_set C Q' ⟶ W ∩ Q ∩ Q' ≠ {})"
definition strong_consensus_cluster where
  "strong_consensus_cluster I ≡ I ⊆ W ∧ (∀ p ∈ I . ∃ Q ⊆ I . quorum_of p Q)
      ∧ (∀ Q Q' . quorum_of_set I Q ∧ quorum_of_set I Q' ⟶ I ∩ Q ∩ Q' ≠ {})"
lemma strong_consensus_cluster_imp_cons_cluster:
  shows "strong_consensus_cluster I ⟹ is_cons_cluster I" 
  unfolding strong_consensus_cluster_def is_cons_cluster_def
  by blast 
lemma cons_cluster_neq_cons_cluster:
  
  shows "is_cons_cluster I ∧ (∀ J . I ⊆ J ⟶ ¬strong_consensus_cluster J)" nitpick[falsify=false, card 'node=3, expect=genuine]
  oops
text ‹Next we show that the union of two consensus clusters that intersect is a consensus cluster.›
theorem cluster_union:
  assumes "is_cons_cluster C⇩1" and "is_cons_cluster C⇩2" and "C⇩1 ∩ C⇩2 ≠ {}"
  shows "is_cons_cluster (C⇩1∪ C⇩2)"
proof -
  have "C⇩1 ∪ C⇩2 ⊆ W"
    using assms(1) assms(2) is_cons_cluster_def by auto 
  moreover
  have "∀ p ∈ (C⇩1∪C⇩2) . ∃ Q ⊆ (C⇩1∪C⇩2) . quorum_of p Q" 
    using ‹is_cons_cluster C⇩1› ‹is_cons_cluster C⇩2› unfolding is_cons_cluster_def
    by (meson UnE le_supI1 le_supI2)
  moreover
  have "W ∩ Q⇩1 ∩ Q⇩2 ≠ {}"
    if "quorum_of_set (C⇩1∪C⇩2) Q⇩1" and "quorum_of_set (C⇩1∪C⇩2) Q⇩2" 
    for Q⇩1 Q⇩2
  proof -
    have "W ∩ Q⇩1 ∩ Q⇩2 ≠ {}" if "quorum_of_set C Q⇩1" and "quorum_of_set C Q⇩2" and "C = C⇩1 ∨ C = C⇩2" for C
      using ‹is_cons_cluster C⇩1› ‹is_cons_cluster C⇩2› ‹quorum_of_set (C⇩1∪C⇩2) Q⇩1› ‹quorum_of_set (C⇩1∪C⇩2) Q⇩2› that
      unfolding quorum_of_set_def is_cons_cluster_def by metis
    moreover
    have ‹W ∩ Q⇩1 ∩ Q⇩2 ≠ {}›  if "is_cons_cluster C⇩1" and "is_cons_cluster C⇩2"
      and "C⇩1 ∩ C⇩2 ≠ {}" and "quorum_of_set C⇩1 Q⇩1" and "quorum_of_set C⇩2 Q⇩2"
    for C⇩1 C⇩2 
    proof -
      obtain p Q where "quorum_of p Q" and "p ∈ C⇩1 ∩ C⇩2" and "Q ⊆ C⇩2" 
        using ‹C⇩1 ∩ C⇩2 ≠ {}› ‹is_cons_cluster C⇩2› unfolding is_cons_cluster_def by blast
      have "Q ∩ Q⇩1 ≠ {}" using ‹is_cons_cluster C⇩1› ‹quorum_of_set C⇩1 Q⇩1› ‹quorum_of p Q› ‹p ∈ C⇩1 ∩ C⇩2›
        unfolding is_cons_cluster_def quorum_of_set_def
        by (metis Int_assoc Int_iff inf_bot_right)
      hence "quorum_of_set C⇩2 Q⇩1"  using ‹Q ⊆ C⇩2› ‹quorum_of_set C⇩1 Q⇩1› quorum_assm unfolding quorum_of_set_def by blast 
      thus "W ∩ Q⇩1 ∩ Q⇩2 ≠ {}" using ‹is_cons_cluster C⇩2› ‹quorum_of_set C⇩2 Q⇩2›
        unfolding is_cons_cluster_def by blast
    qed
    ultimately show ?thesis using assms that unfolding quorum_of_set_def by auto 
  qed
  ultimately show ?thesis using assms
    unfolding is_cons_cluster_def by simp
qed
text ‹Similarly, the union of two strong consensus clusters is a strong consensus cluster.›
lemma strong_cluster_union:
  assumes "strong_consensus_cluster C⇩1" and "strong_consensus_cluster C⇩2" and "C⇩1 ∩ C⇩2 ≠ {}"
  shows "strong_consensus_cluster (C⇩1∪ C⇩2)"
proof -
  have "C⇩1 ∪ C⇩2 ⊆ W"
    using assms(1) assms(2) strong_consensus_cluster_def by auto 
  moreover
  have "∀ p ∈ (C⇩1∪C⇩2) . ∃ Q ⊆ (C⇩1∪C⇩2) . quorum_of p Q" 
    using ‹strong_consensus_cluster C⇩1› ‹strong_consensus_cluster C⇩2› unfolding strong_consensus_cluster_def
    by (meson UnE le_supI1 le_supI2)
  moreover
  have "(C⇩1∪C⇩2) ∩ Q⇩1 ∩ Q⇩2 ≠ {}"
    if "quorum_of_set (C⇩1∪C⇩2) Q⇩1" and "quorum_of_set (C⇩1∪C⇩2) Q⇩2" 
    for Q⇩1 Q⇩2
  proof -
    have "C ∩ Q⇩1 ∩ Q⇩2 ≠ {}" if "quorum_of_set C Q⇩1" and "quorum_of_set C Q⇩2" and "C = C⇩1 ∨ C = C⇩2" for C
      using ‹strong_consensus_cluster C⇩1› ‹strong_consensus_cluster C⇩2› that
      unfolding quorum_of_set_def strong_consensus_cluster_def by metis
    hence "(C⇩1∪C⇩2) ∩ Q⇩1 ∩ Q⇩2 ≠ {}" if "quorum_of_set C Q⇩1" and "quorum_of_set C Q⇩2" and "C = C⇩1 ∨ C = C⇩2" for C
      by (metis Int_Un_distrib2 disjoint_eq_subset_Compl sup.boundedE that)
    moreover
    have ‹(C⇩1∪C⇩2) ∩ Q⇩1 ∩ Q⇩2 ≠ {}›  if "strong_consensus_cluster C⇩1" and "strong_consensus_cluster C⇩2"
      and "C⇩1 ∩ C⇩2 ≠ {}" and "quorum_of_set C⇩1 Q⇩1" and "quorum_of_set C⇩2 Q⇩2"
    for C⇩1 C⇩2 
    proof -
      obtain p Q where "quorum_of p Q" and "p ∈ C⇩1 ∩ C⇩2" and "Q ⊆ C⇩2" 
        using ‹C⇩1 ∩ C⇩2 ≠ {}› ‹strong_consensus_cluster C⇩2› unfolding strong_consensus_cluster_def by blast
      have "Q ∩ Q⇩1 ≠ {}" using ‹strong_consensus_cluster C⇩1› ‹quorum_of_set C⇩1 Q⇩1› ‹quorum_of p Q› ‹p ∈ C⇩1 ∩ C⇩2›
        unfolding strong_consensus_cluster_def quorum_of_set_def
        by (metis Int_assoc Int_iff inf_bot_right)
      hence "quorum_of_set C⇩2 Q⇩1"  using ‹Q ⊆ C⇩2› ‹quorum_of_set C⇩1 Q⇩1› quorum_assm unfolding quorum_of_set_def by blast 
      thus "(C⇩1∪C⇩2) ∩ Q⇩1 ∩ Q⇩2 ≠ {}" using ‹strong_consensus_cluster C⇩2› ‹quorum_of_set C⇩2 Q⇩2›
        unfolding strong_consensus_cluster_def by blast
    qed
    ultimately show ?thesis using assms that unfolding quorum_of_set_def by auto 
  qed
  ultimately show ?thesis using assms
    unfolding strong_consensus_cluster_def by simp
qed
end
section "Stellar quorum systems"
locale stellar =
  fixes slices :: "'node ⇒ 'node set set" 
    and W :: "'node set" 
  assumes slices_ne:"⋀p . p ∈ W ⟹ slices p ≠ {}"
begin
definition quorum where
  "quorum Q ≡ ∀ p ∈ Q ∩ W . (∃ Sl ∈ slices p . Sl ⊆ Q)"
definition quorum_of where "quorum_of p Q ≡ quorum Q ∧ (p ∉ W ∨ (∃ Sl ∈ slices p . Sl ⊆ Q))"
  
lemma quorum_union:"quorum Q ⟹ quorum Q' ⟹ quorum (Q ∪ Q')"
  unfolding quorum_def
  by (metis IntE Int_iff UnE inf_sup_aci(1) sup.coboundedI1 sup.coboundedI2)
lemma l1:
  assumes "⋀ p . p ∈ S ⟹ ∃ Q ⊆ S . quorum_of p Q" and "p∈ S"
  shows "quorum_of p S" using assms unfolding quorum_of_def quorum_def
  by (meson Int_iff subset_trans)
lemma is_pbqs:
  assumes "quorum_of p Q" and "p' ∈ Q"
  shows "quorum_of p' Q" 
  
  using assms
  by (simp add: quorum_def quorum_of_def)
interpretation with_w quorum_of 
  
  unfolding with_w_def personal_quorums_def 
  quorum_def quorum_of_def by simp
lemma quorum_is_quorum_of_some_slice:
  assumes "quorum_of p Q" and "p ∈ W"
  obtains S where "S ∈ slices p" and "S ⊆ Q"
    and "⋀ p' . p' ∈ S ∩ W ⟹ quorum_of p' Q"
  using assms unfolding quorum_def quorum_of_def by fastforce
lemma "is_cons_cluster C ⟹ quorum C" 
  
  unfolding is_cons_cluster_def
  by (metis inf.order_iff l1 quorum_of_def stellar.quorum_def stellar_axioms) 
subsection ‹Properties of blocking sets›
inductive blocking_min where
  
  "⟦p ∈ W; ∀ Sl ∈ slices p . ∃ q ∈ Sl∩W . q ∈ R ∨ blocking_min R q⟧ ⟹ blocking_min R p"
inductive_cases blocking_min_elim:"blocking_min R p"
inductive blocking_max where
  
  "⟦p ∈ W; ∀ Sl ∈ slices p . ∃ q ∈ Sl . q ∈ R∪B ∨ blocking_max R q⟧ ⟹ blocking_max R p"
inductive_cases "blocking_max R p"
text ‹Next we show that if @{term ‹R›} blocks @{term ‹p›} and @{term p} belongs to a consensus cluster @{term S}, then @{term ‹R ∩ S ≠ {}›}.›
text ‹We first prove two auxiliary lemmas:›
lemma cons_cluster_wb:"p ∈ C ⟹ is_cons_cluster C ⟹ p∈W"
  using is_cons_cluster_def  by fastforce 
lemma cons_cluster_has_ne_slices:
  assumes "is_cons_cluster C" and "p∈C"
    and "Sl ∈ slices p" 
  shows "Sl ≠ {}"
  using assms unfolding is_cons_cluster_def quorum_of_set_def quorum_of_def quorum_def
  by (metis empty_iff inf_bot_left inf_bot_right subset_refl)
lemma cons_cluster_has_cons_cluster_slice:
  assumes "is_cons_cluster C" and "p∈C"
  obtains Sl where "Sl ∈ slices p" and "Sl ⊆ C"
  using assms unfolding is_cons_cluster_def quorum_of_set_def quorum_of_def quorum_def
  by (metis Int_commute  empty_iff inf.order_iff  inf_bot_right le_infI1)
theorem blocking_max_intersects_intact:
  
  assumes  "blocking_max R p" and "is_cons_cluster C" and "p ∈ C"
  shows "R ∩ C ≠ {}" using assms
proof (induct)
  case (1 p R)
  obtain Sl where "Sl ∈ slices p" and "Sl ⊆ C" using cons_cluster_has_cons_cluster_slice
    using "1.prems" by blast
  moreover have "Sl ⊆ W" using assms(2) calculation(2) is_cons_cluster_def by auto 
  ultimately show ?case
    using "1.hyps" assms(2) by fastforce
qed
text ‹Now we show that if @{term ‹p ∈ C›}, @{term C} is a consensus cluster, and quorum @{term Q} is such that @{term ‹Q ∩ C ≠ {}›},
    then @{term ‹Q ∩ W›} blocks @{term p}. 
We start by defining the set of participants reachable from a participant through correct participants.
Their union trivially forms a quorum. 
Moreover, if @{term p} is not blocked by a set @{term R}, 
then we show that the set of participants reachable from @{term p} and not blocked by @{term R} forms a quorum disjoint from @{term R}.
It follows that if @{term p } is a member of a consensus cluster @{term C} and @{term Q} is a quorum of a member of @{term C}, then @{term "Q∩W"}
 must block @{term p}, as otherwise quorum intersection would be violated. ›
inductive not_blocked for p R where
  "⟦Sl ∈ slices p; ∀ q ∈ Sl∩W . q ∉ R ∧ ¬blocking_min R q; q ∈ Sl⟧ ⟹ not_blocked p R q"
| "⟦not_blocked p R p'; p' ∈ W; Sl ∈ slices p'; ∀ q ∈ Sl∩W . q ∉ R ∧ ¬blocking_min R q; q ∈ Sl⟧ ⟹ not_blocked p R q"
inductive_cases not_blocked_cases:"not_blocked p R q"
lemma l4:
  fixes Q p R
  defines "Q ≡ {q . not_blocked p R q}"
  shows "quorum Q"
proof -
  have "∃ S ∈ slices n . S ⊆ Q" if "n∈Q∩W" for n
  proof-
    have "not_blocked p R n" using assms that by blast
    hence "n ∉ R" and "¬blocking_min R n" by (metis Int_iff not_blocked.simps that)+
    thus ?thesis  using blocking_min.intros not_blocked.intros(2) that unfolding Q_def 
      by (simp; metis mem_Collect_eq subsetI)
  qed
  thus ?thesis by (simp add: quorum_def)
qed
lemma l5:
  fixes Q p R
  defines "Q ≡ {q . not_blocked p R q}"
  assumes  "¬blocking_min R p" and ‹p∈C› and ‹is_cons_cluster C›
  shows "quorum_of p Q" 
proof -
  have "p∈W"
    using assms(3,4) cons_cluster_wb by blast 
  obtain Sl where "Sl ∈ slices p" and "∀ q ∈ Sl∩W . q ∉ R ∧ ¬blocking_min R q"
    by (meson ‹p ∈ W› assms(2) blocking_min.intros)
  hence "Sl ⊆ Q" unfolding Q_def using not_blocked.intros(1) by blast
  with l4 ‹Sl ∈ slices p› show "quorum_of p Q"
    using Q_def  quorum_of_def by blast
qed
lemma cons_cluster_ne_slices:
  assumes "is_cons_cluster C" and "p∈C" and "Sl ∈ slices p"
  shows "Sl≠{}"
  using assms cons_cluster_has_ne_slices cons_cluster_wb stellar.quorum_of_def stellar_axioms by fastforce
lemma l6:
  fixes Q p R
  defines "Q ≡ {q . not_blocked p R q}"
  shows "Q ∩ R ∩ W = {}"
proof -
  have "q ∉ R" if "not_blocked p R q" and "q∈ W" for q using that
    by (metis Int_iff not_blocked.simps)
  thus ?thesis unfolding Q_def by auto
qed
theorem quorum_blocks_cons_cluster:
  assumes "quorum_of_set C Q" and "p∈C" and "is_cons_cluster C"
  shows "blocking_min (Q ∩ W) p"
proof (rule ccontr) 
  assume "¬ blocking_min (Q ∩ W) p"
  have "p∈W" using assms(2,3) is_cons_cluster_def by auto 
  define Q' where "Q' ≡ {q . not_blocked p (Q∩W) q}"
  have "quorum_of p Q'" using Q'_def ‹¬ blocking_min (Q ∩ W) p› assms(2) assms(3) l5(1) by blast
  moreover have "Q' ∩ Q ∩ W = {}"
    using Q'_def l6 by fastforce
  ultimately show False using assms unfolding is_cons_cluster_def
    by (metis Int_commute inf_sup_aci(2) quorum_of_set_def) 
qed
subsection ‹Reachability through a set›
text ‹Here we define the part of a quorum @{term Q} of @{term p} that is reachable through correct
participants from @{term p}. We show that if @{term p} and @{term p'} are members of the same consensus cluster and @{term Q} is a quorum of @{term p}
 and @{term Q'} is a quorum of @{term p'},
then the intersection @{term "Q∩Q'∩W"} is reachable from both @{term p} and @{term p'} through the consensus cluster.›
inductive reachable_through for p S where
  "reachable_through p S p"
| "⟦reachable_through p S p'; p' ∈ W; Sl ∈ slices p'; Sl ⊆ S; p'' ∈ Sl⟧ ⟹ reachable_through p S p''"
definition truncation where "truncation p S ≡ {p' . reachable_through p S p'}"
lemma l13:
  assumes "quorum_of p Q" and "p ∈ W" and "reachable_through p Q p'"
  shows "quorum_of p' Q"
  using assms using quorum_assm reachable_through.cases
  by (metis is_pbqs subset_iff)
lemma l14:
  assumes "quorum_of p Q" and "p ∈ W"
  shows "quorum (truncation p Q)"
proof -
  have "∃ S ∈ slices p' . ∀ q ∈ S . reachable_through p Q q" if "reachable_through p Q p'" and "p' ∈ W" for p'
    by (meson assms l13 quorum_is_quorum_of_some_slice stellar.reachable_through.intros(2) stellar_axioms that)
  thus ?thesis
    by (metis IntE mem_Collect_eq stellar.quorum_def stellar_axioms subsetI truncation_def)  
qed
lemma l15:
  assumes "is_cons_cluster I" and "quorum_of p Q" and "quorum_of p' Q'" and "p ∈ I" and "p' ∈ I" and "Q ∩ Q' ∩ W ≠ {}"
  shows "W ∩ (truncation p Q) ∩ (truncation p' Q') ≠ {}" 
proof -
  have "quorum (truncation p Q)" and "quorum (truncation p' Q')" using l14 assms is_cons_cluster_def by auto
  moreover have "quorum_of_set I (truncation p Q)" and "quorum_of_set I (truncation p' Q')"
    by (metis IntI assms(4,5) calculation mem_Collect_eq quorum_def quorum_of_def quorum_of_set_def reachable_through.intros(1) truncation_def)+
  moreover note ‹is_cons_cluster I›
  ultimately show ?thesis unfolding is_cons_cluster_def by auto
qed
end
subsection "Elementary quorums"
text ‹In this section we define the notion of elementary quorum, which is a quorum that has no strict subset that is a quorum.
  It follows directly from the definition that every finite quorum contains an elementary quorum. Moreover, we show 
that if @{term Q} is an elementary quorum and @{term n⇩1} and @{term n⇩2} are members of @{term Q}, then @{term n⇩2} is reachable from @{term n⇩1} 
in the directed graph over participants defined as the set of edges @{term "(n,m)"} such that @{term m} is a member of a slice of @{term n}.
This lemma is used in the companion paper to show that probabilistic leader-election is feasible.›
locale elementary = stellar
begin 
definition elementary where
  "elementary s ≡ quorum s ∧ (∀ s' . s' ⊂ s ⟶ ¬quorum s')"
lemma finite_subset_wf:
  shows "wf {(X, Y). X ⊂ Y ∧ finite Y}"
  by (metis finite_psubset_def wf_finite_psubset)
lemma quorum_contains_elementary:
  assumes "finite s" and  "¬ elementary s" and "quorum s" 
  shows "∃ s' . s' ⊂ s ∧ elementary s'" using assms
proof (induct s rule:wf_induct[where ?r="{(X, Y). X ⊂ Y ∧ finite Y}"])
  case 1
  then show ?case using finite_subset_wf by simp
next
  case (2 x)
  then show ?case
    by (metis (full_types) elementary_def finite_psubset_def finite_subset in_finite_psubset less_le psubset_trans)
qed
inductive path where
  "path []"
| "⋀ x . path [x]"
| "⋀ l n . ⟦path l; S ∈ Q (hd l); n ∈ S⟧ ⟹ path (n#l)"
theorem elementary_connected:
  assumes "elementary s" and "n⇩1 ∈ s" and "n⇩2 ∈ s" and "n⇩1 ∈ W" and "n⇩2 ∈ W"
  shows "∃ l . hd (rev l) = n⇩1 ∧ hd l = n⇩2 ∧ path l" (is ?P)
proof -
  { assume "¬?P"
    define x where "x ≡ {n ∈ s . ∃ l . l ≠ [] ∧ hd (rev l) = n⇩1 ∧ hd l = n ∧ path l}"
    have "n⇩2 ∉ x" using ‹¬?P› x_def by auto 
    have "n⇩1 ∈ x" unfolding x_def using assms(2) path.intros(2) by force
    have "quorum x"
    proof -
      { fix n
        assume "n ∈ x"
        have "∃ S . S ∈ slices n ∧ S ⊆ x"
        proof -
          obtain S where "S ∈ slices n" and "S ⊆ s" using ‹elementary s› ‹n ∈ x› unfolding x_def
            by (force simp add:elementary_def quorum_def)
          have "S ⊆ x"
          proof -
            { assume "¬ S ⊆ x"
              obtain m where "m ∈ S" and "m ∉ x" using ‹¬ S ⊆ x› by auto
              obtain l' where "hd (rev l') = n⇩1" and "hd l' = n" and "path l'" and "l' ≠ []"
                using ‹n ∈ x› x_def by blast 
              have "path (m # l')" using ‹path l'› ‹m∈ S› ‹S ∈ slices n› ‹hd l' = n›
                using path.intros(3) by fastforce
              moreover have "hd (rev (m # l')) = n⇩1" using ‹hd (rev l') = n⇩1› ‹l' ≠ []› by auto
              ultimately have "m ∈ x" using ‹m ∈ S› ‹S ⊆ s› x_def by auto 
              hence False using ‹m ∉ x› by blast }
            thus ?thesis by blast
          qed
          thus ?thesis
            using ‹S ∈ slices n› by blast
        qed }
      thus ?thesis by (meson Int_iff quorum_def)
    qed 
    moreover have "x ⊂ s"
      using ‹n⇩2 ∉ x› assms(3) x_def by blast
    ultimately have False using ‹elementary s›
      using elementary_def by auto
  }
  thus ?P by blast  
qed
end
subsection ‹The intact sets of the Stellar Whitepaper›
definition project where 
  "project slices S n ≡ {Sl ∩ S | Sl . Sl ∈ slices n}" 
  
subsubsection ‹Intact and the Cascade Theorem›
locale intact = 
  orig:stellar slices W 
  + proj:stellar "project slices I" W 
  for slices W I +  
  assumes intact_wb:"I ⊆ W"
    and q_avail:"orig.quorum I" 
    and q_inter:"⋀ Q Q' . ⟦proj.quorum Q; proj.quorum Q'; Q ∩ I ≠ {}; Q' ∩ I ≠ {}⟧  ⟹ Q ∩ Q' ∩ I ≠ {}" 
    
begin
theorem blocking_safe: 
  fixes S n
  assumes "n∈I" and "∀ Sl∈ slices n .Sl∩S ≠ {}"
  shows "S ∩ I ≠ {}"
  using assms q_avail intact_wb unfolding orig.quorum_def 
  by auto (metis inf.absorb_iff2 inf_assoc inf_bot_right inf_sup_aci(1)) 
theorem cascade:
  fixes U S
  assumes "orig.quorum U" and "U ∩ I ≠ {}" and "U ⊆ S"
  obtains "I ⊆ S" | "∃ n ∈ I - S . ∀ Sl ∈ slices n . Sl ∩ S ∩ I ≠ {}"
proof -
  have False if 1:"∀ n ∈ I - S . ∃ Sl ∈ slices n . Sl ∩ S ∩ I = {}" and 2:"¬(I ⊆ S)"
  proof -
    text ‹First we show that @{term ‹I-S›} is a quorum in the projected system. This is immediate from the definition of quorum and assumption 1.›
    have "proj.quorum (I-S)" using 1
      by (simp add: proj.quorum_def project_def) (metis DiffI IntE IntI empty_iff subsetI)
    text ‹Then we show that U is also a quorum in the projected system:›
    moreover have "proj.quorum U" using ‹orig.quorum U› 
      unfolding proj.quorum_def orig.quorum_def project_def 
      by (simp; meson Int_commute inf.coboundedI2)
    text ‹Since quorums of @{term I} must intersect, we get a contradiction:›
    ultimately show False using ‹U ⊆ S› ‹U ∩ I ≠ {}› ‹¬(I⊆S)› q_inter by auto
  qed
  thus ?thesis using that by blast
qed
end
subsubsection "The Union Theorem"
text ‹Here we prove that the union of two intact sets that intersect is intact.
This implies that maximal intact sets are disjoint.›
locale intersecting_intact = 
  i1:intact slices W I⇩1 + i2:intact slices W I⇩2 
  + proj:stellar "project slices (I⇩1∪I⇩2)" W 
  for slices W I⇩1 I⇩2 +
assumes inter:"I⇩1 ∩ I⇩2 ≠ {}"
begin
theorem union_quorum: "i1.orig.quorum (I⇩1∪I⇩2)" 
  using i1.intact_axioms i2.intact_axioms
  unfolding  intact_def stellar_def intact_axioms_def i1.orig.quorum_def
  by (metis Int_iff Un_iff le_supI1 le_supI2)
theorem union_quorum_intersection: 
  assumes "proj.quorum Q⇩1" and "proj.quorum Q⇩2" and "Q⇩1 ∩ (I⇩1∪I⇩2) ≠ {}" and "Q⇩2 ∩ (I⇩1∪I⇩2) ≠ {}"
  shows "Q⇩1 ∩ Q⇩2 ∩ (I⇩1∪I⇩2) ≠ {}"
    
proof -
  text ‹First we show that @{term Q⇩1} and @{term Q⇩2} are quorums in the projections on @{term I⇩1} and @{term I⇩2}.›
  have "i1.proj.quorum Q⇩1" using ‹proj.quorum Q⇩1› 
    unfolding i1.proj.quorum_def proj.quorum_def project_def
    by auto (metis Int_Un_distrib Int_iff Un_subset_iff) 
  moreover have "i2.proj.quorum Q⇩2" using ‹proj.quorum Q⇩2› 
    unfolding i2.proj.quorum_def proj.quorum_def project_def
    by auto (metis Int_Un_distrib Int_iff Un_subset_iff) 
  moreover have "i2.proj.quorum Q⇩1" using ‹proj.quorum Q⇩1›
    unfolding proj.quorum_def i2.proj.quorum_def project_def
    by auto (metis Int_Un_distrib Int_iff Un_subset_iff) 
  moreover have "i1.proj.quorum Q⇩2" using ‹proj.quorum Q⇩2›
    unfolding proj.quorum_def i1.proj.quorum_def project_def
    by auto (metis Int_Un_distrib Int_iff Un_subset_iff) 
  text ‹Next we show that @{term Q⇩1} and @{term Q⇩2} intersect if they are quorums of, respectively, @{term I⇩1} and @{term I⇩2}. 
This is the only interesting part of the proof.› 
  moreover have "Q⇩1 ∩ Q⇩2 ∩ (I⇩1∪I⇩2) ≠ {}" 
    if "i1.proj.quorum Q⇩1" and "i2.proj.quorum Q⇩2" and "i2.proj.quorum Q⇩1"
      and "Q⇩1 ∩ I⇩1 ≠ {}" and "Q⇩2 ∩ I⇩2 ≠ {}"
    for Q⇩1 Q⇩2
  proof -
    have "i1.proj.quorum I⇩2" 
    proof -
      have "i1.orig.quorum I⇩2" by (simp add: i2.q_avail)
      thus ?thesis unfolding i1.orig.quorum_def i1.proj.quorum_def project_def
        by auto (meson Int_commute Int_iff inf_le2 subset_trans)
    qed
    moreover note ‹i1.proj.quorum Q⇩1›
    ultimately have "Q⇩1 ∩ I⇩2 ≠ {}" using i1.q_inter inter ‹Q⇩1 ∩ I⇩1 ≠ {}› by blast
    moreover note ‹i2.proj.quorum Q⇩2›  
    moreover note ‹i2.proj.quorum Q⇩1›
    ultimately have "Q⇩1 ∩ Q⇩2 ∩ I⇩2 ≠ {}" using i2.q_inter ‹Q⇩2 ∩ I⇩2 ≠ {}› by blast 
    thus ?thesis by (simp add: inf_sup_distrib1)
  qed
  text ‹Next  we show that @{term Q⇩1} and @{term Q⇩2} intersect if they are quorums of the same intact set. This is obvious.›
  moreover
  have "Q⇩1 ∩ Q⇩2 ∩ (I⇩1∪I⇩2) ≠ {}" 
    if "i1.proj.quorum Q⇩1" and "i1.proj.quorum Q⇩2" and "Q⇩1 ∩ I⇩1 ≠ {}" and "Q⇩2 ∩ I⇩1 ≠ {}"
    for Q⇩1 Q⇩2
    by (simp add: Int_Un_distrib i1.q_inter that)  
  moreover
  have "Q⇩1 ∩ Q⇩2 ∩ (I⇩1∪I⇩2) ≠ {}"
    if "i2.proj.quorum Q⇩1" and "i2.proj.quorum Q⇩2" and "Q⇩1 ∩ I⇩2 ≠ {}" and "Q⇩2 ∩ I⇩2 ≠ {}"
    for Q⇩1 Q⇩2
    by (simp add: Int_Un_distrib i2.q_inter that)
  text ‹Finally we have covered all the cases and get the final result:›
  ultimately
  show ?thesis
    by (smt (verit, best) Int_Un_distrib Int_commute assms(3) assms(4) sup_eq_bot_iff)
qed
end
end